Class: AgentsControl::Daemon

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

Overview

Brings everything together: receiving hooks from agents and talking to Telegram.

One process, because one Telegram token allows exactly one update reader, and a thread waiting on a question's answer has to get that answer from the same process that asked it.

Constant Summary collapse

DEFAULT_PORT =

The port is fixed, not picked freely on every start: the address is written into an agent's own settings and has to survive a daemon restart, or every restart would leave hooks firing into nothing.

47_653

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(config: nil, store: nil, secrets: nil, logger: $stdout) ⇒ Daemon

Returns a new instance of Daemon.



18
19
20
21
22
23
24
25
26
27
28
# File 'lib/agents_control/daemon.rb', line 18

def initialize(config: nil, store: nil, secrets: nil, logger: $stdout)
  @config = config || Config.load
  @store = store || Store.new
  @secrets = secrets || Secrets.new
  @logger = logger

  # Without this, output buffers until the process exits. Under
  # launchd that means an empty log for a daemon that's actually
  # running — blind exactly when the log is what you'd reach for.
  @logger.sync = true if @logger.respond_to?(:sync=)
end

Instance Attribute Details

#botObject (readonly)

Returns the value of attribute bot.



30
31
32
# File 'lib/agents_control/daemon.rb', line 30

def bot
  @bot
end

Instance Method Details

#away_labelObject



81
82
83
# File 'lib/agents_control/daemon.rb', line 81

def away_label
  @config.get("answers.away", false) ? "away — questions go to Telegram" : "present — notifications only"
end

#pendingObject

Exposed: the console needs to show how many questions are currently waiting for an answer.



34
# File 'lib/agents_control/daemon.rb', line 34

def pending = @pending ||= Pending.new

#ready?Boolean

Returns:

  • (Boolean)


85
86
87
88
89
90
91
# File 'lib/agents_control/daemon.rb', line 85

def ready?
  return fail_with("Token not found. Enter /token or run agents_control setup") unless
    @secrets.get(:telegram_token)
  return fail_with("The allowed-chats list is empty. Run: agents_control setup") if chats.empty?

  true
end

#runObject



71
72
73
74
75
76
77
78
79
# File 'lib/agents_control/daemon.rb', line 71

def run
  return false unless start

  Signal.trap("INT") { @bot&.stop }
  Signal.trap("TERM") { @bot&.stop }
  wait
ensure
  stop
end

#startObject

Bring everything up and return control immediately.

Split from waiting for the sake of the interactive console: it holds its own input loop while the daemon runs alongside. The daemon command is this same start plus waiting.



41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
# File 'lib/agents_control/daemon.rb', line 41

def start
  return false unless ready?

  start_hooks
  start_anchors
  start_screen_watcher
  start_rate_limit_watcher
  install_agents
  verify_hooks
  publish_commands
  start_bot

  log("hooks listening on #{server.url}, agents connected: #{installed_agents.size}")
  log("mode: #{away_label}")
  true
rescue Hooks::Server::PortBusy => e
  fail_with(e.message)
end

#stopObject



62
63
64
65
66
67
68
69
# File 'lib/agents_control/daemon.rb', line 62

def stop
  @bot&.stop
  server&.stop
  @scheduler&.stop
  @screen_watcher&.stop
  @rate_limit_watcher&.stop
  remove_agents
end

#waitObject



60
# File 'lib/agents_control/daemon.rb', line 60

def wait = @bot&.wait