@@ -8,7 +8,6 @@ import type {
88import { EMPTY_STRING , UTF8 } from '../../common/strings.ts' ;
99import type { Id , IdOrNull , Ids } from '../../@types/common/index.d.ts' ;
1010import {
11- IdMap ,
1211 IdMap2 ,
1312 mapEnsure ,
1413 mapForEach ,
@@ -17,11 +16,6 @@ import {
1716 mapNew ,
1817 mapSet ,
1918} from '../../common/map.ts' ;
20- import type { Persister , Persists } from '../../@types/persisters/index.d.ts' ;
21- import type {
22- Receive ,
23- Synchronizer ,
24- } from '../../@types/synchronizers/index.d.ts' ;
2519import { WebSocket , WebSocketServer } from 'ws' ;
2620import {
2721 collClear ,
@@ -30,122 +24,59 @@ import {
3024 collSize ,
3125 collSize2 ,
3226} from '../../common/coll.ts' ;
33- import {
34- createPayload ,
35- createRawPayload ,
36- ifPayloadValid ,
37- receivePayload ,
38- } from '../common.ts' ;
27+ import { ifNotUndefined , slice } from '../../common/other.ts' ;
3928import { IdSet2 } from '../../common/set.ts' ;
40- import type { MergeableStore } from '../../@types/mergeable-store/index.d.ts' ;
41- import { createCustomSynchronizer } from '../index.ts' ;
29+ import { MESSAGE_SEPARATOR } from '../common.ts' ;
4230import { getListenerFunctions } from '../../common/listeners.ts' ;
43- import { ifNotUndefined } from '../../common/other.ts' ;
4431import { objFreeze } from '../../common/obj.ts' ;
4532
4633const PATH_REGEX = / \/ ( [ ^ ? ] * ) / ;
47- const SERVER_CLIENT_ID = 'S' ;
48-
49- export const createWsServer = ( <
50- PathPersister extends Persister <
51- Persists . MergeableStoreOnly | Persists . StoreOrMergeableStore
52- > ,
53- > (
54- webSocketServer : WebSocketServer ,
55- createPersisterForPath ?: ( pathId : Id ) => Promise < PathPersister | undefined > ,
56- destroyPersisterForPath ?: ( pathId : Id , persister : PathPersister ) => void ,
57- ) => {
58- type ServerClient = {
59- persister : PathPersister ;
60- synchronizer : Synchronizer ;
61- send : ( payload : string ) => void ;
62- } ;
6334
35+ export const createWsServer = ( ( webSocketServer : WebSocketServer ) => {
6436 const pathIdListeners : IdSet2 = mapNew ( ) ;
6537 const clientIdListeners : IdSet2 = mapNew ( ) ;
6638 const clientsByPath : IdMap2 < WebSocket > = mapNew ( ) ;
67- const serverClientsByPath : IdMap < ServerClient > = mapNew ( ) ;
6839
6940 const [ addListener , callListeners , delListenerImpl ] = getListenerFunctions (
7041 ( ) => wsServer ,
7142 ) ;
7243
73- const startServerClient = async ( pathId : Id ) =>
74- ifNotUndefined (
75- await createPersisterForPath ?.( pathId ) ,
76- async ( persister ) => {
77- const serverClient = mapEnsure (
78- serverClientsByPath ,
79- pathId ,
80- ( ) => ( { persister} ) as ServerClient ,
81- ) ;
82- const messageHandler = getMessageHandler ( SERVER_CLIENT_ID , pathId ) ;
83- serverClient . synchronizer = await createCustomSynchronizer (
84- persister . getStore ( ) as MergeableStore ,
85- ( toClientId , requestId , message , body ) =>
86- messageHandler ( createPayload ( toClientId , requestId , message , body ) ) ,
87- ( receive : Receive ) =>
88- ( serverClient . send = ( payload ) => receivePayload ( payload , receive ) ) ,
89- ( ) => { } ,
90- 0.1 ,
91- ) . startSync ( ) ;
92- } ,
93- ) ;
94-
95- const stopServerClient = ( pathId : Id ) =>
96- ifNotUndefined (
97- mapGet ( serverClientsByPath , pathId ) ,
98- ( { persister, synchronizer} ) => {
99- synchronizer ?. destroy ( ) ;
100- destroyPersisterForPath ?.( pathId , persister ) ;
101- collDel ( serverClientsByPath , pathId ) ;
102- } ,
103- ) ;
104-
105- const getMessageHandler = ( clientId : Id , pathId : Id ) => {
106- const clients = mapGet ( clientsByPath , pathId ) ;
107- const serverClient = mapGet ( serverClientsByPath , pathId ) ;
108- return ( payload : string ) =>
109- ifPayloadValid ( payload , ( toClientId , remainder ) => {
110- const forwardedPayload = createRawPayload ( clientId , remainder ) ;
111- if ( toClientId === EMPTY_STRING ) {
112- clientId !== SERVER_CLIENT_ID
113- ? serverClient ?. send ( forwardedPayload )
114- : 0 ;
115- mapForEach ( clients , ( otherClientId , otherWebSocket ) =>
116- otherClientId !== clientId
117- ? otherWebSocket . send ( forwardedPayload )
118- : 0 ,
119- ) ;
120- } else {
121- ( toClientId === SERVER_CLIENT_ID
122- ? serverClient
123- : mapGet ( clients , toClientId )
124- ) ?. send ( forwardedPayload ) ;
125- }
126- } ) ;
127- } ;
128-
12944 webSocketServer . on ( 'connection' , ( webSocket , request ) =>
13045 ifNotUndefined ( request . url ?. match ( PATH_REGEX ) , ( [ , pathId ] ) =>
131- ifNotUndefined ( request . headers [ 'sec-websocket-key' ] , async ( clientId ) => {
46+ ifNotUndefined ( request . headers [ 'sec-websocket-key' ] , ( clientId ) => {
13247 const clients = mapEnsure ( clientsByPath , pathId , mapNew < Id , WebSocket > ) ;
133- if ( collIsEmpty ( clients ) ) {
48+ mapSet ( clients , clientId , webSocket ) ;
49+
50+ if ( clients . size == 1 ) {
13451 callListeners ( pathIdListeners , undefined , pathId , 1 ) ;
135- await startServerClient ( pathId ) ;
13652 }
137- mapSet ( clients , clientId , webSocket ) ;
13853 callListeners ( clientIdListeners , [ pathId ] , clientId , 1 ) ;
13954
140- const messageHandler = getMessageHandler ( clientId , pathId ) ;
141- webSocket . on ( 'message' , ( data ) => messageHandler ( data . toString ( UTF8 ) ) ) ;
55+ webSocket . on ( 'message' , ( data ) => {
56+ const payload = data . toString ( UTF8 ) ;
57+ const splitAt = payload . indexOf ( MESSAGE_SEPARATOR ) ;
58+ if ( splitAt !== - 1 ) {
59+ const toClientId = slice ( payload , 0 , splitAt ) ;
60+ const message = slice ( payload , splitAt + 1 ) ;
61+ toClientId === EMPTY_STRING
62+ ? mapForEach ( clients , ( otherClientId , otherWebSocket ) =>
63+ otherClientId != clientId
64+ ? otherWebSocket . send (
65+ clientId + MESSAGE_SEPARATOR + message ,
66+ )
67+ : 0 ,
68+ )
69+ : mapGet ( clients , toClientId ) ?. send (
70+ clientId + MESSAGE_SEPARATOR + message ,
71+ ) ;
72+ }
73+ } ) ;
14274
14375 webSocket . on ( 'close' , ( ) => {
14476 collDel ( clients , clientId ) ;
14577 callListeners ( clientIdListeners , [ pathId ] , clientId , - 1 ) ;
14678 if ( collIsEmpty ( clients ) ) {
14779 collDel ( clientsByPath , pathId ) ;
148- stopServerClient ( pathId ) ;
14980 callListeners ( pathIdListeners , undefined , pathId , - 1 ) ;
15081 }
15182 } ) ;
0 commit comments