1313
1414module Async
1515 module Bus
16+ # @namespace
1617 module Protocol
18+ # Create a local Unix domain socket endpoint.
19+ # @parameter path [String] The path to the socket file.
20+ # @returns [IO::Endpoint::Unix] The Unix endpoint.
1721 def self . local_endpoint ( path = "bus.ipc" )
1822 ::IO ::Endpoint . unix ( path )
1923 end
2024
25+ # Represents a connection between client and server for message passing.
2126 class Connection
27+ # Create a client-side connection.
28+ # @parameter peer [IO] The peer connection.
29+ # @parameter options [Hash] Additional options for the connection.
30+ # @returns [Connection] A new client connection.
2231 def self . client ( peer , **options )
2332 self . new ( peer , 1 , **options )
2433 end
2534
35+ # Create a server-side connection.
36+ # @parameter peer [IO] The peer connection.
37+ # @parameter options [Hash] Additional options for the connection.
38+ # @returns [Connection] A new server connection.
2639 def self . server ( peer , **options )
2740 self . new ( peer , 2 , **options )
2841 end
2942
43+ # Initialize a new connection.
44+ # @parameter peer [IO] The peer connection.
45+ # @parameter id [Integer] The initial transaction ID.
46+ # @parameter wrapper [Class] The wrapper class for serialization.
47+ # @parameter timeout [Float] The timeout for transactions.
3048 def initialize ( peer , id , wrapper : Wrapper , timeout : nil )
3149 @peer = peer
3250 @id = id
@@ -47,16 +65,20 @@ def initialize(peer, id, wrapper: Wrapper, timeout: nil)
4765 # @attribute [Float] The timeout for transactions.
4866 attr_accessor :timeout
4967
68+ # Flush the packer buffer.
5069 def flush
5170 @packer . flush
5271 end
5372
73+ # Write a message to the connection.
74+ # @parameter message [Object] The message to write.
5475 def write ( message )
5576 # $stderr.puts "Writing: #{message.inspect}"
5677 @packer . write ( message )
5778 @packer . flush
5879 end
5980
81+ # Close the connection and clean up resources.
6082 def close
6183 @transactions . each do |id , transaction |
6284 transaction . close
@@ -65,23 +87,34 @@ def close
6587 @peer . close
6688 end
6789
90+ # Return a string representation of the connection.
91+ # @returns [String] A string describing the connection.
6892 def inspect
6993 "#<#{ self . class } #{ @objects . size } objects>"
7094 end
7195
96+ # @attribute [Hash] The bound objects.
7297 attr :objects
98+
99+ # @attribute [ObjectSpace::WeakMap] The proxy cache.
73100 attr :proxies
74101
102+ # @attribute [MessagePack::Unpacker] The message unpacker.
75103 attr :unpacker
104+
105+ # @attribute [MessagePack::Packer] The message packer.
76106 attr :packer
77107
108+ # Get the next transaction ID.
109+ # @returns [Integer] The next transaction ID.
78110 def next_id
79111 id = @id
80112 @id += 2
81113
82114 return id
83115 end
84116
117+ # @attribute [Hash] Active transactions.
85118 attr :transactions
86119
87120 Explicit = Struct . new ( :object ) do
@@ -96,8 +129,47 @@ def temporary?
96129 end
97130 end
98131
99- # Bind a local object to a name, such that it could be accessed remotely.
132+ # Explicitly bind an object to a name, such that it could be accessed remotely.
133+ #
134+ # This is the same as {bind} but due to the semantics of the `[]=` operator, it does not return a proxy instance.
135+ #
136+ # Explicitly bound objects are not garbage collected until the connection is closed.
137+ #
138+ # @parameter name [String] The name to bind the object to.
139+ # @parameter object [Object] The object to bind to the given name.
140+ def []=( name , object )
141+ @objects [ name ] = Explicit . new ( object )
142+ end
143+
144+ # Generate a proxy for a remotely bound object.
145+ #
146+ # **This will not return objects bound locally, only proxies for remotely bound objects.**
147+ #
148+ # @parameter name [String] The name of the bound object.
149+ # @returns [Object | Proxy] The object or proxy instance for the bound object.
150+ def []( name )
151+ unless proxy = @proxies [ name ]
152+ proxy = Proxy . new ( self , name )
153+ @proxies [ name ] = proxy
154+
155+ ::ObjectSpace . define_finalizer ( proxy , finalize ( name ) )
156+ end
157+
158+ return proxy
159+ end
160+
161+ # Explicitly bind an object to a name, such that it could be accessed remotely.
162+ #
163+ # This method is identical to {[]=} but also returns a {Proxy} instance for the bound object which can be passed by reference.
100164 #
165+ # Explicitly bound objects are not garbage collected until the connection is closed.
166+ #
167+ # @example Binding an object to a name and accessing it remotely.
168+ # array_proxy = connection.bind(:items, [1, 2, 3])
169+ # connection[:remote].register(array_proxy)
170+ #
171+ # @parameter name [String] The name to bind the object to.
172+ # @parameter object [Object] The object to bind to the given name.
101173 # @returns [Proxy] A proxy instance for the bound object.
102174 def bind ( name , object )
103175 # Bind the object into the local object store (explicitly bound, not temporary):
@@ -107,8 +179,13 @@ def bind(name, object)
107179 return self [ name ]
108180 end
109181
110- # Generate a proxy name for an object and bind it.
182+ # Implicitly bind an object with a temporary name, such that it could be accessed remotely.
183+ #
184+ # Implicitly bound objects are garbage collected when the remote end no longer references them.
111185 #
186+ # This method is simliar to {bind} but is designed to be used to generate temporary proxies for objects that are not explicitly bound.
187+ #
188+ # @parameter object [Object] The object to bind to a temporary name.
112189 # @returns [Proxy] A proxy instance for the bound object.
113190 def proxy ( object )
114191 name = "<#{ object . class } @#{ next_id . to_s ( 16 ) } >" . freeze
@@ -120,9 +197,13 @@ def proxy(object)
120197 return self [ name ]
121198 end
122199
123- # Generate a proxy name for an object and bind it, returning just the name.
124- # Used for serialization when you need the name string, not a Proxy instance.
200+ # Implicitly bind an object with a temporary name, such that it could be accessed remotely.
201+ #
202+ # Implicitly bound objects are garbage collected when the remote end no longer references them.
203+ #
204+ # This method is similar to {proxy} but is designed to be used to generate temporary names for objects that are not explicitly bound during serialization.
125205 #
206+ # @parameter object [Object] The object to bind to a temporary name.
126207 # @returns [String] The name of the bound object.
127208 def proxy_name ( object )
128209 name = "<#{ object . class } @#{ next_id . to_s ( 16 ) } >" . freeze
@@ -134,38 +215,28 @@ def proxy_name(object)
134215 return name
135216 end
136217
137- def object ( name )
138- @objects [ name ] &.object
139- end
140-
141218 private def finalize ( name )
142219 proc do
143220 @finalized . push ( name ) rescue nil
144221 end
145222 end
146223
147- def []=( name , object )
148- @objects [ name ] = Explicit . new ( object )
149- end
150-
151- def []( name )
152- unless proxy = @proxies [ name ]
153- proxy = Proxy . new ( self , name )
154- @proxies [ name ] = proxy
155-
156- ::ObjectSpace . define_finalizer ( proxy , finalize ( name ) )
157- end
158-
159- return proxy
160- end
161-
224+ # Create a new transaction.
225+ # @parameter id [Integer] The transaction ID.
226+ # @returns [Transaction] A new transaction.
162227 def transaction! ( id = self . next_id )
163228 transaction = Transaction . new ( self , id , timeout : @timeout )
164229 @transactions [ id ] = transaction
165230
166231 return transaction
167232 end
168233
234+ # Invoke a remote procedure.
235+ # @parameter name [Symbol] The name of the remote object.
236+ # @parameter arguments [Array] The arguments to pass.
237+ # @parameter options [Hash] The keyword arguments to pass.
238+ # @yields {|*args| ...} Optional block for yielding operations.
239+ # @returns [Object] The result of the invocation.
169240 def invoke ( name , arguments , options = { } , &block )
170241 transaction = self . transaction!
171242
@@ -174,10 +245,14 @@ def invoke(name, arguments, options = {}, &block)
174245 transaction &.close
175246 end
176247
248+ # Send a release message for a named object.
249+ # @parameter name [Symbol] The name of the object to release.
177250 def send_release ( name )
178251 self . write ( Release . new ( name ) )
179252 end
180253
254+ # Run the connection message loop.
255+ # @parameter parent [Async::Task] The parent task to run under.
181256 def run ( parent : Task . current )
182257 finalizer_task = parent . async do
183258 while name = @finalized . pop
0 commit comments