1
0
Fork 0
mirror of https://github.com/FrankerFaceZ/FrankerFaceZ.git synced 2025-06-27 21:05:53 +00:00
FrankerFaceZ/src/main.js
SirStendec 1bc64586ef Continued WIP for async. Yes, this is a garbage giant commit that touches 47 files for over a thousand changed lines. Fight me.
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
2021-02-28 03:02:24 -05:00

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();