process_command 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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,19 @@
1
+ module ProcessCommand
2
+
3
+ class Logger
4
+
5
+ class << self
6
+
7
+ def info(message)
8
+ p "INFO: #{message}"
9
+ end
10
+
11
+ def error(message)
12
+ p "ERROR: #{message}"
13
+ end
14
+
15
+ end
16
+
17
+ end
18
+
19
+ 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: []