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  }