Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #327 from tdakkota/feat/websocket-support
feat(session): add web storage API based session storage
- Loading branch information
Showing
1 changed file
with
85 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
// +build js,wasm | ||
|
||
package session | ||
|
||
import ( | ||
"context" | ||
"syscall/js" | ||
|
||
"golang.org/x/xerrors" | ||
) | ||
|
||
// WebLocalStorage is a Web Storage API based session storage. | ||
type WebLocalStorage struct { | ||
Key string | ||
} | ||
|
||
func getStorage() (js.Value, bool) { | ||
localStorage := js.Global().Get("localStorage") | ||
|
||
if localStorage.IsUndefined() || localStorage.IsNull() { | ||
return js.Value{}, false | ||
} | ||
|
||
const testValue = "__test__" | ||
localStorage.Set(testValue, testValue) | ||
value := localStorage.Get(testValue) | ||
if value.IsUndefined() || value.IsNull() { | ||
return js.Value{}, false | ||
} | ||
localStorage.Delete(testValue) | ||
|
||
return localStorage, true | ||
} | ||
|
||
// ErrLocalStorageIsNotAvailable is returned if localStorage is not available and Storage can't use it. | ||
var ErrLocalStorageIsNotAvailable = xerrors.New("localStorage is not available") | ||
|
||
func catch(err *error) { // nolint:gocritic | ||
if r := recover(); r != nil { | ||
rErr, ok := r.(error) | ||
if !ok { | ||
*err = xerrors.Errorf("catch: %v", r) | ||
} else { | ||
*err = xerrors.Errorf("catch: %w", rErr) | ||
} | ||
} | ||
} | ||
|
||
// LoadSession loads session using Web Storage API. | ||
func (w WebLocalStorage) LoadSession(_ context.Context) (_ []byte, rerr error) { | ||
defer catch(&rerr) | ||
|
||
if w.Key == "" { | ||
return nil, xerrors.Errorf("invalid key %q", w.Key) | ||
} | ||
|
||
store, ok := getStorage() | ||
if !ok { | ||
return nil, ErrLocalStorageIsNotAvailable | ||
} | ||
|
||
value := store.Call("getItem", w.Key) | ||
if value.IsNull() || value.IsUndefined() { | ||
return nil, ErrNotFound | ||
} | ||
|
||
return []byte(value.String()), nil | ||
} | ||
|
||
// StoreSession saves session using Web Storage API. | ||
func (w WebLocalStorage) StoreSession(_ context.Context, data []byte) (rerr error) { | ||
defer catch(&rerr) | ||
|
||
if w.Key == "" { | ||
return xerrors.Errorf("invalid key %q", w.Key) | ||
} | ||
|
||
store, ok := getStorage() | ||
if !ok { | ||
return ErrLocalStorageIsNotAvailable | ||
} | ||
|
||
store.Call("setItem", w.Key, string(data)) | ||
return nil | ||
} |