gloox 0.1 → 0.3

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: 80dc33a83d1cefb944faedb5ce6226c9cdae8c6ddf29d65d90ad0c758f2940bb
4
- data.tar.gz: d931ba3575cb52360374b0c3ed6ce65164a00eafb01f5f967ac7a43a69460638
3
+ metadata.gz: eccb784208387659ae3be5e58844eb75e4e140bf9baeb9779a55e99d1f7a24b4
4
+ data.tar.gz: a5efd4428b5b4817a625358ec2762230c670e21a8c70b6d4f569dce452e306e8
5
5
  SHA512:
6
- metadata.gz: f26d5ff881ce062b70bf478ef7e056fae8c1e989216d1dbd34ea14935df655bc70e63c614790e07604952fb65d5399bcc67502d3f761d333e6b8da1dc6990e0f
7
- data.tar.gz: 31d045c3fb13018903580ff249fc1b83d8b90101eb4465da0d606817f449e5bc3e038a278ddccc0d81da9ba61dd335b092539c799fc1d3bcd25dfa19aade5209
6
+ metadata.gz: c2a1c23e5d171d8ecd457f0e4073b689f1601fddb49f7d3b07e3346dc41f9d7a4f7ec496e8a7c74c4aa9c87164ab34c5aafa3ceb92f7e34dd599612f279b5080
7
+ data.tar.gz: adc38b3f34f3db15d92f0c75192e7e340d9a97ca334a0b08dab002087903c542c7f43e9821125fcaf1edd4f2c069148802e77a678ed5b1d1a33695a4cb36ce05
data/Gemfile CHANGED
@@ -16,10 +16,20 @@ group :prof do
16
16
  gem 'memory_profiler'
17
17
  end
18
18
 
19
- gem "toq", path: '../toq'
20
- gem "slotz", path: '../slotz'
21
- gem "tiq", path: '../tiq'
22
- gem "raktr", path: '../raktr'
23
- gem 'msgpack'
19
+ if File.exist? '../toq'
20
+ gem "toq", path: '../toq'
21
+ end
22
+
23
+ if File.exist? '../slotz'
24
+ gem "slotz", path: '../slotz'
25
+ end
26
+
27
+ if File.exist? '../tiq'
28
+ gem "tiq", path: '../tiq'
29
+ end
30
+
31
+ if File.exist? '../raktr'
32
+ gem "raktr", path: '../raktr'
33
+ end
24
34
 
25
35
  gemspec
data/README.md CHANGED
@@ -1,78 +1,122 @@
1
1
  # GlooX (pronounced _glue-X_)
2
2
 
