@xwiki/cristal-sharedworker-impl 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,225 @@
1
+ /**
2
+ * See the LICENSE file distributed with this work for additional
3
+ * information regarding copyright ownership.
4
+ *
5
+ * This is free software; you can redistribute it and/or modify it
6
+ * under the terms of the GNU Affero General Public License as
7
+ * published by the Free Software Foundation; either version 2.1 of
8
+ * the License, or (at your option) any later version.
9
+ *
10
+ * This software is distributed in the hope that it will be useful,
11
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
+ * Lesser General Public License for more details.
14
+ *
15
+ * You should have received a copy of the GNU Affero General Public
16
+ * License along with this software; if not, write to the Free
17
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
18
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
19
+ *
20
+ * This file is part of the Cristal Wiki software prototype
21
+ * @copyright Copyright (c) 2023 XWiki SAS
22
+ * @license http://opensource.org/licenses/AGPL-3.0 AGPL-3.0
23
+ *
24
+ **/
25
+
26
+ import * as Comlink from "comlink";
27
+ import type { MyWorker, QueueWorker } from "@xwiki/cristal-sharedworker-api";
28
+ import type { CristalApp, WrappingStorage } from "@xwiki/cristal-api";
29
+ import { type WikiConfig } from "@xwiki/cristal-api";
30
+ import { CristalLoader } from "@xwiki/cristal-extension-manager";
31
+ import { ComponentInit as StorageComponentInit } from "@xwiki/cristal-storage";
32
+ import type { Container } from "inversify";
33
+ import { WorkerCristalApp } from "./workerCristalApp";
34
+ import WorkerQueueWorker from "./workerQueueWorker";
35
+
36
+ export class Worker implements MyWorker {
37
+ private currentNumber: number = 0;
38
+ private queue: Array<string> = [];
39
+ private container: Container;
40
+ private cristal: CristalApp;
41
+ private configMap: Map<string, object>;
42
+ private initialized: boolean = false;
43
+ private fct: (a: string) => void;
44
+
45
+ /*
46
+ Start worker thread
47
+ */
48
+ public async start() {
49
+ console.log("Starting worker thread");
50
+ this.initialize();
51
+ // eslint-disable-next-line no-constant-condition
52
+ while (true) {
53
+ await this.sleep(1000);
54
+ this.checkQueue();
55
+ }
56
+ }
57
+
58
+ public setPageLoadedCallback(fct: (a: string) => void): void {
59
+ this.fct = fct;
60
+ }
61
+
62
+ public sleep(ms: number) {
63
+ return new Promise((resolve) => setTimeout(resolve, ms));
64
+ }
65
+
66
+ public async checkQueue(): Promise<void> {
67
+ // console.log("Checking queue");
68
+ const size = this.getQueueSize();
69
+ // console.log("Current queue size is ", size, this.queue);
70
+ if (size > 0) {
71
+ if (this.initialized) {
72
+ const page = this.queue.pop();
73
+ if (page) {
74
+ await this.handleQueueItem(page);
75
+ }
76
+ await this.checkQueue();
77
+ } else {
78
+ console.log(
79
+ "Worker cristal code not initialized yet. Cannot process queue items.",
80
+ );
81
+ }
82
+ }
83
+ }
84
+
85
+ public async handleQueueItem(page: string): Promise<void> {
86
+ console.log("Handling queue item code ready to process", page);
87
+
88
+ try {
89
+ let configName = null;
90
+ let pageName = null;
91
+ let type = null;
92
+ const index1 = page.indexOf(":");
93
+ const index2 = page.lastIndexOf("_");
94
+ if (index1 != -1 && index2 != -1) {
95
+ configName = page.substring(0, index1);
96
+ pageName = page.substring(index1 + 1, index2);
97
+ type = page.substring(index2 + 1);
98
+
99
+ const wikiConfig = this.getWikiConfig(configName);
100
+ if (wikiConfig == undefined) {
101
+ console.log("Could not find config for page", page);
102
+ } else {
103
+ console.log("Updating page ", pageName, type);
104
+ const storage = wikiConfig.storage as WrappingStorage;
105
+ const result = await storage.updatePageContent(pageName, type);
106
+ if (result) {
107
+ console.log("Page updated. Calling back to main thread");
108
+ this.fct(page);
109
+ }
110
+ }
111
+ } else {
112
+ console.log("Could not process page", page);
113
+ }
114
+ } catch (e) {
115
+ console.log("Exception while trying to load", page, e);
116
+ }
117
+ }
118
+
119
+ public add(a: number): number {
120
+ console.log("Worker in add");
121
+ this.currentNumber += a;
122
+ return this.currentNumber;
123
+ }
124
+
125
+ public addToQueue(page: string): void {
126
+ console.log("Worker in addToQueue", page);
127
+ if (!this.queue.includes(page)) {
128
+ this.queue.push(page);
129
+ }
130
+ return;
131
+ }
132
+
133
+ public getQueueSize(): number {
134
+ console.log("Worker in getQueueSize");
135
+ return this.queue.length;
136
+ }
137
+
138
+ public getWikiConfig(configName: string): WikiConfig | undefined {
139
+ const wikiConfigObject = this.configMap.get(configName);
140
+ if (wikiConfigObject == null) {
141
+ console.error("Failed to find wikiConfig for configName", configName);
142
+ return undefined;
143
+ }
144
+ const wikiConfigMap = new Map(Object.entries(wikiConfigObject));
145
+ const configType = wikiConfigMap.get("configType");
146
+ console.log(
147
+ "Looking for wikiConfig for name",
148
+ configName,
149
+ "and type",
150
+ configType,
151
+ );
152
+
153
+ let wikiConfig;
154
+ try {
155
+ wikiConfig = this.container.getNamed<WikiConfig>(
156
+ "WikiConfig",
157
+ configType,
158
+ );
159
+ this.cristal.setWikiConfig(wikiConfig);
160
+ wikiConfig.setConfigFromObject(wikiConfigObject);
161
+
162
+ // Make sure we have initialized this config
163
+ // This is necessary for offline mode
164
+ wikiConfig.initialize();
165
+
166
+ console.debug(
167
+ "Found wikiConfig for",
168
+ configName,
169
+ "and type",
170
+ configType,
171
+ ":",
172
+ wikiConfig,
173
+ );
174
+ return wikiConfig;
175
+ } catch (e) {
176
+ console.error(
177
+ "Failed to find wikiConfig for name",
178
+ configName,
179
+ "and type",
180
+ configType,
181
+ e,
182
+ );
183
+ return undefined;
184
+ }
185
+ }
186
+
187
+ public async initialize() {
188
+ console.log("Starting initialize");
189
+ const extensionList: Array<string> = ["storage"];
190
+ const response = await fetch("/config.json");
191
+ const config = await response.json();
192
+ this.configMap = new Map(Object.entries(config));
193
+ console.log("Loaded json config", this.configMap);
194
+ const cristalLoader = new CristalLoader(extensionList);
195
+ cristalLoader.initializeContainer();
196
+ this.container = cristalLoader.container;
197
+ console.log("Container status", this.container);
198
+ this.container
199
+ .bind<CristalApp>("CristalApp")
200
+ .to(WorkerCristalApp)
201
+ .inSingletonScope();
202
+ this.container
203
+ .bind<QueueWorker>("QueueWorker")
204
+ .to(WorkerQueueWorker)
205
+ .inSingletonScope();
206
+ this.cristal = this.container.get<CristalApp>("CristalApp");
207
+ this.cristal.setContainer(this.container);
208
+ console.log("Container status", this.container);
209
+ new StorageComponentInit(cristalLoader.container);
210
+ console.log("Loading storage components");
211
+ this.initialized = true;
212
+ console.log("Finished initialize");
213
+ }
214
+ }
215
+
216
+ const worker = new Worker();
217
+ worker.start();
218
+
219
+ // @ts-expect-error ignore
220
+ // TODO remove use of any
221
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
222
+ onconnect = (e: any) => {
223
+ Comlink.expose(worker, e.ports[0]);
224
+ };
225
+ console.log("Worker code loaded");
@@ -0,0 +1,146 @@
1
+ /**
2
+ * See the LICENSE file distributed with this work for additional
3
+ * information regarding copyright ownership.
4
+ *
5
+ * This is free software; you can redistribute it and/or modify it
6
+ * under the terms of the GNU Affero General Public License as
7
+ * published by the Free Software Foundation; either version 2.1 of
8
+ * the License, or (at your option) any later version.
9
+ *
10
+ * This software is distributed in the hope that it will be useful,
11
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
+ * Lesser General Public License for more details.
14
+ *
15
+ * You should have received a copy of the GNU Affero General Public
16
+ * License along with this software; if not, write to the Free
17
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
18
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
19
+ *
20
+ * This file is part of the Cristal Wiki software prototype
21
+ * @copyright Copyright (c) 2023 XWiki SAS
22
+ * @license http://opensource.org/licenses/AGPL-3.0 AGPL-3.0
23
+ *
24
+ **/
25
+
26
+ import type {
27
+ CristalApp as CristalApp,
28
+ Logger,
29
+ LoggerConfig,
30
+ PageData,
31
+ SkinManager,
32
+ WikiConfig,
33
+ } from "@xwiki/cristal-api";
34
+ import type { Container } from "inversify";
35
+ import { injectable } from "inversify";
36
+ import type { App, Component } from "vue";
37
+ import type { Router } from "vue-router";
38
+
39
+ @injectable()
40
+ export class WorkerCristalApp implements CristalApp {
41
+ private wikiConfig: WikiConfig;
42
+ private container: Container;
43
+ private availableConfigurations: Map<string, WikiConfig>;
44
+
45
+ public constructor() {
46
+ this.availableConfigurations = new Map<string, WikiConfig>();
47
+ }
48
+
49
+ getApp(): App {
50
+ throw new Error("Method not implemented.");
51
+ }
52
+ getRouter(): Router {
53
+ throw new Error("Method not implemented.");
54
+ }
55
+ getContainer(): Container {
56
+ return this.container;
57
+ }
58
+
59
+ setContainer(container: Container): void {
60
+ this.container = container;
61
+ }
62
+
63
+ getWikiConfig(): WikiConfig {
64
+ return this.wikiConfig;
65
+ }
66
+ setWikiConfig(wikiConfig: WikiConfig): void {
67
+ this.wikiConfig = wikiConfig;
68
+ }
69
+
70
+ getSkinManager(): SkinManager {
71
+ throw new Error("Method not implemented.");
72
+ }
73
+
74
+ switchConfig(): void {}
75
+
76
+ // TODO remove use of any
77
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
78
+ setAvailableConfigurations(config: Map<string, any>) {
79
+ console.log(config);
80
+ // TODO remove use of any
81
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
82
+ config.forEach((wikiConfigObject: any, key: string) => {
83
+ const configType = wikiConfigObject?.configType;
84
+
85
+ if (wikiConfigObject) {
86
+ const wikiConfig = this.container.getNamed<WikiConfig>(
87
+ "WikiConfig",
88
+ configType,
89
+ );
90
+ wikiConfig.setConfigFromObject(wikiConfigObject);
91
+ this.availableConfigurations.set(key, wikiConfig);
92
+ }
93
+ });
94
+ }
95
+
96
+ getAvailableConfigurations(): Map<string, WikiConfig> {
97
+ return this.availableConfigurations;
98
+ }
99
+
100
+ run(): Promise<void> {
101
+ throw new Error("Method not implemented.");
102
+ }
103
+ getUIXTemplates(): Component[] {
104
+ throw new Error("Method not implemented.");
105
+ }
106
+ getMenuEntries(): string[] {
107
+ throw new Error("Method not implemented.");
108
+ }
109
+ getCurrentPage(): string {
110
+ throw new Error("Method not implemented.");
111
+ }
112
+ getCurrentContent(): string {
113
+ throw new Error("Method not implemented.");
114
+ }
115
+ getCurrentSource(): string {
116
+ throw new Error("Method not implemented.");
117
+ }
118
+ getCurrentSyntax(): string {
119
+ throw new Error("Method not implemented.");
120
+ }
121
+ setCurrentPage(): void {
122
+ throw new Error("Method not implemented.");
123
+ }
124
+ setContentRef(): void {
125
+ throw new Error("Method not implemented.");
126
+ }
127
+ loadPageFromURL(): Promise<void> {
128
+ throw new Error("Method not implemented.");
129
+ }
130
+ loadPage(): Promise<void> {
131
+ throw new Error("Method not implemented.");
132
+ }
133
+ getPage(): Promise<PageData> {
134
+ throw new Error("Method not implemented.");
135
+ }
136
+ getLogger(): Logger {
137
+ throw new Error("Method not implemented.");
138
+ }
139
+ getLoggerConfig(): LoggerConfig {
140
+ throw new Error("Method not implemented.");
141
+ }
142
+
143
+ renderContent(): Promise<string> {
144
+ throw new Error("Method not implemented.");
145
+ }
146
+ }
@@ -0,0 +1,50 @@
1
+ /**
2
+ * See the LICENSE file distributed with this work for additional
3
+ * information regarding copyright ownership.
4
+ *
5
+ * This is free software; you can redistribute it and/or modify it
6
+ * under the terms of the GNU Affero General Public License as
7
+ * published by the Free Software Foundation; either version 2.1 of
8
+ * the License, or (at your option) any later version.
9
+ *
10
+ * This software is distributed in the hope that it will be useful,
11
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
+ * Lesser General Public License for more details.
14
+ *
15
+ * You should have received a copy of the GNU Affero General Public
16
+ * License along with this software; if not, write to the Free
17
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
18
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
19
+ *
20
+ * This file is part of the Cristal Wiki software prototype
21
+ * @copyright Copyright (c) 2023 XWiki SAS
22
+ * @license http://opensource.org/licenses/AGPL-3.0 AGPL-3.0
23
+ *
24
+ **/
25
+
26
+ import { injectable } from "inversify";
27
+ import type { QueueWorker } from "@xwiki/cristal-sharedworker-api";
28
+
29
+ @injectable()
30
+ export default class WorkerQueueWorker implements QueueWorker {
31
+ public constructor() {
32
+ this.initialize();
33
+ }
34
+
35
+ public initialize() {}
36
+
37
+ public getStatus(): boolean {
38
+ return true;
39
+ }
40
+
41
+ public async increment(): Promise<number> {
42
+ return 0;
43
+ }
44
+
45
+ public async addToQueue(): Promise<void> {}
46
+
47
+ public async getQueueSize(): Promise<number> {
48
+ return 0;
49
+ }
50
+ }
package/src/index.ts ADDED
@@ -0,0 +1,29 @@
1
+ /**
2
+ * See the LICENSE file distributed with this work for additional
3
+ * information regarding copyright ownership.
4
+ *
5
+ * This is free software; you can redistribute it and/or modify it
6
+ * under the terms of the GNU Affero General Public License as
7
+ * published by the Free Software Foundation; either version 2.1 of
8
+ * the License, or (at your option) any later version.
9
+ *
10
+ * This software is distributed in the hope that it will be useful,
11
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
+ * Lesser General Public License for more details.
14
+ *
15
+ * You should have received a copy of the GNU Affero General Public
16
+ * License along with this software; if not, write to the Free
17
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
18
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
19
+ *
20
+ * This file is part of the Cristal Wiki software prototype
21
+ * @copyright Copyright (c) 2023 XWiki SAS
22
+ * @license http://opensource.org/licenses/AGPL-3.0 AGPL-3.0
23
+ *
24
+ **/
25
+
26
+ import ComponentInit from "./components/componentsInit";
27
+ import type { QueueWorker } from "@xwiki/cristal-sharedworker-api";
28
+ export type { QueueWorker };
29
+ export { ComponentInit };
@@ -0,0 +1,27 @@
1
+ /**
2
+ * See the LICENSE file distributed with this work for additional
3
+ * information regarding copyright ownership.
4
+ *
5
+ * This is free software; you can redistribute it and/or modify it
6
+ * under the terms of the GNU Affero General Public License as
7
+ * published by the Free Software Foundation; either version 2.1 of
8
+ * the License, or (at your option) any later version.
9
+ *
10
+ * This software is distributed in the hope that it will be useful,
11
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
+ * Lesser General Public License for more details.
14
+ *
15
+ * You should have received a copy of the GNU Affero General Public
16
+ * License along with this software; if not, write to the Free
17
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
18
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
19
+ *
20
+ * This file is part of the Cristal Wiki software prototype
21
+ * @copyright Copyright (c) 2023 XWiki SAS
22
+ * @license http://opensource.org/licenses/AGPL-3.0 AGPL-3.0
23
+ *
24
+ **/
25
+
26
+ /// <reference types="vite-plugin-comlink/client" />
27
+ // eslint-disable-line
package/src/vue.d.ts ADDED
@@ -0,0 +1,32 @@
1
+ /**
2
+ * See the LICENSE file distributed with this work for additional
3
+ * information regarding copyright ownership.
4
+ *
5
+ * This is free software; you can redistribute it and/or modify it
6
+ * under the terms of the GNU Affero General Public License as
7
+ * published by the Free Software Foundation; either version 2.1 of
8
+ * the License, or (at your option) any later version.
9
+ *
10
+ * This software is distributed in the hope that it will be useful,
11
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
+ * Lesser General Public License for more details.
14
+ *
15
+ * You should have received a copy of the GNU Affero General Public
16
+ * License along with this software; if not, write to the Free
17
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
18
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
19
+ *
20
+ * This file is part of the Cristal Wiki software prototype
21
+ * @copyright Copyright (c) 2023 XWiki SAS
22
+ * @license http://opensource.org/licenses/AGPL-3.0 AGPL-3.0
23
+ *
24
+ **/
25
+
26
+ // vue.d.ts
27
+ declare module "*.vue" {
28
+ import type { DefineComponent } from "vue";
29
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/ban-types
30
+ const component: DefineComponent<{}, {}, any>;
31
+ export default component;
32
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,10 @@
1
+ {
2
+ "compilerOptions": {
3
+ "rootDir" : "src",
4
+ "outDir" : "dist",
5
+ "resolveJsonModule": true,
6
+ "types": ["vite/client"]
7
+ },
8
+ "extends": "./../../tsconfig.json",
9
+ "include": ["./src/index.ts", "./src/**/*"]
10
+ }
package/vite-env.d.ts ADDED
@@ -0,0 +1,26 @@
1
+ /**
2
+ * See the LICENSE file distributed with this work for additional
3
+ * information regarding copyright ownership.
4
+ *
5
+ * This is free software; you can redistribute it and/or modify it
6
+ * under the terms of the GNU Affero General Public License as
7
+ * published by the Free Software Foundation; either version 2.1 of
8
+ * the License, or (at your option) any later version.
9
+ *
10
+ * This software is distributed in the hope that it will be useful,
11
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
+ * Lesser General Public License for more details.
14
+ *
15
+ * You should have received a copy of the GNU Affero General Public
16
+ * License along with this software; if not, write to the Free
17
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
18
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
19
+ *
20
+ * This file is part of the Cristal Wiki software prototype
21
+ * @copyright Copyright (c) 2023 XWiki SAS
22
+ * @license http://opensource.org/licenses/AGPL-3.0 AGPL-3.0
23
+ *
24
+ **/
25
+
26
+ /// <reference types="vite-plugin-comlink/client" />
package/vite.config.ts ADDED
@@ -0,0 +1,38 @@
1
+ /**
2
+ * See the LICENSE file distributed with this work for additional
3
+ * information regarding copyright ownership.
4
+ *
5
+ * This is free software; you can redistribute it and/or modify it
6
+ * under the terms of the GNU Affero General Public License as
7
+ * published by the Free Software Foundation; either version 2.1 of
8
+ * the License, or (at your option) any later version.
9
+ *
10
+ * This software is distributed in the hope that it will be useful,
11
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
+ * Lesser General Public License for more details.
14
+ *
15
+ * You should have received a copy of the GNU Affero General Public
16
+ * License along with this software; if not, write to the Free
17
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
18
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
19
+ *
20
+ * This file is part of the Cristal Wiki software prototype
21
+ * @copyright Copyright (c) 2023 XWiki SAS
22
+ * @license http://opensource.org/licenses/AGPL-3.0 AGPL-3.0
23
+ *
24
+ **/
25
+
26
+ import { generateConfig } from "../../vite.config";
27
+ import { mergeConfig, defineConfig } from "vite";
28
+ import comlink from "vite-plugin-comlink";
29
+
30
+ export default mergeConfig(
31
+ generateConfig(import.meta.url),
32
+ defineConfig({
33
+ plugins: [comlink()],
34
+ worker: {
35
+ plugins: () => [comlink()],
36
+ },
37
+ }),
38
+ );