gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[taler-wallet-core] 01/02: use buildKeyStorage to prevent different type


From: gnunet
Subject: [taler-wallet-core] 01/02: use buildKeyStorage to prevent different type for same key
Date: Fri, 26 May 2023 21:52:41 +0200

This is an automated email from the git hooks/post-receive script.

sebasjm pushed a commit to branch master
in repository wallet-core.

commit be27647ff73d1529372a80c3e145f3ee4f229a17
Author: Sebastian <sebasjm@gmail.com>
AuthorDate: Fri May 26 16:51:47 2023 -0300

    use buildKeyStorage to prevent different type for same key
---
 .../src/hooks/useSettings.ts                       | 30 ++++++++--
 packages/web-util/src/hooks/index.ts               |  2 +-
 packages/web-util/src/hooks/useLang.ts             | 12 +++-
 packages/web-util/src/hooks/useLocalStorage.ts     | 70 ++++++++++++----------
 packages/web-util/src/hooks/useMemoryStorage.ts    | 60 +++++++++----------
 5 files changed, 101 insertions(+), 73 deletions(-)

diff --git a/packages/taler-wallet-webextension/src/hooks/useSettings.ts 
b/packages/taler-wallet-webextension/src/hooks/useSettings.ts
index ebb1e991c..7e7b26a39 100644
--- a/packages/taler-wallet-webextension/src/hooks/useSettings.ts
+++ b/packages/taler-wallet-webextension/src/hooks/useSettings.ts
@@ -14,8 +14,13 @@
  GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
  */
 
-import { useLocalStorage } from "@gnu-taler/web-util/browser";
+import { buildStorageKey, useLocalStorage } from "@gnu-taler/web-util/browser";
 import { Settings, defaultSettings } from "../platform/api.js";
+import {
+  Codec,
+  buildCodecForObject,
+  codecForBoolean,
+} from "@gnu-taler/taler-util";
 
 function parse_json_or_undefined<T>(str: string | undefined): T | undefined {
   if (str === undefined) return undefined;
@@ -26,17 +31,30 @@ function parse_json_or_undefined<T>(str: string | 
undefined): T | undefined {
   }
 }
 
+export const codecForSettings = (): Codec<Settings> =>
+  buildCodecForObject<Settings>()
+    .property("walletAllowHttp", codecForBoolean())
+    .property("walletBatchWithdrawal", codecForBoolean())
+    .property("injectTalerSupport", codecForBoolean())
+    .property("advanceMode", codecForBoolean())
+    .property("backup", codecForBoolean())
+    .property("langSelector", codecForBoolean())
+    .property("showJsonOnError", codecForBoolean())
+    .property("extendedAccountTypes", codecForBoolean())
+    .property("deleteActiveTransactions", codecForBoolean())
+    .build("Settings");
+
+const SETTINGS_KEY = buildStorageKey("wallet-settings", codecForSettings());
+
 export function useSettings(): [
   Readonly<Settings>,
   <T extends keyof Settings>(key: T, value: Settings[T]) => void,
 ] {
-  const { value, update } = useLocalStorage("wallet-settings");
+  const { value, update } = useLocalStorage(SETTINGS_KEY);
 
-  const parsed: Settings = parse_json_or_undefined(value) ?? defaultSettings;
+  const parsed: Settings = value ?? defaultSettings;
   function updateField<T extends keyof Settings>(k: T, v: Settings[T]) {
-    const newValue = { ...parsed, [k]: v };
-    const json = JSON.stringify(newValue);
-    update(json);
+    update({ ...parsed, [k]: v });
   }
   return [parsed, updateField];
 }
diff --git a/packages/web-util/src/hooks/index.ts 
b/packages/web-util/src/hooks/index.ts
index ae8872497..a3a2053e6 100644
--- a/packages/web-util/src/hooks/index.ts
+++ b/packages/web-util/src/hooks/index.ts
@@ -1,5 +1,5 @@
 export { useLang } from "./useLang.js";
