1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
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
//! Background OAuth polling for the QR-fast-path onboarding modal.
//!
//! On first-launch the wizard renders a QR for the AtomGit OAuth
//! short link and synchronously holds onto the `LoginSession`. This
//! module spawns a background thread that calls `LoginSession::
//! poll_once` every 2s — the moment AtomGit reports the user has
//! finished the in-browser consent, the task calls `finish()` to
//! exchange state → token (writing `auth.toml` as a side effect) and
//! pushes an [`OauthEvent::Authorized`] onto the event-loop channel.
//!
//! Why `std::thread::spawn` and not `tokio::spawn`:
//! [`LoginSession::poll_once`] / `finish` use a `reqwest::blocking::Client`.
//! Running them on a tokio worker would either block other tasks on
//! the same worker (no `spawn_blocking` indirection) or require a
//! reshape of the blocking client into async. A dedicated OS thread
//! sidesteps both — it sleeps between polls without touching the
//! runtime, and `tokio::sync::mpsc::Sender::blocking_send` lets it
//! push events back into the tokio world when it has something to
//! report.
//!
//! Cancellation: there isn't any. If the user hits Esc on the modal,
//! the modal closes but this thread continues polling until it
//! reaches a terminal state (Authorized / Err). `OauthEvent` arriving
//! on a closed-modal event loop is a silent no-op — the handler
//! checks `app.active_modal.is_some()` before acting. Worst case the
//! thread quietly writes a fresh `auth.toml` on its own — which is
//! the same effect as the user later running `/codingplan` after Esc,
//! so it's harmless.
use Arc;
use Duration;
use mpsc;
use ;
use Telemetry;
/// Outcome the background poll thread emits at exactly one of: a
/// successful auth-token exchange, a fatal poll/finish error, or
/// (never) cancellation — the thread doesn't observe cancel signals.
/// Spawn the background poll thread. Returns immediately; the thread
/// owns the [`LoginSession`] and lives until it emits exactly one
/// [`OauthEvent`].
///
/// `wake_tx` is pulsed AFTER the event is queued so the event-loop
/// `tokio::select!` arm that reads `oauth_event_rx` actually fires —
/// `oauth_event_rx.recv()` alone would only fire on the next
/// scheduling tick, which on an idle TUI can be many seconds.