| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183 |
- package app
- import (
- "encoding/json"
- "sync"
- "github.com/maxence-charriere/go-app/v9/pkg/errors"
- )
- // BrowserStorage is the interface that describes a web browser storage.
- type BrowserStorage interface {
- // Set sets the value to the given key. The value must be json convertible.
- Set(k string, v any) error
- // Get gets the item associated to the given key and store it in the given
- // value.
- // It returns an error if v is not a pointer.
- Get(k string, v any) error
- // Del deletes the item associated with the given key.
- Del(k string)
- // Len returns the number of items stored.
- Len() int
- // Key returns the key of the item associated to the given index.
- Key(i int) (string, error)
- // Clear deletes all items.
- Clear()
- }
- type memoryStorage struct {
- mu sync.RWMutex
- data map[string][]byte
- }
- func newMemoryStorage() *memoryStorage {
- return &memoryStorage{
- data: make(map[string][]byte),
- }
- }
- func (s *memoryStorage) Set(k string, v any) error {
- b, err := json.Marshal(v)
- if err != nil {
- return err
- }
- s.mu.Lock()
- s.data[k] = b
- s.mu.Unlock()
- return nil
- }
- func (s *memoryStorage) Get(k string, v any) error {
- s.mu.RLock()
- d, ok := s.data[k]
- if !ok {
- s.mu.RUnlock()
- return nil
- }
- s.mu.RUnlock()
- return json.Unmarshal(d, v)
- }
- func (s *memoryStorage) Del(k string) {
- s.mu.Lock()
- delete(s.data, k)
- s.mu.Unlock()
- }
- func (s *memoryStorage) Clear() {
- s.mu.Lock()
- for k := range s.data {
- delete(s.data, k)
- }
- s.mu.Unlock()
- }
- func (s *memoryStorage) Len() int {
- s.mu.RLock()
- l := len(s.data)
- s.mu.RUnlock()
- return l
- }
- func (s *memoryStorage) Key(i int) (string, error) {
- s.mu.RLock()
- defer s.mu.RUnlock()
- j := 0
- for k := range s.data {
- if i == j {
- return k, nil
- }
- j++
- }
- return "", errors.New("index out of range").
- Tag("index", i).
- Tag("len", s.Len())
- }
- type jsStorage struct {
- name string
- mutex sync.RWMutex
- }
- func newJSStorage(name string) *jsStorage {
- return &jsStorage{name: name}
- }
- func (s *jsStorage) Set(k string, v any) (err error) {
- defer func() {
- r := recover()
- if r != nil {
- err = errors.New("setting storage value failed").
- Tag("storage-type", s.name).
- Tag("key", k).
- Wrap(r.(error))
- }
- }()
- s.mutex.Lock()
- defer s.mutex.Unlock()
- b, err := json.Marshal(v)
- if err != nil {
- return err
- }
- Window().Get(s.name).Call("setItem", k, string(b))
- return nil
- }
- func (s *jsStorage) Get(k string, v any) error {
- s.mutex.RLock()
- defer s.mutex.RUnlock()
- item := Window().Get(s.name).Call("getItem", k)
- if !item.Truthy() {
- return nil
- }
- return json.Unmarshal([]byte(item.String()), v)
- }
- func (s *jsStorage) Del(k string) {
- s.mutex.Lock()
- defer s.mutex.Unlock()
- Window().Get(s.name).Call("removeItem", k)
- }
- func (s *jsStorage) Clear() {
- s.mutex.Lock()
- defer s.mutex.Unlock()
- Window().Get(s.name).Call("clear")
- }
- func (s *jsStorage) Len() int {
- s.mutex.Lock()
- defer s.mutex.Unlock()
- return s.len()
- }
- func (s *jsStorage) len() int {
- return Window().Get(s.name).Get("length").Int()
- }
- func (s *jsStorage) Key(i int) (string, error) {
- if l := s.len(); i < 0 || i >= l {
- return "", errors.New("index out of range").
- Tag("index", i).
- Tag("len", l)
- }
- return Window().Get(s.name).Call("key", i).String(), nil
- }
|