package platforms import ( "context" "fmt" "net/http" "stream-bot/internal/logger" "time" ) type TwitchAuth struct { clientID string clientSecret string redirectURI string server *http.Server waitCh chan string } func NewTwitchAuth(clientID, clientSecret string) *TwitchAuth { return &TwitchAuth{ clientID: clientID, clientSecret: clientSecret, redirectURI: "http://localhost:8089", waitCh: make(chan string, 1), } } func (ta *TwitchAuth) GenerateAuthURL(scope []string, state string) string { url := "https://id.twitch.tv/oauth2/authorize?" + "client_id=" + ta.clientID + "&redirect_uri=" + ta.redirectURI + "&response_type=token" + "&scope=" + scopeString(scope) + "&state=" + state return url } func scopeString(scopes []string) string { s := "" for i, sc := range scopes { if i > 0 { s += "+" } s += sc } return s } func (ta *TwitchAuth) StartTempServer() error { if ta.server != nil { return nil } mux := http.NewServeMux() mux.HandleFunc("/", ta.handleCallback) ta.server = &http.Server{ Addr: ":8089", Handler: mux, } go func() { if err := ta.server.ListenAndServe(); err != nil && err != http.ErrServerClosed { logger.Error("OAuth server error: %v", err) } }() return nil } func (ta *TwitchAuth) StopTempServer() { if ta.server != nil { ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() ta.server.Shutdown(ctx) ta.server = nil } } func (ta *TwitchAuth) handleCallback(w http.ResponseWriter, r *http.Request) { html := ` Twitch Auth

Авторизация Twitch

Обработка токена...

` w.Header().Set("Content-Type", "text/html; charset=utf-8") w.Write([]byte(html)) } func (ta *TwitchAuth) WaitForToken(timeout time.Duration) (string, error) { select { case token := <-ta.waitCh: return token, nil case <-time.After(timeout): return "", fmt.Errorf("timeout waiting for token") } } func (ta *TwitchAuth) SetTokenCallback(token string) { select { case ta.waitCh <- token: default: } }