Browse Source

Implementd client side lookup support.

pull/48/head
Simon Eisenmann 11 years ago
parent
commit
3204c329bc
  1. 31
      doc/CHANNELING-API.txt
  2. 15
      src/app/spreed-webrtc-server/channeling.go
  3. 28
      src/app/spreed-webrtc-server/hub.go
  4. 14
      src/app/spreed-webrtc-server/server.go
  5. 36
      static/js/mediastream/api.js
  6. 40
      static/js/services/buddylist.js

31
doc/CHANNELING-API.txt

@ -52,11 +52,14 @@ Sending vs receiving document data encapsulation
{ {
"Type": "Whatever", "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 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 Received documents are wrapped by a special Document which provides
additional information. additional information.
@ -64,7 +67,8 @@ Sending vs receiving document data encapsulation
{ {
"From": "4", "From": "4",
"To": "5", "To": "5",
"Data": {} "Data": {},
"Iid": "request-identifier-unique-to-client"
} }
The Data key contains the real Document. 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 To : The Id, the server send this Document to. Should be the same as
your current Self Id. your current Self Id.
Data : Contains the payload. 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 Special purpose documents for channling
@ -333,9 +340,7 @@ Additional types for session listing and notifications
"Ua": "Chrome 28", "Ua": "Chrome 28",
"Status": {...} "Status": {...}
} }
], ]
"Index": 0,
"Batch": 0
} }
Note: The Userid field is only present, if that session belongs to a known user. Note: The Userid field is only present, if that session belongs to a known user.
@ -389,9 +394,10 @@ Information retrieval
{ {
"Type": "Sessions", "Type": "Sessions",
"Id": "Client generated request ID", "Sessions": {
"Token": "Request token", "Type": "Token type",
"TokenType": "Token type" "Token": "Request token"
}
} }
Valid known token types are: "contact". Valid known token types are: "contact".
@ -401,9 +407,10 @@ Information retrieval
{ {
"Type": "Sessions", "Type": "Sessions",
"Id": "ID as from request", "Sessions": {
"Token": "Token as in request", "Type": "Type as in request",
"TokenType": "Type as in request", "Token": "Token as in request"
},
"Users": [ "Users": [
{ {
"Type": "Online", "Type": "Online",

15
src/app/spreed-webrtc-server/channeling.go

@ -65,8 +65,8 @@ type DataTurn struct {
} }
type DataSession struct { type DataSession struct {
Type string
Id string Id string
Type string `json:",omitempty"`
Userid string `json:",omitempty"` Userid string `json:",omitempty"`
Ua string `json:",omitempty"` Ua string `json:",omitempty"`
Token string `json:",omitempty"` Token string `json:",omitempty"`
@ -148,22 +148,25 @@ type DataIncoming struct {
Alive *DataAlive Alive *DataAlive
Authentication *DataAuthentication Authentication *DataAuthentication
Sessions *DataSessions Sessions *DataSessions
Iid string `json:",omitempty"`
} }
type DataOutgoing struct { type DataOutgoing struct {
Data interface{} Data interface{}
From string From string
To string To string
Iid string `json:",omitempty"`
} }
type DataSessions struct { type DataSessions struct {
Type string Type string
Sessions *DataSessionsRequest `json:",omitempty"`
Users []*DataSession Users []*DataSession
Id string `json:",omitempty"` }
Token string `json:",omitempty"`
TokenType string `json:",omitempty"` type DataSessionsRequest struct {
Index uint64 `json:",omitempty"` Token string
Batch uint64 `json:",omitempty"` Type string
} }
type DataConference struct { type DataConference struct {

28
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() aliveJson := h.buffers.New()
encoder := json.NewEncoder(aliveJson) 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 { if err != nil {
log.Println("Alive error while encoding JSON", err) log.Println("Alive error while encoding JSON", err)
aliveJson.Decref() 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": case "contact":
contact := &Contact{} contact := &Contact{}
err := h.contacts.Decode("contactRequest", sessions.Token, contact) err := h.contacts.Decode("contactConfirmed", srq.Token, contact)
if err != nil { 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 return
} }
// Use the userid which is not ours from the contact data. // Use the userid which is not ours from the contact data.
@ -451,16 +455,16 @@ func (h *Hub) sessionsHandler(c *Connection, sessions *DataSessions) {
return return
} }
// Add sessions for forein user. // Add sessions for forein user.
sessions.Users = user.SessionsData() users = user.SessionsData()
reply = true
default: 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() sessionsJson := h.buffers.New()
encoder := json.NewEncoder(sessionsJson) 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 { if err != nil {
log.Println("Sessions error while encoding JSON", err) log.Println("Sessions error while encoding JSON", err)
sessionsJson.Decref() sessionsJson.Decref()

14
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) { 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 var msg DataIncoming
err := json.Unmarshal(b.Bytes(), &msg) err := json.Unmarshal(b.Bytes(), &msg)
if err != nil { if err != nil {
@ -167,9 +167,9 @@ func (s *Server) OnText(c *Connection, b Buffer) {
} }
} }
case "Alive": case "Alive":
s.Alive(c, msg.Alive) s.Alive(c, msg.Alive, msg.Iid)
case "Sessions": case "Sessions":
s.Sessions(c, msg.Sessions) s.Sessions(c, msg.Sessions.Sessions, msg.Iid)
default: default:
log.Println("OnText unhandled message type", msg.Type) log.Println("OnText unhandled message type", msg.Type)
} }
@ -192,15 +192,15 @@ func (s *Server) Unicast(c *Connection, to string, m interface{}) {
b.Decref() 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)
} }

36
static/js/mediastream/api.js

@ -29,6 +29,7 @@ define(['jquery', 'underscore'], function($, _) {
this.sid = null; this.sid = null;
this.session = {}; this.session = {};
this.connector = connector; this.connector = connector;
this.iids= 0;
this.e = $({}); this.e = $({});
@ -74,7 +75,7 @@ define(['jquery', 'underscore'], function($, _) {
Type: type Type: type
}; };
payload[type] = data; payload[type] = data;
//console.log("<<<<<<<<<<<<", JSON.stringify(payload)); //console.log("<<<<<<<<<<<<", JSON.stringify(payload, null, 2));
this.connector.send(payload, noqueue); this.connector.send(payload, noqueue);
}; };
@ -91,6 +92,21 @@ define(['jquery', 'underscore'], function($, _) {
return this.apply(name, obj); 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. // Helper hack function to send API requests to other destinations.
// Simply provide an alternative send function on the obj Object. // Simply provide an alternative send function on the obj Object.
Api.prototype.apply = function(name, obj) { Api.prototype.apply = function(name, obj) {
@ -105,9 +121,16 @@ define(['jquery', 'underscore'], function($, _) {
this.last_receive = now; this.last_receive = now;
this.last_receive_overdue = false; this.last_receive_overdue = false;
var iid = d.Iid;
var data = d.Data; var data = d.Data;
var dataType = data.Type; var dataType = data.Type;
if (iid) {
// Shortcut for iid registered responses.
this.e.triggerHandler(iid+".request", [dataType, data]);
return;
}
switch (dataType) { switch (dataType) {
case "Self": case "Self":
console.log("Self received", data); console.log("Self received", data);
@ -321,16 +344,17 @@ define(['jquery', 'underscore'], function($, _) {
return this.send("Alive", data); return this.send("Alive", data);
}; };
Api.prototype.sendSessions = function(token, type) { Api.prototype.sendSessions = function(token, type, cb) {
var data = { var data = {
Type: "Sessions", Type: "Sessions",
Id: "some-random-whatever", Sessions: {
Token: token, Type: type,
TokenType: type Token: token
}
} }
return this.send("Sessions", data); return this.request("Sessions", data, cb);
}; };

40
static/js/services/buddylist.js

@ -129,7 +129,7 @@ define(['underscore', 'modernizr', 'avltree', 'text!partials/buddy.html', 'text!
}; };
// buddyList // 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 buddyTemplate = $compile(templateBuddy);
var buddyActions = $compile(templateBuddyActions); 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.hover(buddyElement, event.type === "mouseenter" ? true : false);
}, this)); }, this));
$element.on("click", ".buddy", _.bind(function(event) { $element.on("click", ".buddy", _.bind(function(event) {
console.log("click event", event);
var buddyElement = $(event.currentTarget); var buddyElement = $(event.currentTarget);
//buddyElement.scope().doDefault();
this.click(buddyElement, event.target); this.click(buddyElement, event.target);
}, this)); }, 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.attr("data-xthreshold", "10");
$element.on("swipeleft", ".buddy", _.bind(function(event) { $element.on("swipeleft", ".buddy", _.bind(function(event) {
event.preventDefault(); event.preventDefault();
@ -658,32 +651,47 @@ define(['underscore', 'modernizr', 'avltree', 'text!partials/buddy.html', 'text!
var scope = buddyElement.scope(); var scope = buddyElement.scope();
var session = scope.session; var session = scope.session;
var sessionData = session.get()
var contact = scope.contact; var contact = scope.contact;
var id;
var promise = (function() {
var deferred = $q.defer();
var sessionData = session.get()
if (!sessionData) { if (!sessionData) {
// TODO(longsleep): Find session with help of contact. // Find session with help of contact.
console.log("No sessions for this buddy.", session, contact);
if (contact && contact.Token) { if (contact && contact.Token) {
mediaStream.api.sendSessions(contact.Token, "contact"); 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);
}
});
} }
return;
} else { } else {
id = sessionData.Id; deferred.resolve(sessionData.Id);
} }
//console.log("id", id); return deferred.promise;
})();
switch (action) { switch (action) {
case "call": case "call":
promise.then(function(id) {
scope.doCall(id); scope.doCall(id);
});
break; break;
case "chat": case "chat":
promise.then(function(id) {
scope.doChat(id); scope.doChat(id);
});
break; break;
case "contact": case "contact":
if (contact) { if (contact) {
scope.doContactRemove(contact.Userid); scope.doContactRemove(contact.Userid);
} else { } else {
promise.then(function(id) {
scope.doContactRequest(id); scope.doContactRequest(id);
});
} }
break; break;
} }

Loading…
Cancel
Save