@@ -8,7 +8,8 @@ import type { ServerOptions } from 'ws'
88import { Converter , ConvertedCallback } from './converter'
99import { isError } from './error'
1010import { File , FileType } from './file'
11- import { debugWatcher } from './utils/debug'
11+ import { watchNotifierWebSocketEntrypoint } from './server'
12+ import { debugWatcher , debugWatcherWS } from './utils/debug'
1213
1314const chokidarWatch : typeof _watch = ( ...args ) => {
1415 debugWatcher ( 'Start watching with chokidar: %O' , args )
@@ -91,26 +92,47 @@ export class Watcher {
9192 }
9293}
9394
95+ export type WatchNotifierEntrypointType = 'static' | 'server'
96+
9497export class WatchNotifier {
9598 listeners = new Map < string , Set < any > > ( )
9699
97100 private wss ?: WebSocketServer
98101 private portNumber ?: number
99102
103+ get server ( ) {
104+ return this . wss
105+ }
106+
100107 async port ( ) {
101108 if ( this . portNumber === undefined )
102109 this . portNumber = await getPortPromise ( { port : 37717 } )
103110
104111 return this . portNumber
105112 }
106113
107- async register ( fn : string ) {
114+ async register (
115+ fn : string ,
116+ entrypointType : WatchNotifierEntrypointType = 'static'
117+ ) {
108118 const identifier = WatchNotifier . sha256 ( fn )
109119
110120 if ( ! this . listeners . has ( identifier ) )
111121 this . listeners . set ( identifier , new Set ( ) )
112122
113- return `ws://localhost:${ await this . port ( ) } /${ identifier } `
123+ return await this . entrypoint ( identifier , entrypointType )
124+ }
125+
126+ async entrypoint (
127+ identifier : string ,
128+ entrypointType : WatchNotifierEntrypointType = 'static'
129+ ) {
130+ if ( entrypointType === 'server' ) {
131+ return `/${ watchNotifierWebSocketEntrypoint } /${ identifier } `
132+ }
133+
134+ const port = await this . port ( )
135+ return `ws://localhost:${ port } /${ identifier } `
114136 }
115137
116138 sendTo ( fn : string , command : string ) {
@@ -124,21 +146,64 @@ export class WatchNotifier {
124146 }
125147
126148 async start ( opts : ServerOptions = { } ) {
127- this . wss = new WebSocketServer ( { ...opts , port : await this . port ( ) } )
128- this . wss . on ( 'connection' , ( ws , sock ) => {
129- if ( sock . url ) {
130- const [ , identifier ] = sock . url . split ( '/' )
131- const wsSet = this . listeners . get ( identifier )
149+ const port = await this . port ( )
132150
133- if ( wsSet !== undefined ) {
134- this . listeners . set ( identifier , wsSet . add ( ws ) )
151+ this . wss = new WebSocketServer ( { ...opts , port } )
135152
136- ws . on ( 'close' , ( ) => this . listeners . get ( identifier ) ! . delete ( ws ) )
153+ debugWatcherWS (
154+ 'WebSocket server for watch notifier started on port %d.' ,
155+ port
156+ )
137157
138- ws . send ( 'ready' )
139- return
158+ this . wss . on ( 'connection' , ( ws , sock ) => {
159+ if ( sock . url ) {
160+ debugWatcherWS ( 'New WebSocket connection: %s' , sock . url )
161+
162+ const identifier = ( ( ) => {
163+ try {
164+ const parsedUrl = new URL ( sock . url , `ws://localhost:${ port } ` )
165+ const detectedIdentifier = parsedUrl . pathname . split ( '/' ) . pop ( )
166+
167+ debugWatcherWS (
168+ 'Detected identifier from WebSocket connection: %s' ,
169+ detectedIdentifier
170+ )
171+
172+ return detectedIdentifier
173+ } catch ( e : unknown ) {
174+ debugWatcherWS ( 'Error occurred during parsing identifier: %o' , e )
175+ return undefined
176+ }
177+ } ) ( )
178+
179+ if ( identifier ) {
180+ const wsSet = this . listeners . get ( identifier )
181+
182+ if ( wsSet !== undefined ) {
183+ this . listeners . set ( identifier , wsSet . add ( ws ) )
184+ debugWatcherWS (
185+ 'WebSocket connection for identifier "%s" registered' ,
186+ identifier
187+ )
188+
189+ ws . on ( 'close' , ( ) => {
190+ this . listeners . get ( identifier ) ! . delete ( ws )
191+ debugWatcherWS (
192+ 'WebSocket connection for identifier "%s" closed' ,
193+ identifier
194+ )
195+ } )
196+
197+ ws . send ( 'ready' )
198+ return
199+ }
140200 }
141201 }
202+
203+ debugWatcherWS (
204+ 'WebSocket connection request has been dismissed: %s' ,
205+ sock . url
206+ )
142207 ws . close ( )
143208 } )
144209 }
0 commit comments