XYOracleNetwork/app-xyo-nodejs

View on GitHub
src/plugin-resolver.ts

Summary

Maintainability
A
2 hrs
Test Coverage
/* eslint-disable @typescript-eslint/explicit-function-return-type */
/* eslint-disable @typescript-eslint/no-explicit-any */
/* eslint-disable @typescript-eslint/no-unused-vars */
import {
  IXyoPlugin,
  IXyoGraphQlDelegate,
  IXyoPluginWithConfig,
  IXyoBoundWitnessMutexDelegate,
  XyoBase
} from '@xyo-network/sdk-base-nodejs'

export class PluginResolver extends XyoBase {
  private resolvedPluginNames: { [key: string]: boolean } = {}
  private resolvedPlugins: { [key: string]: any } = {}
  private lastResolvedPluginCount = 0
  private resolvedPluginCount = -1
  private qlDelegate: IXyoGraphQlDelegate
  private mutexDelegate: IXyoBoundWitnessMutexDelegate

  constructor(
    graphql: IXyoGraphQlDelegate,
    mutex: IXyoBoundWitnessMutexDelegate
  ) {
    super()
    this.qlDelegate = graphql
    this.mutexDelegate = mutex
  }

  public async resolve(plugins: IXyoPluginWithConfig[]) {
    // while we are still resolving plugins
    while (this.lastResolvedPluginCount !== this.resolvedPluginCount) {
      this.lastResolvedPluginCount = this.resolvedPluginCount

      // loop through the plugins to try to resolve one
      for (const plugin of plugins) {
        // if we have not resolved this plugin, do not try to resolve again
        if (!this.resolvedPluginNames[plugin.plugin.getName()]) {
          await this.resolveSinglePlugin(plugin)
        }
      }
    }
  }

  private async resolveSinglePlugin(plugin: IXyoPluginWithConfig) {
    const pluginDependencies = plugin.plugin.getPluginDependencies()
    let hasAllDependencies = true

    // loop through all of the resolved dependencies, to see if it has the dependencies
    for (const pluginDependency of pluginDependencies) {
      const resolvedPluginDependency = this.resolvedPlugins[pluginDependency]

      // if there is no dependency for the plugin, skip and return
      if (!resolvedPluginDependency) {
        hasAllDependencies = false
        break
      }
    }

    // if the plugin has all of the dependencies, initialize it
    if (hasAllDependencies) {
      await plugin.plugin.initialize({
        deps: this.resolvedPlugins,
        config: plugin.config,
        graphql: this.qlDelegate,
        mutex: this.mutexDelegate
      })

      const provides = plugin.plugin.getProvides()

      // after we initialize the plugin, we add what it provides, so that other plugins can use it
      for (const provider of provides) {
        if (this.resolvedPlugins[provider]) {
          throw Error('stub duplicate dependency, pick one')
        }

        this.resolvedPlugins[provider] = (plugin.plugin as any)[provider]
        this.resolvedPluginCount++
      }

      this.logDebug(`Initialized plugin: ${plugin.plugin.getName()}`)

      this.resolvedPluginNames[plugin.plugin.getName()] = true
    }
  }
}