Skip to content

Commit

Permalink
feat: plugin api client storage (#376)
Browse files Browse the repository at this point in the history
* feat: add local storage API

* test: test for return promise

* refactor: clean up

* chore: remove empty file

* refactor: add startEventLoop and clean up

* refactor: remove undefined from type

* refactor: check if promise with instanceof

* refactor: set pluginId as `reearth-plugineditor`

* refactor: prefix store name & reject empty

* refactor:  update default widget/block id

* refactor: use extensionInstanceId & clean type

* fix: unexist extention

* refactor: renaming id

* chore: update package registry to yarnpkg.com
  • Loading branch information
airslice authored Dec 23, 2022
1 parent a8f5bf6 commit 4f36add
Show file tree
Hide file tree
Showing 11 changed files with 289 additions and 21 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@
"jotai": "1.11.2",
"js-file-download": "0.4.12",
"leaflet": "1.9.3",
"localforage": "1.10.0",
"lodash-es": "4.17.21",
"mini-svg-data-uri": "1.4.4",
"parse-domain": "7.0.1",
Expand Down
37 changes: 23 additions & 14 deletions src/components/atoms/Plugin/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ export type API = {
off: (e: (msg: any) => void) => void;
once: (e: (msg: any) => void) => void;
};
startEventLoop: () => void;
};

export type Ref = {
Expand All @@ -51,7 +52,8 @@ export const defaultIsMarshalable = (obj: any): boolean => {
Array.isArray(obj) ||
Object.getPrototypeOf(obj) === Function.prototype ||
Object.getPrototypeOf(obj) === Object.prototype ||
obj instanceof Date
obj instanceof Date ||
obj instanceof Promise
);
};

