diff --git a/src/plugins/PluginIndex.ts b/src/plugins/PluginIndex.ts
new file mode 100644
index 00000000..502161a1
--- /dev/null
+++ b/src/plugins/PluginIndex.ts
@@ -0,0 +1,6 @@
+import { Plugin } from "util/plugin";
+import * as example_plugin from "./example-plugin/TestPlugin";
+
+export const PluginIndex: any = {
+ "example-plugin": new example_plugin.default(),
+};
\ No newline at end of file
diff --git a/src/plugins/example-plugin/ExamplePlugin.ts b/src/plugins/example-plugin/ExamplePlugin.ts
deleted file mode 100644
index e6f70657..00000000
--- a/src/plugins/example-plugin/ExamplePlugin.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-import { Plugin } from "@fosscord/util";
-
-export default class TestPlugin extends Plugin {
- onPluginLoaded(): void {
- console.log("Hello from test plugin! IT WORKS!!!!!!!");
- }
-}
\ No newline at end of file
diff --git a/src/plugins/example-plugin/TestPlugin.ts b/src/plugins/example-plugin/TestPlugin.ts
new file mode 100644
index 00000000..7a86aab2
--- /dev/null
+++ b/src/plugins/example-plugin/TestPlugin.ts
@@ -0,0 +1,12 @@
+import { Plugin } from "@fosscord/util";
+
+export default class TestPlugin implements Plugin {
+ pluginPath: string;
+ async initConfig(): Promise<void> {
+
+ }
+ onPluginLoaded() {
+ console.log("Test plugin active!");
+ }
+
+}
\ No newline at end of file
diff --git a/src/plugins/example-plugin/plugin.json b/src/plugins/example-plugin/plugin.json
index 2fcb7a00..f6c1b7ff 100644
--- a/src/plugins/example-plugin/plugin.json
+++ b/src/plugins/example-plugin/plugin.json
@@ -6,5 +6,5 @@
],
"repository": "https://github.com/fosscord/fosscord-server",
"license": "",
- "index": "ExamplePlugin.js"
+ "mainClass": "TestPlugin"
}
diff --git a/src/util/entities/PluginConfig.ts b/src/util/entities/PluginConfig.ts
new file mode 100644
index 00000000..a1364912
--- /dev/null
+++ b/src/util/entities/PluginConfig.ts
@@ -0,0 +1,11 @@
+import { Column, Entity } from "typeorm";
+import { BaseClassWithoutId, PrimaryIdColumn } from "./BaseClass";
+
+@Entity("plugin_config")
+export class PluginConfigEntity extends BaseClassWithoutId {
+ @PrimaryIdColumn()
+ key: string;
+
+ @Column({ type: "simple-json", nullable: true })
+ value: number | boolean | null | string | undefined;
+}
\ No newline at end of file
diff --git a/src/util/plugin/Plugin.ts b/src/util/plugin/Plugin.ts
index 1c86a006..0fb1732f 100644
--- a/src/util/plugin/Plugin.ts
+++ b/src/util/plugin/Plugin.ts
@@ -1,5 +1,5 @@
import EventEmitter from "events";
-import { TypedEventEmitter } from "@fosscord/util";
+import { PluginLoadedEventArgs, TypedEventEmitter } from "@fosscord/util";
type PluginEvents = {
error: (error: Error | unknown) => void;
@@ -7,14 +7,31 @@ type PluginEvents = {
};
//this doesnt work, check later:
- //(EventEmitter as new () => TypedEventEmitter<PluginEvents>) {
-export class Plugin extends EventEmitter {
- private _untypedOn = this.on
- private _untypedEmit = this.emit
- public on = <K extends keyof PluginEvents>(event: K, listener: PluginEvents[K]): this => this._untypedOn(event, listener)
- public emit = <K extends keyof PluginEvents>(event: K, ...args: Parameters<PluginEvents[K]>): boolean => this._untypedEmit(event, ...args)
-
- async init() {
+ //EventEmitter as new () => TypedEventEmitter<PluginEvents>
+export class Plugin {
+ /**
+ * Path the plugin resides in.
+ *
+ * @type {string}
+ * @memberof Plugin
+ */
+ pluginPath: string;
+ /**
+ *
+ *
+ * @memberof Plugin
+ */
+ async initConfig() {
// insert default config into database?
+ console.log("did you forget to implement initConfig?");
+ }
+ /**
+ *
+ *
+ * @param {PluginLoadedEventArgs} args Info about plugin environment
+ * @memberof Plugin
+ */
+ onPluginLoaded?(args?: PluginLoadedEventArgs) {
+
}
}
diff --git a/src/util/plugin/PluginConfig.ts b/src/util/plugin/PluginConfig.ts
new file mode 100644
index 00000000..c7a7db87
--- /dev/null
+++ b/src/util/plugin/PluginConfig.ts
@@ -0,0 +1,92 @@
+import { ConfigEntity } from "../entities/Config";
+import fs from "fs";
+import { OrmUtils, Environment } from "..";
+
+// TODO: yaml instead of json
+const overridePath = process.env.PLUGIN_CONFIG_PATH ?? "";
+
+let config: any;
+let pairs: ConfigEntity[];
+
+// TODO: use events to inform about config updates
+// Config keys are separated with _
+
+export const Config = {
+ init: async function init() {
+ if (config) return config;
+ console.log('[Config] Loading configuration...')
+ pairs = await ConfigEntity.find();
+ config = pairsToConfig(pairs);
+ //config = (config || {}).merge(new ConfigValue());
+ //config = OrmUtils.mergeDeep(new ConfigValue(), config)
+
+ if(process.env.CONFIG_PATH)
+ try {
+ const overrideConfig = JSON.parse(fs.readFileSync(overridePath, { encoding: "utf8" }));
+ config = overrideConfig.merge(config);
+ } catch (error) {
+ fs.writeFileSync(overridePath, JSON.stringify(config, null, 4));
+ }
+
+ return this.set(config);
+ },
+ get: function get() {
+ if(!config) {
+ if(Environment.isDebug)
+ console.log("Oops.. trying to get config without config existing... Returning defaults... (Is the database still initialising?)");
+ return {};
+ }
+ return config;
+ },
+ set: function set(val: Partial<any>) {
+ if (!config || !val) return;
+ config = val.merge(config);
+
+ return applyConfig(config);
+ },
+};
+
+function applyConfig(val: any) {
+ async function apply(obj: any, key = ""): Promise<any> {
+ if (typeof obj === "object" && obj !== null)
+ return Promise.all(Object.keys(obj).map((k) => apply(obj[k], key ? `${key}_${k}` : k)));
+
+ let pair = pairs.find((x) => x.key === key);
+ if (!pair) pair = new ConfigEntity();
+
+ pair.key = key;
+ pair.value = obj;
+ return pair.save();
+ }
+ if(process.env.CONFIG_PATH) {
+ if(Environment.isDebug)
+ console.log(`Writing config: ${process.env.CONFIG_PATH}`)
+ fs.writeFileSync(overridePath, JSON.stringify(val, null, 4));
+ }
+
+ return apply(val);
+}
+
+function pairsToConfig(pairs: ConfigEntity[]) {
+ let value: any = {};
+
+ pairs.forEach((p) => {
+ const keys = p.key.split("_");
+ let obj = value;
+ let prev = "";
+ let prevObj = obj;
+ let i = 0;
+
+ for (const key of keys) {
+ if (!isNaN(Number(key)) && !prevObj[prev]?.length) prevObj[prev] = obj = [];
+ if (i++ === keys.length - 1) obj[key] = p.value;
+ else if (!obj[key]) obj[key] = {};
+
+ prev = key;
+ prevObj = obj;
+ obj = obj[key];
+ }
+ });
+
+ return value;
+}
diff --git a/src/util/plugin/PluginLoader.ts b/src/util/plugin/PluginLoader.ts
index e69cb499..8c140d29 100644
--- a/src/util/plugin/PluginLoader.ts
+++ b/src/util/plugin/PluginLoader.ts
@@ -1,11 +1,13 @@
import path from "path";
import fs from "fs";
-import { Plugin, PluginManifest } from "./";
+import { Plugin, PluginLoadedEventArgs, PluginManifest } from "./";
+import { PluginIndex } from "plugins/PluginIndex";
const root = process.env.PLUGIN_LOCATION || "dist/plugins";
let pluginsLoaded = false;
export class PluginLoader {
+ public static plugins: Plugin[] = [];
public static loadPlugins() {
console.log(`Plugin root directory: ${path.resolve(root)}`);
const dirs = fs.readdirSync(root).filter((x) => {
@@ -17,6 +19,9 @@ export class PluginLoader {
}
});
console.log(dirs);
+ PluginIndex.forEach((x: any)=>{
+ console.log(x.onPluginLoaded)
+ })
dirs.forEach(async (x) => {
let modPath = path.resolve(path.join(root, x));
console.log(`Trying to load plugin: ${modPath}`);
@@ -24,16 +29,13 @@ export class PluginLoader {
console.log(
`Plugin info: ${manifest.name} (${manifest.id}), written by ${manifest.authors}, available at ${manifest.repository}`
);
- const module_ = require(path.join(modPath, manifest.index)) as Plugin;
- try {
- await module_.init();
- module_.emit("loaded");
- } catch (error) {
- module_.emit("error", error);
- }
+ const module_ = PluginIndex["example-plugin"];
+
+ module_.pluginPath = modPath;
+ if(module_.onPluginLoaded) module_.onPluginLoaded({} as PluginLoadedEventArgs);
+ this.plugins.push(module_);
});
- //
- //module_.pluginPath =
+ console.log(`Done loading ${this.plugins.length} plugins!`)
}
}
diff --git a/src/util/plugin/PluginManifest.ts b/src/util/plugin/PluginManifest.ts
index 01b2b084..79ecc465 100644
--- a/src/util/plugin/PluginManifest.ts
+++ b/src/util/plugin/PluginManifest.ts
@@ -6,5 +6,5 @@ export class PluginManifest {
license: string;
version: string // semver
versionCode: number // integer
- index: string;
+ mainClass: string;
}
\ No newline at end of file
diff --git a/src/util/plugin/index.ts b/src/util/plugin/index.ts
index c4c0c2ac..5974a065 100644
--- a/src/util/plugin/index.ts
+++ b/src/util/plugin/index.ts
@@ -1,3 +1,4 @@
export * from "./Plugin";
export * from "./PluginLoader";
export * from "./PluginManifest";
+export * from "./plugin_data_objects/index";
diff --git a/src/util/plugin/plugin_data_objects/ChannelCreateEventArgs.ts b/src/util/plugin/plugin_data_objects/ChannelCreateEventArgs.ts
new file mode 100644
index 00000000..ce7dec87
--- /dev/null
+++ b/src/util/plugin/plugin_data_objects/ChannelCreateEventArgs.ts
@@ -0,0 +1,7 @@
+export interface PreChannelCreateEventArgs {
+
+}
+
+export interface OnChannelCreateEventArgs {
+
+}
diff --git a/src/util/plugin/plugin_data_objects/GuildCreateEventArgs.ts b/src/util/plugin/plugin_data_objects/GuildCreateEventArgs.ts
new file mode 100644
index 00000000..e10e675a
--- /dev/null
+++ b/src/util/plugin/plugin_data_objects/GuildCreateEventArgs.ts
@@ -0,0 +1,7 @@
+export interface PreGuildCreateEventArgs {
+
+}
+
+export interface OnGuildCreateEventArgs {
+
+}
diff --git a/src/util/plugin/plugin_data_objects/LoginEventArgs.ts b/src/util/plugin/plugin_data_objects/LoginEventArgs.ts
new file mode 100644
index 00000000..391b852e
--- /dev/null
+++ b/src/util/plugin/plugin_data_objects/LoginEventArgs.ts
@@ -0,0 +1,7 @@
+export interface PreLoginEventArgs {
+
+}
+
+export interface OnLoginEventArgs {
+
+}
diff --git a/src/util/plugin/plugin_data_objects/MessageEventArgs.ts b/src/util/plugin/plugin_data_objects/MessageEventArgs.ts
new file mode 100644
index 00000000..0a3498c2
--- /dev/null
+++ b/src/util/plugin/plugin_data_objects/MessageEventArgs.ts
@@ -0,0 +1,7 @@
+export interface PreMessageEventArgs {
+
+}
+
+export interface OnMessageEventArgs {
+
+}
diff --git a/src/util/plugin/plugin_data_objects/PluginLoadedEventArgs.ts b/src/util/plugin/plugin_data_objects/PluginLoadedEventArgs.ts
new file mode 100644
index 00000000..58829f15
--- /dev/null
+++ b/src/util/plugin/plugin_data_objects/PluginLoadedEventArgs.ts
@@ -0,0 +1,3 @@
+export interface PluginLoadedEventArgs {
+
+}
\ No newline at end of file
diff --git a/src/util/plugin/plugin_data_objects/RegisterEventArgs.ts b/src/util/plugin/plugin_data_objects/RegisterEventArgs.ts
new file mode 100644
index 00000000..7f7c0c76
--- /dev/null
+++ b/src/util/plugin/plugin_data_objects/RegisterEventArgs.ts
@@ -0,0 +1,7 @@
+export interface PreRegisterEventArgs {
+
+}
+
+export interface OnRegisterEventArgs {
+
+}
diff --git a/src/util/plugin/plugin_data_objects/TypingEventArgs.ts b/src/util/plugin/plugin_data_objects/TypingEventArgs.ts
new file mode 100644
index 00000000..f6660692
--- /dev/null
+++ b/src/util/plugin/plugin_data_objects/TypingEventArgs.ts
@@ -0,0 +1,7 @@
+export interface PreTypingEventArgs {
+
+}
+
+export interface OnTypingEventArgs {
+
+}
diff --git a/src/util/plugin/plugin_data_objects/_gen.sh b/src/util/plugin/plugin_data_objects/_gen.sh
new file mode 100755
index 00000000..9fbd1749
--- /dev/null
+++ b/src/util/plugin/plugin_data_objects/_gen.sh
@@ -0,0 +1,21 @@
+#!/bin/sh
+while read event
+do
+ if [ ! -f "${event}EventArgs.ts" ]
+ then
+ echo Making event $event...
+ (
+ echo "export interface Pre${event}EventArgs {"
+ echo ' '
+ echo '}'
+ echo ''
+ echo "export interface On${event}EventArgs {"
+ echo ' '
+ echo '}'
+ ) > ${event}EventArgs.ts
+ fi
+done < _pdo
+
+echo ''
+
+node ../../../../scripts/gen_index.js .. --recursive
\ No newline at end of file
diff --git a/src/util/plugin/plugin_data_objects/_pdo b/src/util/plugin/plugin_data_objects/_pdo
new file mode 100644
index 00000000..fa207f77
--- /dev/null
+++ b/src/util/plugin/plugin_data_objects/_pdo
@@ -0,0 +1,7 @@
+Register
+Message
+Login
+GuildCreate
+ChannelCreate
+Typing
+StatusChange
\ No newline at end of file
diff --git a/src/util/plugin/plugin_data_objects/_todo.txt b/src/util/plugin/plugin_data_objects/_todo.txt
new file mode 100644
index 00000000..a6a78c7e
--- /dev/null
+++ b/src/util/plugin/plugin_data_objects/_todo.txt
@@ -0,0 +1 @@
+Voice events when we do voice.
\ No newline at end of file
diff --git a/src/util/plugin/plugin_data_objects/index.ts b/src/util/plugin/plugin_data_objects/index.ts
new file mode 100644
index 00000000..c75d43f9
--- /dev/null
+++ b/src/util/plugin/plugin_data_objects/index.ts
@@ -0,0 +1,7 @@
+export * from "./ChannelCreateEventArgs";
+export * from "./GuildCreateEventArgs";
+export * from "./LoginEventArgs";
+export * from "./MessageEventArgs";
+export * from "./PluginLoadedEventArgs";
+export * from "./RegisterEventArgs";
+export * from "./TypingEventArgs";
diff --git a/src/util/util/Environment.ts b/src/util/util/Environment.ts
new file mode 100644
index 00000000..a6d68785
--- /dev/null
+++ b/src/util/util/Environment.ts
@@ -0,0 +1,3 @@
+export class Environment {
+ static isDebug: boolean = /--debug|--inspect/.test(process.execArgv.join(' '));
+}
diff --git a/src/util/util/index.ts b/src/util/util/index.ts
index 11f0b72a..8135c107 100644
--- a/src/util/util/index.ts
+++ b/src/util/util/index.ts
@@ -23,3 +23,6 @@ export * from "./Snowflake";
export * from "./String";
export * from "./Token";
export * from "./TraverseDirectory";
+export * from "./InvisibleCharacters";
+export * from "./Environment";
+export * from "./Paths";
\ No newline at end of file
|