package omadaapi import ( "fmt" "net/http" "sync" "time" "git.tordarus.net/tordarus/ezhttp" "git.tordarus.net/tordarus/omada-api/model" ) type Api struct { tmpl *http.Request config ApiConfig accessToken string refreshToken string expiration time.Time refreshMutex sync.RWMutex } type ApiConfig struct { BasePath string OmadaID string ClientID string ClientSecret string Username string Password string } func NewApi(config ApiConfig) (*Api, error) { tmpl := ezhttp.Request(ezhttp.URL(config.BasePath)) api := &Api{ tmpl: tmpl, config: config, } loginResponse, err := api.Login() if err != nil { return nil, fmt.Errorf("login request failed: %w", err) } if loginResponse.ErrorCode != 0 { return nil, fmt.Errorf("login request failed: %s", loginResponse.Message) } authCodeResponse, err := api.AuthCode(loginResponse.Result.CsrfToken, loginResponse.Result.SessionID) if err != nil { return nil, fmt.Errorf("auth code request failed: %w", err) } if authCodeResponse.ErrorCode != 0 { return nil, fmt.Errorf("auth code request failed: %s", authCodeResponse.Message) } authTokenResponse, err := api.AuthToken(*authCodeResponse.Result) if err != nil { return nil, fmt.Errorf("auth token request failed: %w", err) } if authTokenResponse.ErrorCode != 0 { return nil, fmt.Errorf("auth token request failed: %s", authTokenResponse.Message) } api.expiration = time.Now().Add(time.Duration(authTokenResponse.Result.ExpiresIn) * time.Second) api.accessToken = authTokenResponse.Result.AccessToken api.refreshToken = authTokenResponse.Result.RefreshToken api.tmpl = ezhttp.Request( ezhttp.Template(api.tmpl), ezhttp.Headers("Authorization", "AccessToken="+api.accessToken), ) return api, nil } func (api *Api) Login() (*model.LoginResponse, error) { api.refreshMutex.RLock() defer api.refreshMutex.RUnlock() reqBody := model.LoginRequest{ Username: api.config.Username, Password: api.config.Password, } req := ezhttp.Request( ezhttp.Template(api.tmpl), ezhttp.Method("POST"), ezhttp.AppendPath("/openapi/authorize/login"), ezhttp.Query("client_id", api.config.ClientID, "omadac_id", api.config.OmadaID), ezhttp.Body(ezhttp.JSON(reqBody)), ) resp, err := ezhttp.Do(req) if err != nil { return nil, err } defer resp.Body.Close() response, err := ezhttp.ParseJsonResponse[model.LoginResponse](resp) if err != nil { return nil, err } return response, nil } func (api *Api) AuthCode(csrfToken, sessionID string) (*model.AuthCodeResponse, error) { api.refreshMutex.RLock() defer api.refreshMutex.RUnlock() req := ezhttp.Request( ezhttp.Template(api.tmpl), ezhttp.Method("POST"), ezhttp.AppendPath("/openapi/authorize/code"), ezhttp.Query("client_id", api.config.ClientID, "omadac_id", api.config.OmadaID, "response_type", "code"), ezhttp.Headers("Csrf-Token", csrfToken, "Cookie", fmt.Sprintf("TPOMADA_SESSIONID=%s", sessionID)), ) resp, err := ezhttp.Do(req) if err != nil { return nil, err } defer resp.Body.Close() response, err := ezhttp.ParseJsonResponse[model.AuthCodeResponse](resp) if err != nil { return nil, err } return response, nil } func (api *Api) AuthToken(authCode string) (*model.AuthTokenResponse, error) { api.refreshMutex.RLock() defer api.refreshMutex.RUnlock() req := ezhttp.Request( ezhttp.Template(api.tmpl), ezhttp.Method("POST"), ezhttp.AppendPath("/openapi/authorize/token"), ezhttp.Query( "code", authCode, "grant_type", "authorization_code", "client_id", api.config.ClientID, "client_secret", api.config.ClientSecret, ), ) resp, err := ezhttp.Do(req) if err != nil { return nil, err } defer resp.Body.Close() response, err := ezhttp.ParseJsonResponse[model.AuthTokenResponse](resp) if err != nil { return nil, err } return response, nil } func (api *Api) Refresh() error { api.refreshMutex.Lock() defer api.refreshMutex.Unlock() req := ezhttp.Request( ezhttp.Template(api.tmpl), ezhttp.Method("POST"), ezhttp.AppendPath("/openapi/authorize/token"), ezhttp.Query( "client_id", api.config.ClientID, "client_secret", api.config.ClientSecret, "refresh_token", api.refreshToken, "grant_type", "refresh_token", ), ) resp, err := ezhttp.Do(req) if err != nil { return err } defer resp.Body.Close() response, err := ezhttp.ParseJsonResponse[model.AuthTokenResponse](resp) if err != nil { return err } api.expiration = time.Now().Add(time.Duration(response.Result.ExpiresIn) * time.Second) api.accessToken = response.Result.AccessToken api.refreshToken = response.Result.RefreshToken return nil }