ooni-probe-cli/internal/engine/probeservices/statefile.go
Simone Basso d57c78bc71
chore: merge probe-engine into probe-cli (#201)
This is how I did it:

1. `git clone https://github.com/ooni/probe-engine internal/engine`

2. ```
(cd internal/engine && git describe --tags)
v0.23.0
```

3. `nvim go.mod` (merging `go.mod` with `internal/engine/go.mod`

4. `rm -rf internal/.git internal/engine/go.{mod,sum}`

5. `git add internal/engine`

6. `find . -type f -name \*.go -exec sed -i 's@/ooni/probe-engine@/ooni/probe-cli/v3/internal/engine@g' {} \;`

7. `go build ./...` (passes)

8. `go test -race ./...` (temporary failure on RiseupVPN)

9. `go mod tidy`

10. this commit message

Once this piece of work is done, we can build a new version of `ooniprobe` that
is using `internal/engine` directly. We need to do more work to ensure all the
other functionality in `probe-engine` (e.g. making mobile packages) are still WAI.

Part of https://github.com/ooni/probe/issues/1335
2021-02-02 12:05:47 +01:00

88 lines
2.2 KiB
Go

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
}