@@ -5,7 +5,10 @@ import (
55 "fmt"
66 "log"
77 "strings"
8+ "sync"
89 "time"
10+
11+ "github.com/cacggghp/vk-turn-proxy/appcontrolpb"
912)
1013
1114const proxyEventProtocolVersion = 1
@@ -91,7 +94,98 @@ func emitProxyEvent(payload any) {
9194 log .Printf ("failed to marshal proxy event: %s" , err )
9295 return
9396 }
97+ // The JSONL line stays on stdout for the log. Control now flows over the
98+ // AppControl StreamEvents gRPC channel: publish the same event typed there.
9499 fmt .Println ("PROXY_EVENT: " + string (encoded ))
100+ publishProxyEvent (payload )
101+ }
102+
103+ // proxyEventBroadcaster fans relay control events out to every active
104+ // StreamEvents subscriber. Sends are non-blocking: a subscriber that falls behind
105+ // drops events rather than stalling the relay - control events are re-emitted
106+ // (captcha / vk-auth) or superseded (status), so a rare drop is tolerable.
107+ type proxyEventBroadcaster struct {
108+ mu sync.Mutex
109+ subs map [chan * appcontrolpb.ProxyEvent ]struct {}
110+ }
111+
112+ var eventHub = & proxyEventBroadcaster {subs : make (map [chan * appcontrolpb.ProxyEvent ]struct {})}
113+
114+ func (h * proxyEventBroadcaster ) publish (ev * appcontrolpb.ProxyEvent ) {
115+ h .mu .Lock ()
116+ defer h .mu .Unlock ()
117+ for ch := range h .subs {
118+ select {
119+ case ch <- ev :
120+ default :
121+ }
122+ }
123+ }
124+
125+ func (h * proxyEventBroadcaster ) subscribe () chan * appcontrolpb.ProxyEvent {
126+ ch := make (chan * appcontrolpb.ProxyEvent , 64 )
127+ h .mu .Lock ()
128+ h .subs [ch ] = struct {}{}
129+ h .mu .Unlock ()
130+ return ch
131+ }
132+
133+ func (h * proxyEventBroadcaster ) unsubscribe (ch chan * appcontrolpb.ProxyEvent ) {
134+ h .mu .Lock ()
135+ delete (h .subs , ch )
136+ h .mu .Unlock ()
137+ close (ch )
138+ }
139+
140+ // publishProxyEvent maps a JSONL event struct to its typed ProxyEvent and pushes
141+ // it to StreamEvents subscribers. Payloads with no control mapping (telemetry,
142+ // vk_cookies_update) are logged as JSONL only and skipped here - telemetry has its
143+ // own StreamTelemetry RPC and the app pulls rotated cookies via GetVKCookies.
144+ func publishProxyEvent (payload any ) {
145+ var ev * appcontrolpb.ProxyEvent
146+ switch p := payload .(type ) {
147+ case proxyStatusEvent :
148+ ev = & appcontrolpb.ProxyEvent {Event : & appcontrolpb.ProxyEvent_Status {
149+ Status : & appcontrolpb.StatusEvent {Phase : p .Phase },
150+ }}
151+ case proxyStreamStatusEvent :
152+ ev = & appcontrolpb.ProxyEvent {Event : & appcontrolpb.ProxyEvent_Status {
153+ Status : & appcontrolpb.StatusEvent {Phase : p .Phase , StreamId : int32 (p .StreamID )},
154+ }}
155+ case proxyDtlsAliveEvent :
156+ ev = & appcontrolpb.ProxyEvent {Event : & appcontrolpb.ProxyEvent_Status {
157+ Status : & appcontrolpb.StatusEvent {Phase : p .Phase , StreamId : int32 (p .StreamID ), ConnectedStreams : int32 (p .ConnectedStreams )},
158+ }}
159+ case proxyCapsEvent :
160+ ev = & appcontrolpb.ProxyEvent {Event : & appcontrolpb.ProxyEvent_Caps {
161+ Caps : & appcontrolpb.CapsEvent {Version : int32 (p .Version ), Capabilities : append ([]string (nil ), p .Capabilities ... )},
162+ }}
163+ case proxyCaptchaEvent :
164+ ev = & appcontrolpb.ProxyEvent {Event : & appcontrolpb.ProxyEvent_Captcha {
165+ Captcha : & appcontrolpb.CaptchaEvent {State : p .State , Source : p .Source , Url : p .URL , UserAgent : p .UserAgent },
166+ }}
167+ case proxyLockoutEvent :
168+ ev = & appcontrolpb.ProxyEvent {Event : & appcontrolpb.ProxyEvent_Lockout {
169+ Lockout : & appcontrolpb.LockoutEvent {Seconds : int32 (p .Seconds )},
170+ }}
171+ case vkAccountAuthEvent :
172+ if p .Type == "vk_cookies_required" {
173+ ev = & appcontrolpb.ProxyEvent {Event : & appcontrolpb.ProxyEvent_VkCookiesRequired {
174+ VkCookiesRequired : & appcontrolpb.VKCookiesRequiredEvent {},
175+ }}
176+ } else {
177+ ev = & appcontrolpb.ProxyEvent {Event : & appcontrolpb.ProxyEvent_VkAccountAuth {
178+ VkAccountAuth : & appcontrolpb.VKAccountAuthEvent {
179+ Phase : strings .TrimPrefix (p .Type , "vk_account_auth_" ),
180+ Link : p .Link ,
181+ Reason : p .Reason ,
182+ },
183+ }}
184+ }
185+ default :
186+ return
187+ }
188+ eventHub .publish (ev )
95189}
96190
97191func applyProxyStatusState (marker string ) {
0 commit comments