cod 0.2.0 → 0.3.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.
@@ -1,72 +1,25 @@
1
1
  require 'weakref'
2
2
 
3
3
  module Cod
4
- # Channels inside a context know each other and can be looked up by their
5
- # identifier. Context is also responsible for holding connections and for
6
- # doing background work. For most purposes, you will only need one context;
7
- # by using methods on the Cod module directly, you implicitly hold a context
8
- # and call methods there.
4
+ # Context will allow to produce channels retaining some state. Until now,
5
+ # this hasn't been neccessary.
9
6
  #
10
7
  class Context
11
-
12
- def self.install_at_fork(ref)
13
- at_fork do |old_handler|
14
- old_handler.call rescue nil
15
-
16
- begin
17
- ref.reset
18
- rescue WeakRef::RefError
19
- # IGNORED EXCEPTION
20
- end
21
- end
22
- end
23
-
24
- def initialize
25
- @connections = {}
26
-
27
- self.class.install_at_fork(WeakRef.new(self))
28
- end
29
-
30
8
  def pipe(name=nil)
31
9
  Cod::Channel::Pipe.new(name)
32
10
  end
33
11
 
34
12
  def beanstalk(url, name=nil)
35
13
  Cod::Channel::Beanstalk.new(
36
- connection(:beanstalk, url), name)
37
- end
38
-
39
- def reset
40
- @connections = {}
41
- end
42
-
43
- private
44
- # Returns a connection to a system identified by type and url. Currently,
45
- # connections are never released or closed. This is only a minor drawback
46
- # since there will be few of them. (considering we only use this for
47
- # beanstalk)
48
- #
49
- def connection(type, url)
50
- key = connection_key(type, url)
51
-
52
- connection = @connections[key]
53
- return connection if connection
54
-
55
- produce_connection(type, url).tap { |connection|
56
- @connections.store(key, connection) }
14
+ Connection::Beanstalk.new(url), name)
57
15
  end
58
16
 
59
- def connection_key(type, url)
60
- [type, url]
17
+ def tcp(destination)
18
+ Cod::Channel::TCPConnection.new(destination)
61
19
  end
62
-
63
- def produce_connection(type, url)
64
- case type
65
- when :beanstalk
66
- return Connection::Beanstalk.new(url)
67
- end
68
-
69
- fail "Tried to produce a connection of unknown type #{type.inspect}."
20
+
21
+ def tcpserver(bind_to)
22
+ Cod::Channel::TCPServer.new(bind_to)
70
23
  end
71
24
  end
72
25
  end
