@skyway-sdk/core
Version:
The official Next Generation JavaScript SDK for SkyWay
268 lines • 11.4 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.SkyWayContext = void 0;
const common_1 = require("@skyway-sdk/common");
const rtc_api_client_1 = require("@skyway-sdk/rtc-api-client");
const token_1 = require("@skyway-sdk/token");
const uuid_1 = require("uuid");
const config_1 = require("./config");
const errors_1 = require("./errors");
const analytics_1 = require("./external/analytics");
const plugin_1 = require("./plugin/internal/person/plugin");
const plugin_2 = require("./plugin/internal/unknown/plugin");
const util_1 = require("./util");
const version_1 = require("./version");
const log = new common_1.Logger('packages/core/src/context.ts');
class SkyWayContext {
/**@private */
constructor(api, config, authToken,
/**@internal */
info) {
this.config = config;
this.authToken = authToken;
this.info = info;
this.disposed = false;
/**@internal */
this.plugins = [];
this._unknownPlugin = new plugin_2.UnknownPlugin();
/**seconds */
this._remindSec = this.config.token.updateRemindSec;
this._events = new common_1.Events();
/**
* @description [japanese] トークンの期限がまもなく切れることを通知するイベント
* @example
* context.onTokenUpdateReminder.add(() => {
context.updateAuthToken(tokenString);
});
*/
this.onTokenUpdateReminder = this._events.make();
/**
* @description [japanese] トークンの期限切れを通知するイベント。このイベントが発火された場合、トークンを更新するまでサービスを利用できない
*/
this.onTokenExpired = this._events.make();
/**
* @description [japanese] 回復不能なエラーが発生したことを通知するイベント。インターネット接続状況を確認した上で別のインスタンスを作り直す必要がある
*/
this.onFatalError = this._events.make();
/**@private @deprecated */
this._onTokenUpdated = this._events.make();
/**@private @deprecated */
this._onDisposed = this._events.make();
/**@description [japanese] トークンが更新されたことを通知するイベント */
this.onTokenUpdated = this._events.make();
/**@description [japanese] コンテキストが破棄されたことを通知するイベント */
this.onDisposed = this._events.make();
this._authTokenString = authToken.tokenString;
this.appId = this.authToken.getAppId();
(0, plugin_1.registerPersonPlugin)(this);
this._api = api;
this._api.onFatalError.once((error) => {
log.error('onFatalError', { appId: this.appId, error });
this.onFatalError.emit((0, util_1.createError)({
operationName: 'SkyWayContext._api.onFatalError',
context: this,
info: errors_1.errors.rtcApiFatalError,
error,
path: log.prefix,
}));
this.dispose();
});
}
/**
* @description [japanese] Contextの作成
*/
static Create(authTokenString, configOptions = {}) {
return __awaiter(this, void 0, void 0, function* () {
const config = new config_1.ContextConfig(configOptions);
common_1.Logger.level = config.log.level;
common_1.Logger.format = config.log.format;
const token = token_1.SkyWayAuthToken.Decode(authTokenString);
const { osName, osVersion, browserName, browserVersion } = (0, util_1.getRuntimeInfo)();
const runtime = {
sdkName: 'core',
sdkVersion: SkyWayContext.version,
osName,
osVersion,
browserName,
browserVersion,
};
const endpoint = {
rapi: config.rtcApi.domain,
signaling: config.signalingService.domain,
ice: config.iceParamServer.domain,
};
log.info('core sdk spawned', {
operationName: 'SkyWayContext.Create',
runtime,
endpoint,
config,
token,
});
try {
const appId = token.getAppId();
const api = yield rtc_api_client_1.RtcApiClient.Create({
appId,
token: authTokenString,
log: config.log,
rtcApi: config.rtcApi,
});
const context = new SkyWayContext(api, config, token, {
endpoint,
runtime,
});
yield context._setTokenExpireTimer();
if (token.getAnalyticsEnabled()) {
context.analyticsSession = yield (0, analytics_1.setupAnalyticsSession)(context);
}
return context;
}
catch (error) {
throw (0, util_1.createError)({
operationName: 'SkyWayContext.Create',
info: errors_1.errors.connectRtcApiFailed,
error,
path: log.prefix,
});
}
});
}
/**@description [japanese] トークンのエンコード済み文字列 */
get authTokenString() {
return this._authTokenString;
}
/**@internal */
_setTokenExpireTimer() {
return __awaiter(this, void 0, void 0, function* () {
// seconds
const now = yield this._api.getServerUnixtimeInSec();
const expiresInSec = this.authToken.exp - now;
if (expiresInSec < 0) {
throw (0, util_1.createError)({
operationName: 'SkyWayContext._setTokenExpireTimer',
context: this,
info: errors_1.errors.invalidExpireTokenValue,
path: log.prefix,
payload: { exp: this.authToken.exp, now },
});
}
if (this._tokenUpdateRemindTimer) {
clearTimeout(this._tokenUpdateRemindTimer);
}
const tokenExpireRemindTimeSec = expiresInSec - this._remindSec;
if (tokenExpireRemindTimeSec < 0) {
throw (0, util_1.createError)({
operationName: 'SkyWayContext._setTokenExpireTimer',
context: this,
info: errors_1.errors.invalidRemindExpireTokenValue,
path: log.prefix,
payload: { expiresInSec, remindSec: this._remindSec },
});
}
log.debug('_setTokenExpireTimer', {
expiresInSec,
tokenExpireReminderTimeSec: tokenExpireRemindTimeSec,
});
this._tokenUpdateRemindTimer = setTimeout(() => {
log.debug('tokenUpdateReminder', { appid: this.appId });
this.onTokenUpdateReminder.emit();
}, tokenExpireRemindTimeSec * 1000);
if (this._tokenExpiredTimer) {
clearTimeout(this._tokenExpiredTimer);
}
this._tokenExpiredTimer = setTimeout(() => {
log.debug('tokenExpired', { appid: this.appId });
this.onTokenExpired.emit();
}, expiresInSec * 1000);
});
}
/**
* @description [japanese] トークンの更新
*/
updateAuthToken(token) {
return __awaiter(this, void 0, void 0, function* () {
const newToken = token_1.SkyWayAuthToken.Decode(token);
const newAppId = newToken.getAppId();
log.info({ operationName: 'SkyWayContext.updateAuthToken' }, { oldToken: this.authToken, newToken });
if (newAppId !== this.appId) {
throw (0, util_1.createError)({
operationName: 'SkyWayContext.updateAuthToken',
context: this,
info: errors_1.errors.invalidTokenAppId,
path: log.prefix,
payload: { invalid: newAppId, expect: this.appId },
});
}
this._authTokenString = token;
this.authToken = newToken;
this._onTokenUpdated.emit(token);
this.onTokenUpdated.emit(token);
yield this._setTokenExpireTimer();
yield this._api.updateAuthToken(token).catch((e) => {
var _a;
log.warn('[failed] SkyWayContext.updateAuthToken', { detail: e });
if (e instanceof common_1.SkyWayError &&
((_a = e.info) === null || _a === void 0 ? void 0 : _a.name) === 'projectUsageLimitExceeded') {
this.dispose();
clearTimeout(this._tokenExpiredTimer);
}
throw e;
});
});
}
/**
* @description [japanese] プラグインの登録
*/
registerPlugin(plugin) {
if (this.plugins.find((p) => p.subtype === plugin.subtype)) {
return;
}
plugin._attachContext(this);
this.plugins.push(plugin);
}
/**@private */
_createRemoteMember(channel, memberDto) {
log.debug('createRemoteMember', { memberDto });
memberDto.type = memberDto.type.toLowerCase();
memberDto.subtype = memberDto.subtype.toLowerCase();
let plugin = this.plugins.find((p) => p.subtype === memberDto.subtype);
if (!plugin) {
plugin = this._unknownPlugin;
}
const member = plugin._createRemoteMember(channel, memberDto);
return member;
}
/**
* @description [japanese] Contextの利用を終了し次のリソースを解放する
* - イベントリスナー
* - バックエンドサーバとの通信
* - コンテキストを参照する全Channelインスタンス
*/
dispose() {
if (this.disposed) {
return;
}
this.disposed = true;
log.debug('disposed', { appid: this.appId });
clearTimeout(this._tokenUpdateRemindTimer);
this._onDisposed.emit();
this.onDisposed.emit();
this._events.dispose();
this._api.close();
common_1.Logger._onLogForAnalytics = () => { };
}
}
exports.SkyWayContext = SkyWayContext;
/**@internal */
SkyWayContext.version = version_1.PACKAGE_VERSION;
/**@internal */
SkyWayContext.id = (0, uuid_1.v4)();
//# sourceMappingURL=context.js.map