samagotchi 0.124.0 → 0.125.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.
Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +29 -1
  3. data/docs/architecture.md +4 -2
  4. data/docs/cli.md +20 -8
  5. data/docs/internals/participants.md +26 -1
  6. data/docs/internals/remote-sessions.md +2 -0
  7. data/docs/sessions.md +2 -2
  8. data/lib/samagotchi/bundles/system/manifest.yml +1 -1
  9. data/lib/samagotchi/process_group.rb +10 -1
  10. data/lib/samagotchi/reminder_carry.rb +92 -0
  11. data/lib/samagotchi/reminder_store.rb +49 -0
  12. data/lib/samagotchi/session_manager.rb +28 -4
  13. data/lib/samagotchi/sessions_command.rb +1 -1
  14. data/lib/samagotchi/terminal_ui/attached_loop/composer.rb +225 -0
  15. data/lib/samagotchi/terminal_ui/attached_loop/exit_commands.rb +138 -0
  16. data/lib/samagotchi/terminal_ui/attached_loop/questions.rb +225 -0
  17. data/lib/samagotchi/terminal_ui/attached_loop/queueing.rb +154 -0
  18. data/lib/samagotchi/terminal_ui/attached_loop/sending.rb +302 -0
  19. data/lib/samagotchi/terminal_ui/attached_loop.rb +16 -1253
  20. data/lib/samagotchi/terminal_ui/exit_lines.rb +141 -0
  21. data/lib/samagotchi/terminal_ui/join_replay.rb +235 -0
  22. data/lib/samagotchi/version.rb +1 -1
  23. data/lib/samagotchi/web/app.rb +7 -3
  24. data/lib/samagotchi/web/participants_admin.rb +15 -4
  25. data/lib/samagotchi/web/public/annotate_bar.css +8 -4
  26. data/lib/samagotchi/web/public/annotate_bar.js +34 -6
  27. data/lib/samagotchi/web/public/app.js +66 -5
  28. data/lib/samagotchi/web/public/claim_link.js +347 -0
  29. data/lib/samagotchi/web/public/participant.html +1 -0
  30. data/lib/samagotchi/web/public/participant.js +46 -4
  31. data/lib/samagotchi/web/public/participants_panel.js +15 -0
  32. data/lib/samagotchi/web/public/route.js +3 -2
  33. data/lib/samagotchi/web/public/tokens.css +2 -1
  34. data/lib/samagotchi/web/public/verify_preset.js +18 -0
  35. data/lib/samagotchi/worker.rb +57 -3
  36. data/lib/samagotchi/worker_idle_exit.rb +7 -6
  37. metadata +11 -1
@@ -21,6 +21,7 @@ require_relative "worker_signals"
21
21
  require_relative "worker_task_wakes"
22
22
  require_relative "session_manager"
23
23
  require_relative "archive_store"
24
+ require_relative "reminder_carry"
24
25
  require_relative "log"
25
26
  require_relative "turn_flow"
26
27
  require_relative "turn_checkpoint"
@@ -248,7 +249,11 @@ module Samagotchi
248
249
  drop_dead_question
249
250
  # The running turn, on disk at its iteration boundaries.
250
251
  @checkpoint = TurnCheckpoint.new(session: @session, state_dir: @state_dir)
252
+ # A restart's hand-off, checked before the Engine's build (its window
253
+ # runs from the leave) and restored into it after.
254
+ carried = take_carried_reminders
251
255
  @engine = build_engine
256
+ restore_carried_reminders(carried)
252
257
  @config_restart_unsubscribe = ConfigFile.watch_restart_settings!(process: :worker) do |message|
253
258
  @engine.announce(type: :hook_notice, hook: "config", text: message, level: :warn, between_turns: true)
254
259
  end
@@ -446,7 +451,9 @@ module Samagotchi
446
451
  return if run_task_wake
447
452
  return if run_due_reminders
448
453
  return left(:idle_exit) if @idle_exit.due? && leave_idle
449
- return left(@exit_restart ? :restart : :exit_requested) if @exit_requested && leave_on_request
454
+
455
+ leaving = @exit_requested && leave_on_request
456
+ return left(leaving) if leaving
450
457
 
451
458
  watch_participants
452
459
  @waker.wait(idle_wait)
@@ -1514,6 +1521,11 @@ module Samagotchi
1514
1521
  def exit_request(client_id, delete: false, restart: false, stop: false, ask: true)
1515
1522
  # The Bridge serves before the idle-exit policy exists.
1516
1523
  return WorkerIdleExit::Hold.new(reason: :starting) unless @idle_exit