@@ -0,0 +1,3 @@
1
+ require 'cod/objectio/reader'
2
+ require 'cod/objectio/writer'
3
+ require 'cod/objectio/serializer'
File without changes
@@ -0,0 +1,129 @@
1
+ module Cod::ObjectIO
2
+ # Reads objects from one or more IO streams.
3
+ #
4
+ class Reader
5
+ attr_reader :waiting_messages
6
+ attr_reader :registered_ios
7
+
8
+ # Initializes an object reader that reads from one or several IO objects.
9
+ # You can either pass the io object in the constructor (io) or you can
10
+ # provide the instance with a block that is called each time a read is
11
+ # attempted. The block should return an array of IO objects to also read
12
+ # from.
13
+ #
14
+ # Example:
15
+ # reader = Reader.new { make_connection }
16
+ #
17
+ def initialize(serializer, io=nil, &block)
18
+ @serializer = serializer
19
+ @waiting_messages = []
20
+ @establish_block = block
21
+ @registered_ios = Set.new
22
+
23
+ register io if io
24
+ end
25
+
26
+ # Called before each attempt to read from the wire. This should return
27
+ # the IO objects that need to be considered when reading.
28
+ #
29
+ def establish
30
+ sockets = @establish_block && @establish_block.call(@io) ||
31
+ nil
32
+
33
+ [sockets].flatten
34
+ end
35
+
36
+ def register(ios)
37
+ return unless ios
38
+ ios.each do |io|
39
+ registered_ios << io
40
+ end
41
+ end
42
+
43
+ def unregister(ios)
44
+ ios.each do |io|
45
+ registered_ios.delete(io)
46
+ end
47
+ end
48
+
49
+ def get(opts={})
50
+ return waiting_messages.shift if queued?
51
+
52
+ start_time = Time.now
53
+ loop do
54
+ # p [:looping, opts]
55
+ read_from_wire opts
56
+
57
+ # Early return in case we have a message waiting
58
+ return waiting_messages.shift if queued?
59
+
60
+ if opts[:timeout] && (Time.now-start_time) > opts[:timeout]
61
+ raise Cod::Channel::TimeoutError,
62
+ "No messages waiting in pipe."
63
+ end
64
+ end
65
+
66
+ fail "NOTREACHED"
67
+ end
68
+
69
+ def waiting?
70
+ read_from_wire
71
+ queued?
72
+ end
73
+
74
+ def queued?
75
+ ! waiting_messages.empty?
76
+ end
77
+
78
+ def close
79
+ @registered_ios.each { |io| io.close }
80
+ end
81
+
82
+ private
83
+
84
+ # Checks if data is waiting and processes messages.
85
+ #
86
+ def read_from_wire(opts={})
87
+ # Establish new connections and register them
88
+ register establish
89
+
90
+ # Wait for sockets to have data
91
+ ready_read, _, _ = IO.select(Array(registered_ios), nil, nil, 0.1)
92
+
93
+ # Read all ready sockets
94
+ process_nonblock(ready_read) if ready_read
95
+ end
96
+
97
+ # Reads all data waiting in each io in the ios array.
98
+ #
99
+ def process_nonblock(ios)
100
+ ios.each do |io|
101
+ process_nonblock_single(io)
102
+ end
103
+ end
104
+
105
+ # Reads all data waiting in a single io.
106
+ #
107
+ def process_nonblock_single(io)
108
+ buffer = io.read_nonblock(1024*1024*1024)
109
+
110
+ sio = StringIO.new(buffer)
111
+ while not sio.eof?
112
+ waiting_messages << deserialize(io, sio)
113
+ end
114
+ rescue EOFError
115
+ # Connection has failed/ been disconnected.
116
+ # We will need to reconnect this. If possible.
117
+ registered_ios.delete(io)
118
+ raise
119
+ end
120
+
121
+ # Deserializes a message (in message format, string) into the object that
122
+ # was transmitted. Overwrite this message if you want to control the
123
+ # message format.
124
+ #
125
+ def deserialize(*args)
126
+ @serializer.deserialize(*args)
127
+ end
128
+ end
129
+ end
@@ -0,0 +1,26 @@
1
+ module Cod::ObjectIO
2
+ class Serializer
3
+ attr_reader :transformer
4
+
5
+ def initialize(transformer=nil)
6
+ @transformer = transformer
7
+ end
8
+
9
+ # NOTE: source_io is provided to be able to provide back-channels through
10
+ # that same, not to read from it. Reading from this IO object will block
11
+ # you.
12
+ #
13
+ def deserialize(source_io, buffer_io)
14
+ if @transformer
15
+ Marshal.load(buffer_io, proc {
16
+ |obj| transformer.transform(source_io, obj) })
17
+ else
18
+ Marshal.load(buffer_io)
19
+ end
20
+ end
21
+
22
+ def serialize(message)
23
+ Marshal.dump(message)
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,32 @@
1
+ module Cod::ObjectIO
2
+ # Writes objects to an IO stream.
3
+ #
4
+ class Writer
5
+ def initialize(serializer, io=nil, &block)
6
+ @serializer = serializer
7
+ @io = io
8
+ @reconnect_block = block
9
+ end
10
+
11
+ def put(message)
12
+ attempt_reconnect
13
+
14
+ @io.write(serialize(message)) if @io
15
+ end
16
+
17
+ def close
18
+ @io.close
19
+ end
20
+
21
+ private
22
+ def attempt_reconnect
23
+ if @reconnect_block
24
+ @io = @reconnect_block[]
25
+ end
26
+ end
27
+
28
+ def serialize(message)
29
+ @serializer.serialize(message)
30
+ end
31
+ end
32
+ end
metadata CHANGED
@@ -1,111 +1,116 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: cod
3
- version: !ruby/object:Gem::Version
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.3.0
4
5
  prerelease:
5
- version: 0.2.0
6
6
  platform: ruby
7
- authors:
7
+ authors:
8
8
  - Kaspar Schiess
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
-
13
- date: 2011-04-27 00:00:00 +02:00
12
+ date: 2011-07-20 00:00:00.000000000 +02:00
14
13
  default_executable:
15
- dependencies:
16
- - !ruby/object:Gem::Dependency
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
17
16
  name: rspec
18
- prerelease: false
19
- requirement: &id001 !ruby/object:Gem::Requirement
17
+ requirement: &2154614480 !ruby/object:Gem::Requirement
20
18
  none: false
21
- requirements:
22
- - - ">="
23
- - !ruby/object:Gem::Version
24
- version: "0"
19
+ requirements:
20
+ - - ! '>='
21
+ - !ruby/object:Gem::Version
22
+ version: '0'
25
23
  type: :development
26
- version_requirements: *id001
27
- - !ruby/object:Gem::Dependency
28
- name: flexmock
29
24
  prerelease: false
30
- requirement: &id002 !ruby/object:Gem::Requirement
25
+ version_requirements: *2154614480
26
+ - !ruby/object:Gem::Dependency
27
+ name: flexmock
28
+ requirement: &2154476000 !ruby/object:Gem::Requirement
31
29
  none: false
32
- requirements:
33
- - - ">="
34
- - !ruby/object:Gem::Version
35
- version: "0"
30
+ requirements:
31
+ - - ! '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
36
34
  type: :development
37
- version_requirements: *id002
38
- - !ruby/object:Gem::Dependency
39
- name: sdoc
40
35
  prerelease: false
41
- requirement: &id003 !ruby/object:Gem::Requirement
36
+ version_requirements: *2154476000
37
+ - !ruby/object:Gem::Dependency
38
+ name: sdoc
39
+ requirement: &2154475480 !ruby/object:Gem::Requirement
42
40
  none: false
43
- requirements:
44
- - - ">="
45
- - !ruby/object:Gem::Version
46
- version: "0"
41
+ requirements:
42
+ - - ! '>='
43
+ - !ruby/object:Gem::Version
44
+ version: '0'
47
45
  type: :development
48
- version_requirements: *id003
46
+ prerelease: false
47
+ version_requirements: *2154475480
49
48
  description:
50
49
  email: kaspar.schiess@absurd.li
51
50
  executables: []
52
-
53
51
  extensions: []
54
-
55
- extra_rdoc_files:
52
+ extra_rdoc_files:
56
53
  - README
57
- files:
54
+ files:
58
55
  - Gemfile
59
56
  - HISTORY.txt
60
57
  - LICENSE
61
58
  - Rakefile
62
59
  - README
63
60
  - lib/at_fork.rb
61
+ - lib/cod/channel/abstract.rb
64
62
  - lib/cod/channel/base.rb
65
63
  - lib/cod/channel/beanstalk.rb
66
64
  - lib/cod/channel/pipe.rb
65
+ - lib/cod/channel/tcp.rb
66
+ - lib/cod/channel/tcpconnection.rb
67
+ - lib/cod/channel/tcpserver.rb
67
68
  - lib/cod/channel.rb
68
69
  - lib/cod/client.rb
69
70
  - lib/cod/connection/beanstalk.rb
70
71
  - lib/cod/context.rb
71
72
  - lib/cod/directory/subscription.rb
72
73
  - lib/cod/directory.rb
74
+ - lib/cod/object_io.rb
75
+ - lib/cod/objectio/connection.rb
76
+ - lib/cod/objectio/reader.rb
77
+ - lib/cod/objectio/serializer.rb
78
+ - lib/cod/objectio/writer.rb
73
79
  - lib/cod/service.rb
74
80
  - lib/cod/topic.rb
75
81
  - lib/cod.rb
82
+ - examples/example_scaffold.rb
76
83
  - examples/master_child.rb
77
84
  - examples/ping.rb
78
85
  - examples/pong.rb
79
86
  - examples/service.rb
80
87
  - examples/service_directory.rb
88
+ - examples/tcp.rb
81
89
  has_rdoc: true
82
90
  homepage: http://kschiess.github.com/cod
83
91
  licenses: []
84
-
85
92
  post_install_message:
86
- rdoc_options:
93
+ rdoc_options:
87
94
  - --main
88
95
  - README
89
- require_paths:
96
+ require_paths:
90
97
  - lib
91
- required_ruby_version: !ruby/object:Gem::Requirement
98
+ required_ruby_version: !ruby/object:Gem::Requirement
92
99
  none: false
93
- requirements:
94
- - - ">="
95
- - !ruby/object:Gem::Version
96
- version: "0"
97
- required_rubygems_version: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ! '>='
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ required_rubygems_version: !ruby/object:Gem::Requirement
98
105
  none: false
99
- requirements:
100
- - - ">="
101
- - !ruby/object:Gem::Version
102
- version: "0"
106
+ requirements:
107
+ - - ! '>='
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
103
110
  requirements: []
104
-
105
111
  rubyforge_project:
106
- rubygems_version: 1.5.2
112
+ rubygems_version: 1.6.2
107
113
  signing_key:
108
114
  specification_version: 3
109
115
  summary: Really simple IPC.
110
116
  test_files: []
111
-