kamerling 0.0.2 → 0.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 +4 -4
- data/.rubocop.yml +4 -13
- data/Gemfile +0 -1
- data/Gemfile.lock +64 -64
- data/README.md +18 -1
- data/Rakefile +5 -3
- data/bin/kamerling +1 -1
- data/config/reek.yml +20 -3
- data/kamerling.gemspec +16 -13
- data/lib/kamerling.rb +2 -28
- data/lib/kamerling/addr.rb +17 -3
- data/lib/kamerling/client.rb +10 -11
- data/lib/kamerling/core_extensions/main.rb +14 -14
- data/lib/kamerling/dispatch.rb +13 -0
- data/lib/kamerling/handler.rb +16 -25
- data/lib/kamerling/http_api.rb +50 -34
- data/lib/kamerling/logging.rb +36 -16
- data/lib/kamerling/mapper.rb +33 -0
- data/lib/kamerling/message.rb +50 -37
- data/lib/kamerling/migrations/2_results_received_at.rb +7 -0
- data/lib/kamerling/migrations/3_dispatches.rb +17 -0
- data/lib/kamerling/migrations/4_registrations_registered_at.rb +7 -0
- data/lib/kamerling/migrations/5_clients_type.rb +7 -0
- data/lib/kamerling/net_dispatcher.rb +12 -7
- data/lib/kamerling/project.rb +7 -3
- data/lib/kamerling/receiver.rb +38 -10
- data/lib/kamerling/registrar.rb +45 -8
- data/lib/kamerling/registration.rb +9 -10
- data/lib/kamerling/repo.rb +33 -26
- data/lib/kamerling/repos.rb +52 -45
- data/lib/kamerling/result.rb +10 -11
- data/lib/kamerling/server/http.rb +28 -21
- data/lib/kamerling/server/sock.rb +32 -24
- data/lib/kamerling/server/tcp.rb +23 -15
- data/lib/kamerling/server/udp.rb +24 -16
- data/lib/kamerling/server_runner.rb +30 -41
- data/lib/kamerling/settings.rb +28 -0
- data/lib/kamerling/task.rb +7 -7
- data/lib/kamerling/task_dispatcher.rb +31 -22
- data/lib/kamerling/uuid.rb +13 -11
- data/lib/kamerling/uuid_entity.rb +23 -9
- data/lib/kamerling/value.rb +13 -0
- data/lib/kamerling/views/clients.slim +3 -1
- data/lib/kamerling/views/project.slim +8 -4
- data/lib/kamerling/views/projects.slim +7 -1
- data/spec/kamerling/addr_spec.rb +32 -22
- data/spec/kamerling/client_spec.rb +9 -5
- data/spec/kamerling/core_extensions/main_spec.rb +18 -13
- data/spec/kamerling/dispatch_spec.rb +16 -0
- data/spec/kamerling/handler_spec.rb +24 -34
- data/spec/kamerling/http_api_spec.rb +94 -73
- data/spec/kamerling/logging_spec.rb +93 -62
- data/spec/kamerling/mapper_spec.rb +151 -0
- data/spec/kamerling/message_spec.rb +73 -49
- data/spec/kamerling/net_dispatcher_spec.rb +22 -16
- data/spec/kamerling/receiver_spec.rb +29 -19
- data/spec/kamerling/registrar_spec.rb +43 -15
- data/spec/kamerling/registration_spec.rb +17 -0
- data/spec/kamerling/repo_spec.rb +63 -47
- data/spec/kamerling/repos_spec.rb +121 -109
- data/spec/kamerling/result_spec.rb +16 -0
- data/spec/kamerling/server/http_spec.rb +19 -14
- data/spec/kamerling/server/tcp_spec.rb +41 -35
- data/spec/kamerling/server/udp_spec.rb +40 -34
- data/spec/kamerling/server_runner_spec.rb +62 -53
- data/spec/kamerling/settings_spec.rb +36 -0
- data/spec/kamerling/task_dispatcher_spec.rb +38 -15
- data/spec/kamerling/task_spec.rb +9 -5
- data/spec/kamerling/uuid_entity_spec.rb +53 -25
- data/spec/kamerling/uuid_spec.rb +19 -16
- data/spec/kamerling/value_spec.rb +21 -0
- data/spec/spec_helper.rb +3 -6
- metadata +54 -8
- data/lib/kamerling/core_extensions.rb +0 -1
data/lib/kamerling/server/tcp.rb
CHANGED
@@ -1,19 +1,27 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
require 'socket'
|
2
|
+
require_relative '../addr'
|
3
|
+
require_relative 'sock'
|
3
4
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
ensure
|
9
|
-
socket.close
|
10
|
-
end
|
5
|
+
module Kamerling
|
6
|
+
module Server
|
7
|
+
class TCP < Sock
|
8
|
+
private
|
11
9
|
|
12
|
-
|
13
|
-
|
14
|
-
|
10
|
+
def handle_connection(socket)
|
11
|
+
client_addr = Addr[*socket.remote_address.ip_unpack, :TCP]
|
12
|
+
input = socket.read
|
13
|
+
handle input, client_addr
|
14
|
+
ensure
|
15
|
+
socket.close
|
16
|
+
end
|
17
|
+
|
18
|
+
def run_loop
|
19
|
+
Socket.tcp_server_loop(*addr) { |socket| handle_connection socket }
|
20
|
+
end
|
15
21
|
|
16
|
-
|
17
|
-
|
22
|
+
def wait_till_started
|
23
|
+
loop { break if addr.connectable? }
|
24
|
+
end
|
25
|
+
end
|
18
26
|
end
|
19
|
-
end
|
27
|
+
end
|
data/lib/kamerling/server/udp.rb
CHANGED
@@ -1,20 +1,28 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
require 'socket'
|
2
|
+
require_relative '../addr'
|
3
|
+
require_relative 'sock'
|
3
4
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
end
|
5
|
+
module Kamerling
|
6
|
+
module Server
|
7
|
+
class UDP < Sock
|
8
|
+
private
|
9
9
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
10
|
+
def handle_connection(socket)
|
11
|
+
input, conn = socket.recvfrom 2**16
|
12
|
+
client_addr = Addr[conn[3], conn[1], :UDP]
|
13
|
+
handle input, client_addr
|
14
|
+
end
|
15
|
+
|
16
|
+
def run_loop
|
17
|
+
socket = UDPSocket.new.tap { |server| server.bind(*addr) }
|
18
|
+
loop { handle_connection socket if IO.select [socket] }
|
19
|
+
ensure
|
20
|
+
socket.close if socket
|
21
|
+
end
|
16
22
|
|
17
|
-
|
18
|
-
|
23
|
+
def wait_till_started
|
24
|
+
200.times { thread.run }
|
25
|
+
end
|
26
|
+
end
|
19
27
|
end
|
20
|
-
end
|
28
|
+
end
|
@@ -1,48 +1,37 @@
|
|
1
|
-
require '
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
servers.each(&:start)
|
19
|
-
self
|
20
|
-
end
|
21
|
-
|
22
|
-
attr_reader :args, :servers
|
23
|
-
private :args, :servers
|
1
|
+
require 'sequel'
|
2
|
+
require_relative 'addr'
|
3
|
+
require_relative 'repos'
|
4
|
+
require_relative 'server/http'
|
5
|
+
require_relative 'server/tcp'
|
6
|
+
require_relative 'server/udp'
|
7
|
+
require_relative 'settings'
|
8
|
+
|
9
|
+
module Kamerling
|
10
|
+
class ServerRunner
|
11
|
+
def initialize(args, classes: def_classes, orm: Sequel, repos: Repos)
|
12
|
+
settings = Settings.new(args)
|
13
|
+
repos.db = orm.connect(settings.db)
|
14
|
+
@servers = settings.server_addrs.map do |type, addr|
|
15
|
+
classes[type].new(addr: addr)
|
16
|
+
end
|
17
|
+
end
|
24
18
|
|
25
|
-
|
19
|
+
def join
|
20
|
+
servers.each(&:join)
|
21
|
+
end
|
26
22
|
|
27
|
-
|
23
|
+
def start
|
24
|
+
servers.each(&:start)
|
25
|
+
self
|
26
|
+
end
|
28
27
|
|
29
|
-
|
30
|
-
|
31
|
-
end
|
28
|
+
attr_reader :servers
|
29
|
+
private :servers
|
32
30
|
|
33
|
-
|
34
|
-
Settings.new 'sqlite::memory:', '127.0.0.1'
|
35
|
-
end
|
31
|
+
private
|
36
32
|
|
37
|
-
|
38
|
-
|
39
|
-
OptionParser.new do |opt|
|
40
|
-
opt.on("--db #{set.db}", String, 'database') { |db| set.db = db }
|
41
|
-
opt.on("--host #{set.host}", String, 'host') { |host| set.host = host }
|
42
|
-
opt.on('--http 0', Integer, 'HTTP port') { |http| set.http = http }
|
43
|
-
opt.on('--tcp 0', Integer, 'TCP port') { |tcp| set.tcp = tcp }
|
44
|
-
opt.on('--udp 0', Integer, 'UDP port') { |udp| set.udp = udp }
|
45
|
-
end.parse! args
|
33
|
+
def def_classes
|
34
|
+
{ http: Server::HTTP, tcp: Server::TCP, udp: Server::UDP }
|
46
35
|
end
|
47
36
|
end
|
48
|
-
end
|
37
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'optparse'
|
2
|
+
require_relative 'addr'
|
3
|
+
require_relative 'value'
|
4
|
+
|
5
|
+
module Kamerling
|
6
|
+
class Settings < Value
|
7
|
+
vals db: String, host: String, http: Integer, tcp: Integer, udp: Integer
|
8
|
+
|
9
|
+
def initialize(args)
|
10
|
+
super db: 'sqlite::memory:', host: '127.0.0.1'
|
11
|
+
OptionParser.new do |opt|
|
12
|
+
opt.on("--db #{db}", String, 'database') { |db| self.db = db }
|
13
|
+
opt.on("--host #{host}", String, 'host') { |host| self.host = host }
|
14
|
+
opt.on('--http 0', Integer, 'HTTP port') { |http| self.http = http }
|
15
|
+
opt.on('--tcp 0', Integer, 'TCP port') { |tcp| self.tcp = tcp }
|
16
|
+
opt.on('--udp 0', Integer, 'UDP port') { |udp| self.udp = udp }
|
17
|
+
end.parse! args
|
18
|
+
end
|
19
|
+
|
20
|
+
def server_addrs
|
21
|
+
{
|
22
|
+
http: Addr[host, http, :TCP],
|
23
|
+
tcp: Addr[host, tcp, :TCP],
|
24
|
+
udp: Addr[host, udp, :UDP],
|
25
|
+
}.select { |_, addr| addr.port }
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
data/lib/kamerling/task.rb
CHANGED
@@ -1,9 +1,9 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
attribute :done, Boolean, default: false
|
4
|
-
attribute :project, Project
|
1
|
+
require_relative 'project'
|
2
|
+
require_relative 'uuid_entity'
|
5
3
|
|
6
|
-
|
7
|
-
|
4
|
+
module Kamerling
|
5
|
+
class Task < UUIDEntity
|
6
|
+
attrs data: String, done: Boolean, project: Project
|
7
|
+
defaults done: false
|
8
8
|
end
|
9
|
-
end
|
9
|
+
end
|
@@ -1,29 +1,38 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
1
|
+
require_relative 'dispatch'
|
2
|
+
require_relative 'message'
|
3
|
+
require_relative 'net_dispatcher'
|
4
|
+
require_relative 'repos'
|
5
|
+
|
6
|
+
module Kamerling
|
7
|
+
class TaskDispatcher
|
8
|
+
def initialize(net_dispatcher: NetDispatcher, repos: Repos)
|
9
|
+
@net_dispatcher = net_dispatcher
|
10
|
+
@repos = repos
|
11
|
+
end
|
6
12
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
13
|
+
def dispatch_all
|
14
|
+
repos.projects.each do |project|
|
15
|
+
repos.free_clients_for(project).each do |client|
|
16
|
+
task = repos.next_task_for(project)
|
17
|
+
dispatch_task client: client, project: project, task: task if task
|
18
|
+
end
|
12
19
|
end
|
13
20
|
end
|
14
|
-
end
|
15
21
|
|
16
|
-
|
17
|
-
|
22
|
+
attr_reader :net_dispatcher, :repos
|
23
|
+
private :net_dispatcher, :repos
|
18
24
|
|
19
|
-
|
25
|
+
private
|
20
26
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
27
|
+
def dispatch_task(client:, project:, task:)
|
28
|
+
message = Message.build(client: client, payload: task.data,
|
29
|
+
project: project, task: task, type: :DATA)
|
30
|
+
dispatch = Dispatch.new(addr: client.addr, client: client,
|
31
|
+
project: project, task: task)
|
32
|
+
net_dispatcher.dispatch client.addr, message
|
33
|
+
client.busy = true
|
34
|
+
repos << client
|
35
|
+
repos << dispatch
|
36
|
+
end
|
28
37
|
end
|
29
|
-
end
|
38
|
+
end
|
data/lib/kamerling/uuid.rb
CHANGED
@@ -1,17 +1,19 @@
|
|
1
1
|
require 'securerandom'
|
2
2
|
|
3
|
-
module Kamerling
|
4
|
-
|
3
|
+
module Kamerling
|
4
|
+
module UUID
|
5
|
+
module_function
|
5
6
|
|
6
|
-
|
7
|
-
|
8
|
-
|
7
|
+
def [](bin)
|
8
|
+
bin.unpack('H8H4H4H4H12').join('-')
|
9
|
+
end
|
9
10
|
|
10
|
-
|
11
|
-
|
12
|
-
|
11
|
+
def bin(uuid)
|
12
|
+
[uuid.tr('-', '')].pack('H*')
|
13
|
+
end
|
13
14
|
|
14
|
-
|
15
|
-
|
15
|
+
def new
|
16
|
+
SecureRandom.uuid
|
17
|
+
end
|
16
18
|
end
|
17
|
-
end
|
19
|
+
end
|
@@ -1,15 +1,29 @@
|
|
1
|
+
require 'equalizer'
|
1
2
|
require 'virtus'
|
3
|
+
require_relative 'uuid'
|
2
4
|
|
3
|
-
module Kamerling
|
4
|
-
|
5
|
+
module Kamerling
|
6
|
+
class UUIDEntity
|
7
|
+
include Equalizer.new(:uuid)
|
5
8
|
|
6
|
-
|
9
|
+
include Virtus.model
|
7
10
|
|
8
|
-
|
11
|
+
attribute :uuid, String, default: -> (*) { UUID.new }
|
9
12
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
+
def self.attrs(hash = {})
|
14
|
+
hash.each { |name, klass| attribute name, klass }
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.defaults(hash = {})
|
18
|
+
hash.each do |name, default|
|
19
|
+
warn_off { attribute name, attribute_set[name].type, default: default }
|
20
|
+
end
|
21
|
+
end
|
13
22
|
|
14
|
-
|
15
|
-
|
23
|
+
def to_h
|
24
|
+
attributes.map do |key, value|
|
25
|
+
value.is_a?(UUIDEntity) ? [key, value.to_h] : [key, value]
|
26
|
+
end.to_h
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -2,5 +2,7 @@ nav
|
|
2
2
|
ul#clients
|
3
3
|
- clients.each do |client|
|
4
4
|
li
|
5
|
-
a
|
5
|
+
a(data-addr=client.addr data-busy=client.busy.to_s data-class='client'
|
6
|
+
data-type=client.type data-uuid=client.uuid
|
7
|
+
href="/clients/#{client.uuid}")
|
6
8
|
= client.busy
|
@@ -2,10 +2,14 @@ nav
|
|
2
2
|
ul#clients
|
3
3
|
- clients.each do |client|
|
4
4
|
li
|
5
|
-
a
|
6
|
-
= client.
|
5
|
+
a(data-busy=client.busy.to_s data-class='client' data-type=client.type
|
6
|
+
data-uuid=client.uuid href="/clients/#{client.uuid}")
|
7
|
+
= client.uuid
|
8
|
+
= "busy: #{client.busy.to_s}"
|
7
9
|
ul#tasks
|
8
10
|
- tasks.each do |task|
|
9
11
|
li
|
10
|
-
a data-done=task.done.to_s data-uuid=task.uuid
|
11
|
-
=
|
12
|
+
a(data-class='task' data-done=task.done.to_s data-uuid=task.uuid
|
13
|
+
href="/tasks/#{task.uuid}")
|
14
|
+
= task.uuid
|
15
|
+
= "done: #{task.done.to_s}"
|
@@ -2,8 +2,14 @@ nav
|
|
2
2
|
ul#projects
|
3
3
|
- projects.each do |project|
|
4
4
|
li
|
5
|
-
a
|
5
|
+
a(data-class='project' data-uuid=project.uuid
|
6
|
+
href="/projects/#{project.uuid}")
|
6
7
|
= project.name
|
7
8
|
|
8
9
|
form action='/projects' method='POST'
|
9
10
|
input name='name'
|
11
|
+
input name='uuid' type='hidden' value=Kamerling::UUID.new
|
12
|
+
input type='submit' value='create'
|
13
|
+
|
14
|
+
form action='/projects/dispatch' method='POST'
|
15
|
+
input type='submit' value='dispatch'
|
data/spec/kamerling/addr_spec.rb
CHANGED
@@ -1,33 +1,43 @@
|
|
1
|
+
require 'socket'
|
1
2
|
require_relative '../spec_helper'
|
3
|
+
require_relative '../../lib/kamerling/addr'
|
2
4
|
|
3
|
-
module Kamerling
|
4
|
-
|
5
|
+
module Kamerling
|
6
|
+
describe Addr do
|
7
|
+
let(:addr) { Addr['localhost', 1981, :TCP] }
|
5
8
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
describe '#connectable?' do
|
10
|
+
it 'is a predicate whether the (TCP) address is connectable' do
|
11
|
+
server = TCPServer.new(*addr)
|
12
|
+
addr.must_be :connectable?
|
13
|
+
server.close
|
14
|
+
addr.wont_be :connectable?
|
15
|
+
end
|
12
16
|
end
|
13
|
-
end
|
14
17
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
18
|
+
describe '#to_a' do
|
19
|
+
it 'returns host + port for splat use' do
|
20
|
+
splat = *addr
|
21
|
+
splat.must_equal ['localhost', 1981]
|
22
|
+
end
|
19
23
|
end
|
20
|
-
end
|
21
24
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
+
describe '#to_h' do
|
26
|
+
it 'returns a Hash with Integer and String values' do
|
27
|
+
addr.to_h.must_equal host: 'localhost', port: 1981, prot: 'TCP'
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
describe '#to_s' do
|
32
|
+
it 'returns the Addr in URI notation' do
|
33
|
+
addr.to_s.must_equal 'tcp://localhost:1981'
|
34
|
+
end
|
25
35
|
end
|
26
|
-
end
|
27
36
|
|
28
|
-
|
29
|
-
|
30
|
-
|
37
|
+
describe '#uri' do
|
38
|
+
it 'returns and URI representation of the Addr' do
|
39
|
+
addr.uri.must_equal URI.parse('tcp://localhost:1981')
|
40
|
+
end
|
31
41
|
end
|
32
42
|
end
|
33
|
-
end
|
43
|
+
end
|