@@ -7,15 +7,16 @@ import {
77import _debug from '@codesandbox/common/lib/utils/debug' ;
88import { camelizeKeys } from 'humps' ;
99import { TextOperation } from 'ot' ;
10- import { Socket , Channel } from 'phoenix' ;
10+ import { Channel , Socket } from 'phoenix' ;
1111import uuid from 'uuid' ;
1212
13- import clientsFactory from './clients' ;
1413import { OPTIMISTIC_ID_PREFIX } from '../utils' ;
14+ import clientsFactory from './clients' ;
1515
1616type Options = {
1717 onApplyOperation ( args : { moduleShortid : string ; operation : any } ) : void ;
1818 provideJwtToken ( ) : string ;
19+ getConnectionsCount ( ) : number ;
1920} ;
2021
2122type JoinChannelResponse = {
@@ -29,27 +30,22 @@ declare global {
2930 }
3031}
3132
32- const identifier = uuid . v4 ( ) ;
33- const sentMessages = new Map ( ) ;
34- const debug = _debug ( 'cs:socket' ) ;
33+ class Live {
34+ private identifier = uuid . v4 ( ) ;
35+ private sentMessages = new Map ( ) ;
36+ private debug = _debug ( 'cs:socket' ) ;
37+ private channel : Channel | null ;
38+ private messageIndex = 0 ;
39+ private clients : ReturnType < typeof clientsFactory > ;
40+ private _socket : Socket ;
3541
36- let channel : Channel | null ;
37- let messageIndex = 0 ;
38- let clients : ReturnType < typeof clientsFactory > ;
39- let _socket : Socket ;
40- let provideJwtToken : ( ) => string ;
42+ private provideJwtToken : ( ) => string ;
43+ private getConnectionsCount : ( ) => number ;
4144
42- export default new ( class Live {
4345 initialize ( options : Options ) {
44- const live = this ;
45-
46- clients = clientsFactory (
46+ this . clients = clientsFactory (
4747 ( moduleShortid , revision , operation ) => {
48- live . send ( 'operation' , {
49- moduleShortid,
50- operation,
51- revision,
52- } ) ;
48+ this . sendOperation ( moduleShortid , revision , operation ) ;
5349 } ,
5450 ( moduleShortid , operation ) => {
5551 options . onApplyOperation ( {
@@ -58,48 +54,49 @@ export default new (class Live {
5854 } ) ;
5955 }
6056 ) ;
61- provideJwtToken = options . provideJwtToken ;
57+ this . provideJwtToken = options . provideJwtToken ;
58+ this . getConnectionsCount = options . getConnectionsCount ;
6259 }
6360
6461 getSocket ( ) {
65- return _socket || this . connect ( ) ;
62+ return this . _socket || this . connect ( ) ;
6663 }
6764
6865 connect ( ) : Socket {
69- if ( ! _socket ) {
66+ if ( ! this . _socket ) {
7067 const protocol = process . env . LOCAL_SERVER ? 'ws' : 'wss' ;
71- _socket = new Socket ( `${ protocol } ://${ location . host } /socket` , {
68+ this . _socket = new Socket ( `${ protocol } ://${ location . host } /socket` , {
7269 params : {
73- guardian_token : provideJwtToken ( ) ,
70+ guardian_token : this . provideJwtToken ( ) ,
7471 } ,
7572 } ) ;
7673
77- _socket . connect ( ) ;
78- window . socket = _socket ;
79- debug ( 'Connecting to socket' , _socket ) ;
74+ this . _socket . connect ( ) ;
75+ window . socket = this . _socket ;
76+ this . debug ( 'Connecting to socket' , this . _socket ) ;
8077 }
8178
82- return _socket ;
79+ return this . _socket ;
8380 }
8481
8582 disconnect ( ) {
8683 return new Promise ( ( resolve , reject ) => {
87- if ( ! channel ) {
84+ if ( ! this . channel ) {
8885 resolve ( { } ) ;
8986 return ;
9087 }
9188
92- channel
89+ this . channel
9390 . leave ( )
9491 . receive ( 'ok' , resp => {
95- if ( ! channel ) {
92+ if ( ! this . channel ) {
9693 return resolve ( { } ) ;
9794 }
9895
99- channel . onMessage = d => d ;
100- channel = null ;
101- sentMessages . clear ( ) ;
102- messageIndex = 0 ;
96+ this . channel . onMessage = d => d ;
97+ this . channel = null ;
98+ this . sentMessages . clear ( ) ;
99+ this . messageIndex = 0 ;
103100
104101 return resolve ( resp ) ;
105102 } )
@@ -110,9 +107,9 @@ export default new (class Live {
110107
111108 joinChannel ( roomId : string ) : Promise < JoinChannelResponse > {
112109 return new Promise ( ( resolve , reject ) => {
113- channel = this . getSocket ( ) . channel ( `live:${ roomId } ` , { version : 2 } ) ;
110+ this . channel = this . getSocket ( ) . channel ( `live:${ roomId } ` , { version : 2 } ) ;
114111
115- channel
112+ this . channel
116113 . join ( )
117114 . receive ( 'ok' , resp => {
118115 const result = camelizeKeys ( resp ) as JoinChannelResponse ;
@@ -130,18 +127,18 @@ export default new (class Live {
130127 data : object ;
131128 } ) => { }
132129 ) {
133- if ( ! channel ) {
130+ if ( ! this . channel ) {
134131 return ;
135132 }
136133
137- channel . onMessage = ( event : any , data : any ) => {
134+ this . channel . onMessage = ( event : any , data : any ) => {
138135 const disconnected =
139136 ( data == null || Object . keys ( data ) . length === 0 ) &&
140137 event === 'phx_error' ;
141138 const alteredEvent = disconnected ? 'connection-loss' : event ;
142139
143140 const _isOwnMessage = Boolean (
144- data && data . _messageId && sentMessages . delete ( data . _messageId )
141+ data && data . _messageId && this . sentMessages . delete ( data . _messageId )
145142 ) ;
146143
147144 action ( {
@@ -155,14 +152,18 @@ export default new (class Live {
155152 }
156153
157154 send ( event : string , payload : { _messageId ?: string ; [ key : string ] : any } ) {
158- const _messageId = identifier + messageIndex ++ ;
155+ if ( this . getConnectionsCount ( ) < 2 ) {
156+ return Promise . resolve ( ) ;
157+ }
158+
159+ const _messageId = this . identifier + this . messageIndex ++ ;
159160 // eslint-disable-next-line
160161 payload . _messageId = _messageId ;
161- sentMessages . set ( _messageId , payload ) ;
162+ this . sentMessages . set ( _messageId , payload ) ;
162163
163164 return new Promise ( ( resolve , reject ) => {
164- if ( channel ) {
165- channel
165+ if ( this . channel ) {
166+ this . channel
166167 . push ( event , payload )
167168 . receive ( 'ok' , resolve )
168169 . receive ( 'error' , reject ) ;
@@ -202,7 +203,7 @@ export default new (class Live {
202203 }
203204
204205 try {
205- clients . get ( moduleShortid ) . applyClient ( operation ) ;
206+ this . clients . get ( moduleShortid ) . applyClient ( operation ) ;
206207 } catch ( e ) {
207208 // Something went wrong, probably a sync mismatch. Request new version
208209 this . send ( 'live:module_state' , { } ) ;
@@ -309,31 +310,59 @@ export default new (class Live {
309310 } ) ;
310311 }
311312
313+ getClient ( moduleShortid : string ) {
314+ return this . clients . get ( moduleShortid ) ;
315+ }
316+
312317 getAllClients ( ) {
313- return clients . getAll ( ) ;
318+ return this . clients . getAll ( ) ;
314319 }
315320
316321 applyClient ( moduleShortid : string , operation : any ) {
317- return clients
322+ return this . clients
318323 . get ( moduleShortid )
319324 . applyClient ( TextOperation . fromJSON ( operation ) ) ;
320325 }
321326
322327 applyServer ( moduleShortid : string , operation : any ) {
323- return clients
328+ return this . clients
324329 . get ( moduleShortid )
325330 . applyServer ( TextOperation . fromJSON ( operation ) ) ;
326331 }
327332
328333 serverAck ( moduleShortid : string ) {
329- return clients . get ( moduleShortid ) . serverAck ( ) ;
334+ return this . clients . get ( moduleShortid ) . serverAck ( ) ;
330335 }
331336
332337 createClient ( moduleShortid : string , revision : number ) {
333- return clients . create ( moduleShortid , revision ) ;
338+ return this . clients . create ( moduleShortid , revision ) ;
334339 }
335340
336341 resetClients ( ) {
337- clients . clear ( ) ;
342+ this . clients . clear ( ) ;
343+ }
344+
345+ private operationToElixir ( ot ) {
346+ return ot . map ( op => {
347+ if ( typeof op === 'number' ) {
348+ if ( op < 0 ) {
349+ return { d : - op } ;
350+ }
351+
352+ return op ;
353+ }
354+
355+ return { i : op } ;
356+ } ) ;
338357 }
339- } ) ( ) ;
358+
359+ private sendOperation ( moduleShortid , revision , operation ) {
360+ this . send ( 'operation' , {
361+ moduleShortid,
362+ operation : this . operationToElixir ( operation . toJSON ( ) ) ,
363+ revision : Number ( revision ) ,
364+ } ) ;
365+ }
366+ }
367+
368+ export default new Live ( ) ;
0 commit comments