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 +4 -4
- data/CHANGELOG.md +8 -0
- data/README.md +10 -0
- data/ext/agoo/agoo.c +9 -6
- data/ext/agoo/con.c +33 -10
- data/ext/agoo/debug.c +2 -0
- data/ext/agoo/debug.h +2 -0
- data/ext/agoo/hook.c +47 -0
- data/ext/agoo/page.c +108 -5
- data/ext/agoo/page.h +22 -3
- data/ext/agoo/pub.c +1 -1
- data/ext/agoo/pub.h +1 -1
- data/ext/agoo/server.c +46 -11
- data/ext/agoo/server.h +0 -1
- data/ext/agoo/text.c +8 -5
- data/ext/agoo/types.h +1 -0
- data/ext/agoo/upgraded.c +31 -6
- data/ext/agoo/upgraded.h +2 -0
- data/ext/agoo/websocket.c +0 -2
- data/lib/agoo/version.rb +1 -1
- data/lib/rack/handler/agoo.rb +11 -3
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: '0618dff57c263cccb782e0fbccc807bf434815109c3809078ebd4d12570e1bde'
|
4
|
+
data.tar.gz: 2603682170f882a06d20e50ad0d9ab753b927f730331c224ce9e4dcc2cbea581
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
-
|
46
|
-
|
46
|
+
int slen;
|
47
|
+
const char *subj = extract_subject(subject, &slen);
|
47
48
|
|
48
|
-
|
49
|
-
|
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 (
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
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
|
-
|
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 =
|
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 =
|
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
|
-
|
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
|
-
|
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 *
|
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,
|
412
|
+
char *s = stpcpy(full_path, cache->root);
|
410
413
|
|
411
|
-
if ('/' != *
|
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
|
49
|
-
extern void
|
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 *
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
618
|
-
|
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
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
|
-
|
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 =
|
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
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
|
-
|
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,
|
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
|
-
|
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
data/lib/rack/handler/agoo.rb
CHANGED
@@ -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.
|
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-
|
11
|
+
date: 2018-05-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: oj
|