3
- Bringing [Qadron](https://github.com/qadron) together, as a very special glue.
3
+ **An effort to make distributed computing a joy!**
4
4
 
5
- ## Agents
5
+ **Do you really need more, or could you do away with less?**
6
6
 
7
- `GlooX::Agent` offers _Agent_ representations, _server-side_ presences if you must,
8
- of armed `Tiq::Nodes`.
7
+ **Lean and mean never fails.**
8
+
9
+ **Introducing GlooX, your new "cloud" taming solution, under Mozilla Public License v2.**
10
+
11
+ _Bringing [Qadron](https://github.com/qadron) together, as a very special glue._
12
+
13
+ ## Table of Contents
14
+
15
+ - [GlooX::Node](#nodes) `<` [Tiq::Node](https://github.com/qadron/tiq)
16
+ - [Add-ons](#add-ons)
17
+ - [Groups](#groups)
18
+ - [Provisioning](#provisioning)
19
+ - [Security](#security)
20
+
21
+ ## Nodes
22
+
23
+ `GlooX::Node` offers _Node_ representations, _server-side_ presences if you must,
24
+ of armed `Tiq::Node`s.
9
25
 
10
26
  They allow for spawning/loading of Processes on remote Nodes, with auto load-balancing
11
27
  across their Grid.
12
28
 
29
+ `demo.rb:`
13
30
  ```ruby
14
31
  require 'gloox'
15
32
 
16
- # Start off with two Agents, in a Grid of their own
17
- agent = GlooX::Agent.new( url: 'localhost:9997' ).start
18
- agent2 = GlooX::Agent.new( url: 'localhost:9999', peer: 'localhost:9997' ).start
33
+ # Setup a Grid of 2, the children will load-balance and connect to the most available node.
34
+ node = GlooX::Node.new( url: '0.0.0.0:9997' )
35
+ node.start
36
+
37
+ node2 = GlooX::Node.new( url: '0.0.0.0:9999', peer: '0.0.0.0:9997' )
38
+ node2.start
19
39
 
20
- # Connect over the network for RPC.
21
- c = Tiq::Client.new( agent2.url )
40
+ # Switchover to network communication over RPC.
41
+ c = GlooX::Client.new( url: node2.url )
22
42
 
23
- p c.spawn(
43
+ c.spawn(
24
44
  'Child',
25
- "#{File.dirname(__FILE__)}/test/child.rb",
26
- { e: 27 } # Global options set for the spawned Child.
45
+ "#{File.dirname(__FILE__)}/child.rb",
46
+ { url: '0.0.0.0:8888', parent_url: '0.0.0.0:9999', daemonize: true }
27
47
  )
28
48
 
29
- p c.utilization
30
- # => 0.7281599728827168
49
+ # Setup the client-side child communication over RPC.
50
+ child_client = GlooX::Client.new( url: '0.0.0.0:8888' )
31
51
 
32
- p "--- #{c.preferred}"
33
- #=> localhost:9997
52
+ # Call the child-implemented method over RPC.
53
+ p child_client.all_well?
54
+ # => :yes!
34
55
  ```
35
56
 
57
+ `child.rb:`
36
58
  ```ruby
59
+ require 'gloox'
60
+
37
61
  p $options
38
- class Child
39
- Slotz::Reservation.provision( self,
40
- disk: 1 * 1_000_000_000, # bytes
41
- memory: 20 * 1_000_000_000 # bytes
42
- )
62
+ # => {:url=>"localhost:8888", :parent_url=>"localhost:9999", :ppid=>846068, :tmpdir=>"/tmp", :execute=>true}
63
+
64
+ class Child < GlooX::Node
65
+ Slotz::Reservation.provision(
66
+ self,
67
+ disk: 1 * 1_000_000_000, # bytes
68
+ memory: 1 * 1_000_000_000 # bytes
69
+ )
70
+
71
+ def all_well?
72
+ :yes!
73
+ end
43
74
  end
75
+
76
+ # Time to execute, sniff was taken care of on prior file inclusion.
77
+ return unless $execute
78
+
79
+ # Start the child-node server, not included in the Grid, only given its own bind URL.
80
+ c = Child.new( url: $options[:url] )
81
+ c.start
82
+
83
+ # Setup communication to the parent.
84
+ parent = GlooX::Client.new( url: $options[:parent_url] )
85
+
86
+ p parent.alive?
87
+ # => true
44
88
  ```
45
89
 
46
90
  ### Add-ons
47
91
 
48
92
  For the _Add-on_ feature see [Tiq](https://github.com/qadron/tiq?tab=readme-ov-file#add-ons).
49
93
 
50
- ## Groups
94
+ ### Groups/Channels
51
95
 
52
- You can group and/or assing duty/purpose to your _Agents_ by creating channels/shared structures across them.
96
+ You can group and/or assign duty/purpose to your _Nodes_ by creating channels/shared structures across them.
53
97
 
54
- There is one such example below, where two Agents share a group named `my_agents`, in addition to the group `data`,
55
- used for internal purposes.
98
+ There is one such example below, where two Nodes share a group named `my_nodes`, in addition to the group `channel`,
99
+ used for initial/internal purposes.
56
100
 
57
101
  ```ruby
58
102
  require 'gloox'
59
103
 
60
- n1 = GlooX::Agent.new( url: "localhost:9999" ).start
61
- n2 = GlooX::Agent.new( url: "localhost:9998", peer: 'localhost:9999' ).start
104
+ n1 = GlooX::Node.new( url: "0.0.0.0:9999" ).start
105
+ n2 = GlooX::Node.new( url: "0.0.0.0:9998", peer: '0.0.0.0:9999' ).start
62
106
 
63
107
  # Add as many groups/channels/shared-data structures as you want.
64
- n1.create_group_handler 'my_agents'
108
+ n1.create_channel 'my_nodes'
65
109
  sleep 1
66
110
 
67
- n2.my_agents.on_set :a1 do |k, v|
111
+ n2.my_nodes.on_set :a1 do |k, v|
68
112
  p "#{k} => #{v}"
69
113
  # => "a1 => 99"
70
114
  end
71
115
 
72
- n1.my_agents.set :a1, 99
116
+ n1.my_nodes.set :a1, 99
73
117
  sleep 1
74
118
 
75
- p n2.my_agents.get :a1
119
+ p n2.my_nodes.get :a1
76
120
  # => 99
77
121
  ```
78
122
 
@@ -99,9 +143,17 @@ end
99
143
  All communications are TLS encrypted by default, using [Raktr](https://github.com/qadron/raktr) to facilitate network
100
144
  communications for RPC, with RPC being offered by [Toq](https://github.com/qadron/toq).
101
145
 
102
- 4 environment variables will have you sleeping safe and sound:
146
+ 7 environment variables will have you sleeping safe and sound:
147
+
148
+ * Certificate Authority (`RAKTR_TLS_CA`)
149
+ * Server
150
+ * Certificate (`RAKTR_TLS_SERVER_CERTIFICATE`)
151
+ * Private Key (`RAKTR_TLS_SERVER_PRIVATE_KEY`)
152
+ * Public Key (`RAKTR_TLS_SERVER_PUBLIC_KEY`)
153
+ * Client
154
+ * Certificate (`RAKTR_TLS_CLIENT_CERTIFICATE`)
155
+ * Private Key (`RAKTR_TLS_CLIENT_PRIVATE_KEY`)
156
+ * Public Key (`RAKTR_TLS_CLIENT_PUBLIC_KEY`)
103
157
 
104
- * Certificate Authority (RAKTR_TLS_CA)
105
- * Private Key (RAKTR_TLS_PRIVATE_KEY)
106
- * Public Key (RAKTR_TLS_PUBLIC_KEY)
107
- * Certificate (RAKTR_TLS_CERTIFICATE)
158
+ Helper:
159
+ https://raw.githubusercontent.com/qadron/raktr/refs/heads/master/spec/support/fixtures/pems/generate-tls-certs.sh
data/gloox.gemspec CHANGED
@@ -8,7 +8,7 @@ Gem::Specification.new do |s|
8
8
  s.date = Time.now.strftime( '%Y-%m-%d' )
9
9
  s.summary = ''
10
10
 
11
- s.homepage = 'https://github.com/qadron/cuboid'
11
+ s.homepage = 'https://github.com/qadron/gloox'
12
12
  s.email = 'tasos.laskos@gmail.com'
13
13
  s.authors = [ 'Tasos Laskos' ]
14
14
  s.licenses = ['MPL v2']
@@ -27,9 +27,9 @@ Gem::Specification.new do |s|
27
27
 
28
28
  s.add_dependency 'awesome_print', '1.9.2'
29
29
  s.add_dependency 'bundler'
30
+ s.add_dependency 'msgpack'
30
31
  s.add_dependency 'slotz'
31
32
  s.add_dependency 'tiq'
32
- s.add_dependency 'toq'
33
33
 
34
34
  s.description = <<DESCRIPTION
35
35
  DESCRIPTION
@@ -0,0 +1,12 @@
1
+ require 'tiq'
2
+
3
+ module GlooX
4
+ class Client < Tiq::Client
5
+ attr_reader :url
6
+
7
+ def initialize( options = {} )
8
+ super( options[:url], options )
9
+ end
10
+
11
+ end
12
+ end
@@ -2,8 +2,8 @@ require 'slotz'
2
2
  require 'tiq'
3
3
 
4
4
  module GlooX
5
- class Agent < Tiq::Node
6
- PREFERENCE_STRATEGIES = Set.new([:horizontal, :vertical, :direct])
5
+ class Node < Tiq::Node
6
+ PREFERENCE_STRATEGIES = Set.new([nil, :horizontal, :vertical, :direct])
7
7
 
8
8
  def initialize(*)
9
9
  super
@@ -11,15 +11,15 @@ class Agent < Tiq::Node
11
11
  @loader = Slotz::Loader.new
12
12
  end
13
13
 
14
- def spawn( *args )
14
+ def spawn( *args, &block )
15
15
  probable_strategy = args.shift
16
16
  strategy = probable_strategy.to_s.to_sym
17
17
 
18
18
  if PREFERENCE_STRATEGIES.include? strategy
19
- spawn2( strategy, *args )
19
+ spawn2( strategy, *args, &block )
20
20
  else
21
21
  args.unshift probable_strategy
22
- spawn2( nil, *args )
22
+ spawn2( nil, *args, &block )
23
23
  end
24
24
 
25
25
  nil
@@ -81,10 +81,16 @@ class Agent < Tiq::Node
81
81
 
82
82
  private
83
83
 
84
- def spawn2( strategy = nil, *args )
84
+
85
+ def spawn2( strategy = nil, *args, &block )
85
86
  if !grid_member?
86
- @loader.load( *args )
87
- return
87
+ pid = @loader.load( *args )
88
+
89
+ if block_given?
90
+ block.call pid
91
+ return
92
+ end
93
+ return pid
88
94
  end
89
95
 
90
96
  preferred strategy do |preferred_url|
@@ -93,14 +99,17 @@ class Agent < Tiq::Node
93
99
  end
94
100
 
95
101
  if preferred_url == @url
96
- @loader.load( *args )
97
- next
102
+ pid = @loader.load( *args )
103
+ block.call pid if block_given?
104
+ return pid
98
105
  end
99
106
 
100
- connect_to_peer( preferred_url ).spawn( :direct, *args ) {}
107
+ connect_to_peer( preferred_url ).spawn( :direct, *args, &block )
101
108
  end
102
109
 
103
110
  nil
111
+ rescue => e
112
+ ap e
104
113
  end
105
114
  end
106
115
  end
@@ -0,0 +1,28 @@
1
+ module Gloox
2
+ module Utilities
3
+
4
+ def self.available_port_mutex
5
+ @available_port_mutex ||= Mutex.new
6
+ end
7
+ available_port_mutex
8
+
9
+ def available_port( range = nil )
10
+ available_port_mutex.synchronize do
11
+ loop do
12
+ port = self.random_port( range )
13
+ return port if port_available?( port )
14
+ end
15
+ end
16
+ end
17
+
18
+ def random_port( range = nil )
19
+ range ||= [1025, 65535]
20
+ first, last = range
21
+ range = (first..last).to_a
22
+
23
+ range[ rand( range.last - range.first ) ]
24
+ end
25
+
26
+ end
27
+ end
28
+
data/lib/gloox/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module GlooX
2
- VERSION = '0.1'
2
+ VERSION = '0.3'
3
3
  end
data/lib/gloox.rb CHANGED
@@ -1,4 +1,6 @@
1
- require_relative 'gloox/agent'
1
+ module GlooX
2
+ require_relative 'gloox/utilities'
3
+ require_relative 'gloox/client'
4
+ require_relative 'gloox/node'
2
5
 
3
- module Gloox
4
6
  end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe 'GlooX Groups' do
6
+ let(:node1) { GlooX::Node.new(url: 'localhost:9999').start }
7
+ let(:node2) { GlooX::Node.new(url: 'localhost:9998', peer: 'localhost:9999').start }
8
+
9
+ before do
10
+ node1.create_channel('my_nodes')
11
+ sleep 1
12
+ end
13
+
14
+ after do
15
+ node1.stop
16
+ node2.stop
17
+ sleep 2
18
+ end
19
+
20
+ it 'shares data between nodes in a group' do
21
+ node2.my_nodes.on_set(:a1) { |k, v| @result = "#{k} => #{v}" }
22
+ node1.my_nodes.set(:a1, 99)
23
+ sleep 1
24
+ expect(@result).to eq('a1 => 99')
25
+ end
26
+ end
@@ -0,0 +1,75 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe GlooX::Node do
6
+ let(:node_port) { 9999 }
7
+ let(:node) { described_class.new(url: "0.0.0.0:#{node_port}" ) }
8
+ let(:spawn_options) do
9
+ [
10
+ 'MyNode',
11
+ "#{File.dirname(__FILE__)}/../support/fixtures/child_node.rb",
12
+ { url: '0.0.0.0:8888' }
13
+ ]
14
+ end
15
+
16
+ before :each do
17
+ node.start
18
+ end
19
+ after :each do
20
+ node.shutdown
21
+ sleep 2
22
+ end
23
+
24
+ describe '#start' do
25
+ it 'starts the node successfully' do
26
+ expect { node }.not_to raise_error
27
+ end
28
+ end
29
+
30
+ describe '#spawn' do
31
+ it 'spawns a process with default strategy' do
32
+ pending
33
+ expect { node.spawn( *spawn_options ) }.not_to raise_error
34
+ end
35
+
36
+ it 'spawns a process with default strategy' do
37
+ node.spawn( *spawn_options )
38
+ sleep 1
39
+
40
+ client = Tiq::Client.new( 'localhost:8888' )
41
+ expect(client.alive?).to be_truthy
42
+ end
43
+
44
+ it 'raises an error for an unknown strategy' do
45
+ pending
46
+ expect { node.spawn(:unknown, 'Child', 'child.rb', { e: 27 }) }.to raise_error(ArgumentError, /Unknown strategy/)
47
+ end
48
+ end
49
+
50
+ describe '#utilization' do
51
+ it 'returns the current utilization' do
52
+ expect(node.utilization).to be_a(Float)
53
+ end
54
+ end
55
+
56
+ describe '#preferred' do
57
+ context 'with a valid strategy' do
58
+ it 'returns the preferred URL' do
59
+ node.start
60
+ node.preferred(:horizontal) do |url|
61
+ expect(url).to eq('localhost:9997')
62
+ end
63
+ end
64
+ end
65
+
66
+ context 'with an invalid strategy' do
67
+ it 'raises an error' do
68
+ expect do
69
+ node.preferred(:invalid) {}
70
+ end.to raise_error(ArgumentError, /Unknown strategy/)
71
+ end
72
+ end
73
+ end
74
+
75
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rspec'
4
+ require 'gloox'
5
+
6
+ RSpec.configure do |config|
7
+ config.expect_with :rspec do |expectations|
8
+ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
9
+ end
10
+
11
+ config.mock_with :rspec do |mocks|
12
+ mocks.verify_partial_doubles = true
13
+ end
14
+
15
+ config.shared_context_metadata_behavior = :apply_to_host_groups
16
+ end
@@ -0,0 +1,8 @@
1
+ require 'gloox'
2
+
3
+ class MyNode < Tiq::Node
4
+ end
5
+
6
+ return unless $execute
7
+
8
+ my_node = MyNode.new( url: $options[:url] ).server.start
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gloox
3
3
  version: !ruby/object:Gem::Version
4
- version: '0.1'
4
+ version: '0.3'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tasos Laskos
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2025-10-25 00:00:00.000000000 Z
10
+ date: 2026-01-04 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: awesome_print
@@ -39,7 +38,7 @@ dependencies:
39
38
  - !ruby/object:Gem::Version
40
39
  version: '0'
41
40
  - !ruby/object:Gem::Dependency
42
- name: slotz
41
+ name: msgpack
43
42
  requirement: !ruby/object:Gem::Requirement
44
43
  requirements:
45
44
  - - ">="
@@ -53,7 +52,7 @@ dependencies:
53
52
  - !ruby/object:Gem::Version
54
53
  version: '0'
55
54
  - !ruby/object:Gem::Dependency
56
- name: tiq
55
+ name: slotz
57
56
  requirement: !ruby/object:Gem::Requirement
58
57
  requirements:
59
58
  - - ">="
@@ -67,7 +66,7 @@ dependencies:
67
66
  - !ruby/object:Gem::Version
68
67
  version: '0'
69
68
  - !ruby/object:Gem::Dependency
70
- name: toq
69
+ name: tiq
71
70
  requirement: !ruby/object:Gem::Requirement
72
71
  requirements:
73
72
  - - ">="
@@ -85,21 +84,26 @@ email: tasos.laskos@gmail.com
85
84
  executables: []
86
85
  extensions: []
87
86
  extra_rdoc_files:
88
- - README.md
89
87
  - LICENSE.md
88
+ - README.md
90
89
  files:
91
90
  - Gemfile
92
91
  - LICENSE.md
93
92
  - README.md
94
93
  - gloox.gemspec
95
94
  - lib/gloox.rb
96
- - lib/gloox/agent.rb
95
+ - lib/gloox/client.rb
96
+ - lib/gloox/node.rb
97
+ - lib/gloox/utilities.rb
97
98
  - lib/gloox/version.rb
98
- homepage: https://github.com/qadron/cuboid
99
+ - spec/gloox/groups_spec.rb
100
+ - spec/gloox/node_spec.rb
101
+ - spec/spec_helper.rb
102
+ - spec/support/fixtures/child_node.rb
103
+ homepage: https://github.com/qadron/gloox
99
104
  licenses:
100
105
  - MPL v2
101
106
  metadata: {}
102
- post_install_message:
103
107
  rdoc_options:
104
108
  - "--charset=UTF-8"
105
109
  require_paths:
@@ -115,8 +119,11 @@ required_rubygems_version: !ruby/object:Gem::Requirement
115
119
  - !ruby/object:Gem::Version
116
120
  version: '0'
117
121
  requirements: []
118
- rubygems_version: 3.4.22
119
- signing_key:
122
+ rubygems_version: 3.6.9
120
123
  specification_version: 4
121
124
  summary: ''
122
- test_files: []
125
+ test_files:
126
+ - spec/gloox/groups_spec.rb
127
+ - spec/gloox/node_spec.rb
128
+ - spec/spec_helper.rb
129
+ - spec/support/fixtures/child_node.rb