Skip to content

Commit

Permalink
feat(plugins): differentiate local and global plugins
Browse files Browse the repository at this point in the history
  • Loading branch information
SewerynKras committed Mar 27, 2024
1 parent 195b624 commit e0bd7c8
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 15 deletions.
51 changes: 44 additions & 7 deletions src/plugins/examplePlugin.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { MarketApi } from "ya-ts-client";
import { GlobalPluginManager, GolemPlugin, registerGlobalPlugin } from "./globalPluginManager";
import { GolemPlugin, registerGlobalPlugin } from "./pluginManager";
import { LocalPluginManager } from "./localPluginManager";

// plugin that will be registered globally
const linearPricingOnlyPlugin: GolemPlugin = {
name: "linearPricingOnlyPlugin",
version: "1.0.0",
Expand All @@ -23,12 +25,47 @@ const linearPricingOnlyPlugin: GolemPlugin = {
},
};

// plugin that will be registered on a particular demand instead of globally
const cpuArchitecturePlugin: GolemPlugin = {
name: "cpuArchitecturePlugin",
version: "1.0.0",
register(golem) {
golem.market.registerHook("beforeDemandPublished", (demand) => {
demand.properties["golem.com.cpu.architecture"] = "x86_64";
return demand;
});
},
};

registerGlobalPlugin(linearPricingOnlyPlugin);

// inside demand publishing logic
const createDemandDTO = () => ({}) as MarketApi.DemandDTO;
let demand = createDemandDTO();
const hooks = GlobalPluginManager.getHooks("beforeDemandPublished");
for (const hook of hooks) {
demand = await hook(demand);
class ExampleDemandManager {
private pluginManager = new LocalPluginManager();
constructor(plugins?: GolemPlugin[]) {
if (plugins) {
plugins.forEach((plugin) => this.pluginManager.registerPlugin(plugin));
}
}

async publish() {
let demand: MarketApi.DemandDTO = {
properties: {},
} as MarketApi.DemandDTO;

const hooks = this.pluginManager.getHooks("beforeDemandPublished");
for (const hook of hooks) {
demand = await hook(demand);
}
this.pluginManager.emitEvent("demandPublished", demand);
return demand;
}
}

const demandManager0 = new ExampleDemandManager([cpuArchitecturePlugin]);
const demandManager1 = new ExampleDemandManager();

const demandWithCpuArchitecture = await demandManager0.publish();
const demandWithOnlyLinearPricing = await demandManager1.publish();

console.log(demandWithCpuArchitecture);
console.log(demandWithOnlyLinearPricing);
23 changes: 23 additions & 0 deletions src/plugins/localPluginManager.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import EventEmitter from "eventemitter3";
import { MarketEvents, MarketHooks } from "./marketPluginContext";
import { GlobalPluginManager, PluginManager } from "./pluginManager";

/**
* Plugin manager that will combine local and global plugins.
* Global plugins should be registered using `GlobalPluginManager`.
* Global hooks will be executed before local hooks, in order of registration.
*/
export class LocalPluginManager extends PluginManager {
getHooks<T extends keyof MarketHooks>(hookName: T): MarketHooks[T][] {
const localHooks = super.getHooks(hookName);
const globalHooks = GlobalPluginManager.getHooks(hookName);
return [...globalHooks, ...localHooks];
}
public emitEvent<T extends keyof MarketEvents>(
eventName: T,
...args: EventEmitter.ArgumentMap<MarketEvents>[Extract<T, keyof MarketEvents>]
): void {
GlobalPluginManager.emitEvent(eventName, ...args);
super.emitEvent(eventName, ...args);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,34 +13,43 @@ export type GolemPlugin = {
type AllHooks = MarketHooks; // | DeploymentHooks | PaymentHooks | ...
type AllEvents = MarketEvents; // | DeploymentEvents | PaymentEvents | ...

export class GlobalPluginManager {
static eventEmitter = new EventEmitter<AllEvents>();
static hooks = new Map<keyof AllHooks, AllHooks[keyof AllHooks][]>();
export class PluginManager {
private eventEmitter = new EventEmitter<AllEvents>();
private hooks = new Map<keyof AllHooks, AllHooks[keyof AllHooks][]>();

static registerHook<T extends keyof AllHooks>(hookName: T, hook: AllHooks[T]) {
private registerHook<T extends keyof AllHooks>(hookName: T, hook: AllHooks[T]) {
if (!this.hooks.has(hookName)) {
this.hooks.set(hookName, []);
}
this.hooks.get(hookName)!.push(hook as NonNullable<AllHooks[T]>);
}

static registerPlugin(plugin: GolemPlugin) {
public registerPlugin(plugin: GolemPlugin) {
const ctx = {
market: new MarketPluginContext(
(eventName, callback) => GlobalPluginManager.eventEmitter.on(eventName, callback),
(hookName, hook) => GlobalPluginManager.registerHook(hookName, hook),
(eventName, callback) => this.eventEmitter.on(eventName, callback),
(hookName, hook) => this.registerHook(hookName, hook),
),
// deployment: ...
// payment: ...
// ...
};
plugin.register(ctx);
}
static getHooks<T extends keyof AllHooks>(hookName: T): AllHooks[T][] {
public getHooks<T extends keyof AllHooks>(hookName: T): AllHooks[T][] {
return (this.hooks.get(hookName) || []) as AllHooks[T][];
}
public emitEvent<T extends keyof AllEvents>(
eventName: T,
...args: EventEmitter.ArgumentMap<MarketEvents>[Extract<T, keyof MarketEvents>]
) {
this.eventEmitter.emit(eventName, ...args);
}
}

// eslint-disable-next-line @typescript-eslint/naming-convention
export const GlobalPluginManager = new PluginManager();

export function registerGlobalPlugin(...plugins: GolemPlugin[]) {
plugins.forEach((plugin) => GlobalPluginManager.registerPlugin(plugin));
}

0 comments on commit e0bd7c8

Please sign in to comment.