-export { useLocalStorage } from "./useLocalStorage.js";
+export { useLocalStorage, buildStorageKey } from "./useLocalStorage.js";
 export { useMemoryStorage } from "./useMemoryStorage.js";
 export {
   useNotifications,
diff --git a/packages/web-util/src/hooks/useLang.ts 
b/packages/web-util/src/hooks/useLang.ts
index d64cf6e1a..448cd8aba 100644
--- a/packages/web-util/src/hooks/useLang.ts
+++ b/packages/web-util/src/hooks/useLang.ts
@@ -14,7 +14,11 @@
  GNU Anastasis; see the file COPYING.  If not, see 
<http://www.gnu.org/licenses/>
  */
 
-import { LocalStorageState, useLocalStorage } from "./useLocalStorage.js";
+import {
+  StorageState,
+  buildStorageKey,
+  useLocalStorage,
+} from "./useLocalStorage.js";
 
 function getBrowserLang(): string | undefined {
   if (typeof window === "undefined") return undefined;
@@ -23,7 +27,9 @@ function getBrowserLang(): string | undefined {
   return undefined;
 }
 
-export function useLang(initial?: string): Required<LocalStorageState> {
+const langPreferenceKey = buildStorageKey("lang-preference");
+
+export function useLang(initial?: string): Required<StorageState> {
   const defaultValue = (getBrowserLang() || initial || "en").substring(0, 2);
-  return useLocalStorage("lang-preference", { defaultValue: defaultValue });
+  return useLocalStorage(langPreferenceKey, defaultValue);
 }
diff --git a/packages/web-util/src/hooks/useLocalStorage.ts 
b/packages/web-util/src/hooks/useLocalStorage.ts
index 55efd01cb..45b7abd3c 100644
--- a/packages/web-util/src/hooks/useLocalStorage.ts
+++ b/packages/web-util/src/hooks/useLocalStorage.ts
@@ -19,7 +19,7 @@
  * @author Sebastian Javier Marchano (sebasjm)
  */
 
-import { Codec } from "@gnu-taler/taler-util";
+import { Codec, codecForString } from "@gnu-taler/taler-util";
 import { useEffect, useState } from "preact/hooks";
 import {
   ObservableMap,
@@ -28,7 +28,26 @@ import {
   memoryMap,
 } from "../utils/observable.js";
 
-export interface LocalStorageState<Type = string> {
+declare const opaque_StorageKey: unique symbol;
+
+export type StorageKey<Key> = {
+  id: string;
+  [opaque_StorageKey]: true;
+  codec: Codec<Key>;
+};
+
+export function buildStorageKey<Key = string>(
+  name: string,
+  codec?: Codec<Key>,
+): StorageKey<Key> {
+  return {
+    id: name,
+    codec: codec ?? (codecForString() as Codec<Key>),
+    [opaque_StorageKey]: true,
+  };
+}
+
+export interface StorageState<Type = string> {
   value?: Type;
   update: (s: Type) => void;
   reset: () => void;
@@ -50,59 +69,48 @@ const storage: ObservableMap<string, string> = (function 
buildStorage() {
 
 //with initial value
 export function useLocalStorage<Type = string>(
-  key: string,
-  options?: {
-    defaultValue: Type;
-    codec?: Codec<Type>;
-  },
-): Required<LocalStorageState<Type>>;
+  key: StorageKey<Type>,
+  defaultValue: Type,
+): Required<StorageState<Type>>;
 //without initial value
 export function useLocalStorage<Type = string>(
-  key: string,
-  options?: {
-    codec?: Codec<Type>;
-  },
-): LocalStorageState<Type>;
+  key: StorageKey<Type>,
+): StorageState<Type>;
 // impl
 export function useLocalStorage<Type = string>(
-  key: string,
-  options?: {
-    defaultValue?: Type;
-    codec?: Codec<Type>;
-  },
-): LocalStorageState<Type> {
+  key: StorageKey<Type>,
+  defaultValue?: Type,
+): StorageState<Type> {
   function convert(updated: string | undefined): Type | undefined {
-    if (updated === undefined) return options?.defaultValue; //optional
+    if (updated === undefined) return defaultValue; //optional
     try {
-      return !options?.codec
-        ? (updated as Type)
-        : options.codec.decode(JSON.parse(updated));
+      return key.codec.decode(JSON.parse(updated));
     } catch (e) {
       //decode error
-      return options?.defaultValue;
+      return defaultValue;
     }
   }
   const [storedValue, setStoredValue] = useState<Type | undefined>(
     (): Type | undefined => {
-      const prev = storage.get(key);
+      const prev = storage.get(key.id);
       return convert(prev);
     },
   );
 
   useEffect(() => {
-    return storage.onUpdate(key, () => {
-      const newValue = storage.get(key);
+    return storage.onUpdate(key.id, () => {
+      const newValue = storage.get(key.id);
       setStoredValue(convert(newValue));
     });
   }, []);
 
   const setValue = (value?: Type): void => {
     if (value === undefined) {
-      storage.delete(key);
+      storage.delete(key.id);
     } else {
       storage.set(
-        key,
-        options?.codec ? JSON.stringify(value) : (value as string),
+        key.id,
+        key.codec ? JSON.stringify(value) : (value as string),
       );
     }
   };
@@ -111,7 +119,7 @@ export function useLocalStorage<Type = string>(
     value: storedValue,
     update: setValue,
     reset: () => {
-      setValue(options?.defaultValue);
+      setValue(defaultValue);
     },
   };
 }
diff --git a/packages/web-util/src/hooks/useMemoryStorage.ts 
b/packages/web-util/src/hooks/useMemoryStorage.ts
index 7160b035e..d8be24c1e 100644
--- a/packages/web-util/src/hooks/useMemoryStorage.ts
+++ b/packages/web-util/src/hooks/useMemoryStorage.ts
@@ -20,48 +20,44 @@
  */
 
 import { useEffect, useState } from "preact/hooks";
-import {
-  ObservableMap,
-  browserStorageMap,
-  localStorageMap,
-  memoryMap,
-} from "../utils/observable.js";
+import { ObservableMap, memoryMap } from "../utils/observable.js";
+import { StorageKey, StorageState } from "./useLocalStorage.js";
 
-export interface LocalStorageState {
-  value?: string;
-  update: (s: string) => void;
-  reset: () => void;
-}
-
-const storage: ObservableMap<string, string> = memoryMap<string>();
+const storage: ObservableMap<string, any> = memoryMap<any>();
 
-export function useMemoryStorage(
-  key: string,
-  initialValue: string,
-): Required<LocalStorageState>;
-export function useMemoryStorage(key: string): LocalStorageState;
-export function useMemoryStorage(
-  key: string,
-  initialValue?: string,
-): LocalStorageState {
-  const [storedValue, setStoredValue] = useState<string | undefined>(
-    (): string | undefined => {
-      return storage.get(key) ?? initialValue;
+//with initial value
+export function useMemoryStorage<Type = string>(
+  key: StorageKey<Type>,
+  defaultValue: Type,
+): Required<StorageState<Type>>;
+//with initial value
+export function useMemoryStorage<Type = string>(
+  key: StorageKey<Type>,
+): StorageState<Type>;
+// impl
+export function useMemoryStorage<Type = string>(
+  key: StorageKey<Type>,
+  defaultValue?: Type,
+): StorageState<Type> {
+  const [storedValue, setStoredValue] = useState<Type | undefined>(
+    (): Type | undefined => {
+      const prev = storage.get(key.id);
+      return prev;
     },
   );
 
   useEffect(() => {
-    return storage.onUpdate(key, () => {
-      const newValue = storage.get(key);
-      setStoredValue(newValue ?? initialValue);
+    return storage.onUpdate(key.id, () => {
+      const newValue = storage.get(key.id);
+      setStoredValue(newValue);
     });
   }, []);
 
-  const setValue = (value?: string): void => {
+  const setValue = (value?: Type): void => {
     if (value === undefined) {
-      storage.delete(key);
+      storage.delete(key.id);
     } else {
-      storage.set(key, value);
+      storage.set(key.id, value);
     }
   };
 
@@ -69,7 +65,7 @@ export function useMemoryStorage(
     value: storedValue,
     update: setValue,
     reset: () => {
-      setValue(initialValue);
+      setValue(defaultValue);
     },
   };
 }

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]