Class: Sockd::Runner
- Inherits:
-
Object
- Object
- Sockd::Runner
- Defined in:
- lib/sockd/runner.rb
Defined Under Namespace
Classes: ServiceError
Instance Attribute Summary collapse
-
#name ⇒ Object
readonly
Returns the value of attribute name.
-
#options ⇒ Object
Returns the value of attribute options.
Instance Method Summary collapse
-
#handle(message = nil, socket = nil, &block) ⇒ Object
define our socket handler by providing a block, or trigger the callback with the provided message.
-
#initialize(name = nil, options = {}) {|_self| ... } ⇒ Runner
constructor
A new instance of Runner.
-
#log(message) ⇒ Object
output a timestamped log message.
-
#restart ⇒ Object
restart our service.
-
#safe_name ⇒ Object
generate a path-safe and username-safe string from our daemon name.
-
#send(message, timeout = 30) ⇒ Object
send a message to a running service and return the response.
-
#setup(&block) ⇒ Object
define a “setup” callback by providing a block, or trigger the callback.
-
#start ⇒ Object
start our service.
-
#stop ⇒ Object
stop our service.
-
#teardown(&block) ⇒ Object
define a “teardown” callback by providing a block, or trigger the callback.
Constructor Details
#initialize(name = nil, options = {}) {|_self| ... } ⇒ Runner
Returns a new instance of Runner.
16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
# File 'lib/sockd/runner.rb', line 16 def initialize(name = nil, = {}, &block) @name = name || File.basename($0) = { :host => "127.0.0.1", :port => 0, :socket => false, :mode => 0660, :daemonize => true, :pid_path => "/var/run/#{safe_name}.pid", :log_path => false, :force => false, :user => false, :group => false }.merge() [:setup, :teardown, :handle].each do |opt| self.public_send(opt, &[opt]) if [opt].respond_to?(:call) end yield self if block_given? end |
Instance Attribute Details
#name ⇒ Object (readonly)
Returns the value of attribute name.
10 11 12 |
# File 'lib/sockd/runner.rb', line 10 def name @name end |
#options ⇒ Object
Returns the value of attribute options.
10 11 12 |
# File 'lib/sockd/runner.rb', line 10 def end |
Instance Method Details
#handle(message = nil, socket = nil, &block) ⇒ Object
define our socket handler by providing a block, or trigger the callback with the provided message
65 66 67 68 69 |
# File 'lib/sockd/runner.rb', line 65 def handle( = nil, socket = nil, &block) return self if block_given? && @handle = block raise ArgumentError, "no message handler provided" unless @handle @handle.call(, socket) end |
#log(message) ⇒ Object
output a timestamped log message
161 162 163 |
# File 'lib/sockd/runner.rb', line 161 def log() puts Time.now.strftime('[%d-%b-%Y %H:%M:%S] ') + end |
#restart ⇒ Object
restart our service
142 143 144 145 |
# File 'lib/sockd/runner.rb', line 142 def restart stop start end |
#safe_name ⇒ Object
generate a path-safe and username-safe string from our daemon name
44 45 46 |
# File 'lib/sockd/runner.rb', line 44 def safe_name name.gsub(/(^[0-9]*|[^0-9a-z])/i, '') end |
#send(message, timeout = 30) ⇒ Object
send a message to a running service and return the response
148 149 150 151 152 153 154 155 156 157 158 |
# File 'lib/sockd/runner.rb', line 148 def send(, timeout = 30) client do |sock| sock.write "#{message}\r\n" ready = IO.select([sock], nil, nil, timeout) raise ServiceError, "timed out waiting for server response" unless ready sock.recv(256) end rescue Errno::ECONNREFUSED, Errno::ENOENT raise ServiceError, "#{name} process not running" unless daemon_running? raise ServiceError, "unable to establish connection" end |
#setup(&block) ⇒ Object
define a “setup” callback by providing a block, or trigger the callback
50 51 52 53 |
# File 'lib/sockd/runner.rb', line 50 def setup(&block) return self if block_given? && @setup = block @setup.call(self) if @setup end |
#start ⇒ Object
start our service
72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 |
# File 'lib/sockd/runner.rb', line 72 def start server do |server| if [:daemonize] pid = daemon_running? raise ServiceError, "#{name} process already running (#{pid})" if pid puts "starting #{name} process..." unless daemonize unless send('ping', 10).chomp == 'pong' raise ServiceError, "invalid ping response" end return self end end drop_privileges [:user], [:group] setup on_interrupt do |signal| log "#{signal} received, shutting down..." teardown # cleanup exit 130 end log "listening on #{server.local_address.inspect_sockaddr}" while true sock = server.accept begin # wait for input if IO.select([sock], nil, nil, 2.0) msg = sock.recv(256, Socket::MSG_PEEK) if msg.chomp == "ping" sock.print "pong\r\n" else handle msg, sock end else log "connection timed out" end rescue Errno::EPIPE, Errno::ECONNRESET log "connection broken" end sock.close unless sock.closed? end end end |
#stop ⇒ Object
stop our service
123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 |
# File 'lib/sockd/runner.rb', line 123 def stop if daemon_running? pid = stored_pid Process.kill('TERM', pid) puts "SIGTERM sent to #{name} (#{pid})" if !wait_until(2) { daemon_stopped? pid } && [:force] Process.kill('KILL', pid) puts "SIGKILL sent to #{name} (#{pid})" end raise ServiceError, "unable to stop #{name} process" if daemon_running? else warn "#{name} process not running" end self rescue Errno::EPERM => e raise ServiceError, "unable to stop #{name} process (#{e.message})" end |
#teardown(&block) ⇒ Object
define a “teardown” callback by providing a block, or trigger the callback
57 58 59 60 |
# File 'lib/sockd/runner.rb', line 57 def teardown(&block) return self if block_given? && @teardown = block @teardown.call(self) if @teardown end |