agoo 1.2.2 → 2.0.0
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/README.md +11 -9
- data/ext/agoo/agoo.c +45 -0
- data/ext/agoo/base64.c +107 -0
- data/ext/agoo/base64.h +15 -0
- data/ext/agoo/ccache.c +301 -0
- data/ext/agoo/ccache.h +53 -0
- data/ext/agoo/con.c +522 -82
- data/ext/agoo/con.h +7 -5
- data/ext/agoo/debug.c +121 -7
- data/ext/agoo/debug.h +11 -6
- data/ext/agoo/error_stream.c +5 -6
- data/ext/agoo/error_stream.h +1 -1
- data/ext/agoo/extconf.rb +2 -1
- data/ext/agoo/hook.c +4 -4
- data/ext/agoo/hook.h +1 -0
- data/ext/agoo/http.c +2 -2
- data/ext/agoo/http.h +2 -0
- data/ext/agoo/log.c +604 -219
- data/ext/agoo/log.h +20 -7
- data/ext/agoo/page.c +20 -23
- data/ext/agoo/page.h +2 -0
- data/ext/agoo/pub.c +111 -0
- data/ext/agoo/pub.h +40 -0
- data/ext/agoo/queue.c +2 -2
- data/ext/agoo/rack_logger.c +15 -71
- data/ext/agoo/rack_logger.h +1 -1
- data/ext/agoo/request.c +96 -21
- data/ext/agoo/request.h +23 -12
- data/ext/agoo/res.c +5 -2
- data/ext/agoo/res.h +4 -0
- data/ext/agoo/response.c +13 -12
- data/ext/agoo/response.h +1 -2
- data/ext/agoo/server.c +290 -428
- data/ext/agoo/server.h +10 -10
- data/ext/agoo/sha1.c +148 -0
- data/ext/agoo/sha1.h +10 -0
- data/ext/agoo/sse.c +26 -0
- data/ext/agoo/sse.h +12 -0
- data/ext/agoo/sub.c +111 -0
- data/ext/agoo/sub.h +36 -0
- data/ext/agoo/subscription.c +54 -0
- data/ext/agoo/subscription.h +18 -0
- data/ext/agoo/text.c +26 -4
- data/ext/agoo/text.h +2 -0
- data/ext/agoo/types.h +13 -0
- data/ext/agoo/upgraded.c +148 -0
- data/ext/agoo/upgraded.h +13 -0
- data/ext/agoo/websocket.c +248 -0
- data/ext/agoo/websocket.h +27 -0
- data/lib/agoo/version.rb +1 -1
- data/lib/rack/handler/agoo.rb +13 -6
- data/test/base_handler_test.rb +24 -22
- data/test/log_test.rb +146 -199
- data/test/rack_handler_test.rb +19 -20
- data/test/static_test.rb +30 -28
- metadata +23 -7
- data/test/rrr/test.rb +0 -26
- data/test/tests.rb +0 -8
data/ext/agoo/server.h
CHANGED
@@ -9,33 +9,30 @@
|
|
9
9
|
|
10
10
|
#include <ruby.h>
|
11
11
|
|
12
|
+
#include "ccache.h"
|
12
13
|
#include "hook.h"
|
13
14
|
#include "log.h"
|
14
15
|
#include "page.h"
|
15
16
|
#include "queue.h"
|
17
|
+
#include "sub.h"
|
16
18
|
|
17
19
|
typedef struct _Server {
|
20
|
+
volatile bool inited;
|
18
21
|
volatile bool active;
|
19
|
-
volatile bool ready;
|
20
22
|
int thread_cnt;
|
23
|
+
int max_push_pending;
|
21
24
|
int port;
|
22
25
|
bool pedantic;
|
23
26
|
char *root;
|
24
27
|
atomic_int running;
|
25
28
|
pthread_t listen_thread;
|
26
29
|
pthread_t con_thread;
|
27
|
-
struct _Log log;
|
28
|
-
struct _LogCat error_cat;
|
29
|
-
struct _LogCat warn_cat;
|
30
|
-
struct _LogCat info_cat;
|
31
|
-
struct _LogCat debug_cat;
|
32
|
-
struct _LogCat con_cat;
|
33
|
-
struct _LogCat req_cat;
|
34
|
-
struct _LogCat resp_cat;
|
35
|
-
struct _LogCat eval_cat;
|
36
30
|
|
37
31
|
struct _Queue con_queue;
|
32
|
+
struct _Queue pub_queue;
|
38
33
|
struct _Cache pages;
|
34
|
+
struct _SubCache sub_cache; // subscription cache
|
35
|
+
struct _CCache con_cache; // Only WebSocket and SSE connections
|
39
36
|
|
40
37
|
Hook hooks;
|
41
38
|
Hook hook404;
|
@@ -44,6 +41,9 @@ typedef struct _Server {
|
|
44
41
|
VALUE *eval_threads; // Qnil terminated
|
45
42
|
} *Server;
|
46
43
|
|
44
|
+
extern struct _Server the_server;
|
45
|
+
|
47
46
|
extern void server_init(VALUE mod);
|
47
|
+
extern void server_shutdown();
|
48
48
|
|
49
49
|
#endif // __AGOO_SERVER_H__
|
data/ext/agoo/sha1.c
ADDED
@@ -0,0 +1,148 @@
|
|
1
|
+
// Taken and modified from the original by Steve Reid which is in the public
|
2
|
+
// domain. It has been modified by James H. Brown, Saul Kravitz, Ralph Giles,
|
3
|
+
// and now Peter Ohler.
|
4
|
+
|
5
|
+
#include <stdio.h>
|
6
|
+
#include <stdint.h>
|
7
|
+
#include <string.h>
|
8
|
+
|
9
|
+
#include "sha1.h"
|
10
|
+
|
11
|
+
typedef struct {
|
12
|
+
uint32_t h0;
|
13
|
+
uint32_t h1;
|
14
|
+
uint32_t h2;
|
15
|
+
uint32_t h3;
|
16
|
+
uint32_t h4;
|
17
|
+
uint32_t count[2];
|
18
|
+
uint8_t buffer[64];
|
19
|
+
} Ctx;
|
20
|
+
|
21
|
+
// TBD make this stuff ENDIAN independent. Now it is little endian only.
|
22
|
+
#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
|
23
|
+
#define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00)|(rol(block->l[i],8)&0x00FF00FF))
|
24
|
+
#define blk(i) (block->l[i&0x0F] = rol(block->l[(i+13)&0x0F]^block->l[(i+8)&0x0F]^block->l[(i+2)&0x0F]^block->l[i&0x0F],1))
|
25
|
+
|
26
|
+
#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30);
|
27
|
+
#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30);
|
28
|
+
#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30);
|
29
|
+
#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30);
|
30
|
+
#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);
|
31
|
+
|
32
|
+
// Transform a 512 bit block.
|
33
|
+
static void
|
34
|
+
transform(Ctx *ctx, const uint8_t buffer[64]) {
|
35
|
+
uint32_t a = ctx->h0;
|
36
|
+
uint32_t b = ctx->h1;
|
37
|
+
uint32_t c = ctx->h2;
|
38
|
+
uint32_t d = ctx->h3;
|
39
|
+
uint32_t e = ctx->h4;
|
40
|
+
|
41
|
+
typedef union {
|
42
|
+
uint8_t c[64];
|
43
|
+
uint32_t l[16];
|
44
|
+
} CHAR64LONG16;
|
45
|
+
CHAR64LONG16* block;
|
46
|
+
|
47
|
+
block = (CHAR64LONG16*)buffer;
|
48
|
+
|
49
|
+
/* 4 rounds of 20 operations each. Loop unrolled. */
|
50
|
+
R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3);
|
51
|
+
R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7);
|
52
|
+
R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11);
|
53
|
+
R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15);
|
54
|
+
R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19);
|
55
|
+
R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23);
|
56
|
+
R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27);
|
57
|
+
R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31);
|
58
|
+
R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35);
|
59
|
+
R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39);
|
60
|
+
R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43);
|
61
|
+
R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47);
|
62
|
+
R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51);
|
63
|
+
R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55);
|
64
|
+
R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59);
|
65
|
+
R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63);
|
66
|
+
R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67);
|
67
|
+
R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71);
|
68
|
+
R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75);
|
69
|
+
R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79);
|
70
|
+
|
71
|
+
ctx->h0 += a;
|
72
|
+
ctx->h1 += b;
|
73
|
+
ctx->h2 += c;
|
74
|
+
ctx->h3 += d;
|
75
|
+
ctx->h4 += e;
|
76
|
+
}
|
77
|
+
|
78
|
+
static void
|
79
|
+
update(Ctx *ctx, const uint8_t* data, const size_t len) {
|
80
|
+
size_t i;
|
81
|
+
size_t j = (ctx->count[0] >> 3) & 0x3F;
|
82
|
+
|
83
|
+
if ((ctx->count[0] += len << 3) < (len << 3)) {
|
84
|
+
ctx->count[1]++;
|
85
|
+
}
|
86
|
+
ctx->count[1] += (len >> 29);
|
87
|
+
if ((j + len) > 63) {
|
88
|
+
i = 64 - j;
|
89
|
+
memcpy(ctx->buffer + j, data, i);
|
90
|
+
transform(ctx, ctx->buffer);
|
91
|
+
for (; i + 63 < len; i += 64) {
|
92
|
+
transform(ctx, data + i);
|
93
|
+
}
|
94
|
+
j = 0;
|
95
|
+
} else {
|
96
|
+
i = 0;
|
97
|
+
}
|
98
|
+
memcpy(ctx->buffer + j, data + i, len - i);
|
99
|
+
}
|
100
|
+
|
101
|
+
void
|
102
|
+
sha1(const uint8_t *data, size_t len, uint8_t *digest) {
|
103
|
+
Ctx ctx;
|
104
|
+
uint32_t i;
|
105
|
+
uint8_t finalcount[8];
|
106
|
+
int shift;
|
107
|
+
|
108
|
+
ctx.h0 = 0x67452301;
|
109
|
+
ctx.h1 = 0xEFCDAB89;
|
110
|
+
ctx.h2 = 0x98BADCFE;
|
111
|
+
ctx.h3 = 0x10325476;
|
112
|
+
ctx.h4 = 0xC3D2E1F0;
|
113
|
+
ctx.count[0] = 0;
|
114
|
+
ctx.count[1] = 0;
|
115
|
+
|
116
|
+
update(&ctx, data, len);
|
117
|
+
|
118
|
+
for (i = 0; i < 8; i++) {
|
119
|
+
finalcount[i] = (uint8_t)((ctx.count[(i >= 4 ? 0 : 1)] >> ((3-(i & 3)) * 8) ) & 0xFF);
|
120
|
+
}
|
121
|
+
update(&ctx, (uint8_t*)"\x80", 1);
|
122
|
+
while ((ctx.count[0] & 0x000001F8) != 0x000001C0) {
|
123
|
+
update(&ctx, (uint8_t*)"", 1);
|
124
|
+
}
|
125
|
+
update(&ctx, finalcount, 8);
|
126
|
+
for (i = 0; i < SHA1_DIGEST_SIZE; i++) {
|
127
|
+
shift = (3 - (i & 3)) * 8;
|
128
|
+
switch (i >> 2) {
|
129
|
+
case 0:
|
130
|
+
digest[i] = (uint8_t)((ctx.h0 >> shift) & 0xFF);
|
131
|
+
break;
|
132
|
+
case 1:
|
133
|
+
digest[i] = (uint8_t)((ctx.h1 >> shift) & 0xFF);
|
134
|
+
break;
|
135
|
+
case 2:
|
136
|
+
digest[i] = (uint8_t)((ctx.h2 >> shift) & 0xFF);
|
137
|
+
break;
|
138
|
+
case 3:
|
139
|
+
digest[i] = (uint8_t)((ctx.h3 >> shift) & 0xFF);
|
140
|
+
break;
|
141
|
+
case 4:
|
142
|
+
digest[i] = (uint8_t)((ctx.h4 >> shift) & 0xFF);
|
143
|
+
break;
|
144
|
+
default:
|
145
|
+
break;
|
146
|
+
}
|
147
|
+
}
|
148
|
+
}
|
data/ext/agoo/sha1.h
ADDED
data/ext/agoo/sse.c
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
// Copyright (c) 2018, Peter Ohler, All rights reserved.
|
2
|
+
|
3
|
+
#include "request.h"
|
4
|
+
#include "sse.h"
|
5
|
+
#include "text.h"
|
6
|
+
|
7
|
+
static const char prefix[] = "event: msg\ndata: ";
|
8
|
+
static const char suffix[] = "\n\n";
|
9
|
+
static const char up[] = "HTTP/1.1 200 OK\r\n\
|
10
|
+
Content-Type: text/event-stream\r\n\
|
11
|
+
Cache-Control: no-cache\r\n\
|
12
|
+
Connection: keep-alive\r\n\
|
13
|
+
\r\n\
|
14
|
+
retry: 5\n\n";
|
15
|
+
|
16
|
+
Text
|
17
|
+
sse_upgrade(Req req, Text t) {
|
18
|
+
t->len = 0; // reset
|
19
|
+
return text_append(t, up, sizeof(up) - 1);
|
20
|
+
}
|
21
|
+
|
22
|
+
Text
|
23
|
+
sse_expand(Text t) {
|
24
|
+
t = text_prepend(t, prefix, sizeof(prefix) - 1);
|
25
|
+
return text_append(t, suffix, sizeof(suffix) - 1);
|
26
|
+
}
|
data/ext/agoo/sse.h
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
// Copyright (c) 2018, Peter Ohler, All rights reserved.
|
2
|
+
|
3
|
+
#ifndef __AGOO_SSE_H__
|
4
|
+
#define __AGOO_SSE_H__
|
5
|
+
|
6
|
+
struct _Req;
|
7
|
+
struct _Text;
|
8
|
+
|
9
|
+
extern struct _Text* sse_upgrade(struct _Req *req, struct _Text *t);
|
10
|
+
extern struct _Text* sse_expand(struct _Text *t);
|
11
|
+
|
12
|
+
#endif // __AGOO_SSE_H__
|
data/ext/agoo/sub.c
ADDED
@@ -0,0 +1,111 @@
|
|
1
|
+
// Copyright (c) 2018, Peter Ohler, All rights reserved.
|
2
|
+
|
3
|
+
#include <stdlib.h>
|
4
|
+
#include <string.h>
|
5
|
+
|
6
|
+
#include "sub.h"
|
7
|
+
|
8
|
+
Sub
|
9
|
+
sub_new(uint64_t cid, uint64_t id, const char *subject, size_t slen) {
|
10
|
+
Sub s = (Sub)malloc(sizeof(struct _Sub) - 8 + slen + 1);
|
11
|
+
|
12
|
+
if (NULL != s) {
|
13
|
+
s->cid = cid;
|
14
|
+
s->id = id;
|
15
|
+
strncpy(s->subject, subject, slen);
|
16
|
+
s->subject[slen] = '\0';
|
17
|
+
}
|
18
|
+
return s;
|
19
|
+
}
|
20
|
+
|
21
|
+
bool
|
22
|
+
sub_match(Sub s, const char *subject, size_t slen) {
|
23
|
+
const char *pat = s->subject;
|
24
|
+
const char *end = subject + slen;
|
25
|
+
|
26
|
+
for (; '\0' != *pat && subject < end; subject++) {
|
27
|
+
if (*subject == *pat) {
|
28
|
+
subject++;
|
29
|
+
} else if ('*' == *pat) {
|
30
|
+
for (; subject < end && '.' != *subject; subject++) {
|
31
|
+
}
|
32
|
+
} else if ('>' == *pat) {
|
33
|
+
return true;
|
34
|
+
} else {
|
35
|
+
break;
|
36
|
+
}
|
37
|
+
}
|
38
|
+
return '\0' == *pat && subject == end;
|
39
|
+
}
|
40
|
+
|
41
|
+
void
|
42
|
+
sub_init(SubCache sc) {
|
43
|
+
memset(sc, 0, sizeof(struct _SubCache));
|
44
|
+
}
|
45
|
+
|
46
|
+
void
|
47
|
+
sub_cleanup(SubCache sc) {
|
48
|
+
Sub s;
|
49
|
+
Sub head;
|
50
|
+
Sub *bucket;
|
51
|
+
int i;
|
52
|
+
|
53
|
+
for (i = 0, bucket = sc->buckets; i < SUB_BUCKET_SIZE; i++, bucket++) {
|
54
|
+
head = *bucket;
|
55
|
+
while (NULL != head) {
|
56
|
+
s = head;
|
57
|
+
head = head->next;
|
58
|
+
free(s);
|
59
|
+
}
|
60
|
+
}
|
61
|
+
}
|
62
|
+
|
63
|
+
static uint64_t
|
64
|
+
calc_hash(uint64_t cid, uint64_t sid) {
|
65
|
+
return (SUB_BUCKET_MASK & (cid ^ sid));
|
66
|
+
}
|
67
|
+
|
68
|
+
void
|
69
|
+
sub_add(SubCache sc, Sub s) {
|
70
|
+
Sub *bucket = sc->buckets + calc_hash(s->cid, s->id);
|
71
|
+
|
72
|
+
s->next = *bucket;
|
73
|
+
*bucket = s;
|
74
|
+
}
|
75
|
+
|
76
|
+
Sub
|
77
|
+
sub_get(SubCache sc, uint64_t cid, uint64_t sid) {
|
78
|
+
Sub s = *(sc->buckets + calc_hash(cid, sid));
|
79
|
+
|
80
|
+
for (; NULL != s; s = s->next) {
|
81
|
+
if (s->cid == cid && s->id == sid) {
|
82
|
+
return s;
|
83
|
+
}
|
84
|
+
}
|
85
|
+
return NULL;
|
86
|
+
}
|
87
|
+
|
88
|
+
void
|
89
|
+
sub_del(SubCache sc, uint64_t cid, uint64_t sid) {
|
90
|
+
Sub *bucket = sc->buckets + calc_hash(cid, sid);
|
91
|
+
|
92
|
+
if (NULL != *bucket) {
|
93
|
+
Sub s = *bucket;
|
94
|
+
|
95
|
+
if (s->cid == cid && s->id == sid) {
|
96
|
+
*bucket = s->next;
|
97
|
+
} else {
|
98
|
+
Sub prev = s;
|
99
|
+
|
100
|
+
for (s = s->next; NULL != s; s = s->next) {
|
101
|
+
if (s->cid == cid && s->id == sid) {
|
102
|
+
prev->next = s->next;
|
103
|
+
free(s);
|
104
|
+
break;
|
105
|
+
}
|
106
|
+
prev = s;
|
107
|
+
}
|
108
|
+
}
|
109
|
+
}
|
110
|
+
}
|
111
|
+
|
data/ext/agoo/sub.h
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
// Copyright (c) 2018, Peter Ohler, All rights reserved.
|
2
|
+
|
3
|
+
#ifndef __AGOO_SUB_H__
|
4
|
+
#define __AGOO_SUB_H__
|
5
|
+
|
6
|
+
#include <stdbool.h>
|
7
|
+
#include <stdint.h>
|
8
|
+
|
9
|
+
#define SUB_BUCKET_SIZE 1024
|
10
|
+
#define SUB_BUCKET_MASK 1023
|
11
|
+
|
12
|
+
struct _Con;
|
13
|
+
|
14
|
+
typedef struct _Sub {
|
15
|
+
struct _Sub *next;
|
16
|
+
uint64_t cid;
|
17
|
+
struct _Con *con;
|
18
|
+
uint64_t id;
|
19
|
+
uint64_t key; // hash key
|
20
|
+
char subject[8];
|
21
|
+
} *Sub;
|
22
|
+
|
23
|
+
typedef struct _SubCache {
|
24
|
+
Sub buckets[SUB_BUCKET_SIZE];
|
25
|
+
} *SubCache;
|
26
|
+
|
27
|
+
extern void sub_init(SubCache sc);
|
28
|
+
extern void sub_cleanup(SubCache sc);
|
29
|
+
|
30
|
+
extern Sub sub_new(uint64_t cid, uint64_t id, const char *subject, size_t slen);
|
31
|
+
extern bool sub_match(Sub s, const char *subject, size_t slen);
|
32
|
+
extern void sub_add(SubCache sc, Sub s);
|
33
|
+
extern Sub sub_get(SubCache sc, uint64_t cid, uint64_t sid);
|
34
|
+
extern void sub_del(SubCache sc, uint64_t cid, uint64_t sid);
|
35
|
+
|
36
|
+
#endif // __AGOO_SUB_H__
|
@@ -0,0 +1,54 @@
|
|
1
|
+
// Copyright (c) 2018, Peter Ohler, All rights reserved.
|
2
|
+
|
3
|
+
#include "pub.h"
|
4
|
+
#include "queue.h"
|
5
|
+
#include "server.h"
|
6
|
+
#include "subscription.h"
|
7
|
+
|
8
|
+
static VALUE subscription_class = Qundef;
|
9
|
+
|
10
|
+
VALUE
|
11
|
+
subscription_new(uint64_t cid, uint64_t id, VALUE handler) {
|
12
|
+
Subscription s = ALLOC(struct _Subscription);
|
13
|
+
|
14
|
+
s->cid = cid;
|
15
|
+
s->id = id;
|
16
|
+
s->handler = handler;
|
17
|
+
s->self = Data_Wrap_Struct(subscription_class, NULL, xfree, s);
|
18
|
+
|
19
|
+
return s->self;
|
20
|
+
}
|
21
|
+
|
22
|
+
/* Document-method: close
|
23
|
+
*
|
24
|
+
* call-seq: close()
|
25
|
+
*
|
26
|
+
* Close or unsubscribe a subscription.
|
27
|
+
*/
|
28
|
+
static VALUE
|
29
|
+
subscription_close(VALUE self) {
|
30
|
+
Subscription s = DATA_PTR(self);
|
31
|
+
|
32
|
+
if (0 != s->cid && 0 != s->id) {
|
33
|
+
Pub p = pub_unsubscribe(s->cid, s->id);
|
34
|
+
|
35
|
+
queue_push(&the_server.pub_queue, (void*)p);
|
36
|
+
queue_wakeup(&the_server.pub_queue);
|
37
|
+
s->cid = 0;
|
38
|
+
s->id = 0;
|
39
|
+
}
|
40
|
+
return Qnil;
|
41
|
+
}
|
42
|
+
|
43
|
+
/* Document-class: Agoo::Subscription
|
44
|
+
*
|
45
|
+
* The handle on a subscriptionscription used to register interest in messages
|
46
|
+
* published on a subscriptionject. Published messages are delivered to Javascript
|
47
|
+
* clients.
|
48
|
+
*/
|
49
|
+
void
|
50
|
+
subscription_init(VALUE mod) {
|
51
|
+
subscription_class = rb_define_class_under(mod, "Subscription", rb_cObject);
|
52
|
+
|
53
|
+
rb_define_method(subscription_class, "close", subscription_close, 0);
|
54
|
+
}
|