WASM: Store User Files in localStorage
* In WASM build, user levels and doodads are written to localStorage using their userdir path as keys (".config/levels/test.level") * LoadFile() and WriteFile() for both Levels and Doodads interact with the localStorage for WASM build instead of filesystem for desktop. * userdir.ListLevels() and ListDoodads() for WASM scan the localStorage keys for file names. * userdir.ResolvePath() now works for WASM (previously was dummied out), checks for the file in localStorage.
This commit is contained in:
parent
b17ca34de2
commit
35a89e5dbe
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -6,6 +6,7 @@ dist/
|
||||||
wasm/assets/
|
wasm/assets/
|
||||||
*.wasm
|
*.wasm
|
||||||
*.doodad
|
*.doodad
|
||||||
|
*.level
|
||||||
docker/ubuntu
|
docker/ubuntu
|
||||||
docker/debian
|
docker/debian
|
||||||
docker/fedora
|
docker/fedora
|
||||||
|
|
|
@ -43,12 +43,8 @@ func (d *Doodle) EditFile(filename string) error {
|
||||||
return d.EditDrawing(filename)
|
return d.EditDrawing(filename)
|
||||||
}
|
}
|
||||||
|
|
||||||
// WASM: no filesystem access, can go no further.
|
// Check the user's levels directory. In WASM this will check in
|
||||||
if runtime.GOOS == "js" {
|
// localStorage.
|
||||||
return fmt.Errorf("EditFile(%s): not found for WASM and can go no further", filename)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check the user's levels directory.
|
|
||||||
if foundFilename := userdir.ResolvePath(filename, extension, false); foundFilename != "" {
|
if foundFilename := userdir.ResolvePath(filename, extension, false); foundFilename != "" {
|
||||||
log.Info("EditFile: resolved name '%s' to path %s", filename, foundFilename)
|
log.Info("EditFile: resolved name '%s' to path %s", filename, foundFilename)
|
||||||
absPath = foundFilename
|
absPath = foundFilename
|
||||||
|
|
|
@ -68,6 +68,14 @@ func LoadFile(filename string) (*Doodad, error) {
|
||||||
|
|
||||||
// WASM: try the file over HTTP ajax request.
|
// WASM: try the file over HTTP ajax request.
|
||||||
if runtime.GOOS == "js" {
|
if runtime.GOOS == "js" {
|
||||||
|
if result, ok := wasm.GetSession(filename); ok {
|
||||||
|
log.Info("recall doodad data from localStorage")
|
||||||
|
return FromJSON(filename, []byte(result))
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: ajax load for doodads might not work, filesystem.FindFile returns
|
||||||
|
// the base file for WASM but for now force it to system doodads path
|
||||||
|
filename = "assets/doodads/" + filename
|
||||||
jsonData, err := wasm.HTTPGet(filename)
|
jsonData, err := wasm.HTTPGet(filename)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -90,13 +98,19 @@ func (d *Doodad) WriteFile(filename string) error {
|
||||||
d.Version = 1
|
d.Version = 1
|
||||||
d.GameVersion = branding.Version
|
d.GameVersion = branding.Version
|
||||||
|
|
||||||
// bin, err := m.ToBinary()
|
|
||||||
bin, err := d.ToJSON()
|
bin, err := d.ToJSON()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save it to their profile directory.
|
// WASM: place in localStorage.
|
||||||
|
if runtime.GOOS == "js" {
|
||||||
|
log.Info("wasm: write %s to localStorage", filename)
|
||||||
|
wasm.SetSession(filename, string(bin))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Desktop: write to disk.
|
||||||
filename = userdir.DoodadPath(filename)
|
filename = userdir.DoodadPath(filename)
|
||||||
log.Info("Write Doodad: %s", filename)
|
log.Info("Write Doodad: %s", filename)
|
||||||
err = ioutil.WriteFile(filename, bin, 0644)
|
err = ioutil.WriteFile(filename, bin, 0644)
|
||||||
|
|
|
@ -105,7 +105,7 @@ func FindFile(filename string) (string, error) {
|
||||||
// WASM: can't check the filesystem. Let the caller go ahead and try
|
// WASM: can't check the filesystem. Let the caller go ahead and try
|
||||||
// loading via ajax request.
|
// loading via ajax request.
|
||||||
if runtime.GOOS == "js" {
|
if runtime.GOOS == "js" {
|
||||||
return candidate, nil
|
return filename, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// external system level?
|
// external system level?
|
||||||
|
@ -133,7 +133,7 @@ func FindFile(filename string) (string, error) {
|
||||||
// WASM: can't check the filesystem. Let the caller go ahead and try
|
// WASM: can't check the filesystem. Let the caller go ahead and try
|
||||||
// loading via ajax request.
|
// loading via ajax request.
|
||||||
if runtime.GOOS == "js" {
|
if runtime.GOOS == "js" {
|
||||||
return candidate, nil
|
return filename, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// external system doodad?
|
// external system doodad?
|
||||||
|
|
|
@ -61,8 +61,14 @@ func LoadFile(filename string) (*Level, error) {
|
||||||
return FromJSON(filename, jsonData)
|
return FromJSON(filename, jsonData)
|
||||||
}
|
}
|
||||||
|
|
||||||
// WASM: try the file over HTTP ajax request.
|
// WASM: try the file from localStorage or HTTP ajax request.
|
||||||
if runtime.GOOS == "js" {
|
if runtime.GOOS == "js" {
|
||||||
|
if result, ok := wasm.GetSession(filename); ok {
|
||||||
|
log.Info("recall level data from localStorage")
|
||||||
|
return FromJSON(filename, []byte(result))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ajax request.
|
||||||
jsonData, err := wasm.HTTPGet(filename)
|
jsonData, err := wasm.HTTPGet(filename)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -98,7 +104,6 @@ func (m *Level) WriteFile(filename string) error {
|
||||||
m.Version = 1
|
m.Version = 1
|
||||||
m.GameVersion = branding.Version
|
m.GameVersion = branding.Version
|
||||||
|
|
||||||
// bin, err := m.ToBinary()
|
|
||||||
bin, err := m.ToJSON()
|
bin, err := m.ToJSON()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -107,6 +112,15 @@ func (m *Level) WriteFile(filename string) error {
|
||||||
// Save it to their profile directory.
|
// Save it to their profile directory.
|
||||||
filename = userdir.LevelPath(filename)
|
filename = userdir.LevelPath(filename)
|
||||||
log.Info("Write Level: %s", filename)
|
log.Info("Write Level: %s", filename)
|
||||||
|
|
||||||
|
// WASM: place in localStorage.
|
||||||
|
if runtime.GOOS == "js" {
|
||||||
|
log.Info("wasm: write %s to localStorage", filename)
|
||||||
|
wasm.SetSession(filename, string(bin))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Desktop: write to disk.
|
||||||
err = ioutil.WriteFile(filename, bin, 0644)
|
err = ioutil.WriteFile(filename, bin, 0644)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("level.WriteFile: %s", err)
|
return fmt.Errorf("level.WriteFile: %s", err)
|
||||||
|
|
|
@ -7,7 +7,7 @@ import (
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"git.kirsle.net/apps/doodle/pkg/log"
|
"git.kirsle.net/apps/doodle/pkg/wasm"
|
||||||
"github.com/kirsle/configdir"
|
"github.com/kirsle/configdir"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -77,6 +77,11 @@ func CacheFilename(filename ...string) string {
|
||||||
func ListDoodads() ([]string, error) {
|
func ListDoodads() ([]string, error) {
|
||||||
var names []string
|
var names []string
|
||||||
|
|
||||||
|
// WASM: list from localStorage.
|
||||||
|
if runtime.GOOS == "js" {
|
||||||
|
return wasm.StorageKeys(DoodadDirectory + "/"), nil
|
||||||
|
}
|
||||||
|
|
||||||
files, err := ioutil.ReadDir(DoodadDirectory)
|
files, err := ioutil.ReadDir(DoodadDirectory)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return names, err
|
return names, err
|
||||||
|
@ -96,6 +101,11 @@ func ListDoodads() ([]string, error) {
|
||||||
func ListLevels() ([]string, error) {
|
func ListLevels() ([]string, error) {
|
||||||
var names []string
|
var names []string
|
||||||
|
|
||||||
|
// WASM: list from localStorage.
|
||||||
|
if runtime.GOOS == "js" {
|
||||||
|
return wasm.StorageKeys(LevelDirectory + "/"), nil
|
||||||
|
}
|
||||||
|
|
||||||
files, err := ioutil.ReadDir(LevelDirectory)
|
files, err := ioutil.ReadDir(LevelDirectory)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return names, err
|
return names, err
|
||||||
|
@ -133,15 +143,11 @@ func resolvePath(directory, filename, extension string) string {
|
||||||
// existed. So the filename should have a ".level" or ".doodad" extension and
|
// existed. So the filename should have a ".level" or ".doodad" extension and
|
||||||
// then this path will resolve the ProfileDirectory of the file.
|
// then this path will resolve the ProfileDirectory of the file.
|
||||||
func ResolvePath(filename, extension string, one bool) string {
|
func ResolvePath(filename, extension string, one bool) string {
|
||||||
// WASM has no file system.
|
|
||||||
if runtime.GOOS == "js" {
|
|
||||||
log.Error("userdir.ResolvePath: not supported in WASM build")
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the filename exists outright, return it.
|
// If the filename exists outright, return it.
|
||||||
if _, err := os.Stat(filename); !os.IsNotExist(err) {
|
if !(runtime.GOOS == "js") {
|
||||||
return filename
|
if _, err := os.Stat(filename); !os.IsNotExist(err) {
|
||||||
|
return filename
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var paths []string
|
var paths []string
|
||||||
|
@ -157,6 +163,15 @@ func ResolvePath(filename, extension string, one bool) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, test := range paths {
|
for _, test := range paths {
|
||||||
|
// WASM: check the path in localStorage.
|
||||||
|
if runtime.GOOS == "js" {
|
||||||
|
if _, ok := wasm.GetSession(test); ok {
|
||||||
|
return test
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Desktop: test the filesystem.
|
||||||
if _, err := os.Stat(test); os.IsNotExist(err) {
|
if _, err := os.Stat(test); os.IsNotExist(err) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,12 @@
|
||||||
|
|
||||||
package wasm
|
package wasm
|
||||||
|
|
||||||
|
// StorageKeys returns the list of localStorage keys matching a prefix.
|
||||||
|
// This is a no-op when not in wasm.
|
||||||
|
func StorageKeys(prefix string) []string {
|
||||||
|
return []string{}
|
||||||
|
}
|
||||||
|
|
||||||
// SetSession sets a binary value on sessionStorage.
|
// SetSession sets a binary value on sessionStorage.
|
||||||
// This is a no-op when not in wasm.
|
// This is a no-op when not in wasm.
|
||||||
func SetSession(key string, value string) {
|
func SetSession(key string, value string) {
|
||||||
|
|
|
@ -3,20 +3,37 @@
|
||||||
package wasm
|
package wasm
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"strings"
|
||||||
"syscall/js"
|
"syscall/js"
|
||||||
|
|
||||||
|
"git.kirsle.net/apps/doodle/pkg/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// StorageKeys returns the list of localStorage keys matching a prefix.
|
||||||
|
func StorageKeys(prefix string) []string {
|
||||||
|
keys := js.Global().Get("Object").Call("keys", js.Global().Get("localStorage"))
|
||||||
|
|
||||||
|
var result []string
|
||||||
|
for i := 0; i < keys.Length(); i++ {
|
||||||
|
value := keys.Index(i).String()
|
||||||
|
if strings.HasPrefix(value, prefix) {
|
||||||
|
result = append(result,
|
||||||
|
strings.TrimPrefix(keys.Index(i).String(), prefix),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log.Info("LS KEYS: %+v", result)
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
// SetSession sets a text value on sessionStorage.
|
// SetSession sets a text value on sessionStorage.
|
||||||
func SetSession(key string, value string) {
|
func SetSession(key string, value string) {
|
||||||
// b64 := base64.StdEncoding.EncodeToString(value)
|
js.Global().Get("localStorage").Call("setItem", key, value)
|
||||||
panic("SesSession: " + key)
|
|
||||||
js.Global().Get("sessionStorage").Call("setItem", key, value)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetSession retrieves a text value from sessionStorage.
|
// GetSession retrieves a text value from sessionStorage.
|
||||||
func GetSession(key string) (string, bool) {
|
func GetSession(key string) (string, bool) {
|
||||||
panic("GetSession: " + key)
|
|
||||||
var value js.Value
|
var value js.Value
|
||||||
value = js.Global().Get("sessionStorage").Call("getItem", key)
|
value = js.Global().Get("localStorage").Call("getItem", key)
|
||||||
return value.String(), value.Type() == js.TypeString
|
return value.String(), value.Type() == js.TypeString
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user