nobject 1.0.0 → 1.0.2

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