/
accounts_local.go
120 lines (105 loc) · 3.27 KB
/
accounts_local.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
package services
import (
"encoding/json"
"errors"
"fmt"
"github.com/alswl/go-toodledo/pkg/common"
"github.com/alswl/go-toodledo/pkg/client0"
"github.com/alswl/go-toodledo/pkg/dal"
"github.com/alswl/go-toodledo/pkg/models"
"github.com/go-openapi/runtime"
"github.com/spf13/viper"
)
const BucketAccount = "account"
const lastSyncInfoKey = "lastSyncInfo"
// meKey is the key of account in db, TODO multi user support
const meKey = "me"
// CurrentUser return live user
// TODO move to cli
func CurrentUser(svc AccountExtService) (*models.Account, error) {
me, _, err := svc.CachedMe()
return me, err
}
type AccountExtService interface {
Me() (*models.Account, error)
CachedMe() (*models.Account, bool, error)
// GetLastFetchInfo return last fetch info in db
// lastFetchInfo maybe nil if never sync
FindLastFetchInfo() (*models.Account, error)
ModifyLastFetchInfo(account *models.Account) error
}
type accountLocalService struct {
svc AccountService
cli *client0.Toodledo
// TODO access service should now own auth, auth is owned by single user
auth runtime.ClientAuthInfoWriter
// TODO no db access
db dal.Backend
}
func NewAccountExtService(
cli *client0.Toodledo,
auth runtime.ClientAuthInfoWriter,
db dal.Backend,
accountSvc AccountService,
) AccountExtService {
return &accountLocalService{cli: cli, auth: auth, db: db, svc: accountSvc}
}
// Me return current user by cli authentication info.
func (s *accountLocalService) Me() (*models.Account, error) {
return s.svc.Me()
}
func (s *accountLocalService) CachedMe() (*models.Account, bool, error) {
bytes, err := s.db.Get(BucketAccount, meKey)
u := models.Account{}
// TODO refactor, cacheOrSet(key, setFn): val
if err != nil {
if errors.Is(err, dal.ErrObjectNotFound) {
me, ierr := s.Me()
if ierr != nil {
return nil, false, fmt.Errorf("get account s.Me() failed: %w", ierr)
}
bytes, ierr = json.Marshal(me)
if ierr != nil {
return nil, false, fmt.Errorf("marshal account failed: %w", ierr)
}
_ = s.db.Put(BucketAccount, meKey, bytes)
return me, false, nil
}
return nil, false, fmt.Errorf("get account in db failed: %w", err)
}
err = json.Unmarshal(bytes, &u)
if err != nil {
return nil, false, fmt.Errorf("unmarshal account failed: %w", err)
}
// TODO check user id for local config
userID := viper.GetString(common.AuthUserID)
if u.Userid != userID {
return nil, false, fmt.Errorf("user id not match, local %s, remote %s, please auth logout", userID, u.Userid)
}
return &u, true, nil
}
func (s *accountLocalService) FindLastFetchInfo() (*models.Account, error) {
bytes, err := s.db.Get(BucketAccount, lastSyncInfoKey)
if errors.Is(err, dal.ErrObjectNotFound) {
return nil, common.ErrNotFound
} else if err != nil {
return nil, fmt.Errorf("get last sync info failed: %w", err)
}
u := models.Account{}
err = json.Unmarshal(bytes, &u)
if err != nil {
return nil, fmt.Errorf("unmarshal last sync info failed: %w", err)
}
return &u, nil
}
func (s *accountLocalService) ModifyLastFetchInfo(account *models.Account) error {
bytes, err := json.Marshal(account)
if err != nil {
return fmt.Errorf("marshal last sync info failed: %w", err)
}
err = s.db.Put(BucketAccount, lastSyncInfoKey, bytes)
if err != nil {
return fmt.Errorf("set last sync info failed: %w", err)
}
return nil
}