socketeer 0.0.17

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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 52a6b2979493d0ddcd9da248609b3b4a6a90c125
4
+ data.tar.gz: 2f017474f0e6369fd09ffaf0eab93da420dcca9e
5
+ SHA512:
6
+ metadata.gz: 8be06b965b173dd97a4b0d3e23b7766019ec6579606e458a54045808fe5657fb737af6926fdcedee1e1e0f9a8c4b922ddcdeac558a3e62c9d1d03e05de4db77a
7
+ data.tar.gz: 924b6b92eb44b5b614d6f41ea7ba7a7f49fd7b994ed57a60e3dcbad502010ec8758056612be77b249a10593dfa17c45c1d5d39327f6b394aec7b394cf106edbb
@@ -0,0 +1 @@
1
+ require_relative 'socketeer/socketeer'
@@ -0,0 +1,61 @@
1
+ require_relative 'selector_mix'
2
+ require_relative 'messenger'
3
+
4
+ class Handler
5
+
6
+ # PUSHES : raw received data
7
+ # PULLS : raw to send data
8
+
9
+ include Selectable
10
+ include Messenger
11
+
12
+ attr_reader :conn_id
13
+
14
+ def initialize socket, conn_id
15
+ @socket = socket
16
+ @conn_id = conn_id
17
+ register_monitor @socket, :r do |m|
18
+ read
19
+ end
20
+ end
21
+
22
+ def cycle
23
+ cycle_data_in
24
+ cycle_data_out
25
+ end
26
+
27
+ def cycle_data_in
28
+ read
29
+ end
30
+
31
+ def cycle_data_out
32
+ 1000.times do
33
+ m = pop_message
34
+ write m
35
+ return if m.nil?
36
+ end
37
+ end
38
+
39
+ def socket
40
+ @socket
41
+ end
42
+
43
+ def read
44
+ begin
45
+ # raises ex if no data to read
46
+ data = ''
47
+ loop do
48
+ data << @socket.read_nonblock(4096)
49
+ end
50
+ rescue
51
+ # no more datas
52
+ end
53
+ push_message data unless data.empty?
54
+ end
55
+
56
+ def write data
57
+ return if data.nil?
58
+ @socket.write data rescue false
59
+ end
60
+
61
+ end
@@ -0,0 +1,27 @@
1
+ require_relative 'messenger'
2
+
3
+ class MessageCollator
4
+
5
+ # PUSHES : full set of overall data (String)
6
+ # PULLS : pieces of overall data (String)
7
+
8
+ include Messenger
9
+
10
+ def initialize deliminator
11
+ @deliminator = deliminator
12
+ @buffer = ''
13
+ end
14
+
15
+ def cycle
16
+ handle_data_in pop_message
17
+ end
18
+
19
+ def handle_data_in data
20
+ return if data.nil?
21
+ @buffer += data
22
+ while @buffer.include? @deliminator
23
+ message_data, _, @buffer = @buffer.partition @deliminator
24
+ push_message message_data
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,19 @@
1
+ require_relative 'messenger'
2
+
3
+ class MessageHandler
4
+
5
+ # PUSHES :
6
+ # PULLS :
7
+
8
+ include Messenger
9
+
10
+ def initialize &handler
11
+ @handler = handler
12
+ end
13
+
14
+ def cycle
15
+ in_message = pop_message
16
+ out_message = @handler.call in_message unless in_message.nil?
17
+ push_message out_message
18
+ end
19
+ end
@@ -0,0 +1,29 @@
1
+ require_relative 'messenger'
2
+
3
+ class MessageTransformer
4
+
5
+ # PUSHES : transformed data (objs)
6
+ # PULLS : raw data (String)
7
+
8
+ include Messenger
9
+
10
+ def initialize &transformer
11
+ @transformer = transformer
12
+ end
13
+
14
+ def cycle
15
+ handle_data_in pop_message
16
+ end
17
+
18
+ def handle_data_in data
19
+ return if data.nil?
20
+ push_message transform data
21
+ end
22
+
23
+ private
24
+
25
+ def transform data
26
+ @transformer.call data
27
+ end
28
+
29
+ end
@@ -0,0 +1,28 @@
1
+ require 'thread'
2
+
3
+ module Messenger
4
+
5
+ attr_reader :in_queue, :out_queue
6
+
7
+ def bind_queues in_queue=nil, out_queue=nil
8
+ @in_queue ||= in_queue
9
+ @out_queue ||= out_queue
10
+ end
11
+
12
+ private
13
+
14
+ def push_message message
15
+ return if message.nil?
16
+ out_queue << message unless out_queue.nil?
17
+ end
18
+
19
+ def pop_message
20
+ # noblock
21
+ begin
22
+ return in_queue.deq true unless in_queue.nil?
23
+ rescue ThreadError
24
+ end
25
+ nil
26
+ end
27
+
28
+ end
@@ -0,0 +1,46 @@
1
+ require_relative 'messenger'
2
+
3
+ class Passthrough
4
+
5
+ include Messenger
6
+
7
+ def initialize attr, messenger
8
+ @attr = attr
9
+ @messenger = messenger
10
+ @in_flight = []
11
+ bind_queues Queue.new, Queue.new
12
+ end
13
+
14
+ def cycle
15
+ cycle_in_queue
16
+ cycle_out_queue
17
+ cycle_messenger
18
+ end
19
+
20
+ def cycle_in_queue
21
+ begin
22
+ in_message = in_queue.deq true
23
+ if in_message
24
+ @in_flight << in_message
25
+ @messenger.in_queue << in_message[@attr]
26
+ end
27
+ rescue ThreadError
28
+ end
29
+ end
30
+
31
+ def cycle_out_queue
32
+ begin
33
+ out_message = @messenger.out_queue.deq true
34
+ if out_message
35
+ original_message = @in_flight.shift
36
+ original_message[@attr] = out_message
37
+ out_queue << original_message
38
+ end
39
+ rescue ThreadError
40
+ end
41
+ end
42
+
43
+ def cycle_messenger
44
+ @messenger.cycle if @messenger.respond_to? 'cycle'
45
+ end
46
+ end
@@ -0,0 +1,19 @@
1
+ require_relative 'messenger'
2
+
3
+ class Pipeline
4
+ def initialize *messengers
5
+ @messengers = messengers
6
+ end
7
+ def cycle
8
+ @messengers.each_cons(2) do |a, b|
9
+ a.cycle if a.respond_to? 'cycle'
10
+ begin
11
+ 1000.times do
12
+ m = a.out_queue.deq true
13
+ b.in_queue << m
14
+ end
15
+ rescue ThreadError
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,22 @@
1
+
2
+ module Selectable
3
+
4
+ def cycle_selector
5
+ @selector.select(0.1) do |monitor|
6
+ monitor.callback.call monitor
7
+ end
8
+ end
9
+
10
+ private
11
+
12
+ def register_monitor obj, mode, &callback
13
+ monitor = selector.register obj, mode
14
+ monitor.class.class_eval { attr_accessor :callback }
15
+ monitor.callback = callback
16
+ monitor
17
+ end
18
+
19
+ def selector
20
+ @selector ||= NIO::Selector.new
21
+ end
22
+ end
@@ -0,0 +1,96 @@
1
+ require 'nio'
2
+ require 'socket'
3
+ require_relative 'selector_mix'
4
+ require_relative 'messenger'
5
+
6
+ class Server
7
+
8
+ # PUSHES : {:conn_id, :data}
9
+ # PULLS : {:conn_id, :data}
10
+
11
+ include Selectable
12
+ include Messenger
13
+
14
+ attr_accessor :host, :port
15
+
16
+ def initialize host='localhost', port=3123, handler=nil
17
+
18
+ @Handler = handler
19
+ @host = host
20
+ @port = port
21
+
22
+ @connections = {}
23
+ puts "BINDING: #{host}:#{port}"
24
+ @tcp_server = TCPServer.new host, port
25
+ register_monitor @tcp_server, :r do |monitor|
26
+ handle_socket_connect @tcp_server.accept
27
+ end
28
+ end
29
+
30
+ def cycle
31
+ cycle_selector
32
+ cycle_connection_queues
33
+ cycle_inbound
34
+ cycle_handlers
35
+ end
36
+
37
+ private
38
+
39
+ def cycle_handlers
40
+ @connections.each {|conn_id, handler| handler.cycle}
41
+ end
42
+
43
+ def cycle_inbound
44
+ 1000.times do
45
+ msg = pop_message
46
+ return if msg.nil?
47
+ handle_new_message msg
48
+ end
49
+ end
50
+
51
+ def cycle_connection_queues
52
+ @connections.each do |conn_id, handler|
53
+ # dont get backed up here
54
+ begin
55
+ 1000.times do
56
+ handle_new_data conn_id, handler.out_queue.deq(true)
57
+ end
58
+ rescue ThreadError
59
+ end
60
+ end
61
+ end
62
+
63
+ def handle_socket_connect socket
64
+ handler = create_handler socket
65
+ return handler.conn_id
66
+ end
67
+
68
+ def create_handler socket
69
+ conn_id = get_conn_id socket
70
+ return unless @connections[conn_id].nil?
71
+ handler = @Handler.new socket, conn_id
72
+ # TODO: not ref Queue directly
73
+ handler.bind_queues Queue.new, Queue.new
74
+ @connections[conn_id] = handler
75
+ return handler
76
+ end
77
+
78
+ def get_conn_id socket
79
+ socket.object_id
80
+ end
81
+
82
+ def handle_new_data conn_id, data
83
+ return if data.nil?
84
+ push_message :conn_id => conn_id, :data => data
85
+ end
86
+
87
+ def handle_new_message message
88
+ return if message.nil?
89
+ unless message[:conn_id].nil?
90
+ @connections[message[:conn_id]].in_queue << message[:data]
91
+ else
92
+ @connections.each { |_, c| c.in_queue << message[:data] }
93
+ end
94
+ end
95
+
96
+ end
@@ -0,0 +1,71 @@
1
+ require 'msgpack'
2
+ require_relative 'server'
3
+ require_relative 'handler'
4
+ require_relative 'message_transformer'
5
+ require_relative 'message_collator'
6
+ require_relative 'message_handler'
7
+ require_relative 'passthrough'
8
+ require_relative 'pipeline'
9
+
10
+ class PrintingQueue < Queue
11
+ def << *args
12
+ r = super *args
13
+ return r
14
+ end
15
+
16
+ def deq *args
17
+ r = super
18
+ return r
19
+ end
20
+ end
21
+
22
+ class IQueue < Queue
23
+ end
24
+
25
+ module Socketeer
26
+
27
+ def bind host, port, &callback
28
+ # will use the passed callback if provided, else calls handle_message
29
+ callback ||= proc { |m| handle_message m }
30
+ @message_handler = MessageHandler.new &callback
31
+ @server = Server.new host, port, Handler
32
+ @collator = MessageCollator.new "\n\n"
33
+ @in_message_transformer = MessageTransformer.new {|d| MessagePack.unpack d }
34
+ @out_message_transformer = MessageTransformer.new { |d|
35
+ MessagePack.pack(d) + "\n\n"
36
+ }
37
+ @server.bind_queues IQueue.new, IQueue.new
38
+ @collator.bind_queues IQueue.new, IQueue.new
39
+ @in_message_transformer.bind_queues IQueue.new, IQueue.new
40
+ @out_message_transformer.bind_queues IQueue.new, IQueue.new
41
+ @message_handler.bind_queues IQueue.new, IQueue.new
42
+ @pipeline = Pipeline.new(@server,
43
+ Passthrough.new(:data, @collator),
44
+ Passthrough.new(:data, @in_message_transformer),
45
+ @message_handler,
46
+ Passthrough.new(:data, @out_message_transformer),
47
+ @server)
48
+ [host, port]
49
+ end
50
+
51
+ def cycle
52
+ @pipeline.cycle
53
+ end
54
+
55
+ private
56
+
57
+ def handle_message message
58
+ end
59
+
60
+ def send_message conn_id, message
61
+ @message_handler.out_queue << { conn_id: conn_id,
62
+ data: message }
63
+ end
64
+
65
+ def register_socket socket
66
+ @server.instance_eval do
67
+ handle_socket_connect socket
68
+ end
69
+ end
70
+
71
+ end
metadata ADDED
@@ -0,0 +1,81 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: socketeer
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.17
5
+ platform: ruby
6
+ authors:
7
+ - Robby Ranshous
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-03-10 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: msgpack
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: nio4r
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ description: simple socket server for doing message passing
42
+ email: rranshous@gmail.com
43
+ executables: []
44
+ extensions: []
45
+ extra_rdoc_files: []
46
+ files:
47
+ - lib/socketeer.rb
48
+ - lib/socketeer/handler.rb
49
+ - lib/socketeer/message_collator.rb
50
+ - lib/socketeer/message_handler.rb
51
+ - lib/socketeer/message_transformer.rb
52
+ - lib/socketeer/messenger.rb
53
+ - lib/socketeer/passthrough.rb
54
+ - lib/socketeer/pipeline.rb
55
+ - lib/socketeer/selector_mix.rb
56
+ - lib/socketeer/server.rb
57
+ - lib/socketeer/socketeer.rb
58
+ homepage: http://oneinchmile.com
59
+ licenses: []
60
+ metadata: {}
61
+ post_install_message:
62
+ rdoc_options: []
63
+ require_paths:
64
+ - lib
65
+ required_ruby_version: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - ">="
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ required_rubygems_version: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ version: '0'
75
+ requirements: []
76
+ rubyforge_project:
77
+ rubygems_version: 2.4.8
78
+ signing_key:
79
+ specification_version: 4
80
+ summary: simple socket server
81
+ test_files: []