| 46 | } |
| 47 | |
| 48 | export class Loader extends Service { |
| 49 | public state: Record<string, Fiber> = Object.create(null); |
| 50 | public suspend = false; |
| 51 | public cache: Record<string, string> = Object.create(null); |
| 52 | private schemaCache = new WeakMap<Schema<any>, Record<string, Schema<any>>>(); |
| 53 | // public warnings: Record<string, string> = Object.create(null); |
| 54 | |
| 55 | static inject = ['setting', 'timer', 'i18n', 'logger']; |
| 56 | |
| 57 | constructor(ctx: Context) { |
| 58 | super(ctx, 'loader'); |
| 59 | |
| 60 | ctx.on('app/started', () => { |
| 61 | ctx.interval(async () => { |
| 62 | const pending = Object.entries(this.state).filter((v) => v[1].state === FiberState.PENDING); |
| 63 | if (pending.length) { |
| 64 | logger.warn('Plugins are still pending: %s', pending.map((v) => v[0]).join(', ')); |
| 65 | for (const [key, value] of pending) { |
| 66 | logger.warn('Plugin %s is still pending', key); |
| 67 | console.log(value); |
| 68 | } |
| 69 | } |
| 70 | const loading = Object.entries(this.state).filter((v) => v[1].state === FiberState.LOADING); |
| 71 | if (loading.length) { |
| 72 | logger.warn('Plugins are still loading: %s', loading.map((v) => v[0]).join(', ')); |
| 73 | for (const [key, value] of loading) { |
| 74 | logger.warn('Plugin %s is still loading', key); |
| 75 | console.log(value); |
| 76 | } |
| 77 | } |
| 78 | const failed = Object.entries(this.state).filter((v) => v[1].state === FiberState.FAILED); |
| 79 | if (failed.length) { |
| 80 | logger.warn('Plugins failed to load: %s', failed.map((v) => v[0]).join(', ')); |
| 81 | for (const [key, value] of failed) { |
| 82 | logger.warn('Plugin %s failed to load', key); |
| 83 | console.log(value); |
| 84 | } |
| 85 | } |
| 86 | }, 10000); |
| 87 | }); |
| 88 | } |
| 89 | |
| 90 | unloadPlugin(key: string) { |
| 91 | const fork = this.state[key]; |
| 92 | if (fork) { |
| 93 | fork.dispose(); |
| 94 | delete this.state[key]; |
| 95 | logger.info('unload plugin %c', key); |
| 96 | } |
| 97 | } |
| 98 | |
| 99 | buildSchema(schema: Schema<any>, scope?: string) { |
| 100 | if (!scope) return schema; |
| 101 | const cache = this.schemaCache.get(schema) || {}; |
| 102 | cache[scope] ||= Schema.object({ [scope]: schema }); |
| 103 | this.schemaCache.set(schema, cache); |
| 104 | return cache[scope]; |
| 105 | } |