1524
+ # One exit is already taken: the first one decides how the worker
1525
+ # leaves (a later stop-all can't turn a restart, whose reminders go to
1526
+ # the next worker, into a plain exit). Held at the leave, it is
1527
+ # forgotten and the next request counts again.
1528
+ return nil if @exit_requested
1517
1529
 
1518
1530
  if restart
1519
1531
  hold = @idle_exit.hold_for_restart
@@ -1551,7 +1563,8 @@ module Samagotchi
1551
1563
  # intake and stop the idle jobs (the Bridge stops after the log). Other clients' streams no longer hold: the asker's
1552
1564
  # may not have closed yet, and a UI joining now finds the worker gone
1553
1565
  # (:stream_closed), the window #leave_idle has too.
1554
- # @return [Boolean] false when something came in since the request
1566
+ # @return [Symbol, false] how it leaves (:restart or :exit_requested,
1567
+ # decided under the lock), false when something came in since the request
1555
1568
  def leave_on_request
1556
1569
  stop_bridge_after do
1557
1570
  @engine.synchronize_events do
@@ -1566,16 +1579,57 @@ module Samagotchi
1566
1579
  Log.info(:worker, "exit_held", reason: hold)
1567
1580
  next false
1568
1581
  end
1582
+ next false if @exit_restart && !carry_reminders
1569
1583
 
1570
1584
  @bridge&.close_intake
1571
1585
  # Not joined: a recap tick's emit waits for the event log held here.
1572
1586
  @engine.stop_idle(join: false)
1573
1587
  Log.info(:worker, @exit_restart ? "restart_requested" : "exit_requested", by: @exit_requested_by || "a client")
1574
- true
1588
+ @exit_restart ? :restart : :exit_requested
1575
1589
  end
1576
1590
  end
1577
1591
  end
1578
1592
 
1593
+ # A restart hands the reminders to the next worker (ReminderCarry), while
1594
+ # the event log is held: no turn can register or fire one from here. A
1595
+ # write that fails keeps this worker up with them rather than losing them.
1596
+ # A session stopped meanwhile drops them (run_session_loop then starts no
1597
+ # successor): nothing is written.
1598
+ # @return [Boolean] false when the write failed
1599
+ def carry_reminders
1600
+ if stopped_on_disk?
1601
+ ReminderCarry.remove(@session_dir)
1602
+ else
1603
+ ReminderCarry.write(@session_dir, session_id: @session_id, store: @engine.reminder_store)
1604
+ end
1605
+ true
1606
+ rescue StandardError => e
1607
+ @exit_requested = nil
1608
+ @exit_restart = false
1609
+ Log.warn(:worker, "reminders_carry_failed", error: e.class.name, msg: e.message)
1610
+ false
1611
+ end
1612
+
1613
+ # The reminders a restart handed over (#carry_reminders), read and
1614
+ # deleted; a stopped session drops them.
1615
+ # @return [Array<Hash>, nil] ReminderStore#export's entries
1616
+ def take_carried_reminders
1617
+ ReminderCarry.take(@session_dir, session_id: @session_id, stopped: stopped_on_disk?)
1618
+ rescue StandardError => e
1619
+ Log.warn(:worker, "reminders_carry_take_failed", error: e.class.name, msg: e.message)
1620
+ nil
1621
+ end
1622
+
1623
+ # Into the new Engine's store, before the idle scheduler starts polling it.
1624
+ def restore_carried_reminders(entries)
1625
+ return unless entries
1626
+
1627
+ names = @engine.reminder_store.restore(entries)
1628
+ Log.info(:worker, "reminders_carried", count: names.size)
1629
+ rescue StandardError => e
1630
+ Log.warn(:worker, "reminders_carry_restore_failed", error: e.class.name, msg: e.message)
1631
+ end
1632
+
1579
1633
  # @return [Symbol] +result+, with #discard? decided and, for a session
1580
1634
  # kept, its recap written: the Bridge is closed and the idle jobs are
1581
1635
  # stopped by now, and nothing waits on this (the TUI has detached). A
@@ -11,7 +11,8 @@ module Samagotchi
11
11
  # * a client holds the Bridge's stream (an attached TUI, even an idle one,
12
12
  # or a web tab);
13
13
  # * a reminder is registered. Reminders live only in the Engine and repeat
14
- # until the agent cancels them, so an exit would drop them for good;
14
+ # until the agent cancels them, so an exit would drop them for good (a
15
+ # restart hands them to the next worker instead: ReminderCarry);
15
16
  # * a continue offer waits for an answer; it too lives only in memory;
16
17
  # * a background task the worker watches for a finish wake (TaskWatch)
17
18
  # still runs, or finished and waits for the next pass's wake: its end
