yekonga-server
Version:
Yekonga Server
436 lines (350 loc) • 15 kB
JavaScript
// @ts-nocheck
/*global Yekonga, global.serverLibrary */
const moment = global.serverLibrary.moment;
const path = global.serverLibrary.path;
const { setupMaster, setupWorker } = serverLibrary.socketSticky;
const { createAdapter, setupPrimary } = serverLibrary.socketClusterAdapter;
const Middleware = require('./middleware');
var ioAccount = null;
var ioSync = null;
class Socket {
constructor() {
this.namespace = null;
this.roomId = null;
this.socket = Yekonga.socketServer;
this.connect = Yekonga.socketServer;
}
of(namespace) {
this.namespace = namespace;
return this;
}
to(id) {
this.roomId = id;
return this;
}
room(id) {
return this.to(id);
}
emit(event, data) {
try {
var io = Yekonga.socketServer;
if (this.namespace) io = io.of(this.namespace);
if (this.roomId) io = io.to(this.roomId);
io.emit(event, data);
} catch (error) {
console.error('Socket.emit', error.message);
}
}
on(event, callback) {
var io = Yekonga.socketServer;
if (this.namespace) io = io.of(this.namespace);
io.on(event, callback);
}
get broadcast() {
return Yekonga.socketServer.broadcast;
}
}
module.exports = async function(server) {
if(Yekonga.socketServer) return console.warn('Socket server is already initialized');
Yekonga.socketServer = new global.serverLibrary.socketServer(server, {
origin: '*',
cors: {
origin: '*',
}
});
if(!(serverLibrary.cluster.isPrimary || serverLibrary.cluster.isMaster)) {
if(Yekonga.Config.localCluster) {
Yekonga.socketServer.adapter(createAdapter());
setupWorker(Yekonga.socketServer);
}
}
console.info('socket is process master?', `${serverLibrary.cluster.isMaster}`);
if(Yekonga.Config.ports.redis) {
const redisClient = global.serverLibrary.createClient({
url: `redis://localhost:${Yekonga.Config.ports.redis}`
});
const subClient = redisClient.duplicate();
await redisClient.connect();
await subClient.connect();
Yekonga.socketServer.adapter(global.serverLibrary.createAdapter(redisClient, subClient));
}
Yekonga.socketSystem = Yekonga.socketServer.of('/system');
Yekonga.pushNotification = Yekonga.socketServer.of('/pushNotification');
// Namespace
Yekonga.socketServer.use(async function(socket, next) {
socket.Yekonga = {}
socket.headers = socket.handshake.headers;
await Middleware.setYekonga(socket, {}, null);
await Middleware.init(socket, {}, null);
await Middleware.setToken(socket, {}, null);
await Middleware.authorization(socket, {}, null);
// console.debug('socket ======> ', socket);
if(typeof next == 'function') {
next();
}
}).on('connection', function(socket) {
// // console.debug(`socket connected`);
socket.on('subscribe', async function(content) {
// console.debug('subscribe', room);
var deviceId = null;
if(typeof content == "object") {
deviceId = content.deviceId;
if(content.userId) {
socket.join(content.userId);
}
if(Yekonga.Helper.isNotEmpty(deviceId)) {
var exists = await Yekonga.Model.UserDevice.findOne({
deviceUuid: deviceId,
});
var body = {
...content,
type: "phone",
deviceUuid: deviceId,
};
if(!exists) {
Yekonga.Model.UserDevice.create(body, true)
} else if(Yekonga.Helper.isNotEmpty(content.userId)) {
Yekonga.Model.UserDevice.update(body, { userDeviceId: exists.userDeviceId }, true)
}
}
} else if(typeof content == "string") {
deviceId = content;
}
if(deviceId) {
socket.join(deviceId);
}
Yekonga.Cloud.runOnMessage(null, 'subscribe', content);
})
socket.on('unsubscribe', function(deviceId) {
// console.debug('unsubscribe', room);
socket.leave(deviceId);
Yekonga.Cloud.runOnMessage(null, 'unsubscribe', deviceId);
})
socket.on('run-on-server', function(content) {
console.debug('data', content);
Yekonga.Cloud.runOnMessage(null, 'run-on-server', content);
});
socket.on('run-on-client', function(content) {
console.debug('data', content);
Yekonga.Cloud.runOnMessage(null, 'run-on-client', content);
});
socket.on('run-on-desktop', function(content) {
console.debug('data', content);
Yekonga.Cloud.runOnMessage(null, 'run-on-desktop', content);
});
socket.on('graphql-request', function({ room, listener, body, headers }) {
var routeApi = (Yekonga.Config.graphql && Yekonga.Config.graphql.apiRoute) ?
Yekonga.Config.graphql.apiRoute :
`graphql`;
Yekonga.Helper.request('post', {
url: `http://127.0.0.1:${Yekonga.Config.ports.server}${routeApi}`,
body: body,
headers: headers,
json: (typeof body == 'object') ? true : false
}).then(
(response) => {
var responseBody = response.data;
var content = (responseBody && responseBody.data) ? responseBody.data : responseBody;
if (content) {
Yekonga.Socket.to(room).emit('graphql-response', {
listener: listener,
body: content,
});
}
},
(error) => {
console.error(error);
}
);
});
});
// Namespace
Yekonga.socketSystem.use(function(socket, next) {
if (!Yekonga.Auth) {
if (socket.handshake.query && socket.handshake.query.token) {
Middleware.setToken(socket.handshake);
} else {
// next(new Error('Authentication error'));
}
}
next();
}).on('connection', function(socket) {
// console.debug(`socket.of('/system') connected`);
socket.on('subscribe', async function(content) {
// console.debug('subscribe', room);
var deviceId = null;
if(typeof content == "object") {
deviceId = content.deviceId;
if(content.userId) {
socket.join(content.userId);
}
if(Yekonga.Helper.isNotEmpty(deviceId)) {
var exists = await Yekonga.Model.UserDevice.findOne({
deviceUuid: deviceId,
});
var body = {
...content,
type: "phone",
deviceUuid: deviceId,
};
if(!exists) {
Yekonga.Model.UserDevice.create(body, true)
} else if(Yekonga.Helper.isNotEmpty(content.userId)) {
Yekonga.Model.UserDevice.update(body, { userDeviceId: exists.userDeviceId }, true)
}
}
} else if(typeof content == "string") {
deviceId = content;
}
if(deviceId) {
socket.join(deviceId);
}
Yekonga.Cloud.runOnMessage('system', 'subscribe', content);
})
socket.on('unsubscribe', function(content) {
// console.debug('unsubscribe', room);
socket.leave(content);
Yekonga.Cloud.runOnMessage('system', 'unsubscribe', content);
})
socket.on('run-on-server', function(content) {
console.debug('data', content);
Yekonga.Cloud.runOnMessage('system', 'run-on-server', content);
});
socket.on('run-on-client', function(content) {
console.debug('data', content);
Yekonga.Cloud.runOnMessage('system', 'run-on-client', content);
});
socket.on('run-on-desktop', function(content) {
console.debug('data', content);
Yekonga.Cloud.runOnMessage('system', 'run-on-desktop', content);
});
socket.on('confirm', function(content) {
console.debug('data', content);
Yekonga.Cloud.runOnMessage('system', 'confirm', content);
});
});
// Namespace
Yekonga.pushNotification.use(function(socket, next) {
if (!Yekonga.Auth) {
if (socket.handshake.query && socket.handshake.query.token) {
// Middleware.setToken(socket.handshake);
} else {
// next(new Error('Authentication error'));
}
}
next();
}).on('connection', function(socket) {
// console.debug(`socket.of('/pushNotification') connected`);
socket.on('subscribe', async function(content) {
// console.debug('subscribe to pushNotification - deviceId:', content);
try {
if(content) {
var deviceId = content.deviceId;
if(content.userId) {
socket.join(content.userId);
}
if(deviceId) {
socket.join(deviceId);
// processPendingPushNotifications(deviceId);
}
if(Yekonga.Helper.isNotEmpty(deviceId)) {
var exists = await Yekonga.Model.UserDevice.findOne({
deviceUuid: deviceId,
});
var body = {
...content,
type: "phone",
deviceUuid: deviceId,
};
if(!exists) {
Yekonga.Model.UserDevice.create(body, true)
} else if(Yekonga.Helper.isNotEmpty(content.userId)) {
Yekonga.Model.UserDevice.update(body, { userDeviceId: exists.userDeviceId }, true)
}
}
}
} catch (error) {
console.error("", error);
}
Yekonga.Cloud.runOnMessage('pushNotification', 'subscribe', content);
})
socket.on('unsubscribe', function(room) {
// console.debug('unsubscribe', room);
socket.leave(room);
Yekonga.Cloud.runOnMessage('pushNotification', 'unsubscribe', room);
})
socket.on('disconnect', function(content) {
// console.debug('unsubscribe', content);
socket.leave(content);
Yekonga.Cloud.runOnMessage('pushNotification', 'disconnect', content);
})
socket.on('acknowledge', async function(id) {
console.debug('acknowledge', id);
await Yekonga.Model.PushNotification.update(
{ status: "delivered" },
{ pushNotificationId: id },
true);
Yekonga.Cloud.runOnMessage('pushNotification', 'acknowledge', id);
});
});
if (typeof Yekonga.setPeer == 'function') {
Yekonga.setPeer(Yekonga.socketServer);
}
if (typeof Yekonga.setChat == 'function') {
Yekonga.setChat(Yekonga.socketServer);
}
setInterval(() => {
processPushNotifications();
}, 5000);
}
var processStatus = false;
async function processPushNotifications() {
if(processStatus) return;
processStatus = true;
try {
let timestamp = Yekonga.Helper.getMoment().format('YYYY-MM-DD HH:mm:ss');
let pastTimestamp = Yekonga.Helper.getMoment().subtract(5, 'minutes').format('YYYY-MM-DD HH:mm:ss');
let list = await Yekonga.Model.PushNotification.find({ status: ["waiting","pending"] }, true);
for (const row of list) {
row.id = row.pushNotificationId;
await Yekonga.Model.PushNotification.update({ status: "sent", updatedAt: timestamp }, { pushNotificationId: row.pushNotificationId }, true);
var s = null;
if(Yekonga.Helper.isNotEmpty(row.namespace)) {
s = Yekonga.socketServer.of(row.namespace);
} else {
s = Yekonga.pushNotification;
}
if (row.deviceUuid) {
s.emit(`notification-${row.deviceUuid}`, row);
s.to(`${row.deviceUuid}`).emit('notification', row);
} else if (row.userId) {
s.emit(`notification-${row.userId}`, row);
s.to(`${row.userId}`).emit('notification', row);
} else {
s.emit('notification', row);
}
}
} catch (error) {
console.error('processPushNotifications', error)
}
processStatus = false;
}
async function processPendingPushNotifications(deviceId) {
let pastTimestamp = Yekonga.Helper.getMoment().subtract(5, 'minutes').format('YYYY-MM-DD HH:mm:ss');
let sentList = await Yekonga.Model.PushNotification.find({ deviceUuid: deviceId, status: { in: ["sent", "waiting"]} }, true);
for (const row of sentList) {
row.id = row.pushNotificationId;
var s = null;
if(Yekonga.Helper.isNotEmpty(row.namespace)) {
s = Yekonga.socketServer.of(row.namespace);
} else {
s = Yekonga.pushNotification;
}
// console.debug(`notification-${row.deviceUuid}`, row.namespace)
s.emit(`notification-${row.deviceUuid}`, row);
s.to(`${row.deviceUuid}`).emit('notification', row);
}
}
Object.defineProperty(Yekonga, "Socket", {
get: function() { return new Socket(); }
});