/
githubmirror
/
client
Обзор
Документация
Войти
/
githubmirror
/
client
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
go/kbhttp/manager/manager.go
162 строки
4 KB
zoom-ua
modernize error handling with errors.As/Is (#29350)
25 июн 2026, 17:41
Не верифицирован
25 июн 2026, 17:41
e09e254
Код
Авторство
О чём код?
package manager import ( "context" "crypto/hmac" "errors" "fmt" "net/http" "runtime" "sync" "github.com/keybase/client/go/kbhttp" "github.com/keybase/client/go/libkb" "github.com/keybase/client/go/protocol/keybase1" ) type SrvTokenMode int const ( SrvTokenModeDefault = iota SrvTokenModeUnchecked // use with caution! ) type srvEndpoint struct { tokenMode SrvTokenMode serve func(w http.ResponseWriter, req *http.Request) } type Srv struct { libkb.Contextified httpSrv *kbhttp.Srv endpoints map[string]srvEndpoint token string startMu sync.Mutex } func NewSrv(g *libkb.GlobalContext) *Srv { h := &Srv{ Contextified: libkb.NewContextified(g), endpoints: make(map[string]srvEndpoint), } h.initHTTPSrv() h.startHTTPSrv() g.PushShutdownHook(func(mctx libkb.MetaContext) error { h.httpSrv.Stop() return nil }) go h.monitorAppState() return h } func (r *Srv) debug(ctx context.Context, msg string, args ...any) { r.G().Log.CDebugf(ctx, "Srv: %s", fmt.Sprintf(msg, args...)) } func (r *Srv) initHTTPSrv() { startPort := r.G().GetEnv().GetAttachmentHTTPStartPort() r.httpSrv = kbhttp.NewSrv(r.G().GetLog(), kbhttp.NewRandomPortRangeListenerSource(startPort, 18000)) } func (r *Srv) startHTTPSrv() { r.startMu.Lock() defer r.startMu.Unlock() ctx := context.Background() token, _ := libkb.RandHexString("", 32) maxTries := 2 success := false for range maxTries { if err := r.httpSrv.Start(); err != nil { if errors.Is(err, kbhttp.ErrPinnedPortInUse) { // If we hit this, just try again and get a different port. // The advantage is that backing in and out of the thread will restore attachments, // whereas if we do nothing you need to bkg/foreground. r.debug(ctx, "startHTTPSrv: pinned port taken error, re-initializing and trying again") r.initHTTPSrv() continue } r.debug(ctx, "startHTTPSrv: failed to start HTTP server: %s", err) break } success = true break } if !success { r.debug(ctx, "startHTTPSrv: exhausted attempts to start HTTP server, giving up") return } for endpoint, serveDesc := range r.endpoints { r.HandleFunc(endpoint, serveDesc.tokenMode, serveDesc.serve) } addr, err := r.httpSrv.Addr() if err != nil { r.debug(ctx, "startHTTPSrv: failed to get address after start?: %s", err) } else { r.debug(ctx, "startHTTPSrv: start success: addr: %s", addr) } r.token = token r.debug(ctx, "startHTTPSrv: addr: %s token: %s", addr, r.token) r.G().NotifyRouter.HandleHTTPSrvInfoUpdate(ctx, keybase1.HttpSrvInfo{ Address: addr, Token: r.token, }) } func (r *Srv) monitorAppState() { ctx := context.Background() r.debug(ctx, "monitorAppState: starting up") state := keybase1.MobileAppState_FOREGROUND // We don't need this on Android if runtime.GOOS == "android" { return } for { state = <-r.G().MobileAppState.NextUpdate(&state) switch state { case keybase1.MobileAppState_FOREGROUND, keybase1.MobileAppState_BACKGROUNDACTIVE: r.startHTTPSrv() case keybase1.MobileAppState_BACKGROUND, keybase1.MobileAppState_INACTIVE: r.httpSrv.Stop() } } } func (r *Srv) HandleFunc(endpoint string, tokenMode SrvTokenMode, serve func(w http.ResponseWriter, req *http.Request), ) { r.httpSrv.HandleFunc("/"+endpoint, func(w http.ResponseWriter, req *http.Request) { switch tokenMode { case SrvTokenModeDefault: if !hmac.Equal([]byte(req.URL.Query().Get("token")), []byte(r.token)) { r.debug(context.Background(), "HandleFunc: token failed: %s != %s", req.URL.Query().Get("token"), r.token) w.WriteHeader(http.StatusForbidden) return } case SrvTokenModeUnchecked: // serve needs to authenticate on its own } serve(w, req) }) r.endpoints[endpoint] = srvEndpoint{ tokenMode: tokenMode, serve: serve, } } func (r *Srv) Active() bool { return r.httpSrv.Active() } func (r *Srv) Addr() (string, error) { r.startMu.Lock() defer r.startMu.Unlock() return r.httpSrv.Addr() } func (r *Srv) Token() string { r.startMu.Lock() defer r.startMu.Unlock() return r.token }