nobject 1.0.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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 8c44de9099814f0327fda7a884decbc6d497f43c071cc284da9ead26b3f2af1a
4
+ data.tar.gz: e1ecc6b707af2c069e8e7a09e2c47063a6d1d2c73f4a6735d541f8fbb4a0abaf
5
+ SHA512:
6
+ metadata.gz: 6770a322292eee28e9bbc9a3cccb0715443beeaba48abeed033c7108ae741a6d8b809eab6511a4f55a133fa9d697d11b322073c034c4efea26bc84c5b0832c82
7
+ data.tar.gz: 0dada952eaef1de493b835fddff04b89ea5c0401ba989a45dadcb2ba0092d9730ae02cdabf679a5678ea39b49182e3730dfcb6ccaaba1e3d37eab8dad573de12
data/lib/nobject.rb ADDED
@@ -0,0 +1,35 @@
1
+ require 'socket'
2
+
3
+ # this class wraps a local object, listens for method invocations over the
4
+ # network, and sends the method invocations onwards to the local object.
5
+ class Nobject
6
+ def initialize(socket)
7
+ @socket = socket
8
+ obj_size = @socket.recv(8).unpack('Q>').first
9
+ @obj = Marshal.load(@socket.recv(obj_size))
10
+ end
11
+
12
+ def serve!
13
+ Thread.new do
14
+ loop do
15
+ msg_size = @socket.recv(8).unpack('Q>').first
16
+ msg = Marshal.load(@socket.recv(msg_size))
17
+
18
+ result = @obj.send(msg[:method], *msg[:args]) #local_method, *msg[:args])
19
+ network_return([
20
+ :ok,
21
+ result
22
+ ])
23
+ end
24
+ end
25
+ end
26
+
27
+ def network_return(data)
28
+ data_bytes = Marshal.dump(data)
29
+
30
+ @socket.send([data_bytes.length].pack('Q>'), 0)
31
+ @socket.send(data_bytes, 0)
32
+ end
33
+ end
34
+
35
+ class Nobject::NoMethodError < NameError; end
@@ -0,0 +1,42 @@
1
+ require 'socket'
2
+ require_relative './nobject'
3
+
4
+ ##
5
+ # this class listens for incoming requests to store an object over the network,
6
+ # accepts connections and then hands those sockets off to server object storage
7
+ # and invocation.
8
+ class NobjectServer
9
+ def initialize(port)
10
+ @server = TCPServer.new(port)
11
+ @keep_running = true
12
+ @nobjects = []
13
+ end
14
+
15
+ def alive?
16
+ @keep_running
17
+ end
18
+
19
+ def start!
20
+ loop do
21
+ break unless @keep_running
22
+
23
+ begin
24
+ incoming_socket = @server.accept_nonblock
25
+ Nobject.new(incoming_socket).serve!
26
+ rescue IO::EAGAINWaitReadable => e
27
+ # no connection pending
28
+ begin
29
+ IO.select([@server])
30
+ retry
31
+ rescue Interrupt, IRB::Abort
32
+ @keep_running = false
33
+ @server&.close
34
+ end
35
+ end
36
+ end
37
+ end
38
+
39
+ def stop!
40
+ @keep_running = false
41
+ end
42
+ end
@@ -0,0 +1,47 @@
1
+ require 'socket'
2
+
3
+ # this is the class that accepts instantiated objects in the main program, and
4
+ # then pushes them to a remote server
5
+ class ProxyNobject
6
+ # host: the hostname of the server to push obj to
7
+ # port: the port number of the server to push obj to
8
+ # obj: the obj to store over the network
9
+ def initialize(host, port, obj)
10
+ @socket = TCPSocket.new(host, port)
11
+ obj_bytes = Marshal.dump(obj)
12
+
13
+ @socket.send([obj_bytes.length].pack('Q>'), 0)
14
+ @socket.send(obj_bytes, 0)
15
+ end
16
+
17
+ def method_missing(method, *args, **kwargs, &block)
18
+ msg = { method: method, args: args }
19
+ msg_bytes = Marshal.dump(msg)
20
+
21
+ @socket.send([msg_bytes.length].pack('Q>'), 0)
22
+ @socket.send(msg_bytes, 0)
23
+
24
+ return_size = @socket.recv(8).unpack('Q>').first
25
+ return_data = Marshal.load(@socket.recv(return_size))
26
+
27
+ case return_data.first
28
+ when :ok then return_data.last
29
+ when :raise then raise return_data.last
30
+ else
31
+ raise ProxyNobject::UnknownReturnDataType.new("unknown data type '#{return_data.first}' within ProxyNobject (ProxyNobject::UnknownReturnDataType)")
32
+ end
33
+ end
34
+
35
+ #####################################
36
+ # method overridden from Object class
37
+ #####################################
38
+ def !~(other); method_missing(:is_a?, other); end
39
+ def <=>(other); method_missing(:<=>, other); end
40
+ def ===(other); method_missing(:<=>, other); end
41
+ def is_a?(klass); method_missing(:is_a?, klass); end
42
+ def inspect; method_missing(:inspect); end
43
+ def object_id; method_missing(:object_id); end
44
+ end
45
+
46
+ class ProxyNobject::UnknownReturnDataType < RuntimeError; end
47
+ class ProxyNobject::InvalidMethod < RuntimeError; end
metadata ADDED
@@ -0,0 +1,42 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: nobject
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Jeff Lunt
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 2025-03-31 00:00:00.000000000 Z
11
+ dependencies: []
12
+ description: network-hosted objects that you can call methods on as if they were local
13
+ email: jefflunt@gmail.com
14
+ executables: []
15
+ extensions: []
16
+ extra_rdoc_files: []
17
+ files:
18
+ - lib/nobject.rb
19
+ - lib/nobject_server.rb
20
+ - lib/proxy_nobject.rb
21
+ homepage: https://github.com/jefflunt/nobject
22
+ licenses:
23
+ - MIT
24
+ metadata: {}
25
+ rdoc_options: []
26
+ require_paths:
27
+ - lib
28
+ required_ruby_version: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ required_rubygems_version: !ruby/object:Gem::Requirement
34
+ requirements:
35
+ - - ">="
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ requirements: []
39
+ rubygems_version: 3.6.2
40
+ specification_version: 4
41
+ summary: network-hosted objects that you can call methods on as if they were local
42
+ test_files: []