fyrehose 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitkeep ADDED
File without changes
data/fyrehose.gemspec ADDED
@@ -0,0 +1,20 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = "fyrehose"
6
+ s.version = "0.0.1"
7
+ s.date = Date.today.to_s
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Paul Asmuth"]
10
+ s.email = ["paul@paulasmuth.com"]
11
+ s.homepage = "http://github.com/paulasmuth/fyrehose"
12
+ s.summary = %q{ruby client for the fyrehose pub/sub protocol}
13
+ s.description = %q{ruby client for the fyrehose pub/sub protocol}
14
+
15
+ s.licenses = ["MIT"]
16
+
17
+ s.files = `git ls-files`.split("\n") - [".gitignore", ".rspec", ".travis.yml"]
18
+ s.test_files = `git ls-files -- spec/*`.split("\n")
19
+ s.require_paths = ["lib"]
20
+ end
@@ -0,0 +1,107 @@
1
+ module Fyrehose
2
+ class InputStream
3
+
4
+ attr_accessor :state, :buf, :pos
5
+
6
+ def initialize
7
+ @state = -7
8
+ @pos = 0
9
+ @buf = ""
10
+ end
11
+
12
+ def <<(chunk)
13
+ buf << chunk
14
+ end
15
+
16
+ def each
17
+ trim = 0
18
+
19
+ while pos < buf.size do
20
+ case state
21
+
22
+ when -7
23
+ self.state += 1
24
+ type = nil
25
+ txid = ""
26
+ channel = ""
27
+ len_or_flags = ""
28
+ body = ""
29
+ next
30
+
31
+ when -6
32
+ raise ProtocolError if buf[pos] != "#"
33
+ self.state += 1
34
+
35
+ when -3, -5
36
+ if buf[pos] == " "
37
+ self.state += 1
38
+ else
39
+ txid << buf[pos] if state == -5
40
+ channel << buf[pos] if state == -3
41
+ end
42
+
43
+ when -4
44
+ if buf[pos] == "$"
45
+ type = :ack
46
+ self.state = -1
47
+ elsif buf[pos] == "@"
48
+ self.state += 1
49
+ else
50
+ raise ProtocolError
51
+ end
52
+
53
+ when -2
54
+ self.state += 1
55
+ if buf[pos] == "*"
56
+ type = :data
57
+ elsif buf[pos] == "+"
58
+ type = :flags
59
+ else
60
+ raise ProtocolError
61
+ end
62
+
63
+ when -1
64
+ if buf[pos] == " " || buf[pos] == "\n"
65
+ len_or_flags = len_or_flags.to_i
66
+ if type == :data
67
+ self.state = len_or_flags
68
+ else
69
+ self.state += 1
70
+ next
71
+ end
72
+ else
73
+ len_or_flags << buf[pos]
74
+ end
75
+
76
+ when 0
77
+ yield({
78
+ :type => type,
79
+ :txid => txid,
80
+ :channel => channel,
81
+ :flags => len_or_flags,
82
+ :body => body
83
+ })
84
+ trim = pos + 1
85
+ self.state = -7
86
+
87
+ else
88
+ self.state -= 1
89
+ body << buf[pos]
90
+
91
+ end
92
+
93
+ self.pos += 1
94
+ end
95
+
96
+ if trim > 0
97
+ self.pos -= trim
98
+ self.buf = self.buf[trim..-1]
99
+ end
100
+
101
+ rescue Fyrehose::ProtocolError => e
102
+ raise Fyrehose::ProtocolError.new(self.buf, self.pos)
103
+ end
104
+
105
+ end
106
+
107
+ end
@@ -0,0 +1,19 @@
1
+ module Fyrehose
2
+ class ProtocolError < StandardError
3
+
4
+ INFO_SIZE = 30
5
+
6
+ def initialize(buf=nil, pos=nil)
7
+ return unless buf
8
+ offset = [0, pos - (INFO_SIZE / 2)].max
9
+ @info = "\n => "
10
+ @info << buf[offset..offset + INFO_SIZE].gsub("\n", " ")
11
+ @info << "\n#{" " * (pos - offset + 7)}^\n"
12
+ end
13
+
14
+ def to_s
15
+ "invalid token#{@info}"
16
+ end
17
+
18
+ end
19
+ end
@@ -0,0 +1,59 @@
1
+ require "eventmachine"
2
+
3
+ class Fyrehose::Reactor < EventMachine::Connection
4
+
5
+ def self.run(host, port, opts = {}, &block)
6
+ unless block
7
+ raise "missing proc{ |channel,data| } for #run"
8
+ end
9
+
10
+ EventMachine.run do
11
+ reactor = EventMachine.connect(host, port, Fyrehose::Reactor)
12
+ reactor.instance_eval(&block)
13
+ end
14
+ end
15
+
16
+ def post_init
17
+ @input_stream = Fyrehose::InputStream.new
18
+ @callbacks = []
19
+ end
20
+
21
+ def deliver(channel, data)
22
+ send_data("##{next_txid} @#{channel} *#{data.size} #{data}\n")
23
+ end
24
+
25
+ def set_flags(channel, flags)
26
+ send_data("##{next_txid} @#{channel} +#{flags}\n")
27
+ end
28
+
29
+ def subscribe(channel)
30
+ set_flags(channel, 1)
31
+ end
32
+
33
+ def unsubscribe(channel)
34
+ set_flags(channel, 0)
35
+ end
36
+
37
+ def on_message(&block)
38
+ @callbacks << block
39
+ end
40
+
41
+ def receive_data(chunk)
42
+ @input_stream << chunk
43
+
44
+ @input_stream.each do |msg|
45
+ next unless msg[:type] == :data
46
+
47
+ @callbacks.each do |block|
48
+ block.call(msg[:channel], msg[:body])
49
+ end
50
+ end
51
+ end
52
+
53
+ private
54
+
55
+ def next_txid
56
+ rand(8**32).to_s(36)
57
+ end
58
+
59
+ end
data/lib/fyrehose.rb ADDED
@@ -0,0 +1,2 @@
1
+ require "fyrehose/input_stream"
2
+ require "fyrehose/protocol_error"
metadata ADDED
@@ -0,0 +1,52 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fyrehose
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Paul Asmuth
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-02-03 00:00:00.000000000 Z
13
+ dependencies: []
14
+ description: ruby client for the fyrehose pub/sub protocol
15
+ email:
16
+ - paul@paulasmuth.com
17
+ executables: []
18
+ extensions: []
19
+ extra_rdoc_files: []
20
+ files:
21
+ - .gitkeep
22
+ - fyrehose.gemspec
23
+ - lib/fyrehose.rb
24
+ - lib/fyrehose/input_stream.rb
25
+ - lib/fyrehose/protocol_error.rb
26
+ - lib/fyrehose/reactor.rb
27
+ homepage: http://github.com/paulasmuth/fyrehose
28
+ licenses:
29
+ - MIT
30
+ post_install_message:
31
+ rdoc_options: []
32
+ require_paths:
33
+ - lib
34
+ required_ruby_version: !ruby/object:Gem::Requirement
35
+ none: false
36
+ requirements:
37
+ - - ! '>='
38
+ - !ruby/object:Gem::Version
39
+ version: '0'
40
+ required_rubygems_version: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ requirements: []
47
+ rubyforge_project:
48
+ rubygems_version: 1.8.24
49
+ signing_key:
50
+ specification_version: 3
51
+ summary: ruby client for the fyrehose pub/sub protocol
52
+ test_files: []