helene
Version:
Real-time Web Apps for Node.js
139 lines • 4.4 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.ClientNode = void 0;
const utils_1 = require("../utils");
const eventemitter2_1 = require("eventemitter2");
const http_1 = __importDefault(require("http"));
const limiter_1 = require("limiter");
const isString_1 = __importDefault(require("lodash/isString"));
const heartbeat_1 = require("./heartbeat");
class ClientNode extends eventemitter2_1.EventEmitter2 {
uuid;
isAuthenticated = false;
meta = {};
context = {};
userId = null;
user = null;
socket;
req = {};
res = {};
isServer = false;
limiter;
server;
headers = {};
remoteAddress;
userAgent;
heartbeat;
constructor(server, socket, req, res, limit) {
super();
this.server = server;
this.socket = socket;
this.req = req;
this.res = res;
if (limit) {
this.limiter = new limiter_1.RateLimiter(limit === true
? {
tokensPerInterval: 60,
interval: 60 * 1000,
}
: {
tokensPerInterval: limit.max,
interval: limit.interval,
});
}
if (socket) {
this.heartbeat = new heartbeat_1.Heartbeat({
sendPing: () => {
this.send({ type: utils_1.PayloadType.HEARTBEAT });
},
onTimeout: () => {
this.emit(utils_1.HeleneEvents.HEARTBEAT_DISCONNECT);
this.socket.disconnect();
},
});
this.heartbeat.start();
}
}
get authenticated() {
return this.isAuthenticated;
}
set authenticated(authenticated) {
this.isAuthenticated = authenticated;
}
get readyState() {
return this.socket?.conn.readyState;
}
setId(uuid) {
this.uuid = uuid;
}
setContext(context) {
this.context = this.authenticated ? context : {};
this.setUserId();
}
setTrackingProperties(socket) {
if (socket instanceof http_1.default.IncomingMessage) {
this.headers = socket.headers;
this.userAgent = socket.headers['user-agent'];
this.remoteAddress =
socket.headers['x-forwarded-for'] || socket.socket.remoteAddress;
}
else {
this.headers = socket.conn.request.headers;
this.userAgent = socket.conn.request.headers['user-agent'];
this.remoteAddress =
socket.conn.request.headers['x-forwarded-for'] ||
socket.conn.remoteAddress;
}
}
// The user ID is used for authorizing the user's channel.
setUserId() {
if (!this.authenticated)
return;
const userId = this.context?.user?._id;
if (!userId) {
throw new Error('The auth function must return a user object with a valid "_id" property');
}
this.userId = this.context.user._id;
this.user = this.context.user;
}
send(payload) {
if (!this.socket) {
throw new Error(':write_no_socket');
}
this.socket?.write((0, isString_1.default)(payload) ? payload : utils_1.Presentation.encode(payload));
}
result(payload) {
this.socket.write(utils_1.Presentation.encode({
type: utils_1.PayloadType.RESULT,
...payload,
}));
}
/**
* @warning There is an `event` property already in the super class.
*/
sendEvent(event, params) {
return this.send({
uuid: utils_1.Presentation.uuid(),
type: utils_1.PayloadType.EVENT,
event,
params,
});
}
error(payload) {
this.socket?.write(utils_1.Presentation.encode({
type: utils_1.PayloadType.ERROR,
...payload,
}));
}
close() {
this.socket?.disconnect();
this.emit(utils_1.ServerEvents.DISCONNECT);
this.server.emit(utils_1.ServerEvents.DISCONNECTION, this);
this.heartbeat?.stop();
}
}
exports.ClientNode = ClientNode;
//# sourceMappingURL=client-node.js.map