Class: Winsvc::Service

Inherits:
Object
  • Object
show all
Defined in:
lib/winsvc.rb

Overview

The object yielded to the Winsvc.run block. A plain Ruby object holding no native pointer; all methods are safe from any thread or fiber.

Instance Method Summary collapse

Constructor Details

#initialize(name, mode, queue) ⇒ Service

name frozen UTF-8; mode :service or :console; queue the control queue.



146
147
148
149
150
151
# File 'lib/winsvc.rb', line 146

def initialize(name, mode, queue)
  @name  = name
  @mode  = mode
  @queue = queue
  @args  = nil
end

Instance Method Details

#argsObject

In service mode, the ServiceMain start parameters minus argv (which Windows sets to the service name). In console mode, a frozen copy of ARGV. Frozen array of frozen UTF-8 strings; computed once, memoized.



169
170
171
172
173
174
175
176
177
178
# File 'lib/winsvc.rb', line 169

def args
  @args ||=
    if service?
      raw = Winsvc.send(:_host_args)
      raw.shift # drop argv[0] (the service name)
      raw.map(&:freeze).freeze
    else
      ARGV.map { |a| a.dup.freeze }.freeze
    end
end

#checkpoint!(wait_hint: nil) ⇒ Object

Re-report the current pending state with dwCheckPoint + 1. wait_hint (ms) overrides the hint for this report. No-op when no transition is pending. Call only on real progress. Raises ArgumentError on a non-positive hint.



233
234
235
236
237
238
239
240
241
242
243
244
245
246
# File 'lib/winsvc.rb', line 233

def checkpoint!(wait_hint: nil)
  hint =
    if wait_hint.nil?
      -1
    else
      unless wait_hint.is_a?(Integer) && wait_hint > 0
        raise ArgumentError, "winsvc: wait_hint must be a positive Integer, got #{wait_hint.inspect}"
      end

      wait_hint
    end
  Winsvc.send(:_checkpoint, hint) if service?
  self
end

#console?Boolean

Returns:

  • (Boolean)


162
163
164
# File 'lib/winsvc.rb', line 162

def console?
  @mode == :console
end

#each_controlObject

wait in a loop, yielding every control INCLUDING the final stop-class one, then return it. Raises ArgumentError without a block.

Raises:

  • (ArgumentError)


204
205
206
207
208
209
210
211
212
213
214
# File 'lib/winsvc.rb', line 204

def each_control
  raise ArgumentError, "winsvc: each_control requires a block" unless block_given?

  loop do
    c = wait
    break c if c.nil?

    yield c
    break c if c.stop?
  end
end

#nameObject

The name passed to run (frozen UTF-8).



154
155
156
# File 'lib/winsvc.rb', line 154

def name
  @name
end

#paused!Object

Report SERVICE_PAUSED (accept mask kept). Call after handling :pause.



225
226
227
228
# File 'lib/winsvc.rb', line 225

def paused!
  Winsvc.send(:_set_paused) if service?
  self
end

#running!Object Also known as: ready!

Report SERVICE_RUNNING with the configured accept mask. Used to leave START_PENDING (manual_ready: true) and to resume after :continue.



218
219
220
221
# File 'lib/winsvc.rb', line 218

def running!
  Winsvc.send(:_set_running) if service?
  self
end

#service?Boolean

Returns:

  • (Boolean)


158
159
160
# File 'lib/winsvc.rb', line 158

def service?
  @mode == :service
end

#stop_requested?Boolean

Non-blocking. True from the instant the C handler saw STOP/SHUTDOWN/ PRESHUTDOWN (interlocked flag — earlier than queue delivery), or after the first console Ctrl-C.

Returns:

  • (Boolean)


198
199
200
# File 'lib/winsvc.rb', line 198

def stop_requested?
  Winsvc.send(:_stop_requested)
end

#wait(timeout: nil) ⇒ Object

Pop the next control from the queue. timeout in seconds (nil = block forever). Returns nil on timeout, and nil immediately once run has torn down (the queue is closed). Under a Fiber scheduler the calling fiber parks; without one it blocks the thread (GVL released by MRI).



184
185
186
187
188
189
190
191
192
193
# File 'lib/winsvc.rb', line 184

def wait(timeout: nil)
  ms = Winsvc.send(:secs_to_timeout, timeout)
  if ms.nil?
    @queue.pop # block forever (returns nil when the queue is closed)
  else
    @queue.pop(timeout: ms)
  end
rescue ClosedQueueError
  nil
end