evesync 1.0.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|