kamerling 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- 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
@@ -1,17 +1,17 @@
|
|
1
|
-
module Kamerling
|
2
|
-
|
1
|
+
module Kamerling
|
2
|
+
module CoreExtensions
|
3
|
+
module Main
|
4
|
+
module_function
|
3
5
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
6
|
+
def warn_off
|
7
|
+
verbose = $VERBOSE
|
8
|
+
$VERBOSE = false
|
9
|
+
yield
|
10
|
+
ensure
|
11
|
+
$VERBOSE = verbose
|
12
|
+
end
|
13
|
+
end
|
8
14
|
end
|
15
|
+
end
|
9
16
|
|
10
|
-
|
11
|
-
verbose = $VERBOSE
|
12
|
-
$VERBOSE = false
|
13
|
-
yield
|
14
|
-
ensure
|
15
|
-
$VERBOSE = verbose
|
16
|
-
end
|
17
|
-
end end end
|
17
|
+
include Kamerling::CoreExtensions::Main
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require_relative 'addr'
|
2
|
+
require_relative 'client'
|
3
|
+
require_relative 'project'
|
4
|
+
require_relative 'task'
|
5
|
+
require_relative 'uuid_entity'
|
6
|
+
|
7
|
+
module Kamerling
|
8
|
+
class Dispatch < UUIDEntity
|
9
|
+
attrs addr: Addr, client: Client, dispatched_at: Time, project: Project,
|
10
|
+
task: Task
|
11
|
+
defaults dispatched_at: -> (*) { Time.now }
|
12
|
+
end
|
13
|
+
end
|
data/lib/kamerling/handler.rb
CHANGED
@@ -1,29 +1,20 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
require_relative 'receiver'
|
2
|
+
require_relative 'registrar'
|
3
3
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
process Message.new(input), addr
|
10
|
-
rescue Message::UnknownType => exception
|
11
|
-
raise UnknownInput, exception.message
|
12
|
-
end
|
13
|
-
|
14
|
-
attr_reader :receiver, :registrar
|
15
|
-
private :receiver, :registrar
|
16
|
-
|
17
|
-
private
|
4
|
+
module Kamerling
|
5
|
+
class Handler
|
6
|
+
def initialize(receiver: Receiver, registrar: Registrar)
|
7
|
+
@receiver, @registrar = receiver, registrar
|
8
|
+
end
|
18
9
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
when :RSLT
|
25
|
-
receiver.receive addr: addr, client_uuid: message.client_uuid,
|
26
|
-
data: message.payload, task_uuid: message.task_uuid
|
10
|
+
def handle(message, addr)
|
11
|
+
case message.type
|
12
|
+
when :RGST then registrar.register addr: addr, message: message
|
13
|
+
when :RSLT then receiver.receive addr: addr, message: message
|
14
|
+
end
|
27
15
|
end
|
16
|
+
|
17
|
+
attr_reader :receiver, :registrar
|
18
|
+
private :receiver, :registrar
|
28
19
|
end
|
29
|
-
end
|
20
|
+
end
|
data/lib/kamerling/http_api.rb
CHANGED
@@ -1,38 +1,54 @@
|
|
1
1
|
require 'forwardable'
|
2
2
|
require 'sinatra/base'
|
3
3
|
require 'slim'
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
4
|
+
require_relative 'project'
|
5
|
+
require_relative 'repos'
|
6
|
+
require_relative 'task_dispatcher'
|
7
|
+
require_relative 'uuid'
|
8
|
+
|
9
|
+
module Kamerling
|
10
|
+
class HTTPAPI < Sinatra::Base
|
11
|
+
extend Forwardable
|
12
|
+
|
13
|
+
delegate %i(task_dispatcher repos) => :settings
|
14
|
+
|
15
|
+
configure { set task_dispatcher: TaskDispatcher.new, repos: Repos }
|
16
|
+
|
17
|
+
get '/' do
|
18
|
+
render_template :root
|
19
|
+
end
|
20
|
+
|
21
|
+
get '/clients' do
|
22
|
+
render_template :clients, locals: { clients: repos.clients }
|
23
|
+
end
|
24
|
+
|
25
|
+
get '/projects' do
|
26
|
+
render_template :projects, locals: { projects: repos.projects }
|
27
|
+
end
|
28
|
+
|
29
|
+
get '/projects/:project_uuid' do
|
30
|
+
project = repos.project(params['project_uuid'])
|
31
|
+
clients = repos.clients_for(project)
|
32
|
+
tasks = repos.tasks_for(project)
|
33
|
+
render_template :project, locals: { clients: clients, tasks: tasks }
|
34
|
+
end
|
35
|
+
|
36
|
+
post '/projects' do
|
37
|
+
name = params.fetch('name')
|
38
|
+
uuid = params.fetch('uuid')
|
39
|
+
repos << Project.new(name: name, uuid: uuid)
|
40
|
+
redirect '/projects'
|
41
|
+
end
|
42
|
+
|
43
|
+
post '/projects/dispatch' do
|
44
|
+
task_dispatcher.dispatch_all
|
45
|
+
redirect '/projects'
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
def render_template(template, locals: {})
|
51
|
+
warn_off { slim template, locals: locals }
|
52
|
+
end
|
20
53
|
end
|
21
|
-
|
22
|
-
get '/projects/:project_uuid' do
|
23
|
-
project = repos.project params['project_uuid']
|
24
|
-
clients = repos.clients_for project
|
25
|
-
tasks = repos.tasks_for project
|
26
|
-
warn_off { slim :project, locals: { clients: clients, tasks: tasks } }
|
27
|
-
end
|
28
|
-
|
29
|
-
post '/projects' do
|
30
|
-
uuid = params.fetch('uuid') { UUID.new }
|
31
|
-
repos << Project.new(name: params['name'], uuid: uuid)
|
32
|
-
redirect '/projects'
|
33
|
-
end
|
34
|
-
|
35
|
-
private
|
36
|
-
|
37
|
-
delegate repos: :settings
|
38
|
-
end end
|
54
|
+
end
|
data/lib/kamerling/logging.rb
CHANGED
@@ -1,32 +1,52 @@
|
|
1
1
|
require 'after_do'
|
2
2
|
require 'logger'
|
3
|
+
require_relative 'net_dispatcher'
|
4
|
+
require_relative 'server/sock'
|
3
5
|
|
4
|
-
module Kamerling
|
5
|
-
|
6
|
+
module Kamerling
|
7
|
+
class Logging
|
8
|
+
def self.log_to(logger = Logger.new($stdout))
|
9
|
+
new logger
|
10
|
+
end
|
6
11
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
12
|
+
def initialize(logger)
|
13
|
+
@logger = logger
|
14
|
+
log_dispatcher
|
15
|
+
log_server
|
16
|
+
end
|
17
|
+
|
18
|
+
attr_reader :logger
|
19
|
+
private :logger
|
11
20
|
|
12
|
-
class << self
|
13
21
|
private
|
14
22
|
|
15
|
-
def
|
23
|
+
def log_dispatcher
|
16
24
|
NetDispatcher.singleton_class.extend AfterDo
|
17
|
-
NetDispatcher.singleton_class.before
|
18
|
-
logger.debug "sent #{addr} #{
|
25
|
+
NetDispatcher.singleton_class.before(:dispatch) do |addr, message|
|
26
|
+
logger.debug "sent #{addr} #{message.to_hex}"
|
19
27
|
end
|
20
28
|
end
|
21
29
|
|
22
|
-
def
|
30
|
+
def log_server
|
23
31
|
Server::Sock.extend AfterDo
|
32
|
+
log_server_lifecycle
|
33
|
+
log_server_communication
|
34
|
+
end
|
35
|
+
|
36
|
+
def log_server_communication
|
37
|
+
Server::Sock.before(:handle) do |input, client_addr|
|
38
|
+
begin
|
39
|
+
logger.info "connect #{client_addr}"
|
40
|
+
logger.debug "received #{client_addr} #{Message.parse(input).to_hex}"
|
41
|
+
rescue Message::UnknownType
|
42
|
+
logger.debug "received #{client_addr} unknown message type"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def log_server_lifecycle
|
24
48
|
Server::Sock.before(:start) { |srv| logger.info "start #{srv.addr}" }
|
25
49
|
Server::Sock.after(:stop) { |srv| logger.info "stop #{srv.addr}" }
|
26
|
-
Server::Sock.before :handle do |input, client_addr|
|
27
|
-
logger.info "connect #{client_addr}"
|
28
|
-
logger.debug "received #{client_addr} #{input}"
|
29
|
-
end
|
30
50
|
end
|
31
51
|
end
|
32
|
-
end
|
52
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require_relative 'addr'
|
2
|
+
|
3
|
+
module Kamerling
|
4
|
+
module Mapper
|
5
|
+
module_function
|
6
|
+
|
7
|
+
def from_h(klass, hash, repos: Repos)
|
8
|
+
attributes = hash.map do |key, value|
|
9
|
+
case key
|
10
|
+
when :host, :port, :prot then [:addr, Addr.new(hash)]
|
11
|
+
when /_uuid$/ then object_pair_from(key, value, repos)
|
12
|
+
else [key, value]
|
13
|
+
end
|
14
|
+
end.to_h
|
15
|
+
klass.new(attributes)
|
16
|
+
end
|
17
|
+
|
18
|
+
def object_pair_from(key, value, repos)
|
19
|
+
type = key[/(.*)_uuid$/, 1].to_sym
|
20
|
+
[type, repos[Kamerling.const_get(type.capitalize)][value]]
|
21
|
+
end
|
22
|
+
|
23
|
+
def to_h(object)
|
24
|
+
object.to_h.reduce({}) do |hash, (key, value)|
|
25
|
+
hash.merge case value
|
26
|
+
when Addr then value.to_h
|
27
|
+
when Hash then { :"#{key}_uuid" => value[:uuid] }
|
28
|
+
else { key => value }
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
data/lib/kamerling/message.rb
CHANGED
@@ -1,47 +1,60 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
require 'equalizer'
|
2
|
+
require_relative 'uuid'
|
3
3
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
end
|
4
|
+
module Kamerling
|
5
|
+
class Message
|
6
|
+
KNOWN_TYPES = %i(DATA PING RGST RSLT)
|
7
|
+
UnknownType = Class.new(RuntimeError)
|
9
8
|
|
10
|
-
|
11
|
-
@raw = raw
|
12
|
-
type = raw[0..3]
|
13
|
-
known_types = %w(DATA PING RGST RSLT)
|
14
|
-
fail UnknownType, type unless known_types.include? type or type.empty?
|
15
|
-
end
|
9
|
+
include Equalizer.new(:raw)
|
16
10
|
|
17
|
-
|
18
|
-
|
19
|
-
|
11
|
+
def self.build(client:, payload:, project:, task:, type:)
|
12
|
+
new([type, "\0\0\0\0\0\0\0\0\0\0\0\0", UUID.bin(client.uuid),
|
13
|
+
UUID.bin(project.uuid), UUID.bin(task.uuid), payload].join)
|
14
|
+
end
|
20
15
|
|
21
|
-
|
22
|
-
|
23
|
-
|
16
|
+
def self.parse(raw)
|
17
|
+
new(raw)
|
18
|
+
end
|
24
19
|
|
25
|
-
|
26
|
-
|
27
|
-
|
20
|
+
def initialize(raw)
|
21
|
+
@raw = raw
|
22
|
+
fail UnknownType, type unless KNOWN_TYPES.include?(type) or type.empty?
|
23
|
+
end
|
28
24
|
|
29
|
-
|
30
|
-
|
31
|
-
|
25
|
+
def client_type
|
26
|
+
raw[4..7].to_sym
|
27
|
+
end
|
32
28
|
|
33
|
-
|
34
|
-
|
35
|
-
|
29
|
+
def client_uuid
|
30
|
+
UUID[raw[16..31]]
|
31
|
+
end
|
36
32
|
|
37
|
-
|
38
|
-
|
39
|
-
|
33
|
+
def payload
|
34
|
+
raw[64..-1]
|
35
|
+
end
|
40
36
|
|
41
|
-
|
42
|
-
|
43
|
-
|
37
|
+
def project_uuid
|
38
|
+
UUID[raw[32..47]]
|
39
|
+
end
|
40
|
+
|
41
|
+
def task_uuid
|
42
|
+
UUID[raw[48..63]]
|
43
|
+
end
|
44
|
+
|
45
|
+
def to_hex
|
46
|
+
raw.unpack('H*').first.scan(/../).join(' ')
|
47
|
+
end
|
44
48
|
|
45
|
-
|
46
|
-
|
47
|
-
end
|
49
|
+
def to_s
|
50
|
+
raw
|
51
|
+
end
|
52
|
+
|
53
|
+
def type
|
54
|
+
raw[0..3].to_sym
|
55
|
+
end
|
56
|
+
|
57
|
+
attr_reader :raw
|
58
|
+
protected :raw
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
Sequel.migration do
|
2
|
+
change do
|
3
|
+
create_table :dispatches do
|
4
|
+
uuid :uuid, primary_key: true
|
5
|
+
inet :host, null: false
|
6
|
+
integer :port, null: false
|
7
|
+
string :prot, null: false
|
8
|
+
timestamp :dispatched_at, null: false
|
9
|
+
foreign_key :client_uuid, :clients, index: true, null: false,
|
10
|
+
type: :uuid
|
11
|
+
foreign_key :project_uuid, :projects, index: true, null: false,
|
12
|
+
type: :uuid
|
13
|
+
foreign_key :task_uuid, :tasks, index: true, null: false,
|
14
|
+
type: :uuid
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -1,10 +1,15 @@
|
|
1
|
-
|
2
|
-
module_function
|
1
|
+
require 'socket'
|
3
2
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
3
|
+
module Kamerling
|
4
|
+
module NetDispatcher
|
5
|
+
module_function
|
6
|
+
|
7
|
+
def dispatch(addr, message)
|
8
|
+
bytes = message.to_s
|
9
|
+
case addr.prot
|
10
|
+
when :TCP then TCPSocket.open(*addr) { |socket| socket << bytes }
|
11
|
+
when :UDP then UDPSocket.new.send bytes, 0, *addr
|
12
|
+
end
|
8
13
|
end
|
9
14
|
end
|
10
|
-
end
|
15
|
+
end
|