using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices.JavaScript;
using System.Runtime.Versioning;
using System.Threading.Tasks;
// Required for the [JSImport]/[JSExport] source generator to compile.
[assembly: SupportedOSPlatform("browser")]
namespace Glass.WebGL2
{
///
/// The browser's local storage, which keeps text for the site across visits and holds only a few megabytes. Only
/// keys that start with a given prefix are visible, so one page can keep several separate stores.
///
public sealed partial class WebGL2LocalStorage : IKeyValueStore
{
private static Task loadTask;
private static partial class Interop
{
[JSImport("getKeys", "glass-webgl2")]
[return: JSMarshalAs>]
public static partial string[] GetKeys();
[JSImport("get", "glass-webgl2")]
public static partial string Get(string key);
[JSImport("set", "glass-webgl2")]
public static partial bool Set(string key, string value);
[JSImport("remove", "glass-webgl2")]
public static partial void Remove(string key);
}
private readonly string keyPrefix;
///
/// Must be awaited exactly once, from the browser host's own startup code, before any store is used.
/// JSHost.ImportAsync can't be awaited synchronously, since nothing can pump the browser's microtask queue
/// while the single WASM thread is blocked on it.
///
public static Task EnsureLoadedAsync()
{
return loadTask ??= JSHost.ImportAsync("glass-webgl2", "../Glass.WebGL2.js");
}
///
/// Makes a store over the local storage keys that start with . An empty prefix
/// covers all of them.
///
public WebGL2LocalStorage(string keyPrefix)
{
this.keyPrefix = keyPrefix ?? throw new ArgumentNullException(nameof(keyPrefix));
}
public IReadOnlyList GetKeys()
{
var returnMe = new List();
foreach (string key in Interop.GetKeys())
{
if (key.StartsWith(keyPrefix, StringComparison.Ordinal))
{
returnMe.Add(key.Substring(keyPrefix.Length));
}
}
return returnMe;
}
public string Get(string key)
{
if (key == null)
{
throw new ArgumentNullException(nameof(key));
}
return Interop.Get(keyPrefix + key);
}
public void Set(string key, string value)
{
if (key == null)
{
throw new ArgumentNullException(nameof(key));
}
if (value == null)
{
throw new ArgumentNullException(nameof(value));
}
if (!Interop.Set(keyPrefix + key, value))
{
throw new IOException("The browser's storage is full or turned off.");
}
}
public void Remove(string key)
{
if (key == null)
{
throw new ArgumentNullException(nameof(key));
}
Interop.Remove(keyPrefix + key);
}
}
}