socketeer 0.0.17

Sign up to get free protection for your applications and to get access to all the features.
@@ -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: []