/// <reference path="Scripts/promise.d.ts" />
var Stormancer;
(function (Stormancer) {
/**
ConnectionHandler
*/
var ConnectionHandler = (function () {
function ConnectionHandler() {
this._current = 0;
this.connectionCount = null;
}
/**
Generates an unique connection id for this node.
*/
ConnectionHandler.prototype.generateNewConnectionId = function () {
return this._current++;
};
/**
Adds a connection to the manager
*/
ConnectionHandler.prototype.newConnection = function (connection) {
};
/**
Returns a connection by id
*/
ConnectionHandler.prototype.getConnection = function (id) {
throw new Error("Not implemented.");
};
/**
Closes the target connection
*/
ConnectionHandler.prototype.closeConnection = function (connection, reason) {
};
return ConnectionHandler;
})();
Stormancer.ConnectionHandler = ConnectionHandler;
var Client = (function () {
/**
Creates a client. You need to construct a configuration before using this method.
@class Client
@classdesc A Stormancer client for connecting to Stormancer server applications.
@memberof Stormancer
@param {Stormancer.Configuration} config The configuration object for constructing the Client.
*/
function Client(config) {
this._tokenHandler = new Stormancer.TokenHandler();
this._serializers = { "msgpack/map": new Stormancer.MsgPackSerializer() };
this._metadata = {};
this._pluginCtx = new Stormancer.PluginBuildContext();
/**
The name of the Stormancer server application the client is connected to.
@member Stormancer.Client#applicationName
@type {string}
*/
this.applicationName = null;
/**
An user specified logger.
@member Stormancer.Client#logger
@type {object}
*/
this.logger = null;
/**
The client's unique stormancer ID. Returns null if the ID has not been acquired yet (connection still in progress).
@member Stormancer.Client#id
@type {string}
*/
this.id = null;
this.serverTransportType = null;
this._systemSerializer = new Stormancer.MsgPackSerializer();
/**
The server connection's ping in milliseconds.
@member Stormancer.Client#serverPing
@type {number}
*/
this.serverPing = null;
this._offset = 0;
this._pingInterval = 5000;
this._watch = new Watch();
this._accountId = config.account;
this._applicationName = config.application;
this._apiClient = new Stormancer.ApiClient(config, this._tokenHandler);
this._transport = config.transport;
this._dispatcher = config.dispatcher;
this._requestProcessor = new Stormancer.RequestProcessor(this.logger, []);
this._scenesDispatcher = new Stormancer.SceneDispatcher();
this._dispatcher.addProcessor(this._requestProcessor);
this._dispatcher.addProcessor(this._scenesDispatcher);
this._metadata = config.metadata;
for (var i = 0; i < config.serializers.length; i++) {
var serializer = config.serializers[i];
this._serializers[serializer.name] = serializer;
}
this._metadata["serializers"] = Stormancer.Helpers.mapKeys(this._serializers).join(',');
this._metadata["transport"] = this._transport.name;
this._metadata["version"] = "1.0.0a";
this._metadata["platform"] = "JS";
this._metadata["protocol"] = "2";
for (var i = 0; i < config.plugins.length; i++) {
config.plugins[i].build(this._pluginCtx);
}
for (var i = 0; i < this._pluginCtx.clientCreated.length; i++) {
this._pluginCtx.clientCreated[i](this);
}
this.initialize();
}
Client.prototype.initialize = function () {
var _this = this;
if (!this._initialized) {
this._initialized = true;
this._transport.packetReceived.push(function (packet) { return _this.transportPacketReceived(packet); });
this._watch.start();
}
};
Client.prototype.transportPacketReceived = function (packet) {
for (var i = 0; i < this._pluginCtx.packetReceived.length; i++) {
this._pluginCtx.packetReceived[i](packet);
}
this._dispatcher.dispatchPacket(packet);
};
/**
Retrieve a public scene object from its ID.
@method Stormancer.Client#getPublicScene
@param {string} sceneId The scene ID
@param {object} userData User data to send
@return {Promise} Promise which complete when the scene is ready to connect.
*/
Client.prototype.getPublicScene = function (sceneId, userData) {
var _this = this;
return this._apiClient.getSceneEndpoint(this._accountId, this._applicationName, sceneId, userData).then(function (ci) { return _this.getSceneImpl(sceneId, ci); });
};
/**
Retrieve a scene object from its ID.
@method Stormancer.Client#getScene
@param {string} token Scene token
@return {Promise} Promise which complete when the scene is ready to connect.
*/
Client.prototype.getScene = function (token) {
var ci = this._tokenHandler.decodeToken(token);
return this.getSceneImpl(ci.tokenData.SceneId, ci);
};
Client.prototype.getSceneImpl = function (sceneId, ci) {
var _this = this;
var self = this;
return this.ensureTransportStarted(ci).then(function () {
if (ci.tokenData.Version > 0) {
_this.startAsyncClock();
}
var parameter = { Metadata: self._serverConnection.metadata, Token: ci.token };
return self.sendSystemRequest(Stormancer.SystemRequestIDTypes.ID_GET_SCENE_INFOS, parameter);
}).then(function (result) {
if (!self._serverConnection.serializerChosen) {
if (!result.SelectedSerializer) {
throw new Error("No serializer selected.");
}
self._serverConnection.serializer = self._serializers[result.SelectedSerializer];
self._serverConnection.metadata["serializer"] = result.SelectedSerializer;
self._serverConnection.serializerChosen = true;
}
return self.updateMetadata().then(function (_) { return result; });
}).then(function (r) {
var scene = new Stormancer.Scene(self._serverConnection, self, sceneId, ci.token, r);
for (var i = 0; i < _this._pluginCtx.sceneCreated.length; i++) {
_this._pluginCtx.sceneCreated[i](scene);
}
return scene;
});
};
Client.prototype.updateMetadata = function () {
return this._requestProcessor.sendSystemRequest(this._serverConnection, Stormancer.SystemRequestIDTypes.ID_SET_METADATA, this._systemSerializer.serialize(this._serverConnection.metadata));
};
Client.prototype.sendSystemRequest = function (id, parameter) {
var _this = this;
return this._requestProcessor.sendSystemRequest(this._serverConnection, id, this._systemSerializer.serialize(parameter)).then(function (packet) { return _this._systemSerializer.deserialize(packet.data); });
};
Client.prototype.ensureTransportStarted = function (ci) {
var self = this;
return Stormancer.Helpers.promiseIf(self._serverConnection == null, function () {
return Stormancer.Helpers.promiseIf(!self._transport.isRunning, self.startTransport, self).then(function () {
return self._transport.connect(ci.tokenData.Endpoints[self._transport.name]).then(function (c) {
self.registerConnection(c);
return self.updateMetadata();
});
});
}, self);
};
Client.prototype.startTransport = function () {
this._cts = new Cancellation.TokenSource();
return this._transport.start("client", new ConnectionHandler(), this._cts.token);
};
Client.prototype.registerConnection = function (connection) {
this._serverConnection = connection;
for (var key in this._metadata) {
this._serverConnection.metadata[key] = this._metadata[key];
}
};
Client.prototype.disconnectScene = function (scene, sceneHandle) {
var _this = this;
return this.sendSystemRequest(Stormancer.SystemRequestIDTypes.ID_DISCONNECT_FROM_SCENE, sceneHandle).then(function () {
_this._scenesDispatcher.removeScene(sceneHandle);
for (var i = 0; i < _this._pluginCtx.sceneConnected.length; i++) {
_this._pluginCtx.sceneConnected[i](scene);
}
});
};
/**
Disconnects the client.
@method Stormancer.Client#disconnect
*/
Client.prototype.disconnect = function () {
if (this._serverConnection) {
this._serverConnection.close();
}
};
Client.prototype.connectToScene = function (scene, token, localRoutes) {
var _this = this;
var parameter = {
Token: token,
Routes: [],
ConnectionMetadata: this._serverConnection.metadata
};
for (var i = 0; i < localRoutes.length; i++) {
var r = localRoutes[i];
parameter.Routes.push({
Handle: r.handle,
Metadata: r.metadata,
Name: r.name
});
}
return this.sendSystemRequest(Stormancer.SystemRequestIDTypes.ID_CONNECT_TO_SCENE, parameter).then(function (result) {
scene.completeConnectionInitialization(result);
_this._scenesDispatcher.addScene(scene);
for (var i = 0; i < _this._pluginCtx.sceneConnected.length; i++) {
_this._pluginCtx.sceneConnected[i](scene);
}
});
};
Client.prototype.startAsyncClock = function () {
if (!this._syncClockIntervalId) {
this._syncClockIntervalId = setInterval(this.syncClockImpl.bind(this), this._pingInterval);
}
};
Client.prototype.stopAsyncClock = function () {
clearInterval(this._syncClockIntervalId);
this._syncClockIntervalId = null;
};
Client.prototype.syncClockImpl = function () {
var _this = this;
try {
var timeStart = Math.floor(this._watch.getElapsedTime());
var data = new Uint32Array(2);
data[0] = timeStart;
data[1] = Math.floor(timeStart / Math.pow(2, 32));
this._requestProcessor.sendSystemRequest(this._serverConnection, Stormancer.SystemRequestIDTypes.ID_PING, new Uint8Array(data.buffer), 0 /* IMMEDIATE_PRIORITY */).then(function (packet) {
var timeEnd = _this._watch.getElapsedTime();
var data = new Uint8Array(packet.data.buffer, packet.data.byteOffset, 8);
var timeRef = 0;
for (var i = 0; i < 8; i++) {
timeRef += (data[i] * Math.pow(2, (i * 8)));
}
_this.serverPing = timeEnd - timeStart;
_this._offset = timeRef - (_this.serverPing / 2) - timeStart;
}).catch(function (e) { return console.error("ping: Failed to ping server.", e); });
}
catch (e) {
console.error("ping: Failed to ping server.", e);
}
};
/**
Get the server clock. Represented by the count of milliseconds since the cluster started.
@method Stormancer.Client#clock
@return {number} The number of milliseconds since the application started.
*/
Client.prototype.clock = function () {
return Math.floor(this._watch.getElapsedTime()) + this._offset;
};
return Client;
})();
Stormancer.Client = Client;
var Watch = (function () {
function Watch() {
this._baseTime = 0;
this._baseTime = this.getTime();
}
Watch.prototype.start = function () {
this._baseTime = this.getTime();
};
Watch.prototype.getTime = function () {
return (typeof (window) !== "undefined" && window.performance && window.performance.now && window.performance.now()) || Date.now();
};
Watch.prototype.getElapsedTime = function () {
return this.getTime() - this._baseTime;
};
return Watch;
})();
})(Stormancer || (Stormancer = {}));
//# sourceMappingURL=Client.js.map