agoo 2.1.0 → 2.1.1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of agoo might be problematic. Click here for more details.

checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 729ca7dab10faf0c9196e1297f814dc06471f5de2948a04e4a3d074067f042d6
4
- data.tar.gz: 65f231b27c3eb5db90db659e920090fc075ffece27f65753d9769c32157f540d
3
+ metadata.gz: '0618dff57c263cccb782e0fbccc807bf434815109c3809078ebd4d12570e1bde'
4
+ data.tar.gz: 2603682170f882a06d20e50ad0d9ab753b927f730331c224ce9e4dcc2cbea581
5
5
  SHA512:
6
- metadata.gz: 8135b9c196acc16c80a81aa532d55f8452c1008f4ab22cd285a3f327655cf66f2f4b4f6177c9e7d3781f05964dde9ffb2d238f0808acd5c0150f95bd58eeec24
7
- data.tar.gz: 7943dc936c2cb113054f04f2780185bbe80d9c62ab94e7a601874219ece58ee2c2ba5f3e8f71e4b23bb8ba24f3a31526bd944ea3351fd62a452c45bf06c0f187
6
+ metadata.gz: cc4b5878761a72885f79ed8baecfb8bf23b6d516e7035ec97d14e655980432feb3923d8bbeae4824bcbfcb5e61c05562fb5e53fda03afdc40e841cbb2676f9fc
7
+ data.tar.gz: 159dba44203a4612598949a47e4fbd8f11a99b19dcceb368f1ebab4c65a5c785790163dcdb6998f780b17d0d9836c26087d3a68ae6367376d144007993094fc0
data/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # CHANGELOG
2
2
 
3
+ ### 2.1.1 - 2018-05-11
4
+
5
+ - Subject can now be Symbols or any other object that responds top `#to_s`.
6
+
7
+ - Fixed bug where publishes from the `#on_open` callback broke the connection.
8
+
9
+ - Super fast asset loading for Rails and Rack using `Agoo::Server.path_group`
10
+
3
11
  ### 2.1.0 - 2018-05-10
4
12
 
