agoo 2.0.5 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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 +5 -2
- data/ext/agoo/agoo.c +35 -2
- data/ext/agoo/con.c +184 -86
- data/ext/agoo/con.h +4 -2
- data/ext/agoo/debug.c +2 -0
- data/ext/agoo/debug.h +2 -0
- data/ext/agoo/page.c +1 -0
- data/ext/agoo/pub.c +31 -27
- data/ext/agoo/pub.h +10 -11
- data/ext/agoo/request.c +5 -4
- data/ext/agoo/request.h +2 -1
- data/ext/agoo/res.c +3 -1
- data/ext/agoo/res.h +4 -1
- data/ext/agoo/server.c +55 -26
- data/ext/agoo/server.h +5 -3
- data/ext/agoo/subject.c +51 -0
- data/ext/agoo/subject.h +17 -0
- data/ext/agoo/text.c +18 -1
- data/ext/agoo/text.h +1 -0
- data/ext/agoo/upgraded.c +264 -57
- data/ext/agoo/upgraded.h +27 -1
- data/ext/agoo/websocket.c +10 -9
- data/lib/agoo/version.rb +1 -1
- metadata +4 -6
- data/ext/agoo/ccache.c +0 -301
- data/ext/agoo/ccache.h +0 -53
- data/ext/agoo/subscription.c +0 -54
- data/ext/agoo/subscription.h +0 -18
    
        data/ext/agoo/server.h
    CHANGED
    
    | @@ -9,12 +9,12 @@ | |
| 9 9 |  | 
| 10 10 | 
             
            #include <ruby.h>
         | 
| 11 11 |  | 
| 12 | 
            -
            #include "ccache.h"
         | 
| 13 12 | 
             
            #include "hook.h"
         | 
| 14 13 | 
             
            #include "log.h"
         | 
| 15 14 | 
             
            #include "page.h"
         | 
| 16 15 | 
             
            #include "queue.h"
         | 
| 17 16 | 
             
            #include "sub.h"
         | 
| 17 | 
            +
            #include "upgraded.h"
         | 
