evesync 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 +7 -0
- data/LICENSE +25 -0
- data/Rakefile +83 -0
- data/bin/evedatad +34 -0
- data/bin/evehand +36 -0
- data/bin/evemond +42 -0
- data/bin/evesync +164 -0
- data/bin/evesyncd +44 -0
- data/bin/start +16 -0
- data/config/example.conf +58 -0
- data/lib/evesync/config.rb +63 -0
- data/lib/evesync/constants.rb +17 -0
- data/lib/evesync/database.rb +107 -0
- data/lib/evesync/discover.rb +77 -0
- data/lib/evesync/err.rb +25 -0
- data/lib/evesync/handler/file.rb +28 -0
- data/lib/evesync/handler/package.rb +30 -0
- data/lib/evesync/handler.rb +89 -0
- data/lib/evesync/ipc/client.rb +37 -0
- data/lib/evesync/ipc/data/file.rb +64 -0
- data/lib/evesync/ipc/data/hashable.rb +74 -0
- data/lib/evesync/ipc/data/ignore.rb +22 -0
- data/lib/evesync/ipc/data/package.rb +58 -0
- data/lib/evesync/ipc/data/utils.rb +14 -0
- data/lib/evesync/ipc/data.rb +50 -0
- data/lib/evesync/ipc/ipc.rb +42 -0
- data/lib/evesync/ipc/server.rb +56 -0
- data/lib/evesync/log.rb +66 -0
- data/lib/evesync/ntp.rb +16 -0
- data/lib/evesync/os/linux/arch/package_manager.rb +29 -0
- data/lib/evesync/os/linux/arch/package_watcher.rb +59 -0
- data/lib/evesync/os/linux/arch.rb +2 -0
- data/lib/evesync/os/linux/base_package_manager.rb +80 -0
- data/lib/evesync/os/linux/deb/dpkg.rb +30 -0
- data/lib/evesync/os/linux/deb/package_manager.rb +38 -0
- data/lib/evesync/os/linux/deb/package_watcher.rb +32 -0
- data/lib/evesync/os/linux/deb.rb +2 -0
- data/lib/evesync/os/linux/rhel/package_manager.rb +42 -0
- data/lib/evesync/os/linux/rhel/package_watcher.rb +32 -0
- data/lib/evesync/os/linux/rhel/rpm.rb +41 -0
- data/lib/evesync/os/linux/rhel.rb +3 -0
- data/lib/evesync/os/linux.rb +9 -0
- data/lib/evesync/os.rb +2 -0
- data/lib/evesync/sync.rb +209 -0
- data/lib/evesync/trigger/base.rb +56 -0
- data/lib/evesync/trigger/file.rb +20 -0
- data/lib/evesync/trigger/package.rb +20 -0
- data/lib/evesync/trigger.rb +106 -0
- data/lib/evesync/utils.rb +51 -0
- data/lib/evesync/watcher/file.rb +156 -0
- data/lib/evesync/watcher/interface.rb +21 -0
- data/lib/evesync/watcher/package.rb +8 -0
- data/lib/evesync/watcher.rb +68 -0
- data/lib/evesync.rb +3 -0
- metadata +198 -0
@@ -0,0 +1,77 @@
|
|
1
|
+
require 'evesync/ipc/client'
|
2
|
+
require 'evesync/log'
|
3
|
+
require 'evesync/config'
|
4
|
+
|
5
|
+
module Evesync
|
6
|
+
|
7
|
+
##
|
8
|
+
# Discover other nodes
|
9
|
+
# Handles discovering messages sending and receiving
|
10
|
+
#
|
11
|
+
# = Example
|
12
|
+
#
|
13
|
+
# disc = Discover.new
|
14
|
+
# disc.send_discovery_message
|
15
|
+
# ...
|
16
|
+
# disc.stop
|
17
|
+
|
18
|
+
class Discover
|
19
|
+
DISCOVERY_REQ = 'EVESYNC'.freeze
|
20
|
+
DISCOVERY_ANS = 'DISCOVERED'.freeze
|
21
|
+
|
22
|
+
def initialize
|
23
|
+
# Starting thread that sends and accepts UDP-packages.
|
24
|
+
# This is how a node can say that it's online
|
25
|
+
@evesync = IPC::Client.new(
|
26
|
+
port: :evemond
|
27
|
+
)
|
28
|
+
@port = Config[:evesyncd]['broadcast_port']
|
29
|
+
@listen_sock = UDPSocket.new
|
30
|
+
@listen_sock.bind('0.0.0.0', @port)
|
31
|
+
@listen_thread = Thread.new { listen_discovery }
|
32
|
+
end
|
33
|
+
|
34
|
+
##
|
35
|
+
# Sending UDP message on broadcast
|
36
|
+
# Discovering our nodes
|
37
|
+
|
38
|
+
def send_discovery_message(ip = '<broadcast>', message = DISCOVERY_REQ)
|
39
|
+
udp_sock = UDPSocket.new
|
40
|
+
if ip == '<broadcast>'
|
41
|
+
udp_sock.setsockopt(
|
42
|
+
Socket::SOL_SOCKET, Socket::SO_BROADCAST, true
|
43
|
+
)
|
44
|
+
end
|
45
|
+
udp_sock.send(message, 0, ip, @port)
|
46
|
+
udp_sock.close
|
47
|
+
end
|
48
|
+
|
49
|
+
def stop
|
50
|
+
@listen_thread.exit
|
51
|
+
end
|
52
|
+
|
53
|
+
private
|
54
|
+
|
55
|
+
def listen_discovery
|
56
|
+
loop do
|
57
|
+
data, recvdata = @listen_sock.recvfrom(1024)
|
58
|
+
node_ip = recvdata[-1]
|
59
|
+
|
60
|
+
next if Utils.local_ip?(node_ip)
|
61
|
+
|
62
|
+
if [DISCOVERY_REQ, DISCOVERY_ANS].include? data
|
63
|
+
# Push new node_ip to trigger
|
64
|
+
@evesync.add_remote_node(node_ip)
|
65
|
+
end
|
66
|
+
|
67
|
+
case data
|
68
|
+
when DISCOVERY_REQ
|
69
|
+
Log.info("Discover host request got: #{node_ip}")
|
70
|
+
send_discovery_message(node_ip, DISCOVERY_ANS)
|
71
|
+
when DISCOVERY_ANS
|
72
|
+
Log.info("Discover host response got: #{node_ip}")
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
data/lib/evesync/err.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# TODO: move to a err directory
|
2
|
+
module Evesync
|
3
|
+
module Err
|
4
|
+
|
5
|
+
# Base Evesync error class.
|
6
|
+
# Using it as a base for all Evesync exceptions.
|
7
|
+
#
|
8
|
+
# = Example:
|
9
|
+
# class MyError < Evesync::Err::Base
|
10
|
+
# def initialize(message, *args)
|
11
|
+
# super(message)
|
12
|
+
# ...
|
13
|
+
# end
|
14
|
+
# ...
|
15
|
+
# end
|
16
|
+
class Base < RuntimeError
|
17
|
+
def initialize(message)
|
18
|
+
super(message)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
class SaveError < Base
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'evesync/ipc/data/file'
|
2
|
+
|
3
|
+
module Evesync
|
4
|
+
class Handler
|
5
|
+
class File
|
6
|
+
def handle(file)
|
7
|
+
Log.debug("Handler File handling started...")
|
8
|
+
content = file.content
|
9
|
+
name = file.name
|
10
|
+
Log.debug("Handler File writing received content to #{name}")
|
11
|
+
|
12
|
+
if file.action == IPC::Data::File::Action::DELETE
|
13
|
+
::File.delete(name)
|
14
|
+
else # TODO: handle move_to and move_from
|
15
|
+
# TODO: handle exceptions or throw them
|
16
|
+
# Writing content
|
17
|
+
::File.write(name, content)
|
18
|
+
# Changing mode
|
19
|
+
::File.chmod(name, file.mode)
|
20
|
+
end
|
21
|
+
|
22
|
+
# Returning all fine!
|
23
|
+
Log.debug("Handler File handling done!")
|
24
|
+
true
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'evesync/log'
|
2
|
+
require 'evesync/os'
|
3
|
+
|
4
|
+
module Evesync
|
5
|
+
class Handler
|
6
|
+
class Package
|
7
|
+
def handle(message)
|
8
|
+
Log.debug('Handler Package handling started...')
|
9
|
+
|
10
|
+
args = [message.name, message.version]
|
11
|
+
|
12
|
+
case message.command
|
13
|
+
when /install/
|
14
|
+
OS::PackageManager.install(*args)
|
15
|
+
when /remove/
|
16
|
+
OS::PackageManager.remove(*args)
|
17
|
+
when /update/
|
18
|
+
OS::PackageManager.update(*args)
|
19
|
+
when /downgrade/
|
20
|
+
OS::PackageManager.downgrade(*args)
|
21
|
+
else
|
22
|
+
Log.warn("Handler Package command unknown: #{message.command}")
|
23
|
+
return false
|
24
|
+
end
|
25
|
+
Log.debug('Handler Package handling done!')
|
26
|
+
true
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
require 'evesync/log'
|
2
|
+
require 'evesync/handler/package'
|
3
|
+
require 'evesync/handler/file'
|
4
|
+
require 'evesync/ipc/client'
|
5
|
+
|
6
|
+
module Evesync
|
7
|
+
|
8
|
+
# Handles package changes, sent via Package class and queue
|
9
|
+
# Sends messages to evedatad and available evehands.
|
10
|
+
#
|
11
|
+
# [See]
|
12
|
+
# - *Evesync::Trigger::File*
|
13
|
+
# - *Evesync::Trigger::Package*
|
14
|
+
#
|
15
|
+
# [Handlers available:]
|
16
|
+
# - *Evesync::Handler::Package*
|
17
|
+
# - *Evesync::Handler::File*
|
18
|
+
#
|
19
|
+
# = Example:
|
20
|
+
#
|
21
|
+
# handler = Evesync::Handler.new(queue)
|
22
|
+
# Evesync::IPC::Server.new(
|
23
|
+
# :proxy => handler,
|
24
|
+
# ...
|
25
|
+
# )
|
26
|
+
#
|
27
|
+
# = Example call:
|
28
|
+
#
|
29
|
+
# Evesync::IPC::Client.new(
|
30
|
+
# :port => :evehand
|
31
|
+
# ).handle(IPC::Data::Package.new(
|
32
|
+
# :name => 'tree',
|
33
|
+
# :version => '0.0.1',
|
34
|
+
# :command => :install
|
35
|
+
# )
|
36
|
+
#
|
37
|
+
# = TODO:
|
38
|
+
#
|
39
|
+
# * Make anoter daemon\Thread to search for available
|
40
|
+
# evehands daemons
|
41
|
+
# * Delegate +handle+ to another daemon if not found
|
42
|
+
class Handler
|
43
|
+
def initialize
|
44
|
+
@package_handler = Handler::Package.new
|
45
|
+
@files_handler = Handler::File.new
|
46
|
+
@monitor = IPC::Client.new(
|
47
|
+
port: :evemond
|
48
|
+
)
|
49
|
+
@database = IPC::Client.new(
|
50
|
+
port: :evedatad
|
51
|
+
)
|
52
|
+
Log.debug('Handler initialization done!')
|
53
|
+
end
|
54
|
+
|
55
|
+
def handle(message)
|
56
|
+
Log.info "Handler triggered with: #{message}"
|
57
|
+
|
58
|
+
handler = if message.is_a? IPC::Data::Package
|
59
|
+
@package_handler
|
60
|
+
elsif message.is_a? IPC::Data::File
|
61
|
+
@files_handler
|
62
|
+
else
|
63
|
+
Log.error('Handler: unknown message type')
|
64
|
+
nil
|
65
|
+
end
|
66
|
+
return unless handler
|
67
|
+
|
68
|
+
@monitor.ignore(message)
|
69
|
+
|
70
|
+
# TODO: add PackageManagerLock exception
|
71
|
+
# FIXME: package manger may be locked
|
72
|
+
# Add sleep and ones again try if PackageManagerLock
|
73
|
+
# exception is cought
|
74
|
+
handler.handle(message) || @monitor.unignore(message)
|
75
|
+
@database.save(message)
|
76
|
+
|
77
|
+
true
|
78
|
+
end
|
79
|
+
|
80
|
+
# For syncing and other remove db access
|
81
|
+
def events
|
82
|
+
@database.events
|
83
|
+
end
|
84
|
+
|
85
|
+
def messages(*args)
|
86
|
+
@database.messages(*args)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'drb/drb'
|
2
|
+
require 'evesync/log'
|
3
|
+
require 'evesync/ipc/ipc'
|
4
|
+
|
5
|
+
module Evesync
|
6
|
+
module IPC
|
7
|
+
class Client
|
8
|
+
include IPC
|
9
|
+
|
10
|
+
attr_reader :ip, :uri
|
11
|
+
|
12
|
+
def initialize(params)
|
13
|
+
check_params_provided(params, [:port])
|
14
|
+
port = get_port(params)
|
15
|
+
@ip = params[:ip] || 'localhost' # TODO: check ip
|
16
|
+
@uri = "druby://#{@ip}:#{port}"
|
17
|
+
# to remote calls for unmarshallable objects
|
18
|
+
DRb.start_service
|
19
|
+
end
|
20
|
+
|
21
|
+
# TODO: add callbacks
|
22
|
+
def method_missing(method, *args, &block)
|
23
|
+
Log.debug("RPC Client calling '#{method}' on #{@uri}")
|
24
|
+
# FIXME: don't send +start+ and +stop+ and +initialize+
|
25
|
+
begin
|
26
|
+
service = DRbObject.new_with_uri(@uri)
|
27
|
+
res = service.send(method, *args, &block)
|
28
|
+
Log.debug("RPC Client method '#{method}' handled on #{@uri}")
|
29
|
+
res
|
30
|
+
rescue StandardError
|
31
|
+
Log.warn("RPC Client ERROR: no connection")
|
32
|
+
nil
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'evesync/ipc/data/hashable'
|
2
|
+
require 'evesync/ntp'
|
3
|
+
|
4
|
+
module Evesync
|
5
|
+
module IPC
|
6
|
+
module Data
|
7
|
+
class File
|
8
|
+
include Hashable
|
9
|
+
extend Unhashable
|
10
|
+
|
11
|
+
module Action
|
12
|
+
MODIFY = :modify # File was modified
|
13
|
+
DELETE = :delete # File was deleted
|
14
|
+
MOVED_TO = :moved_to # File was renamed
|
15
|
+
CREATE = :create # File was created
|
16
|
+
end
|
17
|
+
|
18
|
+
attr_reader :name, :mode, :action, :timestamp
|
19
|
+
|
20
|
+
def initialize(params)
|
21
|
+
@name = params[:name].freeze
|
22
|
+
@mode = params[:mode].freeze
|
23
|
+
@action = parse_action(params[:action]).freeze
|
24
|
+
@timestamp = params[:timestamp] || NTP.timestamp
|
25
|
+
@content = params[:content] || IO.read(@name).freeze if ::File.exist? @name
|
26
|
+
end
|
27
|
+
|
28
|
+
def ==(other)
|
29
|
+
(@name == other.name) &&
|
30
|
+
(@action == other.action) &&
|
31
|
+
(@mode == other.mode)
|
32
|
+
# timestamps may differ
|
33
|
+
# conten comparing may cost too much
|
34
|
+
end
|
35
|
+
|
36
|
+
# The content of a file for remote call. Sends as
|
37
|
+
# a plain text(?), no extra calls between machines.
|
38
|
+
#
|
39
|
+
# = TODO
|
40
|
+
# * Think about binary data
|
41
|
+
# * Encoding information
|
42
|
+
# * Large file sending
|
43
|
+
attr_reader :content
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def parse_action(action)
|
48
|
+
case action.to_s
|
49
|
+
when /modify/i
|
50
|
+
result = Action::MODIFY
|
51
|
+
when /delete/i
|
52
|
+
result = Action::DELETE
|
53
|
+
when /moved_to/i
|
54
|
+
result = Action::MOVED_TO
|
55
|
+
when /create/i
|
56
|
+
result = Action::CREATE
|
57
|
+
end
|
58
|
+
|
59
|
+
result
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
require 'evesync/log'
|
2
|
+
require 'json'
|
3
|
+
|
4
|
+
module Evesync
|
5
|
+
module IPC
|
6
|
+
module Data
|
7
|
+
# The class, that includes it must implement method
|
8
|
+
# *initialize(params)*
|
9
|
+
# This is a MUST BE requirement
|
10
|
+
#
|
11
|
+
module Hashable
|
12
|
+
def to_hash
|
13
|
+
hash = {}
|
14
|
+
instance_variables.each do |var|
|
15
|
+
value = instance_variable_get(var)
|
16
|
+
|
17
|
+
if value.respond_to? :to_hash
|
18
|
+
# FIXME: if it wasn't implemented it'll be an error
|
19
|
+
# for a complex type
|
20
|
+
hash[var] = value.to_hash
|
21
|
+
hash[var]['type'] = value.class.to_s
|
22
|
+
else
|
23
|
+
hash[var] = value
|
24
|
+
end
|
25
|
+
hash['type'] = self.class.to_s
|
26
|
+
end
|
27
|
+
Log.debug("IPC Data message hash created: #{hash}")
|
28
|
+
hash
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
module Unhashable
|
33
|
+
def from_hash(hash)
|
34
|
+
Log.debug("IPC Data message hash parsing: #{hash}")
|
35
|
+
params = {}
|
36
|
+
hash.each do |key, value|
|
37
|
+
next unless key =~ /^@/
|
38
|
+
|
39
|
+
if value.is_a? Hash
|
40
|
+
# FIXME: code dumplication ipc_data.rb:31
|
41
|
+
begin
|
42
|
+
cl = Object.const_get value['type']
|
43
|
+
rescue NameError => e
|
44
|
+
Log.fatal("IPC Data Unsupported type: #{hash['type']}")
|
45
|
+
raise e
|
46
|
+
end
|
47
|
+
|
48
|
+
unless cl.respond_to? :from_hash
|
49
|
+
err_msg = "IPC Data ERROR Class #{cl} must implement `self.from_hash'"
|
50
|
+
Log.fatal(err_msg)
|
51
|
+
raise err_msg
|
52
|
+
end
|
53
|
+
|
54
|
+
complex_value = cl.from_hash value
|
55
|
+
params[key.sub('@', '').to_sym] = complex_value
|
56
|
+
else
|
57
|
+
params[key.sub('@', '').to_sym] = value
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
begin
|
62
|
+
# If the `type' is imported it will be used
|
63
|
+
cl = Object.const_get hash['type']
|
64
|
+
rescue TypeError, NameError
|
65
|
+
# Or the base class will be the type
|
66
|
+
cl = self
|
67
|
+
end
|
68
|
+
|
69
|
+
cl.new(params)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'evesync/ipc/data/hashable'
|
2
|
+
|
3
|
+
module Evesync
|
4
|
+
module IPC
|
5
|
+
module Data
|
6
|
+
class Ignore
|
7
|
+
include Hashable
|
8
|
+
extend Unhashable
|
9
|
+
|
10
|
+
attr_reader :subject
|
11
|
+
|
12
|
+
def initialize(params)
|
13
|
+
@subject = params[:subject]
|
14
|
+
end
|
15
|
+
|
16
|
+
def to_s
|
17
|
+
"Ignoring: #{@subject}"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'evesync/ipc/data/hashable'
|
2
|
+
|
3
|
+
module Evesync
|
4
|
+
module IPC
|
5
|
+
module Data
|
6
|
+
class Package
|
7
|
+
include Data::Hashable
|
8
|
+
extend Data::Unhashable
|
9
|
+
|
10
|
+
module Command
|
11
|
+
INSTALL = :install
|
12
|
+
UPDATE = :update
|
13
|
+
DOWNGRADE = :downgrade
|
14
|
+
REMOVE = :remove
|
15
|
+
UNKNOWN = :unknown
|
16
|
+
end
|
17
|
+
|
18
|
+
attr_reader :name, :version, :command, :timestamp
|
19
|
+
|
20
|
+
def initialize(params)
|
21
|
+
@name = params[:name].freeze
|
22
|
+
@version = params[:version].freeze
|
23
|
+
@command = parse_command(params[:command]).freeze
|
24
|
+
@timestamp = params[:timestamp] || NTP.timestamp
|
25
|
+
end
|
26
|
+
|
27
|
+
def ==(pkg)
|
28
|
+
(pkg.name == @name) &&
|
29
|
+
(pkg.version == @version) &&
|
30
|
+
(pkg.command == @command)
|
31
|
+
end
|
32
|
+
|
33
|
+
def to_s
|
34
|
+
"Package(#{@command.upcase}: #{name}-#{@version})"
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def parse_command(command)
|
40
|
+
cmd = case command
|
41
|
+
when /^inst\w+$/
|
42
|
+
Command::INSTALL
|
43
|
+
when /^(remove\w*|delete\w*)$/
|
44
|
+
Command::REMOVE
|
45
|
+
when /^(update\w*|upgrade\w*)$/
|
46
|
+
Command::UPDATE
|
47
|
+
when /^downgrade\w*$/
|
48
|
+
Command::DOWNGRADE
|
49
|
+
else
|
50
|
+
Command::UNKNOWN
|
51
|
+
end
|
52
|
+
|
53
|
+
cmd.to_s
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
Dir[File.dirname(__FILE__) + '/*.rb'].each do |file|
|
2
|
+
require file unless file.include?(__FILE__)
|
3
|
+
end
|
4
|
+
|
5
|
+
module Evesync
|
6
|
+
module IPC
|
7
|
+
module Data
|
8
|
+
def self.from_json(json)
|
9
|
+
hash = JSON.parse(json)
|
10
|
+
Class.new.extend(Unhashable).from_hash(hash)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'drb/drb'
|
2
|
+
|
3
|
+
# TODO: add custom exceptions for IPCData
|
4
|
+
module Evesync
|
5
|
+
module IPCData
|
6
|
+
def self.pack(message)
|
7
|
+
unless message.respond_to? :to_hash
|
8
|
+
err_msg = "IPC ERROR Instance #{message} must implement `to_hash'"
|
9
|
+
Log.fatal(err_msg)
|
10
|
+
raise err_msg
|
11
|
+
end
|
12
|
+
|
13
|
+
hash = message.to_hash
|
14
|
+
|
15
|
+
hash.to_json
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.unpack(message)
|
19
|
+
unless message.is_a? String
|
20
|
+
raise "IPC ERROR message #{message} must be of type String"
|
21
|
+
end
|
22
|
+
|
23
|
+
begin
|
24
|
+
hash = JSON.parse(message)
|
25
|
+
rescue JSON::ParseError => e
|
26
|
+
Log.fatal("IPC ERROR Unable to parse message #{message}")
|
27
|
+
raise e
|
28
|
+
end
|
29
|
+
|
30
|
+
begin
|
31
|
+
Log.debug("IPC Accepted basic hash #{hash}")
|
32
|
+
cl = Object.const_get hash['type']
|
33
|
+
rescue NameError => e
|
34
|
+
# FIXME: just sent JSON, this event will be delegated
|
35
|
+
# to another daemon (maybe) with fields:
|
36
|
+
# redirect_to_port: <port number>
|
37
|
+
Log.fatal("Unsupported basic type #{hash['type']}")
|
38
|
+
raise e
|
39
|
+
end
|
40
|
+
|
41
|
+
unless cl.respond_to? :from_hash
|
42
|
+
err_msg = "IPC ERROR Class #{cl} must implement `self.from_hash'"
|
43
|
+
Log.fatal(err_msg)
|
44
|
+
raise err_msg
|
45
|
+
end
|
46
|
+
|
47
|
+
cl.from_hash hash
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'evesync/config'
|
2
|
+
|
3
|
+
module Evesync
|
4
|
+
#
|
5
|
+
# Constants and helpful functions for Evesync::IPC module.
|
6
|
+
#
|
7
|
+
module IPC
|
8
|
+
$SAFE = 1 # 'no eval' rule
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
# Checks if params have the provided keys
|
13
|
+
#
|
14
|
+
# [*Raise*] RuntimeError if params don't include on of the
|
15
|
+
# keys
|
16
|
+
def check_params_provided(params, keys)
|
17
|
+
keys.each do |param|
|
18
|
+
raise ":#{param} missed" unless
|
19
|
+
params.key?(param)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# Maps symbols like :evemond, :evehand to appropriate
|
24
|
+
# port number.
|
25
|
+
#
|
26
|
+
# [*Return*] Port number, if it's in (49152..65535)
|
27
|
+
# or one of daemons' name
|
28
|
+
def get_port(params)
|
29
|
+
port = params[:port]
|
30
|
+
if port.is_a? Symbol
|
31
|
+
Config[port.to_s]['port']
|
32
|
+
else
|
33
|
+
port_i = port.to_i
|
34
|
+
unless (port_i < 65_535) && (port_i > 49_152)
|
35
|
+
raise RuntimeError.call('Port MUST be in (49152..65535)')
|
36
|
+
end
|
37
|
+
|
38
|
+
port
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'drb/drb'
|
2
|
+
require 'evesync/log'
|
3
|
+
require 'evesync/ipc/ipc'
|
4
|
+
|
5
|
+
module Evesync
|
6
|
+
module IPC
|
7
|
+
|
8
|
+
##
|
9
|
+
# Server is a DRb object, using +:port+ and +:proxy+
|
10
|
+
# object to handle requests.
|
11
|
+
#
|
12
|
+
# = Params
|
13
|
+
#
|
14
|
+
# [*:proxy*] all methods go to this object
|
15
|
+
# [*:port*] defines which port which port connect to
|
16
|
+
#
|
17
|
+
# = Example:
|
18
|
+
#
|
19
|
+
# # Setup the server
|
20
|
+
# server = Evesync::IPC::Server(
|
21
|
+
# :port => '8089',
|
22
|
+
# :proxy => SomeHandler.new
|
23
|
+
# )
|
24
|
+
# ...
|
25
|
+
# server.start # now it starts recieving requests
|
26
|
+
# ...
|
27
|
+
# server.stop # main thread exits
|
28
|
+
#
|
29
|
+
# TODO:
|
30
|
+
# * Handle blocks
|
31
|
+
|
32
|
+
class Server
|
33
|
+
include IPC
|
34
|
+
|
35
|
+
attr_reader :uri
|
36
|
+
|
37
|
+
def initialize(params)
|
38
|
+
check_params_provided(params, %i[port proxy])
|
39
|
+
port = get_port params
|
40
|
+
ip = params[:ip] || 'localhost'
|
41
|
+
@uri = "druby://#{ip}:#{port}"
|
42
|
+
@proxy = params[:proxy]
|
43
|
+
end
|
44
|
+
|
45
|
+
def start
|
46
|
+
DRb.start_service(@uri, @proxy)
|
47
|
+
self
|
48
|
+
end
|
49
|
+
|
50
|
+
def stop
|
51
|
+
DRb.thread.exit
|
52
|
+
self
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|