goshrine_bot 0.1.1 → 0.1.5

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.
@@ -1,143 +0,0 @@
1
- module Faye
2
- class Channel
3
-
4
- include Observable
5
- attr_reader :name
6
-
7
- def initialize(name)
8
- @name = name
9
- end
10
-
11
- def <<(message)
12
- changed(true)
13
- notify_observers(:message, message)
14
- end
15
-
16
- HANDSHAKE = '/meta/handshake'
17
- CONNECT = '/meta/connect'
18
- SUBSCRIBE = '/meta/subscribe'
19
- UNSUBSCRIBE = '/meta/unsubscribe'
20
- DISCONNECT = '/meta/disconnect'
21
-
22
- META = :meta
23
- SERVICE = :service
24
-
25
- class << self
26
- def valid?(name)
27
- Grammar::CHANNEL_NAME =~ name or
28
- Grammar::CHANNEL_PATTERN =~ name
29
- end
30
-
31
- def parse(name)
32
- return nil unless valid?(name)
33
- name.split('/')[1..-1].map { |s| s.to_sym }
34
- end
35
-
36
- def meta?(name)
37
- segments = parse(name)
38
- segments ? (segments.first == META) : nil
39
- end
40
-
41
- def service?(name)
42
- segments = parse(name)
43
- segments ? (segments.first == SERVICE) : nil
44
- end
45
-
46
- def subscribable?(name)
47
- return nil unless valid?(name)
48
- not meta?(name) and not service?(name)
49
- end
50
- end
51
-
52
- class Tree
53
- include Enumerable
54
- attr_accessor :value
55
-
56
- def initialize(value = nil)
57
- @value = value
58
- @children = {}
59
- end
60
-
61
- # Remove channels that have no subscribers
62
- def delete_unobserved_channels
63
- total_observers = 0
64
- if @value
65
- total_observers += @value.count_observers
66
- @value = nil if @value.count_observers == 0
67
- end
68
-
69
- @children.delete_if { |key, subtree|
70
- num_child_observers = subtree.delete_unobserved_channels
71
- total_observers += num_child_observers
72
- num_child_observers == 0
73
- }
74
- total_observers
75
- end
76
-
77
- def each_child
78
- @children.each { |key, subtree| yield(key, subtree) }
79
- end
80
-
81
- def each(prefix = [], &block)
82
- each_child { |path, subtree| subtree.each(prefix + [path], &block) }
83
- yield(prefix, @value) unless @value.nil?
84
- end
85
-
86
- def keys
87
- map { |key, value| '/' + key * '/' }
88
- end
89
-
90
- def [](name)
91
- subtree = traverse(name)
92
- subtree ? subtree.value : nil
93
- end
94
-
95
- def []=(name, value)
96
- subtree = traverse(name, true)
97
- subtree.value = value unless subtree.nil?
98
- end
99
-
100
- def traverse(path, create_if_absent = false)
101
- path = Channel.parse(path) if String === path
102
-
103
- return nil if path.nil?
104
- return self if path.empty?
105
-
106
- subtree = @children[path.first]
107
- return nil if subtree.nil? and not create_if_absent
108
- subtree = @children[path.first] = self.class.new if subtree.nil?
109
-
110
- subtree.traverse(path[1..-1], create_if_absent)
111
- end
112
-
113
- def glob(path = [])
114
- path = Channel.parse(path) if String === path
115
-
116
- return [] if path.nil?
117
- return @value.nil? ? [] : [@value] if path.empty?
118
-
119
- if path == [:*]
120
- return @children.inject([]) do |list, (key, subtree)|
121
- list << subtree.value unless subtree.value.nil?
122
- list
123
- end
124
- end
125
-
126
- if path == [:**]
127
- list = map { |key, value| value }
128
- list.pop unless @value.nil?
129
- return list
130
- end
131
-
132
- list = @children.values_at(path.first, :*).
133
- compact.
134
- map { |t| t.glob(path[1..-1]) }
135
-
136
- list << @children[:**].value if @children[:**]
137
- list.flatten
138
- end
139
- end
140
-
141
- end
142
- end
143
-
@@ -1,283 +0,0 @@
1
- module Faye
2
- class Client
3
- include EventMachine::Deferrable
4
- include Timeouts
5
-
6
- UNCONNECTED = 1
7
- CONNECTING = 2
8
- CONNECTED = 3
9
- DISCONNECTED = 4
10
-
11
- HANDSHAKE = 'handshake'
12
- RETRY = 'retry'
13
- NONE = 'none'
14
-
15
- CONNECTION_TIMEOUT = 60.0
16
-
17
- attr_reader :endpoint, :namespace, :cookie
18
-
19
- def initialize(endpoint = nil, options = {})
20
- @endpoint = endpoint || RackAdapter::DEFAULT_ENDPOINT
21
- @options = options
22
- @timeout = @options[:timeout] || CONNECTION_TIMEOUT
23
- @cookie = @options[:cookie]
24
-
25
- @transport = Transport.get(self)
26
- @state = UNCONNECTED
27
- @namespace = Namespace.new
28
- @outbox = []
29
- @channels = Channel::Tree.new
30
- @current_id = 0
31
-
32
- @advice = {'reconnect' => RETRY, 'interval' => Connection::INTERVAL}
33
- end
34
-
35
- # Request
36
- # MUST include: * channel
37
- # * version
38
- # * supportedConnectionTypes
39
- # MAY include: * minimumVersion
40
- # * ext
41
- # * id
42
- #
43
- # Success Response Failed Response
44
- # MUST include: * channel MUST include: * channel
45
- # * version * successful
46
- # * supportedConnectionTypes * error
47
- # * clientId MAY include: * supportedConnectionTypes
48
- # * successful * advice
49
- # MAY include: * minimumVersion * version
50
- # * advice * minimumVersion
51
- # * ext * ext
52
- # * id * id
53
- # * authSuccessful
54
- def handshake(&block)
55
- return if @advice['reconnect'] == NONE
56
- return if @state != UNCONNECTED
57
-
58
- @state = CONNECTING
59
- @transport.send({
60
- 'channel' => Channel::HANDSHAKE,
61
- 'version' => BAYEUX_VERSION,
62
- 'supportedConnectionTypes' => Transport.supported_connection_types
63
-
64
- }) do |response|
65
- unless response['successful']
66
- EventMachine.add_timer(@advice['interval'] / 1000.0) { handshake(&block) }
67
- return @state = UNCONNECTED
68
- end
69
-
70
- @state = CONNECTED
71
- @client_id = response['clientId']
72
- @transport = Transport.get(self, response['supportedConnectionTypes'])
73
-
74
- block.call if block_given?
75
- end
76
- end
77
-
78
- # Request Response
79
- # MUST include: * channel MUST include: * channel
80
- # * clientId * successful
81
- # * connectionType * clientId
82
- # MAY include: * ext MAY include: * error
83
- # * id * advice
84
- # * ext
85
- # * id
86
- # * timestamp
87
- def connect(&block)
88
-
89
- return if @advice['reconnect'] == NONE or
90
- @state == DISCONNECTED
91
-
92
- if @advice['reconnect'] == HANDSHAKE or @state == UNCONNECTED
93
- begin_reconnect_timeout
94
- return handshake { connect(&block) }
95
- end
96
-
97
- return callback(&block) if @state == CONNECTING
98
- return unless @state == CONNECTED
99
-
100
- set_deferred_status(:succeeded)
101
- set_deferred_status(:deferred)
102
- block.call if block_given?
103
-
104
- return unless @connection_id.nil?
105
-
106
- @connection_id = @namespace.generate
107
- @transport.send({
108
- 'channel' => Channel::CONNECT,
109
- 'clientId' => @client_id,
110
- 'connectionType' => @transport.connection_type,
111
- 'id' => @connection_id
112
-
113
- }, &verify_client_id { |response|
114
- @namespace.release(@connection_id) if @connection_id
115
- @connection_id = nil
116
- remove_timeout(:reconnect)
117
- EventMachine.add_timer(@advice['interval'] / 1000.0) { connect }
118
- })
119
-
120
- begin_reconnect_timeout
121
- end
122
-
123
- # Request Response
124
- # MUST include: * channel MUST include: * channel
125
- # * clientId * successful
126
- # MAY include: * ext * clientId
127
- # * id MAY include: * error
128
- # * ext
129
- # * id
130
- def disconnect
131
- return unless @state == CONNECTED
132
- @state = DISCONNECTED
133
-
134
- @transport.send({
135
- 'channel' => Channel::DISCONNECT,
136
- 'clientId' => @client_id
137
- })
138
-
139
- @channels = Channel::Tree.new
140
- remove_timeout(:reconnect)
141
- end
142
-
143
- # Request Response
144
- # MUST include: * channel MUST include: * channel
145
- # * clientId * successful
146
- # * subscription * clientId
147
- # MAY include: * ext * subscription
148
- # * id MAY include: * error
149
- # * advice
150
- # * ext
151
- # * id
152
- # * timestamp
153
- def subscribe(channels, &block)
154
- connect {
155
- channels = [channels].flatten
156
- validate_channels(channels)
157
-
158
- @transport.send({
159
- 'channel' => Channel::SUBSCRIBE,
160
- 'clientId' => @client_id,
161
- 'subscription' => channels
162
-
163
- }, &verify_client_id { |response|
164
- if response['successful'] and block
165
- channels = [response['subscription']].flatten
166
- channels.each { |channel| @channels[channel] = block }
167
- end
168
- })
169
- }
170
- end
171
-
172
- # Request Response
173
- # MUST include: * channel MUST include: * channel
174
- # * clientId * successful
175
- # * subscription * clientId
176
- # MAY include: * ext * subscription
177
- # * id MAY include: * error
178
- # * advice
179
- # * ext
180
- # * id
181
- # * timestamp
182
- def unsubscribe(channels, &block)
183
- connect {
184
- channels = [channels].flatten
185
- validate_channels(channels)
186
-
187
- @transport.send({
188
- 'channel' => Channel::UNSUBSCRIBE,
189
- 'clientId' => @client_id,
190
- 'subscription' => channels
191
-
192
- }, &verify_client_id { |response|
193
- if response['successful']
194
- channels = [response['subscription']].flatten
195
- channels.each { |channel| @channels[channel] = nil }
196
- end
197
- })
198
- }
199
- end
200
-
201
- # Request Response
202
- # MUST include: * channel MUST include: * channel
203
- # * data * successful
204
- # MAY include: * clientId MAY include: * id
205
- # * id * error
206
- # * ext * ext
207
- def publish(channel, data, id=nil)
208
- connect {
209
- validate_channels([channel])
210
-
211
- enqueue({
212
- 'id' => (id || next_id),
213
- 'channel' => channel,
214
- 'data' => data,
215
- 'clientId' => @client_id
216
- })
217
-
218
- add_timeout(:publish, Connection::MAX_DELAY) { flush! }
219
- }
220
- end
221
-
222
- def handle_error(msg_id, error)
223
- puts "Message #{msg_id} Error #{error}"
224
- end
225
-
226
- def handle_advice(advice)
227
- @advice.update(advice)
228
- @client_id = nil if @advice['reconnect'] == HANDSHAKE
229
- end
230
-
231
- def deliver_messages(messages)
232
- messages.each do |message|
233
- channels = @channels.glob(message['channel'])
234
- channels.each { |callback| callback.call(message['data']) }
235
- end
236
- end
237
-
238
- private
239
-
240
- def begin_reconnect_timeout
241
- add_timeout(:reconnect, @timeout) do
242
- @namespace.release(@connection_id) if @connection_id
243
- @connection_id = nil
244
- @client_id = nil
245
- @state = UNCONNECTED
246
- subscribe(@channels.keys)
247
- end
248
- end
249
-
250
- def enqueue(message)
251
- @outbox << message
252
- end
253
-
254
- def flush!
255
- @transport.send(@outbox)
256
- @outbox = []
257
- end
258
-
259
- def next_id
260
- @current_id += 1
261
- end
262
-
263
- def validate_channels(channels)
264
- channels.each do |channel|
265
- raise "'#{ channel }' is not a valid channel name" unless Channel.valid?(channel)
266
- raise "Clients may not subscribe to channel '#{ channel }'" unless Channel.subscribable?(channel)
267
- end
268
- end
269
-
270
- def verify_client_id(&block)
271
- lambda do |response|
272
- if response['clientId'] != @client_id
273
- false
274
- else
275
- block.call(response)
276
- true
277
- end
278
- end
279
- end
280
-
281
- end
282
- end
283
-
@@ -1,122 +0,0 @@
1
- module Faye
2
- class Connection
3
- include EventMachine::Deferrable
4
- include Observable
5
- include Timeouts
6
-
7
- MAX_DELAY = 0.1
8
- INTERVAL = 0.4
9
- TIMEOUT = 60.0
10
-
11
- attr_reader :id
12
-
13
- def initialize(id, options = {})
14
- @id = id
15
- @options = options
16
- @timeout = @options[:timeout] || TIMEOUT
17
- @channels = Set.new
18
- @inbox = Set.new
19
- @connected = false
20
- @connection_listener = options[:connection_listener]
21
-
22
- # This is for clients that subscribe, but never re-connect to get messages
23
- # (prevents a memory leak)
24
- add_timeout(:deletion, 60 * INTERVAL) do
25
- puts "Deleting orphaned connection: #{@id}"
26
- delete
27
- end
28
-
29
- end
30
-
31
- def update(message, event)
32
- return unless message == :message
33
- @inbox.add(event)
34
- begin_delivery_timeout!
35
- end
36
-
37
- def subscribe(channel)
38
- if @channels.add?(channel)
39
- channel.add_observer(self)
40
- if @options[:subscription_listener]
41
- @options[:subscription_listener].subscribed(self, channel)
42
- end
43
- end
44
- end
45
-
46
- def unsubscribe(channel)
47
- return @channels.each(&method(:unsubscribe)) if channel == :all
48
- return unless @channels.member?(channel)
49
- @channels.delete(channel)
50
- channel.delete_observer(self)
51
- if @options[:subscription_listener]
52
- @options[:subscription_listener].unsubscribed(self, channel)
53
- end
54
- end
55
-
56
- def connect(transport_authentication, &block)
57
- callback(&block)
58
- return if @connected
59
-
60
- @connected = true
61
-
62
- if @connection_listener
63
- @connection_listener.connected(id, transport_authentication)
64
- end
65
-
66
- remove_timeout(:deletion)
67
-
68
- begin_delivery_timeout!
69
- begin_connection_timeout!
70
- end
71
-
72
- def flush!
73
- return unless @connected
74
- release_connection!
75
-
76
- events = @inbox.entries
77
- @inbox = Set.new
78
-
79
- set_deferred_status(:succeeded, events)
80
- set_deferred_status(:deferred)
81
- end
82
-
83
- def disconnect!
84
- unsubscribe(:all)
85
- flush!
86
- end
87
-
88
- private
89
-
90
- def begin_delivery_timeout!
91
- if @delivery_timeout.nil? && @connected && (!@inbox.empty? || @channels.empty?)
92
- add_timeout(:delivery, MAX_DELAY) { flush! }
93
- end
94
- end
95
-
96
- def begin_connection_timeout!
97
- return unless @connection_timeout.nil? and @connected
98
- add_timeout(:connection, @timeout) { flush! }
99
- end
100
-
101
- def delete
102
- unsubscribe(:all)
103
- if @connection_listener
104
- @connection_listener.disconnected(id)
105
- end
106
- changed(true)
107
- notify_observers(:stale_client, self)
108
- end
109
-
110
- def release_connection!
111
- remove_timeout(:connection)
112
- remove_timeout(:delivery)
113
- @connected = false
114
-
115
- add_timeout(:deletion, 10 * INTERVAL) do
116
- delete
117
- end
118
- end
119
-
120
- end
121
- end
122
-
@@ -1,44 +0,0 @@
1
- module Faye
2
- class Error
3
-
4
- def self.parse(string)
5
- return nil unless Grammar::ERROR =~ string
6
- parts = string.split(':')
7
- args = parts[1].split(',')
8
- new(parts[0].to_i, args, parts[2])
9
- end
10
-
11
- def self.method_missing(type, *args)
12
- code = const_get(type.to_s.upcase)
13
- new(code[0], args, code[1]).to_s
14
- end
15
-
16
- attr_reader :code, :args, :message
17
-
18
- def initialize(code, args, message)
19
- @code = code
20
- @args = args
21
- @message = message
22
- end
23
-
24
- def to_s
25
- "#{ @code }:#{ @args * ',' }:#{ @message }"
26
- end
27
-
28
- # http://code.google.com/p/cometd/wiki/BayeuxCodes
29
- VERSION_MISMATCH = [300, 'Version mismatch']
30
- CONNTYPE_MISMATCH = [301, 'Connection types not supported']
31
- EXT_MISMATCH = [302, 'Extension mismatch']
32
- BAD_REQUEST = [400, 'Bad request']
33
- CLIENT_UNKNOWN = [401, 'Unknown client']
34
- PARAMETER_MISSING = [402, 'Missing required parameter']
35
- CHANNEL_FORBIDDEN = [403, 'Forbidden channel']
36
- CHANNEL_UNKNOWN = [404, 'Unknown channel']
37
- CHANNEL_INVALID = [405, 'Invalid channel']
38
- EXT_UNKNOWN = [406, 'Unknown extension']
39
- PUBLISH_FAILED = [407, 'Failed to publish']
40
- SERVER_ERROR = [500, 'Internal server error']
41
-
42
- end
43
- end
44
-
@@ -1,58 +0,0 @@
1
- module Faye
2
- module Grammar
3
-
4
- def self.rule(&block)
5
- source = instance_eval(&block)
6
- %r{^#{string(source)}$}
7
- end
8
-
9
- def self.choice(*list)
10
- '(' + list.map(&method(:string)) * '|' + ')'
11
- end
12
-
13
- def self.repeat(*pattern)
14
- '(' + string(pattern) + ')*'
15
- end
16
-
17
- def self.oneormore(*pattern)
18
- '(' + string(pattern) + ')+'
19
- end
20
-
21
- def self.string(item)
22
- return item.map(&method(:string)) * '' if Array === item
23
- String === item ? item : item.source.gsub(/^\^/, '').gsub(/\$$/, '')
24
- end
25
-
26
- LOWALPHA = rule {[ '[a-z]' ]}
27
- UPALPHA = rule {[ '[A-Z]' ]}
28
- ALPHA = rule {[ choice(LOWALPHA, UPALPHA) ]}
29
- DIGIT = rule {[ '[0-9]' ]}
30
- ALPHANUM = rule {[ choice(ALPHA, DIGIT) ]}
31
- MARK = rule {[ choice(*%w[\\- \\_ \\! \\~ \\( \\) \\$ \\@]) ]}
32
- STRING = rule {[ repeat(choice(ALPHANUM, MARK, ' ', '\\/', '\\*', '\\.')) ]}
33
- TOKEN = rule {[ oneormore(choice(ALPHANUM, MARK)) ]}
34
- INTEGER = rule {[ oneormore(DIGIT) ]}
35
-
36
- CHANNEL_SEGMENT = rule {[ TOKEN ]}
37
- CHANNEL_SEGMENTS = rule {[ CHANNEL_SEGMENT, repeat('\\/', CHANNEL_SEGMENT) ]}
38
- CHANNEL_NAME = rule {[ '\\/', CHANNEL_SEGMENTS ]}
39
-
40
- WILD_CARD = rule {[ '\\*{1,2}' ]}
41
- CHANNEL_PATTERN = rule {[ repeat('\\/', CHANNEL_SEGMENT), '\\/', WILD_CARD ]}
42
-
43
- VERSION_ELEMENT = rule {[ ALPHANUM, repeat(choice(ALPHANUM, '\\-', '\\_')) ]}
44
- VERSION = rule {[ INTEGER, repeat('\\.', VERSION_ELEMENT) ]}
45
-
46
- CLIENT_ID = rule {[ oneormore(ALPHANUM) ]}
47
-
48
- ID = rule {[ oneormore(ALPHANUM) ]}
49
-
50
- ERROR_MESSAGE = rule {[ STRING ]}
51
- ERROR_ARGS = rule {[ STRING, repeat(',', STRING) ]}
52
- ERROR_CODE = rule {[ DIGIT, DIGIT, DIGIT ]}
53
- ERROR = rule {[ choice(string([ERROR_CODE, ':', ERROR_ARGS, ':', ERROR_MESSAGE]),
54
- string([ERROR_CODE, ':', ':', ERROR_MESSAGE])) ]}
55
-
56
- end
57
- end
58
-
@@ -1,20 +0,0 @@
1
- module Faye
2
- class Namespace
3
-
4
- def initialize
5
- @used = {}
6
- end
7
-
8
- def generate
9
- name = Faye.random
10
- name = Faye.random while @used.has_key?(name)
11
- @used[name] = name
12
- end
13
-
14
- def release(name)
15
- @used.delete(name)
16
- end
17
-
18
- end
19
- end
20
-