| 18 18 |  | 
| 19 19 | 
             
            typedef struct _Server {
         | 
| 20 20 | 
             
                volatile bool	inited;
         | 
| @@ -27,12 +27,14 @@ typedef struct _Server { | |
| 27 27 | 
             
                atomic_int		running;
         | 
| 28 28 | 
             
                pthread_t		listen_thread;
         | 
| 29 29 | 
             
                pthread_t		con_thread;
         | 
| 30 | 
            -
             | 
| 30 | 
            +
             | 
| 31 | 
            +
                pthread_mutex_t	up_lock;
         | 
| 32 | 
            +
                Upgraded		up_list;
         | 
| 33 | 
            +
             | 
| 31 34 | 
             
                struct _Queue	con_queue;
         | 
| 32 35 | 
             
                struct _Queue	pub_queue;
         | 
| 33 36 | 
             
                struct _Cache	pages;
         | 
| 34 37 | 
             
                struct _SubCache	sub_cache; // subscription cache
         | 
| 35 | 
            -
                struct _CCache	con_cache; // Only WebSocket and SSE connections
         | 
| 36 38 |  | 
| 37 39 | 
             
                Hook		hooks;
         | 
| 38 40 | 
             
                Hook		hook404;
         | 
    
        data/ext/agoo/subject.c
    ADDED
    
    | @@ -0,0 +1,51 @@ | |
| 1 | 
            +
            // Copyright (c) 2018, Peter Ohler, All rights reserved.
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            #include <stdio.h>
         | 
| 4 | 
            +
            #include <stdlib.h>
         | 
| 5 | 
            +
            #include <string.h>
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            #include "debug.h"
         | 
| 8 | 
            +
            #include "subject.h"
         | 
| 9 | 
            +
             | 
| 10 | 
            +
            Subject
         | 
| 11 | 
            +
            subject_create(const char *pattern, int plen) {
         | 
| 12 | 
            +
                Subject	subject = (Subject)malloc(sizeof(struct _Subject) - 7 + plen);
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                if (NULL != subject) {
         | 
| 15 | 
            +
            	DEBUG_ALLOC(mem_subject, subject);
         | 
| 16 | 
            +
            	subject->next = NULL;
         | 
| 17 | 
            +
            	memcpy(subject->pattern, pattern, plen);
         | 
| 18 | 
            +
            	subject->pattern[plen] = '\0';
         | 
| 19 | 
            +
                }
         | 
| 20 | 
            +
                return subject;
         | 
| 21 | 
            +
            }
         | 
| 22 | 
            +
             | 
| 23 | 
            +
            void
         | 
| 24 | 
            +
            subject_destroy(Subject subject) {
         | 
| 25 | 
            +
                DEBUG_FREE(mem_subject, subject);
         | 
| 26 | 
            +
                free(subject);
         | 
| 27 | 
            +
            }
         | 
| 28 | 
            +
             | 
| 29 | 
            +
            bool
         | 
| 30 | 
            +
            subject_check(Subject subj, const char *subject) {
         | 
| 31 | 
            +
                const char	*pat = subj->pattern;
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                for (; '\0' != *pat && '\0' != *subject; subject++) {
         | 
| 34 | 
            +
            	if (*subject == *pat) {
         | 
| 35 | 
            +
            	    pat++;
         | 
| 36 | 
            +
            	} else if ('*' == *pat) {
         | 
| 37 | 
            +
            	    for (; '\0' != *subject && '.' != *subject; subject++) {
         | 
| 38 | 
            +
            	    }
         | 
| 39 | 
            +
            	    if ('\0' == *subject) {
         | 
| 40 | 
            +
            		return true;
         | 
| 41 | 
            +
            	    }
         | 
| 42 | 
            +
            	    pat++;
         | 
| 43 | 
            +
            	} else if ('>' == *pat) {
         | 
| 44 | 
            +
            	    return true;
         | 
| 45 | 
            +
            	} else {
         | 
| 46 | 
            +
            	    break;
         | 
| 47 | 
            +
            	}
         | 
| 48 | 
            +
                }
         | 
| 49 | 
            +
                return '\0' == *pat && '\0' == *subject;
         | 
| 50 | 
            +
            }
         | 
| 51 | 
            +
             | 
    
        data/ext/agoo/subject.h
    ADDED
    
    | @@ -0,0 +1,17 @@ | |
| 1 | 
            +
            // Copyright (c) 2018, Peter Ohler, All rights reserved.
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            #ifndef __AGOO_SUBJECT_H__
         | 
| 4 | 
            +
            #define __AGOO_SUBJECT_H__
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            #include <stdbool.h>
         | 
| 7 | 
            +
             | 
| 8 | 
            +
            typedef struct _Subject {
         | 
| 9 | 
            +
                struct _Subject	*next;
         | 
| 10 | 
            +
                char		pattern[8];
         | 
| 11 | 
            +
            } *Subject;
         | 
| 12 | 
            +
             | 
| 13 | 
            +
            extern Subject	subject_create(const char *pattern, int plen);
         | 
| 14 | 
            +
            extern void	subject_destroy(Subject subject);
         | 
| 15 | 
            +
            extern bool	subject_check(Subject subj, const char *subject);
         | 
| 16 | 
            +
             | 
| 17 | 
            +
            #endif // __AGOO_SUBJECT_H__
         | 
    
        data/ext/agoo/text.c
    CHANGED
    
    | @@ -23,6 +23,22 @@ text_create(const char *str, int len) { | |
| 23 23 | 
             
                return t;
         | 
| 24 24 | 
             
            }
         | 
| 25 25 |  | 
| 26 | 
            +
            Text
         | 
| 27 | 
            +
            text_dup(Text t0) {
         | 
| 28 | 
            +
                int		len = t0->len;
         | 
| 29 | 
            +
                Text	t = (Text)malloc(sizeof(struct _Text) - TEXT_MIN_SIZE + len + 1);
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                if (NULL != t) {
         | 
| 32 | 
            +
            	DEBUG_ALLOC(mem_text, t)
         | 
| 33 | 
            +
            	t->len = len;
         | 
| 34 | 
            +
            	t->alen = len;
         | 
| 35 | 
            +
            	t->bin = false;
         | 
| 36 | 
            +
            	atomic_init(&t->ref_cnt, 0);
         | 
| 37 | 
            +
            	memcpy(t->text, t0->text, len + 1);
         | 
| 38 | 
            +
                }
         | 
| 39 | 
            +
                return t;
         | 
| 40 | 
            +
            }
         | 
| 41 | 
            +
             | 
| 26 42 | 
             
            Text
         | 
| 27 43 | 
             
            text_allocate(int len) {
         | 
| 28 44 | 
             
                Text	t = (Text)malloc(sizeof(struct _Text) - TEXT_MIN_SIZE + len + 1);
         | 
| @@ -59,8 +75,9 @@ text_append(Text t, const char *s, int len) { | |
| 59 75 | 
             
                if (t->alen <= t->len + len) {
         | 
| 60 76 | 
             
            	long	new_len = t->alen + len + t->alen / 2;
         | 
| 61 77 | 
             
            	size_t	size = sizeof(struct _Text) - TEXT_MIN_SIZE + new_len + 1;
         | 
| 78 | 
            +
            #ifdef MEM_DEBUG
         | 
| 62 79 | 
             
            	Text	t0 = t;
         | 
| 63 | 
            -
            	
         | 
| 80 | 
            +
            #endif	
         | 
| 64 81 | 
             
            	if (NULL == (t = (Text)realloc(t, size))) {
         | 
| 65 82 | 
             
            	    return NULL;
         | 
| 66 83 | 
             
            	}
         | 
    
        data/ext/agoo/text.h
    CHANGED
    
    
    
        data/ext/agoo/upgraded.c
    CHANGED
    
    | @@ -4,72 +4,221 @@ | |
| 4 4 |  | 
| 5 5 | 
             
            #include <ruby/encoding.h>
         | 
| 6 6 |  | 
| 7 | 
            +
            #include "con.h"
         | 
| 8 | 
            +
            #include "debug.h"
         | 
| 7 9 | 
             
            #include "pub.h"
         | 
| 8 10 | 
             
            #include "server.h"
         | 
| 11 | 
            +
            #include "subject.h"
         | 
| 9 12 | 
             
            #include "upgraded.h"
         | 
| 10 13 |  | 
| 11 | 
            -
            static VALUE	 | 
| 14 | 
            +
            static VALUE	upgraded_class = Qundef;
         | 
| 15 | 
            +
             | 
| 16 | 
            +
            static VALUE	sse_sym;
         | 
| 17 | 
            +
            static VALUE	websocket_sym;
         | 
| 12 18 |  | 
| 13 | 
            -
            static ID	cid_id = 0;
         | 
| 14 | 
            -
            static ID	sid_id = 0;
         | 
| 15 19 | 
             
            static ID	on_open_id = 0;
         | 
| 16 20 | 
             
            static ID	to_s_id = 0;
         | 
| 17 21 |  | 
| 22 | 
            +
            static void
         | 
| 23 | 
            +
            destroy(Upgraded up) {
         | 
| 24 | 
            +
                Subject	subject;
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                if (Qnil != up->wrap) {
         | 
| 27 | 
            +
            	DATA_PTR(up->wrap) = NULL;
         | 
| 28 | 
            +
            	up->wrap = Qnil;
         | 
| 29 | 
            +
                }
         | 
| 30 | 
            +
                if (NULL == up->prev) {
         | 
| 31 | 
            +
            	the_server.up_list = up->next;
         | 
| 32 | 
            +
            	if (NULL != up->next) {
         | 
| 33 | 
            +
            	    up->next->prev = NULL;
         | 
| 34 | 
            +
            	}
         | 
| 35 | 
            +
                } else {
         | 
| 36 | 
            +
            	up->prev->next = up->next;
         | 
| 37 | 
            +
            	if (NULL != up->next) {
         | 
| 38 | 
            +
            	    up->next->prev = up->prev;
         | 
| 39 | 
            +
            	}
         | 
| 40 | 
            +
                }
         | 
| 41 | 
            +
                while (NULL != (subject = up->subjects)) {
         | 
| 42 | 
            +
            	up->subjects = up->subjects->next;
         | 
| 43 | 
            +
            	subject_destroy(subject);
         | 
| 44 | 
            +
                }
         | 
| 45 | 
            +
                DEBUG_FREE(mem_upgraded, up);
         | 
| 46 | 
            +
                free(up);
         | 
| 47 | 
            +
            }
         | 
| 48 | 
            +
             | 
| 49 | 
            +
            void
         | 
| 50 | 
            +
            upgraded_release(Upgraded up) {
         | 
| 51 | 
            +
                pthread_mutex_lock(&the_server.up_lock);
         | 
| 52 | 
            +
                if (atomic_fetch_sub(&up->ref_cnt, 1) <= 1) {
         | 
| 53 | 
            +
            	destroy(up);
         | 
| 54 | 
            +
                }    
         | 
| 55 | 
            +
                pthread_mutex_unlock(&the_server.up_lock);
         | 
| 56 | 
            +
            }
         | 
| 57 | 
            +
             | 
| 58 | 
            +
            void
         | 
| 59 | 
            +
            upgraded_release_con(Upgraded up) {
         | 
| 60 | 
            +
                pthread_mutex_lock(&the_server.up_lock);
         | 
| 61 | 
            +
                up->con = NULL;
         | 
| 62 | 
            +
                if (atomic_fetch_sub(&up->ref_cnt, 1) <= 1) {
         | 
| 63 | 
            +
            	destroy(up);
         | 
| 64 | 
            +
                }
         | 
| 65 | 
            +
                pthread_mutex_unlock(&the_server.up_lock);
         | 
| 66 | 
            +
            }
         | 
| 67 | 
            +
             | 
| 68 | 
            +
            // Called from the con_loop thread, no need to lock, this steals the subject
         | 
| 69 | 
            +
            // so the pub subject should set to NULL
         | 
| 70 | 
            +
            void
         | 
| 71 | 
            +
            upgraded_add_subject(Upgraded up, Subject subject) {
         | 
| 72 | 
            +
                Subject	s;
         | 
| 73 | 
            +
             | 
| 74 | 
            +
                for (s = up->subjects; NULL != s; s = s->next) {
         | 
| 75 | 
            +
            	if (0 == strcmp(subject->pattern, s->pattern)) {
         | 
| 76 | 
            +
            	    subject_destroy(subject);
         | 
| 77 | 
            +
            	    return;
         | 
| 78 | 
            +
            	}
         | 
| 79 | 
            +
                }
         | 
| 80 | 
            +
                subject->next = up->subjects;
         | 
| 81 | 
            +
                up->subjects = subject;
         | 
| 82 | 
            +
            }
         | 
| 83 | 
            +
             | 
| 84 | 
            +
            void
         | 
| 85 | 
            +
            upgraded_del_subject(Upgraded up, Subject subject) {
         | 
| 86 | 
            +
                if (NULL == subject) {
         | 
| 87 | 
            +
            	while (NULL != (subject = up->subjects)) {
         | 
| 88 | 
            +
            	    up->subjects = up->subjects->next;
         | 
| 89 | 
            +
            	    subject_destroy(subject);
         | 
| 90 | 
            +
            	}
         | 
| 91 | 
            +
                } else {
         | 
| 92 | 
            +
            	Subject	s;
         | 
| 93 | 
            +
            	Subject	prev = NULL;
         | 
| 94 | 
            +
             | 
| 95 | 
            +
            	for (s = up->subjects; NULL != s; s = s->next) {
         | 
| 96 | 
            +
            	    if (0 == strcmp(subject->pattern, s->pattern)) {
         | 
| 97 | 
            +
            		if (NULL == prev) {
         | 
| 98 | 
            +
            		    up->subjects = s->next;
         | 
| 99 | 
            +
            		} else {
         | 
| 100 | 
            +
            		    prev->next = s->next;
         | 
| 101 | 
            +
            		}
         | 
| 102 | 
            +
            		subject_destroy(s);
         | 
| 103 | 
            +
            		break;
         | 
| 104 | 
            +
            	    }
         | 
| 105 | 
            +
            	    prev = s;
         | 
| 106 | 
            +
            	}
         | 
| 107 | 
            +
                }
         | 
| 108 | 
            +
            }
         | 
| 109 | 
            +
             | 
| 110 | 
            +
            bool
         | 
| 111 | 
            +
            upgraded_match(Upgraded up, const char *subject) {
         | 
| 112 | 
            +
                Subject	s;
         | 
| 113 | 
            +
             | 
| 114 | 
            +
                for (s = up->subjects; NULL != s; s = s->next) {
         | 
| 115 | 
            +
            	if (subject_check(s, subject)) {
         | 
| 116 | 
            +
            	    return true;
         | 
| 117 | 
            +
            	}
         | 
| 118 | 
            +
                }
         | 
| 119 | 
            +
                return false;
         | 
| 120 | 
            +
            }
         | 
| 121 | 
            +
             | 
| 122 | 
            +
            void
         | 
| 123 | 
            +
            upgraded_ref(Upgraded up) {
         | 
| 124 | 
            +
                atomic_fetch_add(&up->ref_cnt, 1);
         | 
| 125 | 
            +
            }
         | 
| 126 | 
            +
             | 
| 127 | 
            +
            static Upgraded
         | 
| 128 | 
            +
            get_upgraded(VALUE self) {
         | 
| 129 | 
            +
                Upgraded	up = NULL;
         | 
| 130 | 
            +
             | 
| 131 | 
            +
                if (the_server.active) {
         | 
| 132 | 
            +
            	pthread_mutex_lock(&the_server.up_lock);
         | 
| 133 | 
            +
            	if (NULL != (up = DATA_PTR(self))) {
         | 
| 134 | 
            +
            	    atomic_fetch_add(&up->ref_cnt, 1);
         | 
| 135 | 
            +
            	}
         | 
| 136 | 
            +
            	pthread_mutex_unlock(&the_server.up_lock);
         | 
| 137 | 
            +
                }
         | 
| 138 | 
            +
                return up;
         | 
| 139 | 
            +
            }
         | 
| 140 | 
            +
             | 
| 18 141 | 
             
            /* Document-method: write
         | 
| 19 142 | 
             
             *
         | 
| 20 143 | 
             
             * call-seq: write(msg)
         | 
| 21 144 | 
             
             *
         | 
| 22 | 
            -
             * Writes a message to the WebSocket or  | 
| 145 | 
            +
             * Writes a message to the WebSocket or SSE connection. Returns true if the
         | 
| 146 | 
            +
             * message has been queued and false otherwise. A closed connection or too
         | 
| 147 | 
            +
             * many pending messages could cause a value of false to be returned.
         | 
| 23 148 | 
             
             */
         | 
| 24 149 | 
             
            static VALUE
         | 
| 25 150 | 
             
            up_write(VALUE self, VALUE msg) {
         | 
| 26 | 
            -
                 | 
| 151 | 
            +
                Upgraded	up = get_upgraded(self);
         | 
| 27 152 | 
             
                Pub		p;
         | 
| 28 153 |  | 
| 29 | 
            -
                if ( | 
| 30 | 
            -
            	 | 
| 154 | 
            +
                if (NULL == up) {
         | 
| 155 | 
            +
            	return Qfalse;
         | 
| 31 156 | 
             
                }
         | 
| 32 | 
            -
                if (0 < the_server.max_push_pending) {
         | 
| 33 | 
            -
            	 | 
| 34 | 
            -
             | 
| 35 | 
            -
            	 | 
| 36 | 
            -
            	    rb_raise(rb_eIOError, "Too many writes pending. Try again later.");
         | 
| 37 | 
            -
            	}
         | 
| 157 | 
            +
                if (0 < the_server.max_push_pending && the_server.max_push_pending <= atomic_load(&up->pending)) {
         | 
| 158 | 
            +
            	atomic_fetch_sub(&up->ref_cnt, 1);
         | 
| 159 | 
            +
            	// Too many pending messages.
         | 
| 160 | 
            +
            	return Qfalse;
         | 
| 38 161 | 
             
                }
         | 
| 39 162 | 
             
                if (T_STRING == rb_type(msg)) {
         | 
| 40 163 | 
             
            	if (RB_ENCODING_IS_ASCII8BIT(msg)) {
         | 
| 41 | 
            -
            	    p = pub_write( | 
| 164 | 
            +
            	    p = pub_write(up, StringValuePtr(msg), RSTRING_LEN(msg), true);
         | 
| 42 165 | 
             
            	} else {
         | 
| 43 | 
            -
            	    p = pub_write( | 
| 166 | 
            +
            	    p = pub_write(up, StringValuePtr(msg), RSTRING_LEN(msg), false);
         | 
| 44 167 | 
             
            	}
         | 
| 45 168 | 
             
                } else {
         | 
| 46 169 | 
             
            	volatile VALUE	rs = rb_funcall(msg, to_s_id, 0);
         | 
| 47 170 |  | 
| 48 | 
            -
            	p = pub_write( | 
| 171 | 
            +
            	p = pub_write(up, StringValuePtr(rs), RSTRING_LEN(rs), false);
         | 
| 49 172 | 
             
                }
         | 
| 50 | 
            -
                 | 
| 173 | 
            +
                atomic_fetch_add(&up->pending, 1);
         | 
| 51 174 | 
             
                queue_push(&the_server.pub_queue, p);
         | 
| 52 175 |  | 
| 53 | 
            -
                return  | 
| 176 | 
            +
                return Qtrue;
         | 
| 54 177 | 
             
            }
         | 
| 55 178 |  | 
| 56 179 | 
             
            /* Document-method: subscribe
         | 
| 57 180 | 
             
             *
         | 
| 58 181 | 
             
             * call-seq: subscribe(subject)
         | 
| 59 182 | 
             
             *
         | 
| 60 | 
            -
             * Subscribes to messages published on the specified subject.  | 
| 61 | 
            -
             *  | 
| 183 | 
            +
             * Subscribes to messages published on the specified subject. The subject is a
         | 
| 184 | 
            +
             * dot delimited string that can include a '*' character as a wild card that
         | 
| 185 | 
            +
             * matches any set of characters. The '>' character matches all remaining
         | 
| 186 | 
            +
             * characters. Examples: people.fred.log, people.*.log, people.fred.>
         | 
| 62 187 | 
             
             */
         | 
| 63 188 | 
             
            static VALUE
         | 
| 64 189 | 
             
            up_subscribe(VALUE self, VALUE subject) {
         | 
| 190 | 
            +
                Upgraded	up;
         | 
| 191 | 
            +
                
         | 
| 192 | 
            +
                rb_check_type(subject, T_STRING);
         | 
| 193 | 
            +
                if (NULL != (up = get_upgraded(self))) {
         | 
| 194 | 
            +
            	atomic_fetch_add(&up->pending, 1);
         | 
| 195 | 
            +
            	queue_push(&the_server.pub_queue, pub_subscribe(up, StringValuePtr(subject), RSTRING_LEN(subject)));
         | 
| 196 | 
            +
                }
         | 
| 197 | 
            +
                return Qnil;
         | 
| 198 | 
            +
            }
         | 
| 65 199 |  | 
| 66 | 
            -
             | 
| 67 | 
            -
             | 
| 68 | 
            -
             | 
| 69 | 
            -
             | 
| 70 | 
            -
             | 
| 71 | 
            -
             | 
| 200 | 
            +
            /* Document-method: unsubscribe
         | 
| 201 | 
            +
             *
         | 
| 202 | 
            +
             * call-seq: unsubscribe(subject=nil)
         | 
| 203 | 
            +
             *
         | 
| 204 | 
            +
             * Unsubscribes to messages on the provided subject. If the subject is nil
         | 
| 205 | 
            +
             * then all subscriptions for the object are removed.
         | 
| 206 | 
            +
             */
         | 
| 207 | 
            +
            static VALUE
         | 
| 208 | 
            +
            up_unsubscribe(int argc, VALUE *argv, VALUE self) {
         | 
| 209 | 
            +
                Upgraded	up;
         | 
| 210 | 
            +
                const char	*subject = NULL;
         | 
| 211 | 
            +
                int		slen = 0;
         | 
| 72 212 |  | 
| 213 | 
            +
                if (0 < argc) {
         | 
| 214 | 
            +
            	rb_check_type(argv[0], T_STRING);
         | 
| 215 | 
            +
            	subject = StringValuePtr(argv[0]);
         | 
| 216 | 
            +
            	slen = (int)RSTRING_LEN(argv[0]);
         | 
| 217 | 
            +
                }
         | 
| 218 | 
            +
                if (NULL != (up = get_upgraded(self))) {
         | 
| 219 | 
            +
            	atomic_fetch_add(&up->pending, 1);
         | 
| 220 | 
            +
            	queue_push(&the_server.pub_queue, pub_unsubscribe(up, subject, slen));
         | 
| 221 | 
            +
                }
         | 
| 73 222 | 
             
                return Qnil;
         | 
| 74 223 | 
             
            }
         | 
| 75 224 |  | 
| @@ -81,13 +230,12 @@ up_subscribe(VALUE self, VALUE subject) { | |
| 81 230 | 
             
             */
         | 
| 82 231 | 
             
            static VALUE
         | 
| 83 232 | 
             
            up_close(VALUE self) {
         | 
| 84 | 
            -
                 | 
| 233 | 
            +
                Upgraded	up = get_upgraded(self);
         | 
| 85 234 |  | 
| 86 | 
            -
                if ( | 
| 87 | 
            -
            	 | 
| 235 | 
            +
                if (NULL != up) {
         | 
| 236 | 
            +
            	atomic_fetch_add(&up->pending, 1);
         | 
| 237 | 
            +
            	queue_push(&the_server.pub_queue, pub_close(up));
         | 
| 88 238 | 
             
                }
         | 
| 89 | 
            -
                queue_push(&the_server.pub_queue, pub_close(cid));
         | 
| 90 | 
            -
             | 
| 91 239 | 
             
                return Qnil;
         | 
| 92 240 | 
             
            }
         | 
| 93 241 |  | 
| @@ -100,49 +248,108 @@ up_close(VALUE self) { | |
| 100 248 | 
             
             */
         | 
| 101 249 | 
             
            static VALUE
         | 
| 102 250 | 
             
            pending(VALUE self) {
         | 
| 103 | 
            -
                 | 
| 251 | 
            +
                Upgraded	up = get_upgraded(self);
         | 
| 252 | 
            +
                int		pending = -1;
         | 
| 253 | 
            +
                
         | 
| 254 | 
            +
                if (NULL != up) {
         | 
| 255 | 
            +
            	pending = atomic_load(&up->pending);
         | 
| 256 | 
            +
            	atomic_fetch_sub(&up->ref_cnt, 1);
         | 
| 257 | 
            +
                }
         | 
| 258 | 
            +
                return INT2NUM(pending);
         | 
| 259 | 
            +
            }
         | 
| 104 260 |  | 
| 105 | 
            -
             | 
| 106 | 
            -
             | 
| 261 | 
            +
            /* Document-method: protocol
         | 
| 262 | 
            +
             *
         | 
| 263 | 
            +
             * call-seq: protocol()
         | 
| 264 | 
            +
             *
         | 
| 265 | 
            +
             * Returns the protocol of the upgraded connection as either :websocket or
         | 
| 266 | 
            +
             * :sse. If not longer connected nil is returned.
         | 
| 267 | 
            +
             */
         | 
| 268 | 
            +
            static VALUE
         | 
| 269 | 
            +
            protocol(VALUE self) {
         | 
| 270 | 
            +
                VALUE	pro = Qnil;
         | 
| 271 | 
            +
             | 
| 272 | 
            +
                if (the_server.active) {
         | 
| 273 | 
            +
            	Upgraded	up;
         | 
| 274 | 
            +
            	
         | 
| 275 | 
            +
            	pthread_mutex_lock(&the_server.up_lock);
         | 
| 276 | 
            +
            	if (NULL != (up = DATA_PTR(self)) && NULL != up->con) {
         | 
| 277 | 
            +
            	    switch (up->con->kind) {
         | 
| 278 | 
            +
            	    case CON_WS:
         | 
| 279 | 
            +
            		pro = websocket_sym;
         | 
| 280 | 
            +
            		break;
         | 
| 281 | 
            +
            	    case CON_SSE:
         | 
| 282 | 
            +
            		pro = sse_sym;
         | 
| 283 | 
            +
            		break;
         | 
| 284 | 
            +
            	    default:
         | 
| 285 | 
            +
            		break;
         | 
| 286 | 
            +
            	    }
         | 
| 287 | 
            +
            	}
         | 
| 288 | 
            +
            	pthread_mutex_unlock(&the_server.up_lock);
         | 
| 107 289 | 
             
                }
         | 
| 108 | 
            -
                return  | 
| 290 | 
            +
                return pro;
         | 
| 109 291 | 
             
            }
         | 
| 110 292 |  | 
| 111 | 
            -
             | 
| 112 | 
            -
             | 
| 293 | 
            +
            Upgraded
         | 
| 294 | 
            +
            upgraded_create(Con c, VALUE obj) {
         | 
| 295 | 
            +
                Upgraded	up = (Upgraded)malloc(sizeof(struct _Upgraded));
         | 
| 296 | 
            +
             | 
| 113 297 | 
             
                if (!the_server.active) {
         | 
| 114 298 | 
             
            	rb_raise(rb_eIOError, "Server shutdown.");
         | 
| 115 299 | 
             
                }
         | 
| 116 | 
            -
                 | 
| 117 | 
            -
             | 
| 118 | 
            -
             | 
| 119 | 
            -
             | 
| 120 | 
            -
            	 | 
| 300 | 
            +
                if (NULL != up) {
         | 
| 301 | 
            +
            	DEBUG_ALLOC(mem_upgraded, up);
         | 
| 302 | 
            +
            	up->con = c;
         | 
| 303 | 
            +
            	up->handler = obj;
         | 
| 304 | 
            +
            	atomic_init(&up->pending, 0);
         | 
| 305 | 
            +
            	atomic_init(&up->ref_cnt, 1); // start with 1 for the Con reference
         | 
| 306 | 
            +
            	up->on_empty = rb_respond_to(obj, rb_intern("on_drained"));
         | 
| 307 | 
            +
            	up->on_close = rb_respond_to(obj, rb_intern("on_close"));
         | 
| 308 | 
            +
            	up->on_shut = rb_respond_to(obj, rb_intern("on_shutdown"));
         | 
| 309 | 
            +
            	up->on_msg = rb_respond_to(obj, rb_intern("on_message"));
         | 
| 310 | 
            +
            	up->wrap = Data_Wrap_Struct(upgraded_class, NULL, NULL, up);
         | 
| 311 | 
            +
            	up->subjects = NULL;
         | 
| 312 | 
            +
            	up->prev = NULL;
         | 
| 313 | 
            +
            	pthread_mutex_lock(&the_server.up_lock);
         | 
| 314 | 
            +
            	if (NULL == the_server.up_list) {
         | 
| 315 | 
            +
            	    up->next = NULL;
         | 
| 316 | 
            +
            	} else {
         | 
| 317 | 
            +
            	    the_server.up_list->prev = up;
         | 
| 318 | 
            +
            	}
         | 
| 319 | 
            +
            	up->next = the_server.up_list;
         | 
| 320 | 
            +
            	the_server.up_list = up;
         | 
| 321 | 
            +
            	c->up = up;
         | 
| 322 | 
            +
            	pthread_mutex_unlock(&the_server.up_lock);
         | 
| 323 | 
            +
             | 
| 324 | 
            +
            	if (rb_respond_to(obj, on_open_id)) {
         | 
| 325 | 
            +
            	    rb_funcall(obj, on_open_id, 1, up->wrap);
         | 
| 326 | 
            +
            	}
         | 
| 121 327 | 
             
                }
         | 
| 122 | 
            -
                 | 
| 123 | 
            -
            		   rb_respond_to(obj, rb_intern("on_drained")),
         | 
| 124 | 
            -
            		   rb_respond_to(obj, rb_intern("on_close")),
         | 
| 125 | 
            -
            		   rb_respond_to(obj, rb_intern("on_shutdown")),
         | 
| 126 | 
            -
            		   rb_respond_to(obj, rb_intern("on_message")));
         | 
| 127 | 
            -
                rb_funcall(obj, rb_intern("to_s"), 0);
         | 
| 328 | 
            +
                return up;
         | 
| 128 329 | 
             
            }
         | 
| 129 330 |  | 
| 331 | 
            +
            // Use the publish from the Agoo module.
         | 
| 332 | 
            +
            extern VALUE	ragoo_publish(VALUE self, VALUE subject, VALUE message);
         | 
| 333 | 
            +
             | 
| 130 334 | 
             
            /* Document-module: Agoo::Upgraded
         | 
| 131 335 | 
             
             *
         | 
| 132 | 
            -
             * Adds methods to a handler of WebSocket and  | 
| 336 | 
            +
             * Adds methods to a handler of WebSocket and SSE connections.
         | 
| 133 337 | 
             
             */
         | 
| 134 338 | 
             
            void
         | 
| 135 339 | 
             
            upgraded_init(VALUE mod) {
         | 
| 136 | 
            -
                 | 
| 340 | 
            +
                upgraded_class = rb_define_class_under(mod, "Upgraded", rb_cObject);
         | 
| 137 341 |  | 
| 138 | 
            -
                rb_define_method( | 
| 139 | 
            -
                rb_define_method( | 
| 140 | 
            -
                rb_define_method( | 
| 141 | 
            -
                rb_define_method( | 
| 342 | 
            +
                rb_define_method(upgraded_class, "write", up_write, 1);
         | 
| 343 | 
            +
                rb_define_method(upgraded_class, "subscribe", up_subscribe, 1);
         | 
| 344 | 
            +
                rb_define_method(upgraded_class, "unsubscribe", up_unsubscribe, -1);
         | 
| 345 | 
            +
                rb_define_method(upgraded_class, "close", up_close, 0);
         | 
| 346 | 
            +
                rb_define_method(upgraded_class, "pending", pending, 0);
         | 
| 347 | 
            +
                rb_define_method(upgraded_class, "protocol", protocol, 0);
         | 
| 348 | 
            +
                rb_define_method(upgraded_class, "publish", ragoo_publish, 2);
         | 
| 142 349 |  | 
| 143 | 
            -
                cid_id = rb_intern("_cid");
         | 
| 144 | 
            -
                sid_id = rb_intern("_sid");
         | 
| 145 350 | 
             
                on_open_id = rb_intern("on_open");
         | 
| 146 351 | 
             
                to_s_id = rb_intern("to_s");
         | 
| 147 | 
            -
             | 
| 352 | 
            +
             | 
| 353 | 
            +
                sse_sym = ID2SYM(rb_intern("sse"));				rb_gc_register_address(&sse_sym);
         | 
| 354 | 
            +
                websocket_sym = ID2SYM(rb_intern("websocket"));		rb_gc_register_address(&websocket_sym);
         | 
| 148 355 | 
             
            }
         |