diff src/implab/messaging/Session.js @ 0:fc2517695ee1

Initial commit, draft import of existing work
author cin
date Thu, 01 Jun 2017 13:20:03 +0300
parents
children 7d7059d2a810
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/implab/messaging/Session.js	Thu Jun 01 13:20:03 2017 +0300
@@ -0,0 +1,217 @@
+define(
+    [
+        "dojo/_base/declare",
+        "dojo/_base/lang",
+        "dojo/request",
+        "./Destination",
+        "dojo/Evented",
+        "dojo/Deferred",
+        "../_LogMixin" ],
+
+    function(declare, lang, request, Destination, Evented, Deferred, _LogMixin) {
+
+        var cls = declare(
+            [ Evented, _LogMixin ],
+            {
+                _id : null,
+                _baseUrl : null,
+                _destinations : null,
+                _timeout : 100000,
+                _clients : null,
+                _started : null,
+                _starting : false,
+
+                constructor : function(baseUrl, options) {
+                    if (!baseUrl)
+                        throw new Error("baseUrl is required");
+                    options = options || {};
+
+                    this._baseUrl = baseUrl.replace(/\/*$/, "");
+                    this._destinations = {};
+                    this._pending = [];
+                    this._clients = {};
+                    if (options.timeout)
+                        this._timeout = options.timeout;
+
+                    this._started = new Deferred();
+                },
+
+                start : function() {
+                    if (this._starting)
+                        return this._started;
+                    this._starting = true;
+
+                    var me = this;
+                    me.log("START");
+                    request(this._baseUrl, {
+                        method : "POST",
+                        handleAs : "json"
+                    }).then(function(result) {
+                        me._id = result;
+                        me._emitConnected();
+                        me._poll();
+                        me._started.resolve(me);
+                    }, function(error) {
+                        me._emitError(error);
+                        me._started.reject(me);
+                    });
+                    return me._started.promise;
+                },
+
+                createClient : function(options) {
+                    if (!options || !options.destination || !options.mode)
+                        throw new Error("Invalid argument");
+
+                    var me = this;
+
+                    return me._started
+                        .then(function() {
+                            var url = me._makeUrl(me._id);
+                            me.log(
+                                "CREATE mode=${0}, destination=${1}",
+                                options.mode,
+                                options.destination);
+
+                            return request(url, {
+                                method : "POST",
+                                data : {
+                                    mode : options.mode,
+                                    destination : options.destination
+                                },
+                                handleAs : 'json'
+                            })
+                                .then(
+                                    function(id) {
+                                        me
+                                            .log(
+                                                "CLIENT id=${0}, mode=${1}, destination=${2}",
+                                                id,
+                                                options.mode,
+                                                options.destination);
+                                        me._clients[id] = options.client
+                                            ? options.client
+                                            : function(msg) {
+                                                me
+                                                    .warn(
+                                                        "The client id=${0}, mode=${1}, destination=${2} isn't accepting mesages",
+                                                        id,
+                                                        options.mode,
+                                                        options.destination);
+                                            };
+                                        return id;
+                                    });
+                        });
+
+                },
+
+                deleteClient : function(options) {
+                    if (!options || !options.clientId)
+                        throw new Error("Invalid argument");
+
+                    var me = this, id = options.clientId;
+
+                    return me._started.then(function() {
+                        var url = me._makeUrl(me._id, options.clientId);
+
+                        me.log("DELETE CLIENT ${0}", options.clientId);
+
+                        return request(url, {
+                            method : "DELETE",
+                            handleAs : 'json'
+                        }).then(function() {
+                            me.log("CLIENT DELETED ${0}", options.clientId);
+                            me._clients[id] = undefined;
+                        });
+                    });
+                },
+
+                _poll : function() {
+                    var me = this, url = this._makeUrl(this._id);
+                    me.log("POLL timeout=${0}", me._timeout);
+                    request(url, {
+                        method : "GET",
+                        handleAs : "json",
+                        query : {
+                            timeout : me._timeout
+                        }
+                    }).then(function(response) {
+                        me._handlePoll(response);
+                        me._poll();
+                    }, function(err) {
+                        me.error("POLL faield with ${0}", err);
+                        me._emitError(err);
+                    });
+                },
+
+                _handlePoll : function(response) {
+                    if (!response) {
+                        this.log("POLL response undefined, looks like a bug");
+                        return;
+                    }
+                    if (!response.results || !response.results.length) {
+                        this.log("POLL response is empty");
+                        return;
+                    }
+
+                    var results = response.results;
+                    this.log("POLL got ${0} results", results.length);
+
+                    for (var i = 0; i < results.length; i++) {
+                        var result = results[i];
+                        var client = this._clients[result.clientId];
+                        if (!client) {
+                            // TODO this could happen due to client isn't
+                            // registered yet
+                            this.error("Unknown client ${0}", result.clientId);
+                            continue;
+                        }
+                        client.call(this, result);
+                    }
+                },
+
+                _emitError : function(err) {
+                    this.emit("error", err);
+                },
+
+                _emitConnected : function() {
+                    var me = this;
+                    me.log("CONNECTED");
+                    me.emit("connected");
+                },
+
+                _makeUrl : function() {
+                    var parts = [ this._baseUrl ];
+                    for (var i = 0; i < arguments.length; i++)
+                        parts.push(arguments[i].replace(/\/*$/, ""));
+                    return parts.join('/');
+                },
+
+                queue : function(name) {
+                    return this._getDestination("queue://" + name);
+                },
+
+                topic : function(name) {
+                    return this._getDestination("topic://" + name);
+                },
+
+                _getDestination : function(uri) {
+                    if (uri in this._destinations)
+                        return this._destinations[uri];
+
+                    var dest = new Destination(this, uri);
+                    this._destinations[uri] = dest;
+                    return dest;
+                },
+
+                toString : function() {
+                    return [ "[", "SESSION ", this._id, "]" ].join(" ");
+                }
+            });
+
+        cls.connect = function(url, options) {
+            var session = new cls(url, options);
+            return session.start();
+        };
+
+        return cls;
+    });