-
Notifications
You must be signed in to change notification settings - Fork 312
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Change: ブラウザ版のConfigをBaseConfigManagerベースに #1629
Changes from 30 commits
60f4a14
ffa2729
994a656
f5a74e4
ff3f473
2318674
3464c5b
10e8af5
d09df6f
fdffc37
4d9ea03
fc763cc
16d27d0
e880771
00a6acb
08b59d1
690efaa
8ceed61
7cf4411
7b32a2d
45293ee
cb2db2b
af1055d
b7c7d47
8d6cc72
48e898f
a0695f8
50bec9a
31d07cf
4628907
57e6eb1
4d2f0b3
1c0b3db
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,14 +1,11 @@ | ||
import { EngineInfo, EngineId } from "@/type/preload"; | ||
import { EngineInfo, envEngineInfoSchema } from "@/type/preload"; | ||
|
||
const baseEngineInfo = envEngineInfoSchema | ||
.array() | ||
.parse(JSON.parse(import.meta.env.VITE_DEFAULT_ENGINE_INFOS))[0]; | ||
|
||
export const defaultEngine: EngineInfo = { | ||
uuid: EngineId("074fc39e-678b-4c13-8916-ffca8d505d1d"), | ||
host: "http://127.0.0.1:50021", | ||
name: "VOICEVOX Engine", | ||
path: undefined, | ||
executionEnabled: false, | ||
executionFilePath: "", | ||
executionArgs: [], | ||
...baseEngineInfo, | ||
type: "default", | ||
}; | ||
|
||
export const directoryHandleStoreKey = "directoryHandle"; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,19 +1,41 @@ | ||
import AsyncLock from "async-lock"; | ||
import { defaultEngine, directoryHandleStoreKey } from "./contract"; | ||
|
||
import { | ||
configSchema, | ||
ConfigType, | ||
EngineId, | ||
engineSettingSchema, | ||
} from "@/type/preload"; | ||
import { BaseConfigManager, Metadata } from "@/shared/ConfigManager"; | ||
import { ConfigType, EngineId, engineSettingSchema } from "@/type/preload"; | ||
|
||
const dbName = `${import.meta.env.VITE_APP_NAME}-web`; | ||
const settingStoreKey = "electronStore"; | ||
// FIXME: DBのschemaを変更したら、dbVersionを上げる | ||
// TODO: 気づけるようにしたい | ||
const dbVersion = 1; | ||
const settingStoreKey = "config"; | ||
const dbVersion = 1; // 固定値。configのmigrationには使用していない。 | ||
// NOTE: settingを複数持つことはないと仮定して、keyを固定してしまう | ||
export const entryKey = "value"; | ||
const entryKey = "value"; | ||
|
||
let configManager: BrowserConfigManager | undefined; | ||
|
||
const configManagerLock = new AsyncLock(); | ||
const defaultEngineId = EngineId(defaultEngine.uuid); | ||
|
||
export async function withConfigManager<T>( | ||
callback: (configManager: BrowserConfigManager) => Promise<T> | ||
): Promise<T> { | ||
sevenc-nanashi marked this conversation as resolved.
Show resolved
Hide resolved
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ここはどうしてもelectron側と実装が異なるので複雑性を1段階回すことになってしまうことに気づきました。 この辺り見てたんですが、 根本の課題は起動シーケンスの違いで、electronはバックエンドが最初なのに対し、browserはフロントエンドが最初なのでConfigManager初期化のタイミングがないんですよね・・・。 |
||
return await configManagerLock.acquire("configManager", async () => { | ||
if (!configManager) { | ||
configManager = new BrowserConfigManager(); | ||
await configManager.initialize(); | ||
} | ||
return await callback(configManager); | ||
}); | ||
} | ||
|
||
const waitRequest = (request: IDBRequest) => | ||
new Promise<void>((resolve, reject) => { | ||
request.onsuccess = () => { | ||
resolve(); | ||
}; | ||
request.onerror = () => { | ||
reject(request.error); | ||
}; | ||
}); | ||
|
||
export const openDB = () => | ||
new Promise<IDBDatabase>((resolve, reject) => { | ||
|
@@ -29,20 +51,15 @@ export const openDB = () => | |
if (ev.oldVersion === 0) { | ||
// Initialize | ||
const db = request.result; | ||
const baseSchema = configSchema.parse({}); | ||
|
||
const defaultVoicevoxEngineId = EngineId(defaultEngine.uuid); | ||
baseSchema.engineSettings = { | ||
[defaultVoicevoxEngineId]: engineSettingSchema.parse({}), | ||
}; | ||
sevenc-nanashi marked this conversation as resolved.
Show resolved
Hide resolved
|
||
db.createObjectStore(settingStoreKey).add(baseSchema, entryKey); | ||
db.createObjectStore(settingStoreKey); | ||
|
||
// NOTE: fixedExportDirectoryを使用してファイルの書き出しをする際、 | ||
// audio.tsの現在の実装では、ディレクトリを選択するモーダルを表示しないようになっている | ||
// ディレクトリへの書き出し権限の要求は、モーダルの表示かディレクトリを指定したファイルの書き出しの時のみで、 | ||
// directoryHandleがないと権限の要求が出来ないため、directoryHandleを永続化しておく | ||
db.createObjectStore(directoryHandleStoreKey); | ||
} else if (ev.newVersion !== null && ev.newVersion > ev.oldVersion) { | ||
} else if (ev.newVersion != null && ev.newVersion > ev.oldVersion) { | ||
// TODO: migrate | ||
/* eslint-disable no-console */ // logger みたいなパッケージに切り出して、それに依存する形でもいいかも | ||
console.error( | ||
|
@@ -53,49 +70,52 @@ export const openDB = () => | |
}; | ||
}); | ||
|
||
export const setSettingEntry = async <Key extends keyof ConfigType>( | ||
key: Key, | ||
newValue: ConfigType[Key] | ||
) => { | ||
const db = await openDB(); | ||
|
||
// TODO: Schemaに合っているか保存時にvalidationしたい | ||
return new Promise((resolve, reject) => { | ||
const transaction = db.transaction(settingStoreKey, "readwrite"); | ||
const store = transaction.objectStore(settingStoreKey); | ||
const getRequest = store.get(entryKey); | ||
getRequest.onsuccess = () => { | ||
const baseSchema = configSchema.parse(getRequest.result); | ||
baseSchema[key] = newValue; | ||
const validatedSchema = configSchema.parse(baseSchema); | ||
const putRequest = store.put(validatedSchema, entryKey); | ||
putRequest.onsuccess = () => { | ||
resolve(putRequest.result); | ||
}; | ||
putRequest.onerror = () => { | ||
reject(putRequest.error); | ||
}; | ||
}; | ||
getRequest.onerror = () => { | ||
reject(getRequest.error); | ||
}; | ||
}); | ||
}; | ||
class BrowserConfigManager extends BaseConfigManager { | ||
protected getAppVersion() { | ||
return import.meta.env.VITE_APP_VERSION; | ||
} | ||
protected async exists() { | ||
const db = await openDB(); | ||
|
||
export const getSettingEntry = async <Key extends keyof ConfigType>( | ||
key: Key | ||
): Promise<ConfigType[Key]> => { | ||
const db = await openDB(); | ||
try { | ||
const transaction = db.transaction(settingStoreKey, "readonly"); | ||
const store = transaction.objectStore(settingStoreKey); | ||
const request = store.get(entryKey); | ||
await waitRequest(request); | ||
const result = request.result; | ||
return result != undefined; | ||
} catch (e) { | ||
return false; | ||
} | ||
} | ||
protected async load(): Promise<Record<string, unknown> & Metadata> { | ||
const db = await openDB(); | ||
|
||
return new Promise((resolve, reject) => { | ||
const transaction = db.transaction(settingStoreKey, "readonly"); | ||
const store = transaction.objectStore(settingStoreKey); | ||
const request = store.get(entryKey); | ||
request.onsuccess = () => { | ||
resolve(request.result[key]); | ||
}; | ||
request.onerror = () => { | ||
reject(request.error); | ||
}; | ||
}); | ||
}; | ||
await waitRequest(request); | ||
const result = request.result; | ||
if (result == undefined) { | ||
throw new Error("設定ファイルが見つかりません"); | ||
} | ||
return JSON.parse(result); | ||
} | ||
|
||
protected async save(data: ConfigType & Metadata) { | ||
const db = await openDB(); | ||
|
||
const transaction = db.transaction(settingStoreKey, "readwrite"); | ||
const store = transaction.objectStore(settingStoreKey); | ||
const request = store.put(JSON.stringify(data), entryKey); | ||
await waitRequest(request); | ||
} | ||
|
||
protected async getDefaultConfig() { | ||
const baseConfig = await super.getDefaultConfig(); | ||
baseConfig.engineSettings[defaultEngineId] ??= engineSettingSchema.parse( | ||
{} | ||
); | ||
return baseConfig; | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
あ、このあたりも必要な変更だった感じでしょうか 👀
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
色々試してたときのやつですね。問題自体はここには無かったのでいらないっちゃ要らないはず。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
なるほどです!
エンジンIDの変更が意図的かどうかパッとわからないので、やったほうが良さそうであればエンジンリポジトリと同様に環境変数へ、なくても良さそうであればこの行を消すはどうでしょう?
.env.test
を書き換えるかはどちらでも良さそう。(どっちかというと.envを自由に書き換えるほうがローカル変数っぽみがあって直感的だとは思います。.env.testは元からあるのでグローバルっぽみ。)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Viteは
.env
より.env.test
の方が優先度が高いので、.env
と.env.test
は同期しておきたいんですよねThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
あ、たしかに!!気をつけないといけない仕様ですね・・・。
(だとしたら
executionArgs
が元の.env.testの空っぽのに上書きされてそうですけど、なんで今まで動いてたんだろう).env.test直接書き換えで良い気がしました!