|
|
|
@ -7,6 +7,7 @@ package ipn
|
|
|
|
|
import (
|
|
|
|
|
"encoding/json"
|
|
|
|
|
"errors"
|
|
|
|
|
"fmt"
|
|
|
|
|
"io/ioutil"
|
|
|
|
|
"os"
|
|
|
|
|
"path/filepath"
|
|
|
|
@ -19,6 +20,17 @@ import (
|
|
|
|
|
// requested state ID doesn't exist.
|
|
|
|
|
var ErrStateNotExist = errors.New("no state with given ID")
|
|
|
|
|
|
|
|
|
|
const (
|
|
|
|
|
// GlobalDaemonStateKey is the ipn.StateKey that tailscaled
|
|
|
|
|
// loads on startup.
|
|
|
|
|
//
|
|
|
|
|
// We have to support multiple state keys for other OSes (Windows in
|
|
|
|
|
// particular), but right now Unix daemons run with a single
|
|
|
|
|
// node-global state. To keep open the option of having per-user state
|
|
|
|
|
// later, the global state key doesn't look like a username.
|
|
|
|
|
GlobalDaemonStateKey = StateKey("_daemon")
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// StateStore persists state, and produces it back on request.
|
|
|
|
|
type StateStore interface {
|
|
|
|
|
// ReadState returns the bytes associated with ID. Returns (nil,
|
|
|
|
@ -34,6 +46,8 @@ type MemoryStore struct {
|
|
|
|
|
cache map[StateKey][]byte
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (s *MemoryStore) String() string { return "MemoryStore" }
|
|
|
|
|
|
|
|
|
|
// ReadState implements the StateStore interface.
|
|
|
|
|
func (s *MemoryStore) ReadState(id StateKey) ([]byte, error) {
|
|
|
|
|
s.mu.Lock()
|
|
|
|
@ -67,6 +81,8 @@ type FileStore struct {
|
|
|
|
|
cache map[StateKey][]byte
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (s *FileStore) String() string { return fmt.Sprintf("FileStore(%q)", s.path) }
|
|
|
|
|
|
|
|
|
|
// NewFileStore returns a new file store that persists to path.
|
|
|
|
|
func NewFileStore(path string) (*FileStore, error) {
|
|
|
|
|
bs, err := ioutil.ReadFile(path)
|
|
|
|
|