1+ const EventEmitter = require ( 'eventemitter3' )
2+
3+ const dataparty_crypto = require ( '@dataparty/crypto' )
4+ const LokiParty = require ( '../local/loki-party' )
5+ const PeerParty = require ( '../local/peer-party' )
6+ const MemoryConfig = require ( '../../config/memory' )
7+ const WebsocketComms = require ( '../../comms/websocket-comms' )
8+
9+ const PeerInvite = require ( './peer-invite' )
10+
11+ class MatchMakerClient extends EventEmitter {
12+ constructor ( identity , contacts , urlOrParty = 'https://postquantum.one/api/' , wsUrlOrParty = 'https://postquantum.one/api/ws' ) {
13+
14+ super ( )
15+
16+ this . contacts = contacts
17+ this . identity = identity
18+ this . wsParty = null
19+ this . restParty = null
20+
21+ if ( typeof urlOrParty == 'string' ) {
22+ this . restUrl = urlOrParty
23+ this . restParty = null
24+ } else {
25+ this . restParty = urlOrParty
26+ }
27+
28+ if ( typeof wsUrlOrParty == 'string' ) {
29+ this . wsUrl = wsUrlOrParty
30+ this . wsParty = null
31+ } else {
32+ this . wsParty = wsUrlOrParty
33+ }
34+
35+ this . invitesTx = null
36+ this . invitesRx = null
37+
38+ this . pendingInvites = {
39+ tx : { } ,
40+ rx : { }
41+ }
42+ //this.restParty =
43+ }
44+
45+
46+
47+ async start ( ) {
48+ /*
49+ *
50+ */
51+
52+ if ( ! this . restParty ) {
53+ let config = new MemoryConfig ( {
54+ basePath :'match-maker-client' ,
55+ cloud : {
56+ uri : this . restUrl
57+ }
58+ } )
59+
60+ this . restParty = new LokiParty ( {
61+ path : 'match-maker-client' ,
62+ dbAdapter : new LokiParty . Loki . LokiMemoryAdapter ( ) ,
63+ config
64+ } )
65+
66+ if ( this . identity ) { await this . restParty . setIdentity ( this . identity ) }
67+
68+ debug ( 'starting restParty' )
69+ await this . restParty . start ( )
70+
71+ await this . announcePublicKeys ( )
72+ }
73+
74+ if ( ! this . wsParty ) {
75+ this . wsParty = new PeerParty ( {
76+ comms : new WebsocketComms ( {
77+ uri : this . wsUrl ,
78+ discoverRemoteIdentity : false ,
79+ remoteIdentity : await this . restParty . comms . getServiceIdentity ( ) ,
80+ session : Math . random ( ) . toString ( 36 ) . slice ( 2 )
81+ } ) ,
82+ config : this . restParty . config
83+ } )
84+
85+ //if(this.identity){ await this.wsParty.setIdentity(this.identity) }
86+
87+ await this . wsParty . start ( )
88+
89+ debug ( 'starting wsParty' )
90+ await this . wsParty . start ( )
91+ debug ( 'waiting for websocket authorization' )
92+ await this . wsParty . comms . authorized ( )
93+
94+ this . invitesRx = this . wsParty . ROSLIB . Topic ( {
95+ ros : this . wsParty . comms . ros ,
96+ name : '/invites/' + encodeURIComponent ( this . restParty . identity . key . hash ) + '/rx' ,
97+ messageType : 'Object'
98+ } )
99+
100+ this . invitesRx . subscribe ( this . handleInviteRxMsg . bind ( this ) )
101+
102+
103+ this . invitesTx = this . wsParty . ROSLIB . Topic ( {
104+ ros : this . wsParty . comms . ros ,
105+ name : '/invites/' + encodeURIComponent ( this . restParty . identity . key . hash ) + '/tx' ,
106+ messageType : 'Object'
107+ } )
108+
109+ this . invitesTx . subscribe ( this . handleInviteTxMsg . bind ( this ) )
110+ }
111+
112+ }
113+
114+ async handleInviteRxMsg ( msg ) {
115+ debug ( 'handleInviteRxMsg' , this . invitesRx . name , msg )
116+
117+ const inviteId = msg . invite . $meta . id
118+
119+ if ( ! this . pendingInvites . rx [ inviteId ] && msg . invite . state == 'invited' ) {
120+
121+ const from = await this . lookupPublicKey ( msg . invite . fromHash )
122+ const to = await this . lookupPublicKey ( msg . invite . toHash )
123+
124+ let invite = new PeerInvite ( msg . invite , to , this , from )
125+
126+ this . pendingInvites . rx [ inviteId ] = invite
127+
128+ this . emit ( 'invited' , invite )
129+
130+ } else if ( this . pendingInvites . rx [ inviteId ] ) {
131+
132+ let invite = this . pendingInvites . rx [ inviteId ]
133+ invite . onInviteMsg ( msg . invite )
134+ }
135+ }
136+
137+ async handleInviteTxMsg ( msg ) {
138+ debug ( 'handleInviteTxMsg' , this . invitesTx . name , msg )
139+
140+ const inviteId = msg . invite . $meta . id
141+ let pending = this . pendingInvites . tx [ inviteId ]
142+
143+ if ( pending &&
144+ //msg.invite.state == 'accepted' &&
145+ pending . $meta . id == msg . invite . $meta . id
146+ ) {
147+
148+ pending . onInviteMsg ( msg . invite )
149+
150+ }
151+ }
152+
153+ async announcePublicKeys ( ) {
154+ const announceData = {
155+ type : this . restParty . identity . key . type ,
156+ hash : this . restParty . identity . key . hash ,
157+ public : this . restParty . identity . key . public
158+ }
159+
160+ debug ( 'announcePublicKeys' , announceData )
161+
162+ const announceResult = await this . restParty . comms . call ( 'key/announce' , announceData , {
163+ expectClearTextReply : false ,
164+ sendClearTextRequest : false ,
165+ useSessions : false
166+ } )
167+ }
168+
169+
170+ async lookupPublicKey ( hash ) {
171+ debug ( 'lookupPublicKey - hash:' , hash )
172+
173+ if ( hash == this . restParty . identity . key . hash ) {
174+ return this . restParty . identity
175+ }
176+
177+ if ( this . contacts ) {
178+ return await this . contacts . lookupPublicKey ( hash )
179+ }
180+
181+ const lookupData = { hash }
182+
183+ const lookupResult = await restParty . comms . call ( 'key/lookup' , lookupData , {
184+ expectClearTextReply : false ,
185+ sendClearTextRequest : false ,
186+ useSessions : false
187+ } )
188+
189+ if ( ! lookupResult . done ) {
190+ return null
191+ }
192+
193+ debug ( 'lookup result -' , lookupResult )
194+
195+ const identity = new dataparty_crypto . Identity ( {
196+ key : lookupResult . public_key
197+ } )
198+
199+ return identity
200+ }
201+
202+ async createInvite ( toHashOrIdentity , { type, service, role, session} , info ) {
203+
204+ debug ( 'createInvite' )
205+
206+ let toIdentity = null
207+ if ( typeof toHashOrIdentity == 'string' ) {
208+ const toIdentity = await lookupPublicKey ( userCallHashInput . value )
209+ thisotherIdentity = toIdentity
210+ } else {
211+ toIdentity = toHashOrIdentity
212+ }
213+
214+
215+
216+ debug ( 'toIdentity' , toIdentity )
217+
218+ const invitePayload = {
219+ type : type ? type : 'webrtc' ,
220+ service : service ? service : '@dataparty/video-chat' ,
221+ role : role ? role : 'client' ,
222+ timestamp : ( new Date ( ) ) . getTime ( ) ,
223+ from : this . wsParty . identity . key . hash ,
224+ to : toIdentity . key . hash ,
225+ session : session ? session : Math . random ( ) . toString ( 36 ) . slice ( 2 ) ,
226+ info : info ? info : {
227+ roomId : '' ,
228+ action : 'call' ,
229+ }
230+ }
231+
232+ const secureInvite = await this . wsParty . privateIdentity . encrypt ( invitePayload , toIdentity )
233+
234+ debug ( 'secure-invite' , secureInvite )
235+
236+ const invitePostData = {
237+ to : toIdentity . key . hash ,
238+ from : party . identity . key . hash ,
239+ payload : JSON . stringify ( secureInvite . toJSON ( ) )
240+ }
241+
242+ const inviteResult = await this . restParty . comms . call ( 'invite/create' , invitePostData , {
243+ expectClearTextReply : false ,
244+ sendClearTextRequest : false ,
245+ useSessions : false
246+ } )
247+
248+ const inviteDoc = inviteResult . invite
249+
250+ if ( ! inviteDoc ) { return }
251+
252+ let invite = new PeerInvite ( inviteResult . invite , toIdentity , this , this . restParty . identity )
253+
254+ invite . payload = invitePayload
255+
256+ this . pendingInvites . tx [ inviteDoc . $meta . id ] = invite
257+
258+ return invite
259+ }
260+
261+ async lookupInvites ( { createdAfter, type= 'to' , id, actorHash } ) {
262+ let actor = this . wsParty . identity . key . hash
263+
264+ const lookup = {
265+ invite :id , actor :actorHash ? actorHash : this . restParty . identity . key . hash ,
266+ createdAfter,
267+ type : ! type ? 'to' : type
268+ }
269+
270+ const lookupResult = await this . restParty . comms . call ( 'invite/lookup' , lookup , {
271+ expectClearTextReply : false ,
272+ sendClearTextRequest : false ,
273+ useSessions : false
274+ } )
275+
276+ if ( ! lookupResult . done ) {
277+ return null
278+ }
279+
280+ return lookupResult . invites
281+ }
282+
283+ async getPeerInvitesFromInviteDocs ( invites ) {
284+
285+ let peerInvites = [ ]
286+
287+ for ( let i = 0 ; i < invites . length ; i ++ ) {
288+
289+ const invite = invites [ i ]
290+ let to = await this . lookupPublicKey ( invite . toHash )
291+ let from = await this . lookupPublicKey ( invite . fromHash )
292+
293+ let peerInvite = new PeerInvite ( invites [ i ] , to , this , from )
294+
295+ peerInvites . push ( peerInvite )
296+ }
297+
298+ return peerInvites
299+ }
300+
301+ async setInviteState ( invite , newState ) {
302+
303+ debug ( 'setInviteState' )
304+ let actor = this . restParty . identity . key . hash
305+
306+ const inviteState = {
307+ invite : invite . inviteDoc . $meta . id ,
308+ actor,
309+ state : newState
310+ }
311+
312+ const inviteStateResult = await this . restParty . comms . call ( 'invite/set-state' , inviteState , {
313+ expectClearTextReply : false ,
314+ sendClearTextRequest : false ,
315+ useSessions : false
316+ } )
317+
318+ console . log ( 'setInviteState result' , inviteStateResult )
319+
320+ if ( ! inviteStateResult . done ) {
321+ return null
322+ }
323+
324+ return inviteStateResult . invite
325+ }
326+ }
327+
328+ module . exports = MatchMakerClient
0 commit comments