5
13
  - This is a minor release even though the API has changed. The changed API is the one for Rack based WebSocket and SSE connection upgrades. The PR for the spec addition is currently stalled but some suggestions for a stateless API are implemented in this release. The proposed Rack SPEC is [here](misc/SPEC). The PR is [here](https://github.com/rack/rack/pull/1272)
data/README.md CHANGED
@@ -50,6 +50,16 @@ limits. Ruby benchmarks driver could not push Agoo hard enough.
50
50
  Agoo supports the [Ruby rack API](https://rack.github.io) which allows for the
51
51
  use of rack compatible gems such as Hanami and Rails. Agoo also supports WebSockets and SSE.
52
52
 
53
+ ## News
54
+
55
+ - WebSocket and SSE are supported and a PR has been submitted to updated the
56
+ Rack spec. Go over to the [proposed Rack
57
+ extension](https://github.com/rack/rack/pull/1272) and give it a look and a
58
+ thumbs-up or heart if you like it.
59
+
60
+ - Agoo now serves Rails static assets 2000 times faster than the default
61
+ Puma. Thats right, 2000 times faster.
62
+
53
63
  ## Releases
54
64
 
55
65
  See [file:CHANGELOG.md](CHANGELOG.md)
data/ext/agoo/agoo.c CHANGED
@@ -38,15 +38,16 @@ ragoo_shutdown(VALUE self) {
38
38
  *
39
39
  * call-seq: publish(subject, message)
40
40
  *
41
- * Publish a message on the given subject.
41
+ * Publish a message on the given subject. A subject is normally a String but
42
+ * Symbols can also be used as can any other object that responds to #to_s.
42
43
  */
43
44
  VALUE
44
45
  ragoo_publish(VALUE self, VALUE subject, VALUE message) {
45
- rb_check_type(subject, T_STRING);
46
- rb_check_type(message, T_STRING);
46
+ int slen;
47
+ const char *subj = extract_subject(subject, &slen);
47
48
 
48
- queue_push(&the_server.pub_queue, pub_publish(StringValuePtr(subject), (int)RSTRING_LEN(subject),
49
- StringValuePtr(message), (int)RSTRING_LEN(message)));
49
+ rb_check_type(message, T_STRING);
50
+ queue_push(&the_server.pub_queue, pub_publish(subj, slen, StringValuePtr(message), (int)RSTRING_LEN(message)));
50
51
 
51
52
  return Qnil;
52
53
  }
@@ -55,7 +56,9 @@ ragoo_publish(VALUE self, VALUE subject, VALUE message) {
55
56
  *
56
57
  * call-seq: unsubscribe(subject)
57
58
  *
58
- * Unsubscribes on client listeners on the specified subject.
59
+ * Unsubscribes on client listeners on the specified subject. Subjects are
60
+ * normally Strings but Symbols can also be used as can any other object that
61
+ * responds to #to_s.
59
62
  */
60
63
  static VALUE
61
64
  ragoo_unsubscribe(VALUE self, VALUE subject) {
data/ext/agoo/con.c CHANGED
@@ -141,7 +141,10 @@ con_header_read(Con c) {
141
141
  size_t clen = 0;
142
142
  long mlen;
143
143
  Hook hook = NULL;
144
-
144
+ Page p;
145
+ struct _Err err = ERR_INIT;
146
+ Res res;
147
+
145
148
  if (NULL == hend) {
146
149
  if (sizeof(c->buf) - 1 <= c->bcnt) {
147
150
  return bad_request(c, 431, __LINE__);
@@ -239,13 +242,29 @@ con_header_read(Con c) {
239
242
  qend = b;
240
243
  }
241
244
  mlen = hend - c->buf + 4 + clen;
242
- if (NULL == (hook = hook_find(the_server.hooks, method, path, pend))) {
243
- if (GET == method) {
244
- struct _Err err = ERR_INIT;
245
- Page p = page_get(&err, &the_server.pages, the_server.root, path, (int)(pend - path));
246
- Res res;
245
+ if (GET == method &&
246
+ NULL != (p = group_get(&err, &the_server.pages, path, (int)(pend - path)))) {
247
+ if (NULL == (res = res_create(c))) {
248
+ return bad_request(c, 500, __LINE__);
249
+ }
250
+ if (NULL == c->res_tail) {
251
+ c->res_head = res;
252
+ } else {
253
+ c->res_tail->next = res;
254
+ }
255
+ c->res_tail = res;
256
+
257
+ b = strstr(c->buf, "\r\n");
258
+ res->close = should_close(b, (int)(hend - b));
259
+ if (res->close) {
260
+ c->closing = true;
261
+ }
262
+ res_set_message(res, p->resp);
247
263
 
248
- if (NULL == p) {
264
+ return -mlen;
265
+ } else if (NULL == (hook = hook_find(the_server.hooks, method, path, pend))) {
266
+ if (GET == method) {
267
+ if (NULL == (p = page_get(&err, &the_server.pages, path, (int)(pend - path)))) {
249
268
  if (NULL != the_server.hook404) {
250
269
  // There would be too many parameters to pass to a
251
270
  // separate function so just goto the hook processing.
@@ -620,6 +639,10 @@ con_ws_write(Con c) {
620
639
  }
621
640
  } else {
622
641
  ws_req_close(c);
642
+ c->res_head = res->next;
643
+ if (res == c->res_tail) {
644
+ c->res_tail = NULL;
645
+ }
623
646
  res_destroy(res);
624
647
  return true;
625
648
  }
@@ -764,7 +787,7 @@ con_write(Con c) {
764
787
  default:
765
788
  break;
766
789
  }
767
- if (kind != c->kind) {
790
+ if (kind != c->kind && CON_ANY != kind) {
768
791
  c->kind = kind;
769
792
  /*
770
793
  if (CON_HTTP != kind && !remove) {
@@ -792,7 +815,7 @@ publish_pub(Pub pub) {
792
815
  up->con->res_tail->next = res;
793
816
  }
794
817
  up->con->res_tail = res;
795
- res->con_kind = up->con->kind;
818
+ res->con_kind = CON_ANY;
796
819
  res_set_message(res, text_dup(pub->msg));
797
820
  }
798
821
  }
@@ -849,7 +872,7 @@ process_pub_con(Pub pub) {
849
872
  up->con->res_tail->next = res;
850
873
  }
851
874
  up->con->res_tail = res;
852
- res->con_kind = up->con->kind;
875
+ res->con_kind = CON_ANY;
853
876
  res_set_message(res, pub->msg);
854
877
  }
855
878
  }
data/ext/agoo/debug.c CHANGED
@@ -25,6 +25,8 @@ atomic_int mem_con = 0;
25
25
  atomic_int mem_cslot = 0;
26
26
  atomic_int mem_err_stream = 0;
27
27
  atomic_int mem_eval_threads = 0;
28
+ atomic_int mem_group = 0;
29
+ atomic_int mem_group_path = 0;
28
30
  atomic_int mem_header = 0;
29
31
  atomic_int mem_hook = 0;
30
32
  atomic_int mem_hook_pattern = 0;
data/ext/agoo/debug.h CHANGED
@@ -20,6 +20,8 @@ extern atomic_int mem_con;
20
20
  extern atomic_int mem_cslot;
21
21
  extern atomic_int mem_err_stream;
22
22
  extern atomic_int mem_eval_threads;
23
+ extern atomic_int mem_group;
24
+ extern atomic_int mem_group_path;
23
25
  extern atomic_int mem_header;
24
26
  extern atomic_int mem_hook;
25
27
  extern atomic_int mem_hook_pattern;
data/ext/agoo/hook.c CHANGED
@@ -6,6 +6,50 @@
6
6
  #include "debug.h"
7
7
  #include "hook.h"
8
8
 
9
+ static VALUE
10
+ resolve_classname(VALUE mod, const char *classname) {
11
+ VALUE clas;
12
+ ID ci = rb_intern(classname);
13
+
14
+ if (rb_const_defined_at(mod, ci)) {
15
+ clas = rb_const_get_at(mod, ci);
16
+ } else {
17
+ clas = Qundef;
18
+ }
19
+ return clas;
20
+ }
21
+
22
+ static VALUE
23
+ resolve_classpath(const char *name, size_t len) {
24
+ char class_name[1024];
25
+ VALUE clas;
26
+ char *end = class_name + sizeof(class_name) - 1;
27
+ char *s;
28
+ const char *n = name;
29
+
30
+ clas = rb_cObject;
31
+ for (s = class_name; 0 < len; n++, len--) {
32
+ if (':' == *n) {
33
+ *s = '\0';
34
+ n++;
35
+ len--;
36
+ if (':' != *n) {
37
+ return Qundef;
38
+ }
39
+ if (Qundef == (clas = resolve_classname(clas, class_name))) {
40
+ return Qundef;
41
+ }
42
+ s = class_name;
43
+ } else if (end <= s) {
44
+ return Qundef;
45
+ } else {
46
+ *s++ = *n;
47
+ }
48
+ }
49
+ *s = '\0';
50
+ return resolve_classname(clas, class_name);
51
+ }
52
+
9
53
  Hook
10
54
  hook_create(Method method, const char *pattern, VALUE handler) {
11
55
  Hook hook = (Hook)malloc(sizeof(struct _Hook));
@@ -16,6 +60,9 @@ hook_create(Method method, const char *pattern, VALUE handler) {
16
60
  pattern = "";
17
61
  }
18
62
  hook->next = NULL;
63
+ if (T_STRING == rb_type(handler)) {
64
+ handler = resolve_classpath(StringValuePtr(handler), RSTRING_LEN(handler));
65
+ }
19
66
  hook->handler = handler;
20
67
  rb_gc_register_address(&handler);
21
68
  hook->pattern = strdup(pattern);
data/ext/agoo/page.c CHANGED
@@ -4,6 +4,7 @@
4
4
  #include <stdio.h>
5
5
  #include <stdlib.h>
6
6
  #include <sys/stat.h>
7
+ #include <unistd.h>
7
8
 
8
9
  #include <ruby.h>
9
10
 
@@ -225,7 +226,7 @@ cache_set(Cache cache, const char *key, int klen, Page value) {
225
226
  }
226
227
 
227
228
  void
228
- cache_init(Cache cache) {
229
+ pages_init(Cache cache) {
229
230
  Mime m;
230
231
 
231
232
  memset(cache, 0, sizeof(struct _Cache));
@@ -235,7 +236,7 @@ cache_init(Cache cache) {
235
236
  }
236
237
 
237
238
  void
238
- cache_cleanup(Cache cache) {
239
+ pages_cleanup(Cache cache) {
239
240
  Slot *sp = cache->buckets;
240
241
  Slot s;
241
242
  Slot n;
@@ -262,6 +263,7 @@ cache_cleanup(Cache cache) {
262
263
  }
263
264
  *mp = NULL;
264
265
  }
266
+ free(cache->root);
265
267
  }
266
268
 
267
269
  // The page resp contents point to the page resp msg to save memory and reduce
@@ -400,15 +402,16 @@ update_contents(Cache cache, Page p) {
400
402
  }
401
403
 
402
404
  Page
403
- page_get(Err err, Cache cache, const char *dir, const char *path, int plen) {
405
+ page_get(Err err, Cache cache, const char *path, int plen) {
404
406
  Page page;
405
407
 
408
+ // TBD check for .. and ~
406
409
  if (NULL == (page = cache_get(cache, path, plen))) {
407
410
  Page old;
408
411
  char full_path[2048];
409
- char *s = stpcpy(full_path, dir);
412
+ char *s = stpcpy(full_path, cache->root);
410
413
 
411
- if ('/' != *dir && '/' != *path) {
414
+ if ('/' != *cache->root && '/' != *path) {
412
415
  *s++ = '/';
413
416
  }
414
417
  if ((int)sizeof(full_path) <= plen + (s - full_path)) {
@@ -448,3 +451,103 @@ page_get(Err err, Cache cache, const char *dir, const char *path, int plen) {
448
451
  }
449
452
  return page;
450
453
  }
454
+
455
+ Page
456
+ group_get(Err err, Cache cache, const char *path, int plen) {
457
+ Page page = NULL;
458
+ Group g = NULL;
459
+ char full_path[2048];
460
+ Page old;
461
+ char *s;
462
+ Dir d;
463
+
464
+ // TBD check for .. and ~
465
+ for (g = cache->groups; NULL != g; g = g->next) {
466
+ if (g->plen < plen && 0 == strncmp(path, g->path, g->plen) && '/' == path[g->plen]) {
467
+ break;
468
+ }
469
+ }
470
+ if (NULL == g) {
471
+ return NULL;
472
+ }
473
+ for (d = g->dirs; NULL != d; d = d->next) {
474
+ if (sizeof(full_path) <= d->plen + plen) {
475
+ continue;
476
+ }
477
+ s = stpcpy(full_path, d->path);
478
+ strncpy(s, path + g->plen, plen - g->plen);
479
+ s += plen - g->plen;
480
+ *s = '\0';
481
+ if (0 == access(full_path, R_OK)) {
482
+ break;
483
+ }
484
+ }
485
+ if (NULL == d) {
486
+ return NULL;
487
+ }
488
+ plen = s - full_path;
489
+ path = full_path;
490
+ if (NULL == (page = cache_get(cache, path, plen))) {
491
+ Page old;
492
+
493
+ if (NULL == (page = page_create(path))) {
494
+ err_set(err, ERR_MEMORY, "Failed to allocate memory for Page.");
495
+ return NULL;
496
+ }
497
+ if (!update_contents(cache, page) || NULL == page->resp) {
498
+ page_destroy(page);
499
+ err_set(err, ERR_NOT_FOUND, "not found.");
500
+ return NULL;
501
+ }
502
+ if (NULL != (old = cache_set(cache, path, plen, page))) {
503
+ page_destroy(old);
504
+ }
505
+ } else {
506
+ double now = dtime();
507
+
508
+ if (page->last_check + PAGE_RECHECK_TIME < now) {
509
+ struct stat fattr;
510
+
511
+ if (0 == stat(page->path, &fattr) && page->mtime != fattr.st_mtime) {
512
+ update_contents(cache, page);
513
+ if (NULL == page->resp) {
514
+ page_destroy(page);
515
+ err_set(err, ERR_NOT_FOUND, "not found.");
516
+ return NULL;
517
+ }
518
+ }
519
+ page->last_check = now;
520
+ }
521
+ }
522
+ return page;
523
+ }
524
+
525
+ Group
526
+ group_create(Cache cache, const char *path) {
527
+ Group g = (Group)malloc(sizeof(struct _Group));
528
+
529
+ if (NULL != g) {
530
+ DEBUG_ALLOC(mem_group, g);
531
+ g->next = cache->groups;
532
+ cache->groups = g;
533
+ g->path = strdup(path);
534
+ g->plen = strlen(path);
535
+ DEBUG_ALLOC(mem_group_path, g->path);
536
+ g->dirs = NULL;
537
+ }
538
+ return g;
539
+ }
540
+
541
+ void
542
+ group_add(Group g, const char *dir) {
543
+ Dir d = (Dir)malloc(sizeof(struct _Dir));
544
+
545
+ if (NULL != d) {
546
+ DEBUG_ALLOC(mem_dir, d);
547
+ d->next = g->dirs;
548
+ g->dirs = d;
549
+ d->path = strdup(dir);
550
+ d->plen = strlen(dir);
551
+ DEBUG_ALLOC(mem_dir_path, d->path);
552
+ }
553
+ }
data/ext/agoo/page.h CHANGED
@@ -40,16 +40,35 @@ typedef struct _MimeSlot {
40
40
  int klen;
41
41
  } *MimeSlot;
42
42
 
43
+ typedef struct _Dir {
44
+ struct _Dir *next;
45
+ char *path;
46
+ int plen;
47
+ } *Dir;
48
+
49
+ typedef struct _Group {
50
+ struct _Group *next;
51
+ char *path;
52
+ int plen;
53
+ Dir dirs;
54
+ } *Group;
55
+
43
56
  typedef struct _Cache {
44
57
  Slot buckets[PAGE_BUCKET_SIZE];
45
58
  MimeSlot muckets[MIME_BUCKET_SIZE];
59
+ char *root;
60
+ Group groups;
46
61
  } *Cache;
47
62
 
48
- extern void cache_init(Cache cache);
49
- extern void cache_cleanup(Cache cache);
63
+ extern void pages_init(Cache cache);
64
+ extern void pages_cleanup(Cache cache);
65
+
66
+ extern Group group_create(Cache cache, const char *path);
67
+ extern void group_add(Group g, const char *dir);
68
+ extern Page group_get(Err err, Cache cache, const char *path, int plen);
50
69
 
51
70
  extern void page_destroy(Page p);
52
- extern Page page_get(Err err, Cache cache, const char *dir, const char *path, int plen);
71
+ extern Page page_get(Err err, Cache cache, const char *path, int plen);
53
72
  extern void mime_set(Cache cache, const char *key, const char *value);
54
73
 
55
74
  #endif /* __AGOO_PAGE_H__ */
data/ext/agoo/pub.c CHANGED
@@ -60,7 +60,7 @@ pub_unsubscribe(Upgraded up, const char *subject, int slen) {
60
60
  }
61
61
 
62
62
  Pub
63
- pub_publish(char *subject, int slen, const char *message, size_t mlen) {
63
+ pub_publish(const char *subject, int slen, const char *message, size_t mlen) {
64
64
  Pub p = (Pub)malloc(sizeof(struct _Pub));
65
65
 
66
66
  if (NULL != p) {
data/ext/agoo/pub.h CHANGED
@@ -32,7 +32,7 @@ typedef struct _Pub {
32
32
  extern Pub pub_close(struct _Upgraded *up);
33
33
  extern Pub pub_subscribe(struct _Upgraded *up, const char *subject, int slen);
34
34
  extern Pub pub_unsubscribe(struct _Upgraded *up, const char *subject, int slen);
35
- extern Pub pub_publish(char *subject, int slen, const char *message, size_t mlen);
35
+ extern Pub pub_publish(const char *subject, int slen, const char *message, size_t mlen);
36
36
  extern Pub pub_write(struct _Upgraded *up, const char *message, size_t mlen, bool bin);
37
37
  extern void pub_destroy(Pub pub);
38
38
 
data/ext/agoo/server.c CHANGED
@@ -121,7 +121,7 @@ server_shutdown() {
121
121
  queue_cleanup(&the_server.con_queue);
122
122
  queue_cleanup(&the_server.pub_queue);
123
123
  queue_cleanup(&the_server.eval_queue);
124
- cache_cleanup(&the_server.pages);
124
+ pages_cleanup(&the_server.pages);
125
125
  http_cleanup();
126
126
  }
127
127
  }
@@ -129,7 +129,7 @@ server_shutdown() {
129
129
  static int
130
130
  configure(Err err, int port, const char *root, VALUE options) {
131
131
  the_server.port = port;
132
- the_server.root = strdup(root);
132
+ the_server.pages.root = strdup(root);
133
133
  the_server.thread_cnt = 0;
134
134
  the_server.running = 0;
135
135
  the_server.listen_thread = 0;
@@ -228,6 +228,9 @@ rserver_init(int argc, VALUE *argv, VALUE self) {
228
228
  options = argv[2];
229
229
  }
230
230
  memset(&the_server, 0, sizeof(struct _Server));
231
+ pages_init(&the_server.pages);
232
+ sub_init(&the_server.sub_cache);
233
+
231
234
  if (ERR_OK != configure(&err, port, root, options)) {
232
235
  rb_raise(rb_eArgError, "%s", err.msg);
233
236
  }
@@ -235,9 +238,6 @@ rserver_init(int argc, VALUE *argv, VALUE self) {
235
238
  queue_multi_init(&the_server.pub_queue, 256, true, false);
236
239
  queue_multi_init(&the_server.eval_queue, 1024, false, true);
237
240
 
238
- cache_init(&the_server.pages);
239
- sub_init(&the_server.sub_cache);
240
-
241
241
  pthread_mutex_init(&the_server.up_lock, 0);
242
242
  the_server.up_list = NULL;
243
243
 
@@ -609,15 +609,18 @@ handle_push_inner(void *x) {
609
609
 
610
610
  switch (req->method) {
611
611
  case ON_MSG:
612
- rb_funcall(req->handler, on_message_id, 2, req->up->wrap, rb_str_new(req->msg, req->mlen));
612
+ if (req->up->on_msg) { // TBD move this to earlier
613
+ rb_funcall(req->handler, on_message_id, 2, req->up->wrap, rb_str_new(req->msg, req->mlen));
614
+ }
613
615
  break;
614
- case ON_BIN: {
615
- volatile VALUE rstr = rb_str_new(req->msg, req->mlen);
616
+ case ON_BIN:
617
+ if (req->up->on_msg) { // TBD move this to earlier
618
+ volatile VALUE rstr = rb_str_new(req->msg, req->mlen);
616
619
 
617
- rb_enc_associate(rstr, rb_ascii8bit_encoding());
618
- rb_funcall(req->handler, on_message_id, 2, req->up->wrap, rstr);
620
+ rb_enc_associate(rstr, rb_ascii8bit_encoding());
621
+ rb_funcall(req->handler, on_message_id, 2, req->up->wrap, rstr);
622
+ }
619
623
  break;
620
- }
621
624
  case ON_CLOSE:
622
625
  upgraded_ref(req->up);
623
626
  queue_push(&the_server.pub_queue, pub_close(req->up));
@@ -872,6 +875,37 @@ add_mime(VALUE self, VALUE suffix, VALUE type) {
872
875
  return Qnil;
873
876
  }
874
877
 
878
+ /* Document-method: path_group
879
+ *
880
+ * call-seq: path_group(path, dirs)
881
+ *
882
+ * Sets up a path group where the path defines a group of directories to
883
+ * search for a file. For example a path of '/assets' could be mapped to a set
884
+ * of [ 'home/user/images', '/home/user/app/assets/images' ].
885
+ */
886
+ static VALUE
887
+ path_group(VALUE self, VALUE path, VALUE dirs) {
888
+ Group g;
889
+
890
+ rb_check_type(path, T_STRING);
891
+ rb_check_type(dirs, T_ARRAY);
892
+
893
+ if (NULL != (g = group_create(&the_server.pages, StringValuePtr(path)))) {
894
+ int i;
895
+ int dcnt = (int)RARRAY_LEN(dirs);
896
+ VALUE entry;
897
+
898
+ for (i = dcnt - 1; 0 <= i; i--) {
899
+ entry = rb_ary_entry(dirs, i);
900
+ if (T_STRING != rb_type(entry)) {
901
+ entry = rb_funcall(entry, rb_intern("to_s"), 0);
902
+ }
903
+ group_add(g, StringValuePtr(entry));
904
+ }
905
+ }
906
+ return Qnil;
907
+ }
908
+
875
909
  /* Document-class: Agoo::Server
876
910
  *
877
911
  * An HTTP server that support the rack API as well as some other optimized
@@ -888,6 +922,7 @@ server_init(VALUE mod) {
888
922
  rb_define_module_function(server_mod, "handle", handle, 3);
889
923
  rb_define_module_function(server_mod, "handle_not_found", handle_not_found, 1);
890
924
  rb_define_module_function(server_mod, "add_mime", add_mime, 2);
925
+ rb_define_module_function(server_mod, "path_group", path_group, 2);
891
926
 
892
927
  call_id = rb_intern("call");
893
928
  each_id = rb_intern("each");
data/ext/agoo/server.h CHANGED
@@ -23,7 +23,6 @@ typedef struct _Server {
23
23
  int max_push_pending;
24
24
  int port;
25
25
  bool pedantic;
26
- char *root;
27
26
  atomic_int running;
28
27
  pthread_t listen_thread;
29
28
  pthread_t con_thread;
data/ext/agoo/text.c CHANGED
@@ -25,16 +25,15 @@ text_create(const char *str, int len) {
25
25
 
26
26
  Text
27
27
  text_dup(Text t0) {
28
- int len = t0->len;
29
- Text t = (Text)malloc(sizeof(struct _Text) - TEXT_MIN_SIZE + len + 1);
28
+ Text t = (Text)malloc(sizeof(struct _Text) - TEXT_MIN_SIZE + t0->alen + 1);
30
29
 
31
30
  if (NULL != t) {
32
31
  DEBUG_ALLOC(mem_text, t)
33
- t->len = len;
34
- t->alen = len;
32
+ t->len = t0->len;
33
+ t->alen = t0->alen;
35
34
  t->bin = false;
36
35
  atomic_init(&t->ref_cnt, 0);
37
- memcpy(t->text, t0->text, len + 1);
36
+ memcpy(t->text, t0->text, t0->len + 1);
38
37
  }
39
38
  return t;
40
39
  }
@@ -99,10 +98,14 @@ text_prepend(Text t, const char *s, int len) {
99
98
  if (t->alen <= t->len + len) {
100
99
  long new_len = t->alen + len + t->alen / 2;
101
100
  size_t size = sizeof(struct _Text) - TEXT_MIN_SIZE + new_len + 1;
101
+ #ifdef MEM_DEBUG
102
+ Text t0 = t;
103
+ #endif
102
104
 
103
105
  if (NULL == (t = (Text)realloc(t, size))) {
104
106
  return NULL;
105
107
  }
108
+ DEBUG_REALLOC(mem_text, t0, t);
106
109
  t->alen = new_len;
107
110
  }
108
111
  memmove(t->text + len, t->text, t->len + 1);
data/ext/agoo/types.h CHANGED
@@ -23,6 +23,7 @@ typedef enum {
23
23
  } Method;
24
24
 
25
25
  typedef enum {
26
+ CON_ANY = '\0',
26
27
  CON_HTTP = 'H',
27
28
  CON_WS = 'W',
28
29
  CON_SSE = 'S',
data/ext/agoo/upgraded.c CHANGED
@@ -46,6 +46,28 @@ destroy(Upgraded up) {
46
46
  free(up);
47
47
  }
48
48
 
49
+ const char*
50
+ extract_subject(VALUE subject, int *slen) {
51
+ const char *subj;
52
+
53
+ switch (rb_type(subject)) {
54
+ case T_STRING:
55
+ subj = StringValuePtr(subject);
56
+ *slen = (int)RSTRING_LEN(subject);
57
+ break;
58
+ case T_SYMBOL:
59
+ subj = rb_id2name(rb_sym2id(subject));
60
+ *slen = strlen(subj);
61
+ break;
62
+ default:
63
+ subject = rb_funcall(subject, to_s_id, 0);
64
+ subj = StringValuePtr(subject);
65
+ *slen = (int)RSTRING_LEN(subject);
66
+ break;
67
+ }
68
+ return subj;
69
+ }
70
+
49
71
  void
50
72
  upgraded_release(Upgraded up) {
51
73
  pthread_mutex_lock(&the_server.up_lock);
@@ -184,15 +206,18 @@ up_write(VALUE self, VALUE msg) {
184
206
  * dot delimited string that can include a '*' character as a wild card that
185
207
  * matches any set of characters. The '>' character matches all remaining
186
208
  * characters. Examples: people.fred.log, people.*.log, people.fred.>
209
+ *
210
+ * Symbols can also be used as can any other object that responds to #to_s.
187
211
  */
188
212
  static VALUE
189
213
  up_subscribe(VALUE self, VALUE subject) {
190
214
  Upgraded up;
191
-
192
- rb_check_type(subject, T_STRING);
215
+ int slen;
216
+ const char *subj = extract_subject(subject, &slen);
217
+
193
218
  if (NULL != (up = get_upgraded(self))) {
194
219
  atomic_fetch_add(&up->pending, 1);
195
- queue_push(&the_server.pub_queue, pub_subscribe(up, StringValuePtr(subject), RSTRING_LEN(subject)));
220
+ queue_push(&the_server.pub_queue, pub_subscribe(up, subj, slen));
196
221
  }
197
222
  return Qnil;
198
223
  }
@@ -203,6 +228,8 @@ up_subscribe(VALUE self, VALUE subject) {
203
228
  *
204
229
  * Unsubscribes to messages on the provided subject. If the subject is nil
205
230
  * then all subscriptions for the object are removed.
231
+ *
232
+ * Symbols can also be used as can any other object that responds to #to_s.
206
233
  */
207
234
  static VALUE
208
235
  up_unsubscribe(int argc, VALUE *argv, VALUE self) {
@@ -211,9 +238,7 @@ up_unsubscribe(int argc, VALUE *argv, VALUE self) {
211
238
  int slen = 0;
212
239
 
213
240
  if (0 < argc) {
214
- rb_check_type(argv[0], T_STRING);
215
- subject = StringValuePtr(argv[0]);
216
- slen = (int)RSTRING_LEN(argv[0]);
241
+ subject = extract_subject(argv[0], &slen);
217
242
  }
218
243
  if (NULL != (up = get_upgraded(self))) {
219
244
  atomic_fetch_add(&up->pending, 1);
data/ext/agoo/upgraded.h CHANGED
@@ -36,4 +36,6 @@ extern void upgraded_add_subject(Upgraded up, struct _Subject *subject);
36
36
  extern void upgraded_del_subject(Upgraded up, struct _Subject *subject);
37
37
  extern bool upgraded_match(Upgraded up, const char *subject);
38
38
 
39
+ extern const char* extract_subject(VALUE subject, int *slen);
40
+
39
41
  #endif // __AGOO_UPGRADED_H__
data/ext/agoo/websocket.c CHANGED
@@ -215,7 +215,6 @@ ws_ping(Con c) {
215
215
  if (NULL == (res = res_create(c))) {
216
216
  log_cat(&error_cat, "Memory allocation of response failed on connection %llu.", c->id);
217
217
  } else {
218
- DEBUG_ALLOC(mem_res, res)
219
218
  if (NULL == c->res_tail) {
220
219
  c->res_head = res;
221
220
  } else {
@@ -235,7 +234,6 @@ ws_pong(Con c) {
235
234
  if (NULL == (res = res_create(c))) {
236
235
  log_cat(&error_cat, "Memory allocation of response failed on connection %llu.", c->id);
237
236
  } else {
238
- DEBUG_ALLOC(mem_res, res)
239
237
  if (NULL == c->res_tail) {
240
238
  c->res_head = res;
241
239
  } else {
data/lib/agoo/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
 
2
2
  module Agoo
3
3
  # Agoo version.
4
- VERSION = '2.1.0'
4
+ VERSION = '2.1.1'
5
5
  end
@@ -27,12 +27,15 @@ module Rack
27
27
  elsif :root == k
28
28
  root = v
29
29
  options.delete(k)
30
- elsif k.is_a?(String) && k.start_with?('/')
31
- path_map[k] = v
32
- options.delete(k)
33
30
  elsif k.nil?
34
31
  not_found_handler = v
35
32
  options.delete(k)
33
+ elsif
34
+ k = k.to_s
35
+ if k.start_with?('/')
36
+ path_map[k] = v
37
+ options.delete(k)
38
+ end
36
39
  end
37
40
  }
38
41
  options[:thread_count] = 0
@@ -40,6 +43,11 @@ module Rack
40
43
  path_map.each { |path,handler|
41
44
  ::Agoo::Server.handle(nil, path, handler)
42
45
  }
46
+ begin
47
+ # If Rails is loaded this should work else just ignore.
48
+ ::Agoo::Server.path_group('/assets', Rails.configuration.assets.paths)
49
+ rescue Exception
50
+ end
43
51
  unless default_handler.nil?
44
52
  ::Agoo::Server.handle(nil, '**', default_handler)
45
53
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: agoo
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.0
4
+ version: 2.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Peter Ohler
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-05-10 00:00:00.000000000 Z
11
+ date: 2018-05-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: oj