github.com/aacfactory/fns@v1.2.86-0.20240310083819-80d667fc0a17/services/authorizations/store.go (about) 1 /* 2 * Copyright 2023 Wang Min Xiang 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 * 16 */ 17 18 package authorizations 19 20 import ( 21 "bytes" 22 "fmt" 23 "github.com/aacfactory/avro" 24 "github.com/aacfactory/errors" 25 "github.com/aacfactory/fns/context" 26 "github.com/aacfactory/fns/runtime" 27 "github.com/aacfactory/fns/services" 28 "time" 29 ) 30 31 type TokenStore interface { 32 services.Component 33 Get(ctx context.Context, account Id, id Id) (v Authorization, has bool, err error) 34 List(ctx context.Context, account Id) (v []Authorization, err error) 35 Save(ctx context.Context, v Authorization) (err error) 36 Remove(ctx context.Context, account Id, ids []Id) (err error) 37 } 38 39 type defaultTokenStore struct { 40 keyPrefix []byte 41 } 42 43 func (store *defaultTokenStore) Name() (name string) { 44 return "default" 45 } 46 47 func (store *defaultTokenStore) Construct(_ services.Options) (err error) { 48 store.keyPrefix = []byte("fns:authorizations:") 49 return 50 } 51 52 func (store *defaultTokenStore) Shutdown(_ context.Context) { 53 return 54 } 55 56 func (store *defaultTokenStore) Get(ctx context.Context, account Id, id Id) (v Authorization, has bool, err error) { 57 if !id.Exist() { 58 err = errors.Warning("authorizations: get authorization failed").WithCause(fmt.Errorf("id is required")) 59 return 60 } 61 entries, listErr := store.List(ctx, account) 62 if listErr != nil { 63 err = errors.Warning("authorizations: get authorization failed").WithCause(listErr) 64 return 65 } 66 for _, entry := range entries { 67 if bytes.Equal(entry.Id, id) { 68 v = entry 69 has = true 70 return 71 } 72 } 73 return 74 } 75 76 func (store *defaultTokenStore) List(ctx context.Context, account Id) (v []Authorization, err error) { 77 if !account.Exist() { 78 err = errors.Warning("authorizations: list authorization failed").WithCause(fmt.Errorf("account is required")) 79 return 80 } 81 sc := runtime.SharedStore(ctx) 82 key := append(store.keyPrefix, account...) 83 p, has, getErr := sc.Get(ctx, key) 84 if getErr != nil { 85 err = errors.Warning("authorizations: list authorization failed").WithCause(getErr) 86 return 87 } 88 if !has { 89 return 90 } 91 v = make([]Authorization, 0) 92 err = avro.Unmarshal(p, &v) 93 if err != nil { 94 err = errors.Warning("authorizations: list authorization failed").WithCause(err) 95 return 96 } 97 return 98 } 99 100 func (store *defaultTokenStore) Save(ctx context.Context, v Authorization) (err error) { 101 if !v.Exist() || !v.Validate() { 102 return 103 } 104 entries, listErr := store.List(ctx, v.Account) 105 if listErr != nil { 106 err = errors.Warning("authorizations: save authorization failed").WithCause(listErr) 107 return 108 } 109 entries = append(entries, v) 110 expire := time.Time{} 111 for _, entry := range entries { 112 if entry.ExpireAT.After(expire) { 113 expire = entry.ExpireAT 114 } 115 } 116 p, encodeErr := avro.Marshal(entries) 117 if encodeErr != nil { 118 err = errors.Warning("authorizations: save authorization failed").WithCause(encodeErr) 119 return 120 } 121 sc := runtime.SharedStore(ctx) 122 key := append(store.keyPrefix, v.Account...) 123 setErr := sc.SetWithTTL(ctx, key, p, expire.Sub(time.Now())) 124 if setErr != nil { 125 err = errors.Warning("authorizations: save authorization failed").WithCause(setErr) 126 return 127 } 128 return 129 } 130 131 func (store *defaultTokenStore) Remove(ctx context.Context, account Id, ids []Id) (err error) { 132 entries, listErr := store.List(ctx, account) 133 if listErr != nil { 134 err = errors.Warning("authorizations: remove authorization failed").WithCause(listErr) 135 return 136 } 137 if len(entries) == 0 { 138 return 139 } 140 sc := runtime.SharedStore(ctx) 141 key := append(store.keyPrefix, account...) 142 if len(ids) == 0 { 143 rmErr := sc.Remove(ctx, key) 144 if rmErr != nil { 145 err = errors.Warning("authorizations: remove authorization failed").WithCause(rmErr) 146 return 147 } 148 return 149 } 150 news := make([]Authorization, 0, 1) 151 expire := time.Time{} 152 for _, entry := range entries { 153 if !entry.Validate() { 154 continue 155 } 156 in := false 157 for _, id := range ids { 158 if bytes.Equal(id, entry.Id) { 159 in = true 160 break 161 } 162 } 163 if in { 164 continue 165 } 166 news = append(news, entry) 167 if entry.ExpireAT.After(expire) { 168 expire = entry.ExpireAT 169 } 170 } 171 if len(news) == 0 { 172 rmErr := sc.Remove(ctx, key) 173 if rmErr != nil { 174 err = errors.Warning("authorizations: remove authorization failed").WithCause(rmErr) 175 return 176 } 177 return 178 } 179 p, encodeErr := avro.Marshal(news) 180 if encodeErr != nil { 181 err = errors.Warning("authorizations: remove authorization failed").WithCause(encodeErr) 182 return 183 } 184 setErr := sc.SetWithTTL(ctx, key, p, expire.Sub(time.Now())) 185 if setErr != nil { 186 err = errors.Warning("authorizations: remove authorization failed").WithCause(setErr) 187 return 188 } 189 return 190 }