From 3204c329bcb61429216926d463a301550c008247 Mon Sep 17 00:00:00 2001 From: Simon Eisenmann Date: Mon, 16 Jun 2014 15:38:00 +0200 Subject: [PATCH] Implementd client side lookup support. --- doc/CHANNELING-API.txt | 31 ++++++++----- src/app/spreed-webrtc-server/channeling.go | 19 ++++---- src/app/spreed-webrtc-server/hub.go | 28 ++++++----- src/app/spreed-webrtc-server/server.go | 14 +++--- static/js/directives/audiolevel.js | 2 +- static/js/mediastream/api.js | 36 ++++++++++++--- static/js/services/buddylist.js | 54 +++++++++++++--------- 7 files changed, 115 insertions(+), 69 deletions(-) diff --git a/doc/CHANNELING-API.txt b/doc/CHANNELING-API.txt index edadbd2c..6716855e 100644 --- a/doc/CHANNELING-API.txt +++ b/doc/CHANNELING-API.txt @@ -52,11 +52,14 @@ Sending vs receiving document data encapsulation { "Type": "Whatever", - "Whatever": { /* your document */ } + "Whatever": { /* your document */ }, + "Iid": "request-identifier-unique-to-client" } So any document you sent, you have to specify a Type key pointing - to the key where the real document is to be found. + to the key where the real document is to be found. The Iid field is + optional and is returned back with the response wrapper document to + match requests with response data when supported by the type. Received documents are wrapped by a special Document which provides additional information. @@ -64,7 +67,8 @@ Sending vs receiving document data encapsulation { "From": "4", "To": "5", - "Data": {} + "Data": {}, + "Iid": "request-identifier-unique-to-client" } The Data key contains the real Document. @@ -76,6 +80,9 @@ Sending vs receiving document data encapsulation To : The Id, the server send this Document to. Should be the same as your current Self Id. Data : Contains the payload. + Iid : Optional request identifier to match this response to the calling + request. Only available when sent by the client and the requested + type implementation does support it. Special purpose documents for channling @@ -333,9 +340,7 @@ Additional types for session listing and notifications "Ua": "Chrome 28", "Status": {...} } - ], - "Index": 0, - "Batch": 0 + ] } Note: The Userid field is only present, if that session belongs to a known user. @@ -389,9 +394,10 @@ Information retrieval { "Type": "Sessions", - "Id": "Client generated request ID", - "Token": "Request token", - "TokenType": "Token type" + "Sessions": { + "Type": "Token type", + "Token": "Request token" + } } Valid known token types are: "contact". @@ -401,9 +407,10 @@ Information retrieval { "Type": "Sessions", - "Id": "ID as from request", - "Token": "Token as in request", - "TokenType": "Type as in request", + "Sessions": { + "Type": "Type as in request", + "Token": "Token as in request" + }, "Users": [ { "Type": "Online", diff --git a/src/app/spreed-webrtc-server/channeling.go b/src/app/spreed-webrtc-server/channeling.go index 00a19aea..608c8e8c 100644 --- a/src/app/spreed-webrtc-server/channeling.go +++ b/src/app/spreed-webrtc-server/channeling.go @@ -65,8 +65,8 @@ type DataTurn struct { } type DataSession struct { + Type string Id string - Type string `json:",omitempty"` Userid string `json:",omitempty"` Ua string `json:",omitempty"` Token string `json:",omitempty"` @@ -148,22 +148,25 @@ type DataIncoming struct { Alive *DataAlive Authentication *DataAuthentication Sessions *DataSessions + Iid string `json:",omitempty"` } type DataOutgoing struct { Data interface{} From string To string + Iid string `json:",omitempty"` } type DataSessions struct { - Type string - Users []*DataSession - Id string `json:",omitempty"` - Token string `json:",omitempty"` - TokenType string `json:",omitempty"` - Index uint64 `json:",omitempty"` - Batch uint64 `json:",omitempty"` + Type string + Sessions *DataSessionsRequest `json:",omitempty"` + Users []*DataSession +} + +type DataSessionsRequest struct { + Token string + Type string } type DataConference struct { diff --git a/src/app/spreed-webrtc-server/hub.go b/src/app/spreed-webrtc-server/hub.go index a16ba59f..d1002fb3 100644 --- a/src/app/spreed-webrtc-server/hub.go +++ b/src/app/spreed-webrtc-server/hub.go @@ -405,11 +405,11 @@ func (h *Hub) unicastHandler(m *MessageRequest) { } -func (h *Hub) aliveHandler(c *Connection, alive *DataAlive) { +func (h *Hub) aliveHandler(c *Connection, alive *DataAlive, iid string) { aliveJson := h.buffers.New() encoder := json.NewEncoder(aliveJson) - err := encoder.Encode(&DataOutgoing{From: c.Id, Data: alive}) + err := encoder.Encode(&DataOutgoing{From: c.Id, Data: alive, Iid: iid}) if err != nil { log.Println("Alive error while encoding JSON", err) aliveJson.Decref() @@ -420,16 +420,20 @@ func (h *Hub) aliveHandler(c *Connection, alive *DataAlive) { } -func (h *Hub) sessionsHandler(c *Connection, sessions *DataSessions) { +func (h *Hub) sessionsHandler(c *Connection, srq *DataSessionsRequest, iid string) { - reply := false + var users []*DataSession - switch sessions.TokenType { + switch srq.Type { case "contact": contact := &Contact{} - err := h.contacts.Decode("contactRequest", sessions.Token, contact) + err := h.contacts.Decode("contactConfirmed", srq.Token, contact) if err != nil { - log.Println("Failed to decode incoming contact token", err, sessions.Token) + log.Println("Failed to decode incoming contact token", err, srq.Token) + return + } + if !contact.Ok { + log.Println("Ignoring contact token without Ok", contact) return } // Use the userid which is not ours from the contact data. @@ -451,16 +455,16 @@ func (h *Hub) sessionsHandler(c *Connection, sessions *DataSessions) { return } // Add sessions for forein user. - sessions.Users = user.SessionsData() - reply = true + users = user.SessionsData() default: - log.Println("Unkown incoming sessions request type", sessions.TokenType) + log.Println("Unkown incoming sessions request type", srq.Type) } - if reply { + if users != nil { + sessions := &DataSessions{Type: "Sessions", Users: users, Sessions: srq} sessionsJson := h.buffers.New() encoder := json.NewEncoder(sessionsJson) - err := encoder.Encode(&DataOutgoing{From: c.Id, Data: sessions}) + err := encoder.Encode(&DataOutgoing{From: c.Id, Data: sessions, Iid: iid}) if err != nil { log.Println("Sessions error while encoding JSON", err) sessionsJson.Decref() diff --git a/src/app/spreed-webrtc-server/server.go b/src/app/spreed-webrtc-server/server.go index 9c7668de..392048a6 100644 --- a/src/app/spreed-webrtc-server/server.go +++ b/src/app/spreed-webrtc-server/server.go @@ -68,7 +68,7 @@ func (s *Server) OnUnregister(c *Connection) { func (s *Server) OnText(c *Connection, b Buffer) { - //log.Printf("OnText from %d: %s\n", c.id, b) + //log.Printf("OnText from %d: %s\n", c.Id, b) var msg DataIncoming err := json.Unmarshal(b.Bytes(), &msg) if err != nil { @@ -167,9 +167,9 @@ func (s *Server) OnText(c *Connection, b Buffer) { } } case "Alive": - s.Alive(c, msg.Alive) + s.Alive(c, msg.Alive, msg.Iid) case "Sessions": - s.Sessions(c, msg.Sessions) + s.Sessions(c, msg.Sessions.Sessions, msg.Iid) default: log.Println("OnText unhandled message type", msg.Type) } @@ -192,15 +192,15 @@ func (s *Server) Unicast(c *Connection, to string, m interface{}) { b.Decref() } -func (s *Server) Alive(c *Connection, alive *DataAlive) { +func (s *Server) Alive(c *Connection, alive *DataAlive, iid string) { - c.h.aliveHandler(c, alive) + c.h.aliveHandler(c, alive, iid) } -func (s *Server) Sessions(c *Connection, sessions *DataSessions) { +func (s *Server) Sessions(c *Connection, srq *DataSessionsRequest, iid string) { - c.h.sessionsHandler(c, sessions) + c.h.sessionsHandler(c, srq, iid) } diff --git a/static/js/directives/audiolevel.js b/static/js/directives/audiolevel.js index 74fd62d9..0ab7de42 100644 --- a/static/js/directives/audiolevel.js +++ b/static/js/directives/audiolevel.js @@ -44,7 +44,7 @@ define(['jquery', 'underscore'], function($, _) { var element = $element[0]; var width = 0; this.update = _.bind(function() { - if (this.active || width > 0) { + if (this.active || width > 0) { if (webrtc.usermedia.audioLevel) { width = Math.round(100 * webrtc.usermedia.audioLevel); // Hide low volumes. diff --git a/static/js/mediastream/api.js b/static/js/mediastream/api.js index 756ac4ac..c7f8b110 100644 --- a/static/js/mediastream/api.js +++ b/static/js/mediastream/api.js @@ -29,6 +29,7 @@ define(['jquery', 'underscore'], function($, _) { this.sid = null; this.session = {}; this.connector = connector; + this.iids= 0; this.e = $({}); @@ -74,7 +75,7 @@ define(['jquery', 'underscore'], function($, _) { Type: type }; payload[type] = data; - //console.log("<<<<<<<<<<<<", JSON.stringify(payload)); + //console.log("<<<<<<<<<<<<", JSON.stringify(payload, null, 2)); this.connector.send(payload, noqueue); }; @@ -91,6 +92,21 @@ define(['jquery', 'underscore'], function($, _) { return this.apply(name, obj); }; + Api.prototype.request = function(type, data, cb) { + + var payload = { + Type: type + } + payload[type] = data; + if (cb) { + var iid = ""+(this.iids++); + payload.Iid = iid; + this.e.one(iid+".request", cb); + } + this.connector.send(payload); + + } + // Helper hack function to send API requests to other destinations. // Simply provide an alternative send function on the obj Object. Api.prototype.apply = function(name, obj) { @@ -105,9 +121,16 @@ define(['jquery', 'underscore'], function($, _) { this.last_receive = now; this.last_receive_overdue = false; + var iid = d.Iid; var data = d.Data; var dataType = data.Type; + if (iid) { + // Shortcut for iid registered responses. + this.e.triggerHandler(iid+".request", [dataType, data]); + return; + } + switch (dataType) { case "Self": console.log("Self received", data); @@ -321,16 +344,17 @@ define(['jquery', 'underscore'], function($, _) { return this.send("Alive", data); }; - Api.prototype.sendSessions = function(token, type) { + Api.prototype.sendSessions = function(token, type, cb) { var data = { Type: "Sessions", - Id: "some-random-whatever", - Token: token, - TokenType: type + Sessions: { + Type: type, + Token: token + } } - return this.send("Sessions", data); + return this.request("Sessions", data, cb); }; diff --git a/static/js/services/buddylist.js b/static/js/services/buddylist.js index 6378b778..93e997cc 100644 --- a/static/js/services/buddylist.js +++ b/static/js/services/buddylist.js @@ -129,7 +129,7 @@ define(['underscore', 'modernizr', 'avltree', 'text!partials/buddy.html', 'text! }; // buddyList - return ["$window", "$compile", "playSound", "buddyData", "buddySession", "fastScroll", "mediaStream", "animationFrame", function($window, $compile, playSound, buddyData, buddySession, fastScroll, mediaStream, animationFrame) { + return ["$window", "$compile", "playSound", "buddyData", "buddySession", "fastScroll", "mediaStream", "animationFrame", "$q", function($window, $compile, playSound, buddyData, buddySession, fastScroll, mediaStream, animationFrame, $q) { var buddyTemplate = $compile(templateBuddy); var buddyActions = $compile(templateBuddyActions); @@ -158,16 +158,9 @@ define(['underscore', 'modernizr', 'avltree', 'text!partials/buddy.html', 'text! this.hover(buddyElement, event.type === "mouseenter" ? true : false); }, this)); $element.on("click", ".buddy", _.bind(function(event) { - console.log("click event", event); var buddyElement = $(event.currentTarget); - //buddyElement.scope().doDefault(); this.click(buddyElement, event.target); }, this)); - /*$element.on("click", ".fa.contact", _.bind(function(event) { - event.stopPropagation(); - var buddyElement = $(event.currentTarget); - buddyElement.scope().doDefaultContact(); - }, this));*/ $element.attr("data-xthreshold", "10"); $element.on("swipeleft", ".buddy", _.bind(function(event) { event.preventDefault(); @@ -658,32 +651,47 @@ define(['underscore', 'modernizr', 'avltree', 'text!partials/buddy.html', 'text! var scope = buddyElement.scope(); var session = scope.session; - var sessionData = session.get() var contact = scope.contact; - var id; - if (!sessionData) { - // TODO(longsleep): Find session with help of contact. - console.log("No sessions for this buddy.", session, contact); - if (contact && contact.Token) { - mediaStream.api.sendSessions(contact.Token, "contact"); + + var promise = (function() { + var deferred = $q.defer(); + var sessionData = session.get() + if (!sessionData) { + // Find session with help of contact. + if (contact && contact.Token) { + mediaStream.api.sendSessions(contact.Token, "contact", function(event, type, data) { + //console.log("oooooooooooooooo", type, data); + if (data.Users && data.Users.length > 0) { + var s = data.Users[0]; + buddyData.set(s.Id, scope); + deferred.resolve(s.Id); + } + }); + } + } else { + deferred.resolve(sessionData.Id); } - return; - } else { - id = sessionData.Id; - } - //console.log("id", id); + return deferred.promise; + })(); + switch (action) { case "call": - scope.doCall(id); + promise.then(function(id) { + scope.doCall(id); + }); break; case "chat": - scope.doChat(id); + promise.then(function(id) { + scope.doChat(id); + }); break; case "contact": if (contact) { scope.doContactRemove(contact.Userid); } else { - scope.doContactRequest(id); + promise.then(function(id) { + scope.doContactRequest(id); + }); } break; }