func readTokenFile(tokenFile string) (*Token, error) {
	bytes, err := ioutil.ReadFile(tokenFile)
	if err != nil {
		return nil, err
	}
	return deserializeToken(bytes)
}
readTokenFile reads a single token from a file and returns it deserialized.
package lsat
import (
	"errors"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
)
var (
	ErrNoToken = errors.New("no token in store")
	storeFileName = "lsat.token"
	storeFileNamePending = "lsat.token.pending"
	errNoReplace = errors.New("won't replace existing paid token with " +
		"new token. " + manualRetryHint)
)
type Store interface {
	CurrentToken() (*Token, error)
	AllTokens() (map[string]*Token, error)
	StoreToken(*Token) error
	RemovePendingToken() error
}
type FileStore struct {
	fileName        string
	fileNamePending string
}
var _ Store = (*FileStore)(nil)
func NewFileStore(storeDir string) (*FileStore, error) {
	if !fileExists(storeDir) {
		if err := os.MkdirAll(storeDir, 0700); err != nil {
			return nil, err
		}
	}
	return &FileStore{
		fileName:        filepath.Join(storeDir, storeFileName),
		fileNamePending: filepath.Join(storeDir, storeFileNamePending),
	}, nil
}
func (f *FileStore) CurrentToken() (*Token, error) {
	return f.currentToken()
}
func (f *FileStore) currentToken() (*Token, error) {
	switch {
	case fileExists(f.fileName):
		return readTokenFile(f.fileName)
	case fileExists(f.fileNamePending):
		return readTokenFile(f.fileNamePending)
	default:
		return nil, ErrNoToken
	}
}
func (f *FileStore) AllTokens() (map[string]*Token, error) {
	tokens := make(map[string]*Token)
	tokenDir := filepath.Dir(f.fileName)
	files, err := ioutil.ReadDir(tokenDir)
	if err != nil {
		return nil, err
	}
	for _, file := range files {
		name := file.Name()
		if !strings.HasPrefix(name, storeFileName) {
			continue
		}
		fileName := filepath.Join(tokenDir, name)
		token, err := readTokenFile(fileName)
		if err != nil {
			return nil, err
		}
		tokens[fileName] = token
	}
	return tokens, nil
}
func (f *FileStore) StoreToken(newToken *Token) error {
	bytes, err := serializeToken(newToken)
	if err != nil {
		return err
	}
	currentToken, err := f.currentToken()
	switch {
	case err == ErrNoToken:
		newFileName := f.fileName
		if newToken.isPending() {
			newFileName = f.fileNamePending
		}
		return ioutil.WriteFile(newFileName, bytes, 0600)
	case err != nil:
		return err
	case currentToken.isPending() && !newToken.isPending():
		if currentToken.PaymentHash != newToken.PaymentHash {
			return fmt.Errorf("new paid token doesn't match " +
				"existing pending token")
		}
		err := ioutil.WriteFile(f.fileName, bytes, 0600)
		if err != nil {
			return err
		}
		_ = os.Remove(f.fileNamePending)
		return nil
	default:
		return errNoReplace
	}
}
func (f *FileStore) RemovePendingToken() error {
	if !fileExists(f.fileNamePending) {
		return ErrNoToken
	}
	return os.Remove(f.fileNamePending)
}