@@ -167,18 +168,18 @@ module Samagotchi
167
168
  # approval waiting (a turn's), a /btw (or another anytime command)
168
169
  # running, a delegate's approval relay this worker still answers for,
169
170
  # background tasks this conversation started (their output and end are
170
- # this worker's to report). Clients' streams don't hold: a web tab
171
- # reconnects on the new worker's bridge_up, an attached terminal finds
172
- # the new worker's Bridge.
171
+ # this worker's to report). Reminders don't hold: the worker writes them
172
+ # for its successor as it leaves (Worker#leave_on_request, ReminderCarry).
173
+ # Clients' streams don't hold either: a web tab reconnects on the new
174
+ # worker's bridge_up, an attached terminal finds the new worker's Bridge.
173
175
  # @return [Symbol, nil] :turn_running, :input_queued, :continue_offered,
174
- # :question_pending, :reminders, :command_running, :relays_open or
176
+ # :question_pending, :command_running, :relays_open or
175
177
  # :background_tasks
176
178
  def hold_for_restart
177
179
  return :turn_running if @engine.turn_running?
178
180
  return :input_queued if @input_pending.call
179
181
  return :continue_offered if @awaiting_continue.call
180
182
  return :question_pending if @engine.pending_question
181
- return :reminders if @engine.reminder_store&.any?
182
183
  return :command_running if @engine.anytime_running?
183
184
  return :relays_open if @engine.relay_desk.active?
184
185
  return :background_tasks if @running_tasks.call.any?
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: samagotchi
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.124.0
4
+ version: 0.125.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dmitry Dedov
@@ -528,6 +528,7 @@ files:
528
528
  - lib/samagotchi/relay_desk.rb
529
529
  - lib/samagotchi/relay_verifier.rb
530
530
  - lib/samagotchi/relay_watcher.rb
531
+ - lib/samagotchi/reminder_carry.rb
531
532
  - lib/samagotchi/reminder_queue.rb
532
533
  - lib/samagotchi/reminder_store.rb
533
534
  - lib/samagotchi/remote_attach_command.rb
@@ -603,13 +604,20 @@ files:
603
604
  - lib/samagotchi/terminal_ui/attach_launcher.rb
604
605
  - lib/samagotchi/terminal_ui/attach_link.rb
605
606
  - lib/samagotchi/terminal_ui/attached_loop.rb
607
+ - lib/samagotchi/terminal_ui/attached_loop/composer.rb
608
+ - lib/samagotchi/terminal_ui/attached_loop/exit_commands.rb
609
+ - lib/samagotchi/terminal_ui/attached_loop/questions.rb
610
+ - lib/samagotchi/terminal_ui/attached_loop/queueing.rb
611
+ - lib/samagotchi/terminal_ui/attached_loop/sending.rb
606
612
  - lib/samagotchi/terminal_ui/attached_view.rb
607
613
  - lib/samagotchi/terminal_ui/between_turns.rb
608
614
  - lib/samagotchi/terminal_ui/event_renderer.rb
615
+ - lib/samagotchi/terminal_ui/exit_lines.rb
609
616
  - lib/samagotchi/terminal_ui/formatting.rb
610
617
  - lib/samagotchi/terminal_ui/gap_clock.rb
611
618
  - lib/samagotchi/terminal_ui/image_input.rb
612
619
  - lib/samagotchi/terminal_ui/input_support.rb
620
+ - lib/samagotchi/terminal_ui/join_replay.rb
613
621
  - lib/samagotchi/terminal_ui/line_reader.rb
614
622
  - lib/samagotchi/terminal_ui/live_region.rb
615
623
  - lib/samagotchi/terminal_ui/local_link.rb
@@ -757,6 +765,7 @@ files:
757
765
  - lib/samagotchi/web/public/chains.js
758
766
  - lib/samagotchi/web/public/chip_popover.js
759
767
  - lib/samagotchi/web/public/chunk_router.js
768
+ - lib/samagotchi/web/public/claim_link.js
760
769
  - lib/samagotchi/web/public/command_complete.js
761
770
  - lib/samagotchi/web/public/command_list.js
762
771
  - lib/samagotchi/web/public/command_view.js
@@ -871,6 +880,7 @@ files:
871
880
  - lib/samagotchi/web/public/vendor/directives/repeat.js
872
881
  - lib/samagotchi/web/public/vendor/directives/unsafe-html.js
873
882
  - lib/samagotchi/web/public/vendor/lit-html.js
883
+ - lib/samagotchi/web/public/verify_preset.js
874
884
  - lib/samagotchi/web/public/working_set.js
875
885
  - lib/samagotchi/web/public/working_set_rail.js
876
886
  - lib/samagotchi/web/public/working_set_view.js