|
|
|
|
@ -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) |
|
|
|
|
|