Changeset View
Standalone View
web/database/worker/web-db-worker.js
// @flow | // @flow | ||||
import localforage from 'localforage'; | import localforage from 'localforage'; | ||||
import initSqlJs from 'sql.js'; | |||||
import { isDev } from 'lib/utils/dev-utils.js'; | |||||
import { | import { | ||||
type SharedWorkerMessageEvent, | type SharedWorkerMessageEvent, | ||||
type WorkerRequestMessage, | type WorkerRequestMessage, | ||||
type WorkerResponseMessage, | type WorkerResponseMessage, | ||||
workerRequestMessageTypes, | workerRequestMessageTypes, | ||||
workerResponseMessageTypes, | workerResponseMessageTypes, | ||||
type WorkerRequestProxyMessage, | type WorkerRequestProxyMessage, | ||||
} from '../../types/worker-types.js'; | } from '../../types/worker-types.js'; | ||||
import { SQLITE_CONTENT } from '../utils/constants.js'; | |||||
const localforageConfig: PartialConfig = { | const localforageConfig: PartialConfig = { | ||||
driver: localforage.INDEXEDDB, | driver: localforage.INDEXEDDB, | ||||
name: 'comm', | name: 'comm', | ||||
storeName: 'commStorage', | storeName: 'commStorage', | ||||
description: 'Comm encrypted database storage', | description: 'Comm encrypted database storage', | ||||
version: '1.0', | version: '1.0', | ||||
}; | }; | ||||
localforage.config(localforageConfig); | localforage.config(localforageConfig); | ||||
function processAppRequest( | let sqliteDb = null; | ||||
async function initDatabase() { | |||||
const content = await localforage.getItem(SQLITE_CONTENT); | |||||
kamil: in current state this is always empty - there is no persistence mechanism yet | |||||
const wasmFilePath = isDev | |||||
? 'http://localhost:3000/comm/compiled' | |||||
: 'https://web.comm.app/compiled'; | |||||
tomekUnsubmitted Not Done Inline ActionsWondering if we have to hardcode the urls here. It seems like this depends on the configuration from commapp_url so if someone decides to e.g. configure the server on different port, this code will break. Not sure what is the right solution, but we can try:
tomek: Wondering if we have to hardcode the urls here. It seems like this depends on the configuration… | |||||
kamilAuthorUnsubmitted Done Inline ActionsIt's more complicated than simply using window/self, eg. in the worker context, I am able to check only for the host (localhost:3000), but the file is under the path http://localhost:3000/comm/ so it's still part that needs to be hardcoded and it's defined in config. Can I create a follow-up task for this and figure out the best solution also for other cases (I think it's common to hardcode URLs, eg. in service worker)? kamil: It's more complicated than simply using `window`/`self`, eg. in the worker context, I am able… | |||||
tomekUnsubmitted Not Done Inline ActionsOk, we can do that. But we should probably prioritize it before the migration to the db so that we don't break workflows of some devs (we can also check if there are devs who use different config). tomek: Ok, we can do that. But we should probably prioritize it before the migration to the db so that… | |||||
kamilAuthorUnsubmitted Done Inline ActionsThis thing is now fixed by the latest changes caused by changing the file name, should be okay when devs have different configs I think kamil: This thing is now fixed by the latest changes caused by changing the file name, should be okay… | |||||
const SQL = await initSqlJs({ | |||||
locateFile: file => `${wasmFilePath}/${file}`, | |||||
}); | |||||
if (content) { | |||||
sqliteDb = new SQL.Database(new Uint8Array(content)); | |||||
} else { | |||||
sqliteDb = new SQL.Database(); | |||||
} | |||||
const versionData = sqliteDb.exec('PRAGMA user_version;'); | |||||
const dbVersion = versionData[0].values[0]; | |||||
tomekUnsubmitted Not Done Inline ActionsShouldn't we validate the returned data, so that we're sure that these arrays are not empty? tomek: Shouldn't we validate the returned data, so that we're sure that these arrays are not empty? | |||||
kamilAuthorUnsubmitted Done Inline ActionsStill in development so I read the value only for showing that we can query something. In the very near future, I will need to add some kind of mapper that will modify results and make data more accessible, then I will be able to type result.user_verision because there is access to columns' result. But adding checks for now kamil: Still in development so I read the value only for showing that we can query something.
In the… | |||||
console.info(`Db version: ${dbVersion}`); | |||||
} | |||||
async function processAppRequest( | |||||
message: WorkerRequestMessage, | message: WorkerRequestMessage, | ||||
): ?WorkerResponseMessage { | ): Promise<?WorkerResponseMessage> { | ||||
if (message.type === workerRequestMessageTypes.PING) { | if (message.type === workerRequestMessageTypes.PING) { | ||||
return { | return { | ||||
type: workerResponseMessageTypes.PONG, | type: workerResponseMessageTypes.PONG, | ||||
text: 'PONG', | text: 'PONG', | ||||
}; | }; | ||||
} else if (message.type === workerRequestMessageTypes.INIT) { | |||||
await initDatabase(); | |||||
return; | |||||
} | } | ||||
throw new Error('Request type not supported'); | throw new Error('Request type not supported'); | ||||
} | } | ||||
function connectHandler(event: SharedWorkerMessageEvent) { | function connectHandler(event: SharedWorkerMessageEvent) { | ||||
const port: MessagePort = event.ports[0]; | const port: MessagePort = event.ports[0]; | ||||
console.log('Web database worker alive!'); | console.log('Web database worker alive!'); | ||||
port.onmessage = async function (messageEvent: MessageEvent) { | port.onmessage = async function (messageEvent: MessageEvent) { | ||||
const data: WorkerRequestProxyMessage = (messageEvent.data: any); | const data: WorkerRequestProxyMessage = (messageEvent.data: any); | ||||
const { id, message } = data; | const { id, message } = data; | ||||
if (!id) { | if (!id) { | ||||
port.postMessage({ | port.postMessage({ | ||||
error: new Error('Request without identifier'), | error: new Error('Request without identifier'), | ||||
}); | }); | ||||
} | } | ||||
try { | try { | ||||
const result = processAppRequest(message); | const result = await processAppRequest(message); | ||||
port.postMessage({ | port.postMessage({ | ||||
id, | id, | ||||
message: result, | message: result, | ||||
}); | }); | ||||
} catch (e) { | } catch (e) { | ||||
port.postMessage({ | port.postMessage({ | ||||
id, | id, | ||||
error: e, | error: e, | ||||
}); | }); | ||||
} | } | ||||
}; | }; | ||||
} | } | ||||
self.addEventListener('connect', connectHandler); | self.addEventListener('connect', connectHandler); |
in current state this is always empty - there is no persistence mechanism yet