File Coverage

lib/Hypersonic/WebSocket/Room.pm
Criterion Covered Total %
statement 74 74 100.0
branch n/a
condition 3 6 50.0
subroutine 20 20 100.0
pod 0 16 0.0
total 97 116 83.6


line stmt bran cond sub pod time code
1             package Hypersonic::WebSocket::Room;
2 1     1   1408 use strict;
  1         2  
  1         41  
3 1     1   5 use warnings;
  1         1  
  1         61  
4              
5             # Hypersonic::WebSocket::Room - XS Broadcast support for WebSocket connections
6             #
7             # All room management is done in C via XS::JIT::Builder.
8             # This module generates XS functions callable from Perl.
9              
10             our $VERSION = '0.15';
11              
12             # Maximum rooms and clients per room
13 1     1   4 use constant MAX_ROOMS => 1000;
  1         1  
  1         49  
14 1     1   4 use constant MAX_CLIENTS_PER_ROOM => 10000;
  1         1  
  1         2167  
15              
16             # Generate all Room XS code
17             sub generate_c_code {
18 1     1 0 17 my ($class, $builder, $opts) = @_;
19 1   50     9 $opts //= {};
20            
21 1   50     6 my $max_rooms = $opts->{max_rooms} // MAX_ROOMS;
22 1   50     3 my $max_clients = $opts->{max_clients_per_room} // MAX_CLIENTS_PER_ROOM;
23            
24             # Generate room registry (static C)
25 1         5 $class->gen_room_registry($builder, $max_rooms, $max_clients);
26            
27             # Generate XS functions
28 1         6 $class->gen_xs_new($builder);
29 1         9 $class->gen_xs_destroy($builder);
30 1         6 $class->gen_xs_join($builder);
31 1         4 $class->gen_xs_leave($builder);
32 1         3 $class->gen_xs_has($builder);
33 1         7 $class->gen_xs_broadcast($builder);
34 1         7 $class->gen_xs_broadcast_binary($builder);
35 1         3 $class->gen_xs_count($builder);
36 1         5 $class->gen_xs_count_open($builder);
37 1         3 $class->gen_xs_close_all($builder);
38 1         5 $class->gen_xs_name($builder);
39 1         3 $class->gen_xs_clear($builder);
40 1         5 $class->gen_xs_clients($builder);
41            
42 1         3 return $builder;
43             }
44              
45             # Generate room registry (C data structures)
46             sub gen_room_registry {
47 1     1 0 2 my ($class, $builder, $max_rooms, $max_clients) = @_;
48            
49 1         69 $builder->comment('Room registry')
50             ->line('#define ROOM_MAX_ROOMS ' . $max_rooms)
51             ->line('#define ROOM_MAX_CLIENTS ' . $max_clients)
52             ->blank
53             ->comment('Room structure')
54             ->line('typedef struct {')
55             ->line(' int active;')
56             ->line(' char name[256];')
57             ->line(' int client_fds[ROOM_MAX_CLIENTS];')
58             ->line(' int client_count;')
59             ->line('} WSRoom;')
60             ->blank
61             ->line('static WSRoom room_registry[ROOM_MAX_ROOMS];')
62             ->line('static int room_count = 0;')
63             ->blank
64             ->comment('Find room by name, returns index or -1')
65             ->line('static int find_room_by_name(const char* name) {')
66             ->line(' int i;')
67             ->line(' for (i = 0; i < ROOM_MAX_ROOMS; i++) {')
68             ->if('room_registry[i].active && strcmp(room_registry[i].name, name) == 0')
69             ->line('return i;')
70             ->endif
71             ->line(' }')
72             ->line('return -1;')
73             ->line('}')
74             ->blank
75             ->comment('Find free room slot')
76             ->line('static int find_free_room_slot() {')
77             ->line(' int i;')
78             ->line(' for (i = 0; i < ROOM_MAX_ROOMS; i++) {')
79             ->if('!room_registry[i].active')
80             ->line('return i;')
81             ->endif
82             ->line(' }')
83             ->line('return -1;')
84             ->line('}')
85             ->blank
86             ->comment('Extract fd from SV - handles both integer and WebSocket object')
87             ->line('static int extract_fd(SV* sv) {')
88             ->if('SvROK(sv)')
89             ->comment('Reference - check if hash with fd key')
90             ->line('SV* deref = SvRV(sv);')
91             ->if('SvTYPE(deref) == SVt_PVHV')
92             ->line('HV* hv = (HV*)deref;')
93             ->line('SV** fd_sv = hv_fetchs(hv, "fd", 0);')
94             ->if('fd_sv && *fd_sv')
95             ->line('return SvIV(*fd_sv);')
96             ->endif
97             ->endif
98             ->line('return -1;')
99             ->else
100             ->comment('Plain integer')
101             ->line('return SvIV(sv);')
102             ->endif
103             ->line('}')
104             ->blank;
105            
106 1         1 return $builder;
107             }
108              
109             # XS: new(name) - returns blessed object
110             sub gen_xs_new {
111 1     1 0 2 my ($class, $builder) = @_;
112            
113 1         82 $builder->xs_function('xs_room_new')
114             ->xs_preamble
115             ->line('STRLEN name_len;')
116             ->line('const char* name;')
117             ->line('int room_id;')
118             ->line('WSRoom* room;')
119             ->line('SV* room_sv;')
120             ->line('SV* room_ref;')
121             ->blank
122             ->if('items != 2')
123             ->line('croak("Usage: Hypersonic::WebSocket::Room->new(name)");')
124             ->endif
125             ->blank
126             ->line('name = SvPV(ST(1), name_len);')
127             ->blank
128             ->comment('Check if room already exists')
129             ->line('room_id = find_room_by_name(name);')
130             ->if('room_id < 0')
131             ->comment('Find free slot')
132             ->line('room_id = find_free_room_slot();')
133             ->if('room_id < 0')
134             ->line('croak("Maximum rooms reached");')
135             ->endif
136             ->blank
137             ->line('room = &room_registry[room_id];')
138             ->line('room->active = 1;')
139             ->if('name_len >= sizeof(room->name)')
140             ->line('name_len = sizeof(room->name) - 1;')
141             ->endif
142             ->line('memcpy(room->name, name, name_len);')
143             ->line('room->name[name_len] = \'\\0\';')
144             ->line('room->client_count = 0;')
145             ->line('memset(room->client_fds, -1, sizeof(room->client_fds));')
146             ->line('room_count++;')
147             ->endif
148             ->blank
149             ->comment('Create blessed object: bless \\$room_id, class')
150             ->line('room_sv = newSViv(room_id);')
151             ->line('room_ref = newRV_noinc(room_sv);')
152             ->line('sv_bless(room_ref, gv_stashpv("Hypersonic::WebSocket::Room", GV_ADD));')
153             ->line('ST(0) = sv_2mortal(room_ref);')
154             ->line('XSRETURN(1);')
155             ->xs_end
156             ->blank;
157            
158 1         3 return $builder;
159             }
160              
161             # XS: destroy() - instance method
162             sub gen_xs_destroy {
163 1     1 0 3 my ($class, $builder) = @_;
164            
165 1         28 $builder->xs_function('xs_room_destroy')
166             ->xs_preamble
167             ->if('items != 1')
168             ->line('croak("Usage: $room->destroy()");')
169             ->endif
170             ->blank
171             ->line('int room_id = SvIV(SvRV(ST(0)));')
172             ->blank
173             ->if('room_id < 0 || room_id >= ROOM_MAX_ROOMS')
174             ->line('XSRETURN_NO;')
175             ->endif
176             ->if('!room_registry[room_id].active')
177             ->line('XSRETURN_NO;')
178             ->endif
179             ->blank
180             ->line('memset(&room_registry[room_id], 0, sizeof(WSRoom));')
181             ->line('room_count--;')
182             ->line('XSRETURN_YES;')
183             ->xs_end
184             ->blank;
185            
186 1         1 return $builder;
187             }
188              
189             # XS: join(fd|ws) - instance method
190             sub gen_xs_join {
191 1     1 0 3 my ($class, $builder) = @_;
192            
193 1         43 $builder->xs_function('xs_room_join')
194             ->xs_preamble
195             ->line('int room_id;')
196             ->line('int fd;')
197             ->line('int i;')
198             ->line('WSRoom* room;')
199             ->blank
200             ->if('items != 2')
201             ->line('croak("Usage: $room->join(fd)");')
202             ->endif
203             ->blank
204             ->line('room_id = SvIV(SvRV(ST(0)));')
205             ->line('fd = extract_fd(ST(1));')
206             ->blank
207             ->if('fd < 0')
208             ->line('XSRETURN_NO;')
209             ->endif
210             ->if('room_id < 0 || room_id >= ROOM_MAX_ROOMS')
211             ->line('XSRETURN_NO;')
212             ->endif
213             ->if('!room_registry[room_id].active')
214             ->line('XSRETURN_NO;')
215             ->endif
216             ->blank
217             ->line('room = &room_registry[room_id];')
218             ->blank
219             ->comment('Check if already in room')
220             ->line('for (i = 0; i < room->client_count; i++) {')
221             ->if('room->client_fds[i] == fd')
222             ->line('XSRETURN_YES;')
223             ->endif
224             ->line('}')
225             ->blank
226             ->comment('Add to room')
227             ->if('room->client_count >= ROOM_MAX_CLIENTS')
228             ->line('XSRETURN_NO;')
229             ->endif
230             ->blank
231             ->line('room->client_fds[room->client_count++] = fd;')
232             ->line('XSRETURN_YES;')
233             ->xs_end
234             ->blank;
235            
236 1         1 return $builder;
237             }
238              
239             # XS: leave(fd|ws) - instance method
240             sub gen_xs_leave {
241 1     1 0 2 my ($class, $builder) = @_;
242            
243 1         37 $builder->xs_function('xs_room_leave')
244             ->xs_preamble
245             ->line('int room_id;')
246             ->line('int fd;')
247             ->line('int i;')
248             ->line('WSRoom* room;')
249             ->blank
250             ->if('items != 2')
251             ->line('croak("Usage: $room->leave(fd)");')
252             ->endif
253             ->blank
254             ->line('room_id = SvIV(SvRV(ST(0)));')
255             ->line('fd = extract_fd(ST(1));')
256             ->blank
257             ->if('fd < 0')
258             ->line('XSRETURN_NO;')
259             ->endif
260             ->if('room_id < 0 || room_id >= ROOM_MAX_ROOMS')
261             ->line('XSRETURN_NO;')
262             ->endif
263             ->if('!room_registry[room_id].active')
264             ->line('XSRETURN_NO;')
265             ->endif
266             ->blank
267             ->line('room = &room_registry[room_id];')
268             ->blank
269             ->comment('Find and remove')
270             ->line('for (i = 0; i < room->client_count; i++) {')
271             ->if('room->client_fds[i] == fd')
272             ->comment('Shift remaining down')
273             ->line('memmove(&room->client_fds[i], &room->client_fds[i+1], (room->client_count - i - 1) * sizeof(int));')
274             ->line('room->client_count--;')
275             ->line('XSRETURN_YES;')
276             ->endif
277             ->line('}')
278             ->blank
279             ->line('XSRETURN_NO;')
280             ->xs_end
281             ->blank;
282            
283 1         23 return $builder;
284             }
285              
286             # XS: has(fd|ws) - instance method
287             sub gen_xs_has {
288 1     1 0 4 my ($class, $builder) = @_;
289            
290 1         34 $builder->xs_function('xs_room_has')
291             ->xs_preamble
292             ->line('int room_id;')
293             ->line('int fd;')
294             ->line('int i;')
295             ->line('WSRoom* room;')
296             ->blank
297             ->if('items != 2')
298             ->line('croak("Usage: $room->has(fd)");')
299             ->endif
300             ->blank
301             ->line('room_id = SvIV(SvRV(ST(0)));')
302             ->line('fd = extract_fd(ST(1));')
303             ->blank
304             ->if('fd < 0')
305             ->line('XSRETURN_NO;')
306             ->endif
307             ->if('room_id < 0 || room_id >= ROOM_MAX_ROOMS')
308             ->line('XSRETURN_NO;')
309             ->endif
310             ->if('!room_registry[room_id].active')
311             ->line('XSRETURN_NO;')
312             ->endif
313             ->blank
314             ->line('room = &room_registry[room_id];')
315             ->line('for (i = 0; i < room->client_count; i++) {')
316             ->if('room->client_fds[i] == fd')
317             ->line('XSRETURN_YES;')
318             ->endif
319             ->line('}')
320             ->blank
321             ->line('XSRETURN_NO;')
322             ->xs_end
323             ->blank;
324            
325 1         2 return $builder;
326             }
327              
328             # XS: broadcast(message, [exclude_fd|ws]) - instance method
329             sub gen_xs_broadcast {
330 1     1 0 6 my ($class, $builder) = @_;
331            
332 1         144 $builder->xs_function('xs_room_broadcast')
333             ->xs_preamble
334             ->if('items < 2')
335             ->line('croak("Usage: $room->broadcast(message, [exclude_fd])");')
336             ->endif
337             ->blank
338             ->line('int room_id = SvIV(SvRV(ST(0)));')
339             ->line('STRLEN msg_len;')
340             ->line('const char* message = SvPV(ST(1), msg_len);')
341             ->line('int exclude_fd = (items >= 3) ? extract_fd(ST(2)) : -1;')
342             ->line('int i;')
343             ->blank
344             ->if('room_id < 0 || room_id >= ROOM_MAX_ROOMS')
345             ->line('XSRETURN_IV(0);')
346             ->endif
347             ->if('!room_registry[room_id].active')
348             ->line('XSRETURN_IV(0);')
349             ->endif
350             ->blank
351             ->line('WSRoom* room = &room_registry[room_id];')
352             ->blank
353             ->comment('Encode message as WebSocket text frame')
354             ->line('uint8_t frame[65546];')
355             ->line('size_t frame_len = ws_encode_text(frame, sizeof(frame), message, msg_len);')
356             ->if('frame_len == 0')
357             ->line('XSRETURN_IV(0);')
358             ->endif
359             ->blank
360             ->line('int sent = 0;')
361             ->for('i = 0', 'i < room->client_count', 'i++')
362             ->line('int fd = room->client_fds[i];')
363             ->if('fd >= 0 && fd != exclude_fd')
364             ->line('send(fd, frame, frame_len, 0);')
365             ->line('sent++;')
366             ->endif
367             ->endfor
368             ->blank
369             ->line('XSRETURN_IV(sent);')
370             ->xs_end
371             ->blank;
372            
373 1         2 return $builder;
374             }
375              
376             # XS: broadcast_binary(data, [exclude_fd|ws]) - instance method
377             sub gen_xs_broadcast_binary {
378 1     1 0 3 my ($class, $builder) = @_;
379            
380 1         40 $builder->xs_function('xs_room_broadcast_binary')
381             ->xs_preamble
382             ->if('items < 2')
383             ->line('croak("Usage: $room->broadcast_binary(data, [exclude_fd])");')
384             ->endif
385             ->blank
386             ->line('int room_id = SvIV(SvRV(ST(0)));')
387             ->line('STRLEN data_len;')
388             ->line('const char* data = SvPV(ST(1), data_len);')
389             ->line('int exclude_fd = (items >= 3) ? extract_fd(ST(2)) : -1;')
390             ->line('int i;')
391             ->blank
392             ->if('room_id < 0 || room_id >= ROOM_MAX_ROOMS')
393             ->line('XSRETURN_IV(0);')
394             ->endif
395             ->if('!room_registry[room_id].active')
396             ->line('XSRETURN_IV(0);')
397             ->endif
398             ->blank
399             ->line('WSRoom* room = &room_registry[room_id];')
400             ->blank
401             ->comment('Encode as binary frame')
402             ->line('uint8_t frame[65546];')
403             ->line('size_t frame_len = ws_encode_binary(frame, sizeof(frame), (const uint8_t*)data, data_len);')
404             ->if('frame_len == 0')
405             ->line('XSRETURN_IV(0);')
406             ->endif
407             ->blank
408             ->line('int sent = 0;')
409             ->for('i = 0', 'i < room->client_count', 'i++')
410             ->line('int fd = room->client_fds[i];')
411             ->if('fd >= 0 && fd != exclude_fd')
412             ->line('send(fd, frame, frame_len, 0);')
413             ->line('sent++;')
414             ->endif
415             ->endfor
416             ->blank
417             ->line('XSRETURN_IV(sent);')
418             ->xs_end
419             ->blank;
420            
421 1         1 return $builder;
422             }
423              
424             # XS: count() - instance method
425             sub gen_xs_count {
426 1     1 0 1 my ($class, $builder) = @_;
427            
428 1         16 $builder->xs_function('xs_room_count')
429             ->xs_preamble
430             ->if('items != 1')
431             ->line('croak("Usage: $room->count()");')
432             ->endif
433             ->blank
434             ->line('int room_id = SvIV(SvRV(ST(0)));')
435             ->blank
436             ->if('room_id < 0 || room_id >= ROOM_MAX_ROOMS')
437             ->line('XSRETURN_IV(0);')
438             ->endif
439             ->if('!room_registry[room_id].active')
440             ->line('XSRETURN_IV(0);')
441             ->endif
442             ->blank
443             ->line('XSRETURN_IV(room_registry[room_id].client_count);')
444             ->xs_end
445             ->blank;
446            
447 1         1 return $builder;
448             }
449              
450             # XS: count_open() - instance method, counts open connections, removes closed ones
451             sub gen_xs_count_open {
452 1     1 0 2 my ($class, $builder) = @_;
453            
454 1         31 $builder->xs_function('xs_room_count_open')
455             ->xs_preamble
456             ->if('items != 1')
457             ->line('croak("Usage: $room->count_open()");')
458             ->endif
459             ->blank
460             ->line('int room_id = SvIV(SvRV(ST(0)));')
461             ->blank
462             ->if('room_id < 0 || room_id >= ROOM_MAX_ROOMS')
463             ->line('XSRETURN_IV(0);')
464             ->endif
465             ->if('!room_registry[room_id].active')
466             ->line('XSRETURN_IV(0);')
467             ->endif
468             ->blank
469             ->line('WSRoom* room = &room_registry[room_id];')
470             ->line('int open_count = 0;')
471             ->line('int write_idx = 0;')
472             ->line('int i;')
473             ->blank
474             ->comment('Compact array, removing closed connections')
475             ->for('i = 0', 'i < room->client_count', 'i++')
476             ->line('int fd = room->client_fds[i];')
477             ->comment('Check if fd is still valid/open in handler registry')
478             ->if('fd >= 0 && fd < WS_MAX_CONNECTIONS && ws_handler_registry[fd].active')
479             ->line('room->client_fds[write_idx++] = fd;')
480             ->line('open_count++;')
481             ->endif
482             ->endfor
483             ->line('room->client_count = write_idx;')
484             ->blank
485             ->line('XSRETURN_IV(open_count);')
486             ->xs_end
487             ->blank;
488            
489 1         1 return $builder;
490             }
491              
492             # XS: close_all([code], [reason]) - instance method
493             sub gen_xs_close_all {
494 1     1 0 1 my ($class, $builder) = @_;
495            
496 1         34 $builder->xs_function('xs_room_close_all')
497             ->xs_preamble
498             ->if('items < 1')
499             ->line('croak("Usage: $room->close_all([code], [reason])");')
500             ->endif
501             ->blank
502             ->line('int room_id = SvIV(SvRV(ST(0)));')
503             ->line('int code = (items >= 2) ? SvIV(ST(1)) : 1000;')
504             ->blank
505             ->if('room_id < 0 || room_id >= ROOM_MAX_ROOMS')
506             ->line('XSRETURN_IV(0);')
507             ->endif
508             ->if('!room_registry[room_id].active')
509             ->line('XSRETURN_IV(0);')
510             ->endif
511             ->blank
512             ->line('WSRoom* room = &room_registry[room_id];')
513             ->line('int closed = 0;')
514             ->line('int i;')
515             ->blank
516             ->comment('Send close frame to all clients')
517             ->line('uint8_t close_frame[4];')
518             ->line('close_frame[0] = 0x88;')
519             ->line('close_frame[1] = 2;')
520             ->line('close_frame[2] = (code >> 8) & 0xFF;')
521             ->line('close_frame[3] = code & 0xFF;')
522             ->blank
523             ->for('i = 0', 'i < room->client_count', 'i++')
524             ->line('int fd = room->client_fds[i];')
525             ->if('fd >= 0')
526             ->line('send(fd, close_frame, 4, 0);')
527             ->line('closed++;')
528             ->endif
529             ->endfor
530             ->blank
531             ->comment('Clear room')
532             ->line('room->client_count = 0;')
533             ->line('memset(room->client_fds, -1, sizeof(room->client_fds));')
534             ->blank
535             ->line('XSRETURN_IV(closed);')
536             ->xs_end
537             ->blank;
538            
539 1         1 return $builder;
540             }
541              
542             # XS: name() - instance method, returns room name
543             sub gen_xs_name {
544 1     1 0 3 my ($class, $builder) = @_;
545            
546 1         16 $builder->xs_function('xs_room_name')
547             ->xs_preamble
548             ->if('items != 1')
549             ->line('croak("Usage: $room->name()");')
550             ->endif
551             ->blank
552             ->line('int room_id = SvIV(SvRV(ST(0)));')
553             ->blank
554             ->if('room_id < 0 || room_id >= ROOM_MAX_ROOMS')
555             ->line('XSRETURN_UNDEF;')
556             ->endif
557             ->if('!room_registry[room_id].active')
558             ->line('XSRETURN_UNDEF;')
559             ->endif
560             ->blank
561             ->line('ST(0) = sv_2mortal(newSVpv(room_registry[room_id].name, 0));')
562             ->line('XSRETURN(1);')
563             ->xs_end
564             ->blank;
565            
566 1         2 return $builder;
567             }
568              
569             # XS: clear() - instance method
570             sub gen_xs_clear {
571 1     1 0 1 my ($class, $builder) = @_;
572            
573 1         17 $builder->xs_function('xs_room_clear')
574             ->xs_preamble
575             ->if('items != 1')
576             ->line('croak("Usage: $room->clear()");')
577             ->endif
578             ->blank
579             ->line('int room_id = SvIV(SvRV(ST(0)));')
580             ->blank
581             ->if('room_id < 0 || room_id >= ROOM_MAX_ROOMS')
582             ->line('XSRETURN_NO;')
583             ->endif
584             ->if('!room_registry[room_id].active')
585             ->line('XSRETURN_NO;')
586             ->endif
587             ->blank
588             ->line('room_registry[room_id].client_count = 0;')
589             ->line('memset(room_registry[room_id].client_fds, -1, sizeof(room_registry[room_id].client_fds));')
590             ->line('XSRETURN_YES;')
591             ->xs_end
592             ->blank;
593            
594 1         1 return $builder;
595             }
596              
597             # XS: clients() - instance method, returns list of client fds
598             sub gen_xs_clients {
599 1     1 0 2 my ($class, $builder) = @_;
600            
601 1         27 $builder->xs_function('xs_room_clients')
602             ->xs_preamble
603             ->if('items != 1')
604             ->line('croak("Usage: $room->clients()");')
605             ->endif
606             ->blank
607             ->line('int room_id = SvIV(SvRV(ST(0)));')
608             ->blank
609             ->if('room_id < 0 || room_id >= ROOM_MAX_ROOMS')
610             ->line('XSRETURN_EMPTY;')
611             ->endif
612             ->if('!room_registry[room_id].active')
613             ->line('XSRETURN_EMPTY;')
614             ->endif
615             ->blank
616             ->line('WSRoom* room = &room_registry[room_id];')
617             ->line('int count = 0;')
618             ->line('int i;')
619             ->blank
620             ->for('i = 0', 'i < room->client_count', 'i++')
621             ->if('room->client_fds[i] >= 0')
622             ->line('XPUSHs(sv_2mortal(newSViv(room->client_fds[i])));')
623             ->line('count++;')
624             ->endif
625             ->endfor
626             ->blank
627             ->line('XSRETURN(count);')
628             ->xs_end
629             ->blank;
630            
631 1         2 return $builder;
632             }
633              
634             # Get XS function mappings for XS::JIT->compile
635             sub get_xs_functions {
636             return {
637 1     1 0 55 'Hypersonic::WebSocket::Room::new' => { source => 'xs_room_new', is_xs_native => 1 },
638             'Hypersonic::WebSocket::Room::destroy' => { source => 'xs_room_destroy', is_xs_native => 1 },
639             'Hypersonic::WebSocket::Room::join' => { source => 'xs_room_join', is_xs_native => 1 },
640             'Hypersonic::WebSocket::Room::leave' => { source => 'xs_room_leave', is_xs_native => 1 },
641             'Hypersonic::WebSocket::Room::has' => { source => 'xs_room_has', is_xs_native => 1 },
642             'Hypersonic::WebSocket::Room::broadcast' => { source => 'xs_room_broadcast', is_xs_native => 1 },
643             'Hypersonic::WebSocket::Room::broadcast_binary' => { source => 'xs_room_broadcast_binary', is_xs_native => 1 },
644             'Hypersonic::WebSocket::Room::count' => { source => 'xs_room_count', is_xs_native => 1 },
645             'Hypersonic::WebSocket::Room::count_open' => { source => 'xs_room_count_open', is_xs_native => 1 },
646             'Hypersonic::WebSocket::Room::close_all' => { source => 'xs_room_close_all', is_xs_native => 1 },
647             'Hypersonic::WebSocket::Room::name' => { source => 'xs_room_name', is_xs_native => 1 },
648             'Hypersonic::WebSocket::Room::clear' => { source => 'xs_room_clear', is_xs_native => 1 },
649             'Hypersonic::WebSocket::Room::clients' => { source => 'xs_room_clients', is_xs_native => 1 },
650             };
651             }
652              
653             1;
654              
655             __END__