Expand Down Expand Up @@ -114,6 +116,22 @@ export default function useHook({
[messageEvents, messageOnceEvents, onError, rawOnMessage],
);

const eventLoopCb = useCallback(() => {
if (!arena.current) return;
try {
arena.current.executePendingJobs();
if (arena.current.context.runtime.hasPendingJob()) {
eventLoop.current = window.setTimeout(eventLoopCb, 0);
}
} catch (err) {
onError(err);
}
}, [onError]);

const startEventLoop = useCallback(() => {
eventLoop.current = window.setTimeout(eventLoopCb, 0);
}, [eventLoopCb]);

const evalCode = useCallback(
(code: string): any => {
if (!arena.current) return;
Expand All @@ -125,22 +143,11 @@ export default function useHook({
onError(err);
}

const eventLoopCb = () => {
if (!arena.current) return;
try {
arena.current.executePendingJobs();
if (arena.current.context.runtime.hasPendingJob()) {
eventLoop.current = window.setTimeout(eventLoopCb, 0);
}
} catch (err) {
onError(err);
}
};
eventLoop.current = window.setTimeout(eventLoopCb, 0);
startEventLoop();

return result;
},
[onError],
[onError, startEventLoop],
);

useEffect(() => {
Expand Down Expand Up @@ -179,6 +186,7 @@ export default function useHook({
off: offMessage,
once: onceMessage,
},
startEventLoop,
})
: exposed;
if (e) {
Expand Down Expand Up @@ -225,6 +233,7 @@ export default function useHook({
mainIFrameRef,
messageEvents,
messageOnceEvents,
startEventLoop,
]);

useImperativeHandle(
Expand Down
10 changes: 5 additions & 5 deletions src/components/molecules/PluginEditor/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,15 +72,15 @@ export default () => {
...(mode === "block"
? [
{
id: "xxx",
id: "reearth-plugineditor-block",
__REEARTH_SOURCECODE: executableSourceCode,
} as any,
]
: []),
{
id: "yyy",
pluginId: "plugins",
extensionId: "block",
id: "reearth-plugineditor-locationblock",
pluginId: "reearth",
extensionId: "locationblock",
property: {
location: { lat: 0, lng: 139 },
},
Expand All @@ -99,7 +99,7 @@ export default () => {

const widget = [
{
id: "xxx",
id: "reearth-plugineditor-widget",
// extended: true,
__REEARTH_SOURCECODE: executableSourceCode,
},
Expand Down
75 changes: 74 additions & 1 deletion src/components/molecules/Visualizer/Plugin/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import type { Events } from "@reearth/util/event";
import { merge } from "@reearth/util/object";

import type { LayerStore } from "../Layers";
import type { ClientStorage } from "../useClientStorage";
import type { PluginInstances } from "../usePluginInstances";

import type {
Expand All @@ -19,7 +20,7 @@ import type {

export type CommonReearth = Omit<
Reearth,
"plugin" | "ui" | "modal" | "popup" | "block" | "layer" | "widget"
"plugin" | "ui" | "modal" | "popup" | "block" | "layer" | "widget" | "clientStorage"
>;

export function exposed({
Expand All @@ -41,9 +42,11 @@ export function exposed({
layer,
block,
widget,
startEventLoop,
overrideSceneProperty,
moveWidget,
pluginPostMessage,
clientStorage,
}: {
render: (
html: string,
Expand Down Expand Up @@ -78,9 +81,11 @@ export function exposed({
layer?: () => Layer | undefined;
block?: () => Block | undefined;
widget?: () => Widget | undefined;
startEventLoop?: () => void;
overrideSceneProperty?: (pluginId: string, property: any) => void;
moveWidget?: (widgetId: string, options: WidgetLocationOptions) => void;
pluginPostMessage: (extentionId: string, msg: any, sender: string) => void;
clientStorage: ClientStorage;
}): GlobalThis {
return merge({
console: {
Expand Down Expand Up @@ -188,6 +193,74 @@ export function exposed({
return commonReearth.plugins.instances;
},
},
clientStorage: {
get getAsync() {
return (key: string) => {
const promise = clientStorage.getAsync(
(plugin?.extensionType === "widget"
? widget?.()?.id
: plugin?.extensionType === "block"
? block?.()?.id
: "") ?? "",
key,
);
promise.finally(() => {
startEventLoop?.();
});
return promise;
};
},
get setAsync() {
return (key: string, value: any) => {
const localValue =
typeof value === "object" ? JSON.parse(JSON.stringify(value)) : value;
const promise = clientStorage.setAsync(
(plugin?.extensionType === "widget"
? widget?.()?.id
: plugin?.extensionType === "block"
? block?.()?.id
: "") ?? "",
key,
localValue,
);
promise.finally(() => {
startEventLoop?.();
});
return promise;
};
},
get deleteAsync() {
return (key: string) => {
const promise = clientStorage.deleteAsync(
(plugin?.extensionType === "widget"
? widget?.()?.id
: plugin?.extensionType === "block"
? block?.()?.id
: "") ?? "",
key,
);
promise.finally(() => {
startEventLoop?.();
});
return promise;
};
},
get keysAsync() {
return () => {
const promise = clientStorage.keysAsync(
(plugin?.extensionType === "widget"
? widget?.()?.id
: plugin?.extensionType === "block"
? block?.()?.id
: "") ?? "",
);
promise.finally(() => {
startEventLoop?.();
});
return promise;
};
},
},
...events,
},
plugin?.extensionType === "block"
Expand Down
6 changes: 6 additions & 0 deletions src/components/molecules/Visualizer/Plugin/context.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { MouseEvents, MouseEventHandles } from "../Engine/ref";
import { Viewport as VisualizerViewport } from "../hooks";
import type { LayerStore } from "../Layers";
import type { Component as PrimitiveComponent } from "../Primitive";
import type { ClientStorage } from "../useClientStorage";
import { PluginInstances } from "../usePluginInstances";
import { useGet } from "../utils";

Expand Down Expand Up @@ -57,6 +58,7 @@ export type Props = {
layerOverridenInfobox?: OverriddenInfobox;
layerOverriddenProperties?: { [key: string]: any };
viewport: VisualizerViewport;
clientStorage: ClientStorage;
showLayer: (...id: string[]) => void;
hideLayer: (...id: string[]) => void;
addLayer: (layer: Layer, parentId?: string, creator?: string) => string | undefined;
Expand Down Expand Up @@ -97,6 +99,7 @@ export type Context = {
reearth: CommonReearth;
engine: EngineContext;
pluginInstances: PluginInstances;
clientStorage: ClientStorage;
overrideSceneProperty: (id: string, property: any) => void;
emit: EventEmitter<SelectedReearthEventType>;
moveWidget: (widgetId: string, options: WidgetLocationOptions) => void;
Expand Down Expand Up @@ -126,6 +129,7 @@ export function Provider({
layerOverridenInfobox,
layerOverriddenProperties,
viewport,
clientStorage,
showLayer,
hideLayer,
addLayer,
Expand Down Expand Up @@ -235,12 +239,14 @@ export function Provider({
emit,
moveWidget,
pluginInstances,
clientStorage,
}),
[
api,
builtinPrimitives,
engineName,
ev,
clientStorage,
getLayers,
getSceneProperty,
getInEditor,
Expand Down
5 changes: 4 additions & 1 deletion src/components/molecules/Visualizer/Plugin/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,7 @@ export function useAPI({

const staticExposed = useMemo((): ((api: IFrameAPI) => GlobalThis) | undefined => {
if (!ctx?.reearth) return;
return ({ main, modal, popup, messages }: IFrameAPI) => {
return ({ main, modal, popup, messages, startEventLoop }: IFrameAPI) => {
return exposed({
commonReearth: ctx.reearth,
events: {
Expand Down Expand Up @@ -387,16 +387,19 @@ export function useAPI({
main.resize(width, height);
onResize?.(width, height, extended);
},
startEventLoop,
overrideSceneProperty: ctx.overrideSceneProperty,
moveWidget: ctx.moveWidget,
pluginPostMessage: ctx.pluginInstances.postMessage,
clientStorage: ctx.clientStorage,
});
};
}, [
ctx?.reearth,
ctx?.overrideSceneProperty,
ctx?.moveWidget,
ctx?.pluginInstances,
ctx?.clientStorage,
extensionId,
extensionType,
pluginId,
Expand Down
8 changes: 8 additions & 0 deletions src/components/molecules/Visualizer/Plugin/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export type Reearth = {
readonly block?: Block;
readonly scene: Scene;
readonly viewport: Viewport;
readonly clientStorage: ClientStorage;
readonly on: <T extends keyof ReearthEventType>(
type: T,
callback: (...args: ReearthEventType[T]) => void,
Expand Down Expand Up @@ -515,3 +516,10 @@ export type Clock = {
readonly play: () => void;
readonly pause: () => void;
};

export type ClientStorage = {
readonly getAsync: (key: string) => Promise<any>;
readonly setAsync: (key: string, value: any) => Promise<void>;
readonly deleteAsync: (key: string) => Promise<void>;
readonly keysAsync: () => Promise<string[]>;
};
4 changes: 4 additions & 0 deletions src/components/molecules/Visualizer/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import type {
LookAtDestination,
Tag,
} from "./Plugin/types";
import useClientStorage from "./useClientStorage";
import usePluginInstances from "./usePluginInstances";
import useViewport from "./useViewport";
import useWidgetAlignSystem from "./useWidgetAlignSystem";
Expand Down Expand Up @@ -222,6 +223,8 @@ export default ({
blocks: selectedLayer?.infobox?.blocks,
});

const clientStorage = useClientStorage();

const providerProps: ProviderProps = useProviderProps(
{
engineName: engineType || "",
Expand All @@ -236,6 +239,7 @@ export default ({
layerOverridenInfobox,
layerOverriddenProperties,
viewport,
clientStorage,
showLayer: showLayers,
hideLayer: hideLayers,
addLayer,
Expand Down
11 changes: 11 additions & 0 deletions src/components/molecules/Visualizer/storybook.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,17 @@ export const context: ProviderProps = {
addPluginMessageSender: () => {},
removePluginMessageSender: () => {},
},
clientStorage: {
getAsync: act("clientStorage.getAsync"),
setAsync: act("clientStorage.setAsync"),
deleteAsync: act("clientStorage.deleteAsync"),
keysAsync: act("clientStorage.keysAsync"),
dropStore: () => {
return new Promise<void>(resolve => {
resolve();
});
},
},
flyTo: act("flyTo"),
lookAt: act("lookAt"),
zoomIn: act("zoomIn"),
Expand Down
Loading

0 comments on commit 4f36add

Please sign in to comment.