mirror of
https://github.com/FrankerFaceZ/FrankerFaceZ.git
synced 2025-06-27 21:05:53 +00:00
This actually loads, though some add-ons will need some work due to Module changes. * Modules aren't instantiated immediately when they're registered. * A Module is only instantiated when it's resolved, with construct = true. * Modules have `construct_requires` for injecting dependencies within the constructor super call * All modules have `settings`, `i18n`, and `experiments` as their default construct requires. * Requirements lists are frozen after the constructor super call. * Injected dependencies are not injected immediately, even if the module is available. This enforces coding standards. * All Module data is stored in `__module_data` now, rather than defining an ever growing number of properties on every module. * `should_enable` is now a static property, because Modules aren't instantiated. To be replaced with module metadata. * `addons` is now `addon`, with an alias to `addons`. This is done so add-ons can continue loading in the `addon` namespace without complaining. * HierarchicalEventEmitter forbids `.` within a name, now. * `abs_path(path, origin)` now accepts an optional origin parameter which overrides the current module's path as the source for normalizing the path
194 lines
5.5 KiB
JavaScript
194 lines
5.5 KiB
JavaScript
'use strict';
|
|
|
|
import dayjs from 'dayjs';
|
|
import RavenLogger from './raven';
|
|
|
|
import Logger from 'utilities/logging';
|
|
import Module from 'utilities/module';
|
|
import { timeout } from 'utilities/object';
|
|
|
|
import {DEBUG} from 'utilities/constants';
|
|
|
|
import SettingsManager from './settings/index';
|
|
import AddonManager from './addons';
|
|
import ExperimentManager from './experiments';
|
|
import {TranslationManager} from './i18n';
|
|
import SocketClient from './socket';
|
|
//import PubSubClient from './pubsub';
|
|
import Site from 'site';
|
|
import Vue from 'utilities/vue';
|
|
//import Timing from 'utilities/timing';
|
|
|
|
class FrankerFaceZ extends Module {
|
|
constructor() {
|
|
super();
|
|
const start_time = performance.now(),
|
|
VER = FrankerFaceZ.version_info;
|
|
|
|
FrankerFaceZ.instance = this;
|
|
|
|
this.name = 'frankerfacez';
|
|
this.__data.state = 0;
|
|
//this.__modules.core = this;
|
|
|
|
// Timing
|
|
//this.inject('timing', Timing);
|
|
this.__time('instance');
|
|
|
|
// ========================================================================
|
|
// Error Reporting and Logging
|
|
// ========================================================================
|
|
|
|
this.inject('raven', RavenLogger);
|
|
|
|
this.log = new Logger(null, null, null, this.raven);
|
|
this.log.init = true;
|
|
|
|
this.core_log = this.log.get('core');
|
|
|
|
this.log.info(`FrankerFaceZ v${VER} (build ${VER.build}${VER.commit ? ` - commit ${VER.commit}` : ''})`);
|
|
|
|
|
|
// ========================================================================
|
|
// Core Systems
|
|
// ========================================================================
|
|
|
|
this.inject('settings', SettingsManager);
|
|
this.inject('experiments', ExperimentManager);
|
|
this.inject('i18n', TranslationManager);
|
|
this.inject('socket', SocketClient);
|
|
//this.inject('pubsub', PubSubClient);
|
|
this.inject('site', Site);
|
|
this.inject('addon', AddonManager);
|
|
|
|
this.register('vue', Vue);
|
|
|
|
|
|
// ========================================================================
|
|
// Startup
|
|
// ========================================================================
|
|
|
|
this.discoverModules()
|
|
.then(() => this.enable())
|
|
.then(() => this.enableInitialModules()).then(() => {
|
|
const duration = performance.now() - start_time;
|
|
this.core_log.info(`Initialization complete in ${duration.toFixed(5)}ms.`);
|
|
this.log.init = false;
|
|
|
|
}).catch(err => {
|
|
this.core_log.error('An error occurred during initialization.', err);
|
|
this.log.init = false;
|
|
});
|
|
}
|
|
|
|
static get() {
|
|
return FrankerFaceZ.instance;
|
|
}
|
|
|
|
|
|
// ========================================================================
|
|
// Generate Log
|
|
// ========================================================================
|
|
|
|
async generateLog() {
|
|
const promises = [];
|
|
for(const key in this.__modules) {
|
|
const module = this.__modules[key];
|
|
if ( module instanceof Module && module.generateLog && module != this )
|
|
promises.push((async () => {
|
|
try {
|
|
return [
|
|
key,
|
|
await timeout(Promise.resolve(module.generateLog()), 5000)
|
|
];
|
|
} catch(err) {
|
|
return [
|
|
key,
|
|
`Error: ${err}`
|
|
]
|
|
}
|
|
})());
|
|
}
|
|
|
|
const out = await Promise.all(promises);
|
|
|
|
if ( this.log.captured_init && this.log.captured_init.length > 0 ) {
|
|
const logs = [];
|
|
for(const msg of this.log.captured_init) {
|
|
const time = dayjs(msg.time).locale('en').format('H:mm:ss');
|
|
logs.push(`[${time}] ${msg.level} | ${msg.category || 'core'}: ${msg.message}`);
|
|
}
|
|
|
|
out.unshift(['initialization', logs.join('\n')]);
|
|
}
|
|
|
|
return out.map(x => `${x[0]}
|
|
-------------------------------------------------------------------------------
|
|
${typeof x[1] === 'string' ? x[1] : JSON.stringify(x[1], null, 4)}`).join('\n\n');
|
|
}
|
|
|
|
|
|
// ========================================================================
|
|
// Modules
|
|
// ========================================================================
|
|
|
|
async discoverModules() {
|
|
// TODO: Actually do async modules.
|
|
const ctx = await require.context('src/modules', true, /^(?:\.\/)?([^/]+)(?:\/index)?\.jsx?$/ /*, 'lazy-once' */);
|
|
const modules = this.populate(ctx, this.core_log);
|
|
|
|
this.core_log.info(`Loaded descriptions of ${Object.keys(modules).length} modules.`);
|
|
}
|
|
|
|
|
|
async enableInitialModules() {
|
|
const promises = [];
|
|
|
|
for(const [key, data] of Object.entries(this.__module_data)) {
|
|
if ( data.source?.should_enable )
|
|
promises.push(this.resolve(key, true).then(module => {
|
|
return module.enable();
|
|
}));
|
|
}
|
|
|
|
await Promise.all(promises);
|
|
}
|
|
}
|
|
|
|
FrankerFaceZ.Logger = Logger;
|
|
|
|
const VER = FrankerFaceZ.version_info = {
|
|
major: __version_major__,
|
|
minor: __version_minor__,
|
|
revision: __version_patch__,
|
|
extra: __version_prerelease__?.length && __version_prerelease__[0],
|
|
commit: __git_commit__,
|
|
build: __webpack_hash__,
|
|
toString: () =>
|
|
`${VER.major}.${VER.minor}.${VER.revision}${VER.extra || ''}${DEBUG ? '-dev' : ''}`
|
|
}
|
|
|
|
|
|
FrankerFaceZ.utilities = {
|
|
addon: require('utilities/addon'),
|
|
color: require('utilities/color'),
|
|
constants: require('utilities/constants'),
|
|
dialog: require('utilities/dialog'),
|
|
dom: require('utilities/dom'),
|
|
events: require('utilities/events'),
|
|
fontAwesome: require('utilities/font-awesome'),
|
|
graphql: require('utilities/graphql'),
|
|
logging: require('utilities/logging'),
|
|
module: require('utilities/module'),
|
|
object: require('utilities/object'),
|
|
time: require('utilities/time'),
|
|
tooltip: require('utilities/tooltip'),
|
|
i18n: require('utilities/translation-core'),
|
|
dayjs: require('dayjs'),
|
|
popper: require('popper.js').default
|
|
}
|
|
|
|
|
|
|
|
window.FrankerFaceZ = FrankerFaceZ;
|
|
window.ffz = new FrankerFaceZ();
|