process_command 0.1.0
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.
- data/README.md +39 -0
- data/lib/process_command/base_receiver.rb +40 -0
- data/lib/process_command/logger.rb +19 -0
- data/lib/process_command/signal/command.rb +20 -0
- data/lib/process_command/signal/receiver.rb +55 -0
- data/lib/process_command/signal/sender.rb +37 -0
- data/lib/process_command/signal/setting.rb +41 -0
- data/lib/process_command/socket/receiver.rb +33 -0
- data/lib/process_command/socket/sender.rb +26 -0
- data/lib/process_command/socket/setting.rb +31 -0
- data/lib/process_command.rb +57 -0
- metadata +61 -0
data/README.md
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# ProcessCommand
|
|
2
|
+
|
|
3
|
+
Interprocess communication with command for ruby
|
|
4
|
+
|
|
5
|
+
## Usage
|
|
6
|
+
|
|
7
|
+
#in receiver process(pid: 9999)
|
|
8
|
+
require 'process_command'
|
|
9
|
+
ProcessCommand.init_receiver
|
|
10
|
+
ProcessCommand.on(:pause) { p "server paused" }
|
|
11
|
+
ProcessCommand.on(:resume) { p "server resumed" }
|
|
12
|
+
|
|
13
|
+
#in sender process
|
|
14
|
+
require 'process_command'
|
|
15
|
+
ProcessCommand.send :pause, 9999
|
|
16
|
+
|
|
17
|
+
## Mode
|
|
18
|
+
|
|
19
|
+
* Unix socket (default)
|
|
20
|
+
|
|
21
|
+
ProcessCommand.mode = :socket
|
|
22
|
+
|
|
23
|
+
* Signal
|
|
24
|
+
|
|
25
|
+
ProcessCommand.mode = :signal
|
|
26
|
+
|
|
27
|
+
## Customization
|
|
28
|
+
|
|
29
|
+
For logger
|
|
30
|
+
|
|
31
|
+
ProcessCommand.logger = ProcessCommand::Logger
|
|
32
|
+
|
|
33
|
+
For mode socket, default path /tmp, you can change it
|
|
34
|
+
ProcessCommand::Socket::Setting.set_path(path)
|
|
35
|
+
|
|
36
|
+
For mode signal, default signals are USR1, USR2, HUP, you can change them both in sender and receiver
|
|
37
|
+
|
|
38
|
+
ProcessCommand::Signal::Setting.set_bits(bit0_signal, bit1_signal)
|
|
39
|
+
ProcessCommand::Signal::Setting.set_control(control_signal)
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
module ProcessCommand
|
|
2
|
+
|
|
3
|
+
class BaseReceiver
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class << self
|
|
7
|
+
|
|
8
|
+
def init
|
|
9
|
+
init_listener
|
|
10
|
+
Thread.new do
|
|
11
|
+
init_handler
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def add_command_block(command, block)
|
|
16
|
+
@command_blocks ||= {}
|
|
17
|
+
@command_blocks[command.to_s] = block
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def run_command_block(command)
|
|
21
|
+
command = command.to_s
|
|
22
|
+
block = @command_blocks[command]
|
|
23
|
+
if block
|
|
24
|
+
Thread.new do
|
|
25
|
+
begin
|
|
26
|
+
block.call
|
|
27
|
+
rescue Exception => e
|
|
28
|
+
ProcessCommand.logger.error "block execute error for command (#{command}), error: #{e.message}"
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
else
|
|
32
|
+
ProcessCommand.logger.error "block not found for command (#{command})"
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
module ProcessCommand
|
|
2
|
+
|
|
3
|
+
module Signal
|
|
4
|
+
|
|
5
|
+
class Command
|
|
6
|
+
|
|
7
|
+
def self.i2s(command)
|
|
8
|
+
command.to_s(16).scan(/.{2}/).map{|c| c.to_i(16).chr}.join
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def self.s2i(command)
|
|
12
|
+
command.to_s.each_char.map{|c| c.ord.to_s(16)}.join.to_i(16)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
end
|
|
20
|
+
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
module ProcessCommand
|
|
2
|
+
|
|
3
|
+
module Signal
|
|
4
|
+
|
|
5
|
+
class Receiver < ProcessCommand::BaseReceiver
|
|
6
|
+
|
|
7
|
+
class << self
|
|
8
|
+
|
|
9
|
+
attr_accessor :command
|
|
10
|
+
RECEIVER_QUEUE = Queue.new
|
|
11
|
+
|
|
12
|
+
def init
|
|
13
|
+
@command = 0
|
|
14
|
+
super
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def init_listener
|
|
18
|
+
::Signal.trap(Setting.bit0) do
|
|
19
|
+
Thread.new{ RECEIVER_QUEUE << 0}
|
|
20
|
+
end
|
|
21
|
+
::Signal.trap(Setting.bit1) do
|
|
22
|
+
Thread.new{ RECEIVER_QUEUE << 1}
|
|
23
|
+
end
|
|
24
|
+
::Signal.trap(Setting.control) do
|
|
25
|
+
Thread.new{ RECEIVER_QUEUE << :control}
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def init_handler
|
|
30
|
+
while value = RECEIVER_QUEUE.pop
|
|
31
|
+
command = Receiver.command
|
|
32
|
+
case value
|
|
33
|
+
when 0
|
|
34
|
+
command <<= 1
|
|
35
|
+
when 1
|
|
36
|
+
command <<= 1
|
|
37
|
+
command |= 1
|
|
38
|
+
when :control
|
|
39
|
+
run_command_block Command.i2s(command) if command
|
|
40
|
+
command = 0
|
|
41
|
+
else
|
|
42
|
+
ProcessCommand.logger.error "illegal value #{value}, reset command 0"
|
|
43
|
+
command = 0
|
|
44
|
+
end
|
|
45
|
+
self.command = command
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
module ProcessCommand
|
|
2
|
+
|
|
3
|
+
module Signal
|
|
4
|
+
|
|
5
|
+
class Sender
|
|
6
|
+
|
|
7
|
+
SENDER_LOCK = Mutex.new
|
|
8
|
+
DEFAULT_DELAY = 0.05
|
|
9
|
+
|
|
10
|
+
class << self
|
|
11
|
+
|
|
12
|
+
def set_delay(delay)
|
|
13
|
+
@delay = delay
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def send(command, pid)
|
|
17
|
+
@delay ||= DEFAULT_DELAY
|
|
18
|
+
command = Command.s2i(command).to_s(2)
|
|
19
|
+
return if command.empty?
|
|
20
|
+
SENDER_LOCK.synchronize do
|
|
21
|
+
while bit = command.slice!(0)
|
|
22
|
+
signal = bit == '0' ? Setting.bit0 : Setting.bit1
|
|
23
|
+
Process.kill(signal, pid)
|
|
24
|
+
sleep @delay
|
|
25
|
+
end
|
|
26
|
+
Process.kill(Setting.control, pid)
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
module ProcessCommand
|
|
2
|
+
|
|
3
|
+
module Signal
|
|
4
|
+
|
|
5
|
+
class Setting
|
|
6
|
+
|
|
7
|
+
DEFAULT_BIT0 = :USR1
|
|
8
|
+
DEFAULT_BIT1 = :USR2
|
|
9
|
+
DEFAULT_CONTROL = :HUP
|
|
10
|
+
|
|
11
|
+
class << self
|
|
12
|
+
|
|
13
|
+
def set_bits(bit0, bit1)
|
|
14
|
+
@bit0 = bit0
|
|
15
|
+
@bit1 = bit1
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def set_control(control)
|
|
19
|
+
@control = control
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def bit0
|
|
23
|
+
@bit0 ||= DEFAULT_BIT0
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def bit1
|
|
27
|
+
@bit1 ||= DEFAULT_BIT1
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def control
|
|
31
|
+
@control ||= DEFAULT_CONTROL
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
end
|
|
41
|
+
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
require 'socket'
|
|
2
|
+
module ProcessCommand
|
|
3
|
+
|
|
4
|
+
module Socket
|
|
5
|
+
|
|
6
|
+
class Receiver < ProcessCommand::BaseReceiver
|
|
7
|
+
|
|
8
|
+
class << self
|
|
9
|
+
|
|
10
|
+
RECEIVER_QUEUE = Queue.new
|
|
11
|
+
|
|
12
|
+
def init_listener
|
|
13
|
+
path = Setting.socket_path Process.pid
|
|
14
|
+
File.delete path if File.exists? path
|
|
15
|
+
@server = UNIXServer.new path
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def init_handler
|
|
19
|
+
while client = @server.accept
|
|
20
|
+
Thread.new do
|
|
21
|
+
command = client.read
|
|
22
|
+
run_command_block command
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
require 'socket'
|
|
2
|
+
module ProcessCommand
|
|
3
|
+
|
|
4
|
+
module Socket
|
|
5
|
+
|
|
6
|
+
class Sender
|
|
7
|
+
|
|
8
|
+
class << self
|
|
9
|
+
|
|
10
|
+
def send(command, pid)
|
|
11
|
+
command = command.to_s
|
|
12
|
+
path = Setting.socket_path pid
|
|
13
|
+
server = UNIXSocket.new path
|
|
14
|
+
server.write command
|
|
15
|
+
server.close
|
|
16
|
+
rescue Exception => e
|
|
17
|
+
ProcessCommand.logger.error "send error, #{e.message}"
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
module ProcessCommand
|
|
2
|
+
|
|
3
|
+
module Socket
|
|
4
|
+
|
|
5
|
+
class Setting
|
|
6
|
+
|
|
7
|
+
DEFAULT_PATH = "/tmp"
|
|
8
|
+
|
|
9
|
+
class << self
|
|
10
|
+
|
|
11
|
+
def set_path(path)
|
|
12
|
+
@path = path
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def path
|
|
16
|
+
@path ||= DEFAULT_PATH
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def socket_path(pid)
|
|
20
|
+
"#{self.path}/process_command_#{pid}.sock"
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
end
|
|
31
|
+
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
require 'process_command/base_receiver'
|
|
2
|
+
require 'process_command/logger'
|
|
3
|
+
require 'process_command/signal/command'
|
|
4
|
+
require 'process_command/signal/setting'
|
|
5
|
+
require 'process_command/signal/receiver'
|
|
6
|
+
require 'process_command/signal/sender'
|
|
7
|
+
require 'process_command/socket/setting'
|
|
8
|
+
require 'process_command/socket/receiver'
|
|
9
|
+
require 'process_command/socket/sender'
|
|
10
|
+
require 'active_support/core_ext/module/attribute_accessors'
|
|
11
|
+
|
|
12
|
+
module ProcessCommand
|
|
13
|
+
|
|
14
|
+
mattr_accessor :mode
|
|
15
|
+
mattr_accessor :logger
|
|
16
|
+
|
|
17
|
+
def self.receiver
|
|
18
|
+
case self.mode
|
|
19
|
+
when :signal
|
|
20
|
+
ProcessCommand::Signal::Receiver
|
|
21
|
+
when :socket
|
|
22
|
+
ProcessCommand::Socket::Receiver
|
|
23
|
+
else
|
|
24
|
+
nil
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def self.sender
|
|
29
|
+
case self.mode
|
|
30
|
+
when :signal
|
|
31
|
+
ProcessCommand::Signal::Sender
|
|
32
|
+
when :socket
|
|
33
|
+
ProcessCommand::Socket::Sender
|
|
34
|
+
else
|
|
35
|
+
nil
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def self.init_receiver
|
|
40
|
+
self.receiver.init
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
#for receiver
|
|
44
|
+
def self.on(command, &block)
|
|
45
|
+
self.receiver.add_command_block command, block
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
#for sender
|
|
49
|
+
def self.send(command, pid)
|
|
50
|
+
self.sender.send(command, pid)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
ProcessCommand.mode = :socket #:signal
|
|
56
|
+
ProcessCommand.logger = ProcessCommand::Logger
|
|
57
|
+
|
metadata
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: process_command
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
prerelease:
|
|
6
|
+
platform: ruby
|
|
7
|
+
authors:
|
|
8
|
+
- Leon Li
|
|
9
|
+
autorequire:
|
|
10
|
+
bindir: bin
|
|
11
|
+
cert_chain: []
|
|
12
|
+
date: 2012-04-06 00:00:00.000000000Z
|
|
13
|
+
dependencies: []
|
|
14
|
+
description: Interprocess communication with command for ruby
|
|
15
|
+
email: qianthinking@gmail.com
|
|
16
|
+
executables: []
|
|
17
|
+
extensions: []
|
|
18
|
+
extra_rdoc_files: []
|
|
19
|
+
files:
|
|
20
|
+
- lib/process_command/base_receiver.rb
|
|
21
|
+
- lib/process_command/logger.rb
|
|
22
|
+
- lib/process_command/signal/receiver.rb
|
|
23
|
+
- lib/process_command/signal/command.rb
|
|
24
|
+
- lib/process_command/signal/setting.rb
|
|
25
|
+
- lib/process_command/signal/sender.rb
|
|
26
|
+
- lib/process_command/socket/receiver.rb
|
|
27
|
+
- lib/process_command/socket/setting.rb
|
|
28
|
+
- lib/process_command/socket/sender.rb
|
|
29
|
+
- lib/process_command.rb
|
|
30
|
+
- README.md
|
|
31
|
+
homepage: https://github.com/qianthinking/process_command
|
|
32
|
+
licenses: []
|
|
33
|
+
post_install_message:
|
|
34
|
+
rdoc_options:
|
|
35
|
+
- --line-numbers
|
|
36
|
+
- --inline-source
|
|
37
|
+
- --title
|
|
38
|
+
- RAlgorithms
|
|
39
|
+
- --main
|
|
40
|
+
- README.md
|
|
41
|
+
require_paths:
|
|
42
|
+
- lib
|
|
43
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
44
|
+
none: false
|
|
45
|
+
requirements:
|
|
46
|
+
- - ! '>='
|
|
47
|
+
- !ruby/object:Gem::Version
|
|
48
|
+
version: '0'
|
|
49
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
50
|
+
none: false
|
|
51
|
+
requirements:
|
|
52
|
+
- - ! '>='
|
|
53
|
+
- !ruby/object:Gem::Version
|
|
54
|
+
version: '1.2'
|
|
55
|
+
requirements: []
|
|
56
|
+
rubyforge_project:
|
|
57
|
+
rubygems_version: 1.8.10
|
|
58
|
+
signing_key:
|
|
59
|
+
specification_version: 2
|
|
60
|
+
summary: Interprocess communication with command for ruby.
|
|
61
|
+
test_files: []
|