package transport import ( "encoding/gob" "os" "path/filepath" "sync" "ripple/bug" "ripple/config" "ripple/errmsgs" "ripple/helpers" "ripple/types" ) type User struct { types.UserIdentifier SecretKey [32]byte Counter uint32 } type Account struct { Port int SecretKey [32]byte CounterIn uint32 CounterOut uint32 } type Counterpart struct { Identifier types.UserIdentifier Port int SecretKey [32]byte CounterIn uint32 CounterOut uint32 } type Storage struct { Port int User Accounts map[types.UserIdentifier]Account } type Memory struct { Counterpart Counterpart } type Data struct { mu sync.RWMutex Storage Storage Memory Memory } func getFilePath() (string, error) { homeDir, err := os.UserHomeDir() if err != nil { return "", err } dataDir := filepath.Join(homeDir, config.DataDir) filePath := filepath.Join(dataDir, config.TransportFile) return filePath, nil } func (d *Data) saveLocked() error { filePath, err := helpers.GetFilePath(config.TransportFile) if err != nil { return err } f, err := os.Create(filePath) if err != nil { return err } defer f.Close() enc := gob.NewEncoder(f) return enc.Encode(d.Storage) } func Load() (*Data, error) { filePath, err := helpers.GetFilePath(config.TransportFile) if err != nil { return nil, err } f, err := os.Open(filePath) if err != nil { return nil, err } defer f.Close() dec := gob.NewDecoder(f) d := &Data{} if err := dec.Decode(&d.Storage); err != nil { return nil, err } return d, nil } func Init(port int, id types.UserIdentifier, secretKey [32]byte) error { d := &Data{} d.Storage.Port = port d.Storage.User.UserIdentifier = id d.Storage.User.SecretKey = secretKey d.Storage.Accounts = make(map[types.UserIdentifier]Account) return d.saveLocked() } func (d *Data) AccountExists(id types.UserIdentifier) bool { _, ok := d.Storage.Accounts[id] return ok } func (d *Data) AddAccount(id types.UserIdentifier, port int, secretKey [32]byte) error { if d.AccountExists(id) { panic(bug.BugStateViolated) } if len(d.Storage.Accounts) >= config.BufferSize { return errmsgs.ErrBufferFull } d.Storage.Accounts[id] = Account{ Port: port, SecretKey: secretKey, } return d.saveLocked() } func (d *Data) RemoveAccount(id types.UserIdentifier) error { d.mu.Lock() defer d.mu.Unlock() if !d.AccountExists(id) { panic(bug.BugStateViolated) } delete(d.Storage.Accounts, id) return d.saveLocked() } func (d *Data) AddCounterpart(id types.UserIdentifier, port int, secretKey [32]byte) { d.Memory.Counterpart.Identifier = id d.Memory.Counterpart.Port = port d.Memory.Counterpart.SecretKey = secretKey d.Memory.Counterpart.CounterIn = 0 d.Memory.Counterpart.CounterOut = 0 } func (d *Data) setUserCounter(val uint32) error { d.mu.Lock() defer d.mu.Unlock() d.Storage.User.Counter = val return d.saveLocked() } func (d *Data) mustSetAccountCounterIn(id types.UserIdentifier, val uint32) error { d.mu.Lock() defer d.mu.Unlock() acc, ok := d.Storage.Accounts[id] if !ok { panic(bug.BugStateViolated) } acc.CounterIn = val d.Storage.Accounts[id] = acc return d.saveLocked() } func (d *Data) getAccount(id types.UserIdentifier) (Account, bool) { d.mu.RLock() defer d.mu.RUnlock() acc, ok := d.Storage.Accounts[id] return acc, ok } func (d *Data) incrementAndGetAccountCounterOut(id types.UserIdentifier) (uint32, error) { d.mu.Lock() defer d.mu.Unlock() acc, ok := d.Storage.Accounts[id] if !ok { return 0, errmsgs.ErrKeyNotFound } acc.CounterOut++ d.Storage.Accounts[id] = acc return acc.CounterOut, d.saveLocked() }