@skyway-sdk/core
Version:
The official Next Generation JavaScript SDK for SkyWay
221 lines • 9.2 kB
JavaScript
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.SignalingSession = exports.setupSignalingSession = void 0;
const common_1 = require("@skyway-sdk/common");
const signaling_client_1 = require("@skyway-sdk/signaling-client");
const token_1 = require("@skyway-sdk/token");
const errors_1 = require("../errors");
const util_1 = require("../util");
const log = new common_1.Logger('packages/core/src/external/signaling.ts');
function setupSignalingSession(context, channel, memberDto) {
return __awaiter(this, void 0, void 0, function* () {
const { signalingService } = context.config;
const client = new signaling_client_1.SignalingClient({
token: context.authTokenString,
channelId: channel.id,
channelName: channel.name,
memberId: memberDto.id,
memberName: memberDto.name,
}, {
logger: {
error: (error) => __awaiter(this, void 0, void 0, function* () {
log.error('SignalingClient error', (0, util_1.createError)({
operationName: 'SignalingClient.logger',
context,
info: Object.assign(Object.assign({}, errors_1.errors.internal), { detail: 'signalingClient error' }),
error,
path: log.prefix,
channel,
}));
}),
debug: () => { },
},
signalingServerDomain: signalingService.domain,
secure: signalingService.secure,
});
const signalingSession = new SignalingSession(client, context);
yield signalingSession.connect();
return signalingSession;
});
}
exports.setupSignalingSession = setupSignalingSession;
class SignalingSession {
constructor(_client, context) {
this._client = _client;
this.context = context;
this.onConnectionFailed = new common_1.Event();
this.onConnectionStateChanged = new common_1.Event();
this.onMessage = new common_1.Event();
this.closed = false;
this._chunkedMessageBuffer = {};
this._backoffUpdateSkyWayAuthToken = new common_1.BackOff({
times: 8,
interval: 100,
jitter: 100,
});
this._disposer = new common_1.EventDisposer();
this._listen();
context.onTokenUpdated
.add((token) => __awaiter(this, void 0, void 0, function* () {
yield this._updateSkyWayAuthToken(token);
}))
.disposer(this._disposer);
}
updateClient(client) {
this._client = client;
this._listen();
}
_listen() {
this._client.onConnectionFailed.addOneTimeListener(() => {
this.onConnectionFailed.emit({});
});
this._client.onConnectionStateChanged.addListener((state) => {
log.debug('signalingClient onConnectionStateChanged', state);
this.onConnectionStateChanged.emit(state);
});
this._client.onRequested.addListener(({ data, src, reply }) => __awaiter(this, void 0, void 0, function* () {
var _a;
const messageChunk = data;
const { chunk, length, offset, id, type } = messageChunk;
if (type !== messageType)
return;
if (length === 0) {
this.onMessage.emit({
src,
data: JSON.parse(chunk),
});
}
else {
this._chunkedMessageBuffer[id] = [
...((_a = this._chunkedMessageBuffer[id]) !== null && _a !== void 0 ? _a : []),
messageChunk.chunk,
];
if (length === offset) {
const message = this._chunkedMessageBuffer[id].join('');
delete this._chunkedMessageBuffer[id];
this.onMessage.emit({
src,
data: JSON.parse(message),
});
}
}
yield reply({}).catch((e) => {
if (this.closed)
return;
log.warn('failed to reply', (0, util_1.createWarnPayload)({
operationName: 'SignalingSession.reply',
detail: 'SignalingClient failed to reply',
}), e);
});
}));
}
_updateSkyWayAuthToken(token) {
return __awaiter(this, void 0, void 0, function* () {
if (this._backoffUpdateSkyWayAuthToken.exceeded) {
log.error('[failed] updateSkyWayAuthToken');
return;
}
yield this._backoffUpdateSkyWayAuthToken.wait();
log.debug('[start] updateSkyWayAuthToken', {
count: this._backoffUpdateSkyWayAuthToken.count,
});
const e = yield this._client
.updateSkyWayAuthToken(token)
.catch((e) => e);
if (e) {
log.warn('[retry] updateSkyWayAuthToken', (0, util_1.createWarnPayload)({
operationName: 'SignalingSession._updateSkyWayAuthToken',
detail: '[retry] updateSkyWayAuthToken',
}), e);
yield this._updateSkyWayAuthToken(token);
return;
}
log.debug('[end] updateSkyWayAuthToken');
this._backoffUpdateSkyWayAuthToken.reset();
});
}
get connectionState() {
return this._client.connectionState;
}
connect() {
return __awaiter(this, void 0, void 0, function* () {
log.debug('[start] connect signalingService');
yield this._client.connect().catch((err) => {
throw (0, util_1.createError)({
operationName: 'signalingSession.connect',
path: log.prefix,
info: Object.assign(Object.assign({}, errors_1.errors.internal), { detail: 'signalingClient failed to connect Server' }),
context: this.context,
error: err,
});
});
log.debug('[end] connect signalingService');
});
}
close() {
this.closed = true;
this._disposer.dispose();
this._client.disconnect();
}
/**@throws {@link SkyWayError} */
send(target, data,
/**ms */
timeout = 10000) {
var _a;
return __awaiter(this, void 0, void 0, function* () {
try {
const payload = JSON.stringify(data);
const id = (0, token_1.uuidV4)();
// chunking message
if (payload.length > 20480) {
const split = (_a = payload.match(/.{1,20480}/g)) !== null && _a !== void 0 ? _a : [];
let offset = 0;
for (const chunk of split) {
const chunkMessage = {
type: messageType,
length: split.length - 1,
offset: offset++,
chunk,
id,
};
yield this._client.request(target, chunkMessage, timeout / 1000);
}
}
else {
const chunkMessage = {
type: messageType,
length: 0,
offset: 0,
chunk: payload,
id,
};
yield this._client.request(target, chunkMessage, timeout / 1000);
}
}
catch (error) {
if (this.closed || target.state !== 'joined')
return;
throw (0, util_1.createError)({
operationName: 'SignalingSession.send',
context: this.context,
info: Object.assign(Object.assign({}, errors_1.errors.internal), { detail: 'signalingClient' }),
error,
path: log.prefix,
payload: { target, data },
});
}
});
}
}
exports.SignalingSession = SignalingSession;
const messageType = 'signalingMessage';
//# sourceMappingURL=signaling.js.map