ooni-probe-cli/internal/engine/probeservices/statefile.go

88 lines
2.2 KiB
Go
Raw Normal View History

package probeservices
import (
"encoding/json"
"time"
"github.com/ooni/probe-cli/v3/internal/engine/model"
)
// State is the state stored inside the state file
type State struct {
ClientID string
Expire time.Time
Password string
Token string
}
// Auth returns an authentication structure, if possible, otherwise
// it returns nil, meaning that you should login again.
func (s State) Auth() *LoginAuth {
if s.Token == "" {
return nil
}
if time.Now().Add(30 * time.Second).After(s.Expire) {
return nil
}
return &LoginAuth{Expire: s.Expire, Token: s.Token}
}
// Credentials returns login credentials, if possible, otherwise it
// returns nil, meaning that you should create an account.
func (s State) Credentials() *LoginCredentials {
if s.ClientID == "" {
return nil
}
if s.Password == "" {
return nil
}
return &LoginCredentials{ClientID: s.ClientID, Password: s.Password}
}
// StateFile is the orchestra state file. It is backed by
// a generic key-value store configured by the user.
type StateFile struct {
Store model.KeyValueStore
key string
}
// NewStateFile creates a new state file backed by a key-value store
func NewStateFile(kvstore model.KeyValueStore) StateFile {
return StateFile{key: "orchestra.state", Store: kvstore}
}
// SetMockable is a mockable version of Set
func (sf StateFile) SetMockable(s State, mf func(interface{}) ([]byte, error)) error {
data, err := mf(s)
if err != nil {
return err
}
return sf.Store.Set(sf.key, data)
}
// Set saves the current state on the key-value store.
func (sf StateFile) Set(s State) error {
return sf.SetMockable(s, json.Marshal)
}
// GetMockable is a mockable version of Get
func (sf StateFile) GetMockable(sfget func(string) ([]byte, error),
unmarshal func([]byte, interface{}) error) (State, error) {
value, err := sfget(sf.key)
if err != nil {
return State{}, err
}
var state State
if err := unmarshal(value, &state); err != nil {
return State{}, err
}
return state, nil
}
// Get returns the current state. In case of any error with the
// underlying key-value store, we return an empty state.
func (sf StateFile) Get() (state State) {
state, _ = sf.GetMockable(sf.Store.Get, json.Unmarshal)
return
}