feat(lib/plugins): switch to objects for storage
This commit is contained in:
parent
00638ed845
commit
d3b754d2cc
3 changed files with 36 additions and 28 deletions
|
|
@ -36,12 +36,12 @@ export const pEmitter = new TypedEventEmitter<{
|
||||||
export const pList = new Map<PluginManifest['id'], InternalPlugin>()
|
export const pList = new Map<PluginManifest['id'], InternalPlugin>()
|
||||||
export const pMetadata = new Map<
|
export const pMetadata = new Map<
|
||||||
PluginManifest['id'],
|
PluginManifest['id'],
|
||||||
[
|
{
|
||||||
api: PreInitPluginApi | InitPluginApi | PluginApi | undefined,
|
api: PreInitPluginApi | InitPluginApi | PluginApi | undefined
|
||||||
promises: Promise<void>[],
|
promises: Promise<void>[]
|
||||||
iflags: number,
|
iflags: number
|
||||||
apiLevel: number,
|
apiLevel: number
|
||||||
]
|
}
|
||||||
>()
|
>()
|
||||||
|
|
||||||
export function registerPlugin<O extends PluginApiExtensionsOptions>(
|
export function registerPlugin<O extends PluginApiExtensionsOptions>(
|
||||||
|
|
@ -71,7 +71,12 @@ export function registerPlugin<O extends PluginApiExtensionsOptions>(
|
||||||
stop: () => stopPlugin(plugin),
|
stop: () => stopPlugin(plugin),
|
||||||
}
|
}
|
||||||
|
|
||||||
pMetadata.set(manifest.id, [undefined, [], iflags, PluginApiLevel.None])
|
pMetadata.set(manifest.id, {
|
||||||
|
api: undefined,
|
||||||
|
promises: [],
|
||||||
|
iflags,
|
||||||
|
apiLevel: PluginApiLevel.None,
|
||||||
|
})
|
||||||
pList.set(manifest.id, plugin)
|
pList.set(manifest.id, plugin)
|
||||||
|
|
||||||
pEmitter.emit('register', plugin, options)
|
pEmitter.emit('register', plugin, options)
|
||||||
|
|
@ -80,7 +85,7 @@ export function registerPlugin<O extends PluginApiExtensionsOptions>(
|
||||||
function handlePluginError(e: unknown, plugin: InternalPlugin) {
|
function handlePluginError(e: unknown, plugin: InternalPlugin) {
|
||||||
plugin.errors.push(e)
|
plugin.errors.push(e)
|
||||||
plugin.flags |= Flag.Errored
|
plugin.flags |= Flag.Errored
|
||||||
const [api, , iflags] = pMetadata.get(plugin.manifest.id)!
|
const { api, iflags } = pMetadata.get(plugin.manifest.id)!
|
||||||
|
|
||||||
;(api as InitPluginApi).logger.error('Plugin encountered an error', e)
|
;(api as InitPluginApi).logger.error('Plugin encountered an error', e)
|
||||||
nativeLoggingHook(
|
nativeLoggingHook(
|
||||||
|
|
@ -100,7 +105,7 @@ function preparePluginPreInit(plugin: InternalPlugin) {
|
||||||
plugin.errors = []
|
plugin.errors = []
|
||||||
plugin.status &= ~Flag.Errored
|
plugin.status &= ~Flag.Errored
|
||||||
|
|
||||||
const api = (meta[0] = {
|
const api = (meta.api = {
|
||||||
cleanup: (...items) => {
|
cleanup: (...items) => {
|
||||||
plugin._c.push(...items)
|
plugin._c.push(...items)
|
||||||
},
|
},
|
||||||
|
|
@ -109,28 +114,28 @@ function preparePluginPreInit(plugin: InternalPlugin) {
|
||||||
})
|
})
|
||||||
|
|
||||||
pEmitter.emit('preInit', plugin, api)
|
pEmitter.emit('preInit', plugin, api)
|
||||||
meta[3] = PluginApiLevel.PreInit
|
meta.apiLevel = PluginApiLevel.PreInit
|
||||||
}
|
}
|
||||||
|
|
||||||
function preparePluginInit(plugin: InternalPlugin) {
|
function preparePluginInit(plugin: InternalPlugin) {
|
||||||
const meta = pMetadata.get(plugin.manifest.id)!
|
const meta = pMetadata.get(plugin.manifest.id)!
|
||||||
|
|
||||||
pEmitter.emit('init', plugin, meta[0] as InitPluginApi)
|
pEmitter.emit('init', plugin, meta.api as InitPluginApi)
|
||||||
meta[3] = PluginApiLevel.Init
|
meta.apiLevel = PluginApiLevel.Init
|
||||||
}
|
}
|
||||||
|
|
||||||
function preparePluginStart(plugin: InternalPlugin) {
|
function preparePluginStart(plugin: InternalPlugin) {
|
||||||
const meta = pMetadata.get(plugin.manifest.id)!
|
const meta = pMetadata.get(plugin.manifest.id)!
|
||||||
|
|
||||||
pEmitter.emit('start', plugin, meta[0] as PluginApi)
|
pEmitter.emit('start', plugin, meta.api as PluginApi)
|
||||||
meta[3] = PluginApiLevel.Start
|
meta.apiLevel = PluginApiLevel.Start
|
||||||
}
|
}
|
||||||
|
|
||||||
async function disablePlugin(plugin: InternalPlugin) {
|
async function disablePlugin(plugin: InternalPlugin) {
|
||||||
if (!(plugin.flags & Flag.Enabled))
|
if (!(plugin.flags & Flag.Enabled))
|
||||||
throw new Error(`Plugin "${plugin.manifest.id}" is not enabled`)
|
throw new Error(`Plugin "${plugin.manifest.id}" is not enabled`)
|
||||||
|
|
||||||
const iflags = pMetadata.get(plugin.manifest.id)![2] ?? 0
|
const iflags = pMetadata.get(plugin.manifest.id)!.iflags ?? 0
|
||||||
if (iflags & InternalPluginFlags.Essential)
|
if (iflags & InternalPluginFlags.Essential)
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Plugin "${plugin.manifest.id}" is essential and cannot be disabled`,
|
`Plugin "${plugin.manifest.id}" is essential and cannot be disabled`,
|
||||||
|
|
@ -166,7 +171,7 @@ export async function preInitPlugin(plugin: InternalPlugin) {
|
||||||
if (!lifecycles.preInit) return
|
if (!lifecycles.preInit) return
|
||||||
|
|
||||||
const meta = pMetadata.get(id)!
|
const meta = pMetadata.get(id)!
|
||||||
const [, promises] = meta
|
const { promises } = meta
|
||||||
|
|
||||||
if (!(plugin.flags & Flag.Enabled))
|
if (!(plugin.flags & Flag.Enabled))
|
||||||
throw new Error(`Plugin "${id}" is not enabled`)
|
throw new Error(`Plugin "${id}" is not enabled`)
|
||||||
|
|
@ -180,7 +185,7 @@ export async function preInitPlugin(plugin: InternalPlugin) {
|
||||||
plugin.status |= Status.PreIniting
|
plugin.status |= Status.PreIniting
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const prom = lifecycles.preInit(meta[0] as PreInitPluginApi)
|
const prom = lifecycles.preInit(meta.api as PreInitPluginApi)
|
||||||
promises.push(prom)
|
promises.push(prom)
|
||||||
await prom
|
await prom
|
||||||
|
|
||||||
|
|
@ -205,7 +210,7 @@ export async function initPlugin(plugin: InternalPlugin) {
|
||||||
if (!lifecycles.init) return
|
if (!lifecycles.init) return
|
||||||
|
|
||||||
const meta = pMetadata.get(id)!
|
const meta = pMetadata.get(id)!
|
||||||
const [, promises, , apiLevel] = meta
|
const { promises, apiLevel } = meta
|
||||||
|
|
||||||
if (!(plugin.flags & Flag.Enabled))
|
if (!(plugin.flags & Flag.Enabled))
|
||||||
throw new Error(`Plugin "${id}" is not enabled`)
|
throw new Error(`Plugin "${id}" is not enabled`)
|
||||||
|
|
@ -220,7 +225,7 @@ export async function initPlugin(plugin: InternalPlugin) {
|
||||||
plugin.status |= Status.Initing
|
plugin.status |= Status.Initing
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const prom = lifecycles.init(meta[0] as InitPluginApi)
|
const prom = lifecycles.init(meta.api as InitPluginApi)
|
||||||
promises.push(prom)
|
promises.push(prom)
|
||||||
await prom
|
await prom
|
||||||
|
|
||||||
|
|
@ -245,7 +250,7 @@ export async function startPlugin(plugin: InternalPlugin) {
|
||||||
if (!lifecycles.start) return
|
if (!lifecycles.start) return
|
||||||
|
|
||||||
const meta = pMetadata.get(id)!
|
const meta = pMetadata.get(id)!
|
||||||
const [, promises, , apiLevel] = meta
|
const { promises, apiLevel } = meta
|
||||||
|
|
||||||
if (!(plugin.flags & Flag.Enabled))
|
if (!(plugin.flags & Flag.Enabled))
|
||||||
throw new Error(`Plugin "${id}" is not enabled`)
|
throw new Error(`Plugin "${id}" is not enabled`)
|
||||||
|
|
@ -261,7 +266,7 @@ export async function startPlugin(plugin: InternalPlugin) {
|
||||||
plugin.status |= Status.Starting
|
plugin.status |= Status.Starting
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const prom = lifecycles.start(meta[0] as PluginApi)
|
const prom = lifecycles.start(meta.api as PluginApi)
|
||||||
promises.push(prom)
|
promises.push(prom)
|
||||||
await prom
|
await prom
|
||||||
|
|
||||||
|
|
@ -284,7 +289,7 @@ export async function stopPlugin(plugin: InternalPlugin) {
|
||||||
lifecycles,
|
lifecycles,
|
||||||
} = plugin
|
} = plugin
|
||||||
const meta = pMetadata.get(id)!
|
const meta = pMetadata.get(id)!
|
||||||
const [, promises, iflags, apiLevel] = meta
|
const { promises, iflags, apiLevel } = meta
|
||||||
|
|
||||||
if (iflags & InternalPluginFlags.Essential)
|
if (iflags & InternalPluginFlags.Essential)
|
||||||
throw new Error(`Plugin "${id}" is essential and cannot be stopped`)
|
throw new Error(`Plugin "${id}" is essential and cannot be stopped`)
|
||||||
|
|
@ -326,7 +331,7 @@ export async function stopPlugin(plugin: InternalPlugin) {
|
||||||
if (!lifecycles.stop) return
|
if (!lifecycles.stop) return
|
||||||
|
|
||||||
await Promise.race([
|
await Promise.race([
|
||||||
lifecycles.stop(meta[0] as PluginApi),
|
lifecycles.stop(meta.api as PluginApi),
|
||||||
sleepReject(
|
sleepReject(
|
||||||
MaxWaitTime,
|
MaxWaitTime,
|
||||||
'Plugin stop lifecycle timed out, force stopping',
|
'Plugin stop lifecycle timed out, force stopping',
|
||||||
|
|
@ -360,11 +365,11 @@ export async function stopPlugin(plugin: InternalPlugin) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset APIs
|
// Reset APIs
|
||||||
meta[0] = undefined
|
meta.api = undefined
|
||||||
meta[3] = PluginApiLevel.None
|
meta.apiLevel = PluginApiLevel.None
|
||||||
|
|
||||||
// Clear temp data
|
// Clear temp data
|
||||||
meta[1] = []
|
meta.promises = []
|
||||||
plugin._c = []
|
plugin._c = []
|
||||||
|
|
||||||
// Reset status
|
// Reset status
|
||||||
|
|
|
||||||
|
|
@ -109,7 +109,10 @@ function Screen() {
|
||||||
() =>
|
() =>
|
||||||
[...pList.values()].map(
|
[...pList.values()].map(
|
||||||
plugin =>
|
plugin =>
|
||||||
[plugin, pMetadata.get(plugin.manifest.id)![2]] as const,
|
[
|
||||||
|
plugin,
|
||||||
|
pMetadata.get(plugin.manifest.id)!.iflags,
|
||||||
|
] as const,
|
||||||
),
|
),
|
||||||
[],
|
[],
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ const { NavigatorHeader } = Design
|
||||||
// TODO(plugins/settings): Register a custom route instead, so plugin "settings" can actually be pinned and navigated to without hassle.
|
// TODO(plugins/settings): Register a custom route instead, so plugin "settings" can actually be pinned and navigated to without hassle.
|
||||||
// This would require us to implement the event-based plugin management system first, so we can listen to plugin enable/disable events and update the settings accordingly.
|
// This would require us to implement the event-based plugin management system first, so we can listen to plugin enable/disable events and update the settings accordingly.
|
||||||
export function navigatePluginSettings(plugin: Plugin) {
|
export function navigatePluginSettings(plugin: Plugin) {
|
||||||
const [api] = pMetadata.get(plugin.manifest.id)!
|
const { api } = pMetadata.get(plugin.manifest.id)!
|
||||||
const navigation =
|
const navigation =
|
||||||
RootNavigationRef.getRootNavigationRef<ReactNavigationParamList>()
|
RootNavigationRef.getRootNavigationRef<ReactNavigationParamList>()
|
||||||
if (!navigation.isReady()) return
|
if (!navigation.isReady()) return
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue