1717
1818"use strict" ;
1919
20- const SerializationUtils = require ( '../utils/serialization_utils.js' ) ;
21- const Serialize = SerializationUtils . Serialize ;
22- const TcprosUtils = require ( '../utils/tcpros_utils.js' ) ;
2320const EventEmitter = require ( 'events' ) ;
24- const Logging = require ( './Logging.js' ) ;
25- const { REGISTERING , REGISTERED , SHUTDOWN } = require ( '../utils/ClientStates.js' ) ;
21+ const { rebroadcast} = require ( '../utils/event_utils.js' ) ;
2622
2723class Publisher extends EventEmitter {
28- constructor ( options , nodeHandle ) {
24+ constructor ( impl ) {
2925 super ( ) ;
30- this . _topic = options . topic ;
3126
32- this . _type = options . type ;
27+ ++ impl . count ;
28+ this . _impl = impl ;
3329
34- this . _latching = ! ! options . latching ;
35-
36- this . _tcpNoDelay = ! ! options . tcpNoDelay ;
37-
38-
39- if ( options . queueSize ) {
40- this . _queueSize = options . queueSize ;
41- }
42- else {
43- this . _queueSize = 1 ;
44- }
45-
46- /**
47- * throttleMs interacts with queueSize to determine when to send
48- * messages.
49- * < 0 : send immediately - no interaction with queue
50- * >= 0 : place event at end of event queue to publish message
51- after minimum delay (MS)
52- */
53- if ( options . hasOwnProperty ( 'throttleMs' ) ) {
54- this . _throttleMs = options . throttleMs ;
55- }
56- else {
57- this . _throttleMs = 0 ;
58- }
59-
60- // OPTIONS STILL NOT HANDLED:
61- // headers: extra headers to include
62- // subscriber_listener: callback for new subscribers connect/disconnect
63-
64- this . _resolve = ! ! options . resolve ;
65-
66- this . _lastSentMsg = null ;
67-
68- this . _nodeHandle = nodeHandle ;
69- this . _nodeHandle . getSpinner ( ) . addClient ( this , this . _getSpinnerId ( ) , this . _queueSize , this . _throttleMs ) ;
70-
71- this . _log = Logging . getLogger ( 'ros.rosnodejs' ) ;
72-
73- this . _subClients = { } ;
74-
75- this . _messageHandler = options . typeClass ;
76-
77- this . _state = REGISTERING ;
78- this . _register ( ) ;
79- }
80-
81- _getSpinnerId ( ) {
82- return `Publisher://${ this . getTopic ( ) } ` ;
30+ rebroadcast ( 'registered' , this . _impl , this ) ;
31+ rebroadcast ( 'connection' , this . _impl , this ) ;
32+ rebroadcast ( 'disconnect' , this . _impl , this ) ;
33+ rebroadcast ( 'error' , this . _impl , this ) ;
8334 }
8435
8536 getTopic ( ) {
86- return this . _topic ;
37+ if ( this . _impl ) {
38+ return this . _impl . getTopic ( ) ;
39+ }
40+ // else
41+ return null ;
8742 }
8843
8944 getType ( ) {
90- return this . _type ;
45+ if ( this . _impl ) {
46+ return this . _impl . getType ( ) ;
47+ }
48+ // else
49+ return null ;
9150 }
9251
9352 getLatching ( ) {
94- return this . _latching ;
53+ if ( this . _impl ) {
54+ return this . _impl . getLatching ( ) ;
55+ }
56+ // else
57+ return false ;
9558 }
9659
9760 getNumSubscribers ( ) {
98- return Object . keys ( this . _subClients ) . length ;
61+ if ( this . _impl ) {
62+ return this . _impl . getNumSubscribers ( ) ;
63+ }
64+ // else
65+ return 0 ;
9966 }
10067
10168 shutdown ( ) {
102- this . _nodeHandle . unadvertise ( this . getTopic ( ) ) ;
69+ const topic = this . getTopic ( ) ;
70+ if ( this . _impl ) {
71+ const impl = this . _impl
72+ this . _impl = null ;
73+ this . removeAllListeners ( ) ;
74+
75+ -- impl . count ;
76+ if ( impl . count <= 0 ) {
77+ return impl . shutdown ( ) ;
78+ }
79+ }
80+ // else
81+ return Promise . resolve ( ) ;
10382 }
10483
10584 isShutdown ( ) {
106- return this . _state === SHUTDOWN ;
107- }
108-
109- disconnect ( ) {
110- this . _state = SHUTDOWN ;
111-
112- Object . keys ( this . _subClients ) . forEach ( ( clientId ) => {
113- const client = this . _subClients [ clientId ] ;
114- client . end ( ) ;
115- } ) ;
116-
117- // disconnect from the spinner in case we have any pending callbacks
118- this . _nodeHandle . getSpinner ( ) . disconnect ( this . _getSpinnerId ( ) ) ;
119- this . _subClients = { } ;
85+ return ! ! this . _impl ;
12086 }
12187
12288 /**
@@ -126,141 +92,7 @@ class Publisher extends EventEmitter {
12692 * @param [throttleMs] {number} optional override for publisher setting
12793 */
12894 publish ( msg , throttleMs ) {
129- if ( this . isShutdown ( ) ) {
130- return ;
131- }
132-
133- if ( typeof throttleMs !== 'number' ) {
134- throttleMs = this . _throttleMs ;
135- }
136-
137- if ( throttleMs < 0 ) {
138- // short circuit JS event queue, publish "synchronously"
139- this . _handleMsgQueue ( [ msg ] ) ;
140- }
141- else {
142- this . _nodeHandle . getSpinner ( ) . ping ( this . _getSpinnerId ( ) , msg ) ;
143- }
144- }
145-
146- /**
147- * Pulls all msgs off queue, serializes, and publishes them
148- */
149- _handleMsgQueue ( msgQueue ) {
150-
151- // There's a small chance that we were shutdown while the spinner was locked
152- // which could cause _handleMsgQueue to be called if this publisher was in there.
153- if ( this . isShutdown ( ) ) {
154- return ;
155- }
156-
157- const numClients = this . getNumSubscribers ( ) ;
158- if ( numClients === 0 ) {
159- this . _log . debugThrottle ( 2000 , `Publishing message on ${ this . getTopic ( ) } with no subscribers` ) ;
160- }
161-
162- try {
163- msgQueue . forEach ( ( msg ) => {
164- if ( this . _resolve ) {
165- msg = this . _messageHandler . Resolve ( msg ) ;
166- }
167-
168- const serializedMsg = TcprosUtils . serializeMessage ( this . _messageHandler , msg ) ;
169-
170- Object . keys ( this . _subClients ) . forEach ( ( client ) => {
171- this . _subClients [ client ] . write ( serializedMsg ) ;
172- } ) ;
173-
174- // if this publisher is supposed to latch,
175- // save the last message. Any subscribers that connect
176- // before another call to publish() will receive this message
177- if ( this . getLatching ( ) ) {
178- this . _lastSentMsg = serializedMsg ;
179- }
180- } ) ;
181- }
182- catch ( err ) {
183- this . _log . error ( 'Error when publishing message on topic %s: %s' , this . getTopic ( ) , err . stack ) ;
184- this . emit ( 'error' , err ) ;
185- }
186- }
187-
188- handleSubscriberConnection ( subscriber , header ) {
189- let error = TcprosUtils . validateSubHeader (
190- header , this . getTopic ( ) , this . getType ( ) ,
191- this . _messageHandler . md5sum ( ) ) ;
192- if ( error !== null ) {
193- this . _log . error ( 'Unable to validate subscriber connection header '
194- + JSON . stringify ( header ) ) ;
195- subscriber . end ( Serialize ( error ) ) ;
196- return ;
197- }
198- // else
199- this . _log . info ( 'Pub %s got connection header %s' , this . getTopic ( ) , JSON . stringify ( header ) ) ;
200-
201- // create and send response
202- let respHeader =
203- TcprosUtils . createPubHeader (
204- this . _nodeHandle . getNodeName ( ) ,
205- this . _messageHandler . md5sum ( ) ,
206- this . getType ( ) ,
207- this . getLatching ( ) ,
208- this . _messageHandler . messageDefinition ( ) ) ;
209- subscriber . write ( respHeader ) ;
210-
211- // if this publisher had the tcpNoDelay option set
212- // disable the nagle algorithm
213- if ( this . _tcpNoDelay ) {
214- subscriber . setNoDelay ( true ) ;
215- }
216-
217- subscriber . on ( 'close' , ( ) => {
218- this . _log . info ( 'Publisher %s client %s disconnected!' ,
219- this . getTopic ( ) , subscriber . name ) ;
220- delete this . _subClients [ subscriber . name ] ;
221- this . emit ( 'disconnect' ) ;
222- } ) ;
223-
224- subscriber . on ( 'end' , ( ) => {
225- this . _log . info ( 'Sub %s sent END' , subscriber . name ) ;
226- } ) ;
227-
228- subscriber . on ( 'error' , ( ) => {
229- this . _log . warn ( 'Sub %s had error' , subscriber . name ) ;
230- } ) ;
231-
232- if ( this . _lastSentMsg !== null ) {
233- this . _log . debug ( 'Sending latched msg to new subscriber' ) ;
234- subscriber . write ( this . _lastSentMsg ) ;
235- }
236-
237- // if handshake good, add to list, we'll start publishing to it
238- this . _subClients [ subscriber . name ] = subscriber ;
239-
240- this . emit ( 'connection' , header , subscriber . name ) ;
241- }
242-
243- _register ( ) {
244- this . _nodeHandle . registerPublisher ( this . _topic , this . _type )
245- . then ( ( resp ) => {
246- // if we were shutdown between the starting the registration and now, bail
247- if ( this . isShutdown ( ) ) {
248- return ;
249- }
250-
251- this . _log . info ( 'Registered %s as a publisher: %j' , this . _topic , resp ) ;
252- let code = resp [ 0 ] ;
253- let msg = resp [ 1 ] ;
254- let subs = resp [ 2 ] ;
255- if ( code === 1 ) {
256- // registration worked
257- this . _state = REGISTERED ;
258- this . emit ( 'registered' ) ;
259- }
260- } )
261- . catch ( ( err ) => {
262- this . _log . error ( 'Error while registering publisher %s: %s' , this . getTopic ( ) , err ) ;
263- } )
95+ this . _impl . publish ( msg , throttleMs ) ;
26496 }
26597}
26698
0 commit comments