import * as fs from 'fs' ; import * as path from 'path' ; import SwPlugin from '../core/SwPlugin' ; import { createLogger } from '../logging' ; import * as semver from 'semver' ; import config from '../config/AgentConfig' ; const logger = createLogger ( __filename ) ; let topModule = module ; while ( topModule . parent ) { const filename = topModule . filename ; topModule = topModule . parent ; if ( filename . endsWith ( '/skywalking-nodejs/lib/index.js' ) ) break ; } export default class PluginInstaller { private readonly pluginDir : string ; readonly require : ( name : string ) => any = topModule . require . bind ( topModule ) ; private readonly resolve = ( request ) => ( module . constructor as any ) . _resolveFilename ( request , topModule ) ; constructor ( ) { this . pluginDir = path . resolve ( __dirname , '..' , 'plugins' ) ; } private isBuiltIn = ( module ) : boolean => this . resolve ( module ) === module ; private checkModuleVersion = ( plugin ) : { version : string ; isSupported : boolean ; } => { try { if ( this . isBuiltIn ( plugin . module ) ) { return { version : '*' , isSupported : true , } ; } } catch { return { version : 'not found,' , isSupported : false , } ; } const packageJsonPath = this . resolve ( `${ plugin . module }/package.json` ) ; const version = this . require ( packageJsonPath ) . version ; if ( ! semver . satisfies ( version , plugin . versions ) ) { logger . info ( `Plugin ${ plugin . module } ${ version } doesn't satisfy the supported version ${ plugin . versions }` ) ; return { version , isSupported : false , } ; } return { version , isSupported : true , } ; } ; isPluginEnabled = ( name ) : boolean => ! name . match ( config . reDisablePlugins ) ; install ( ) { fs . readdirSync ( this . pluginDir ) . filter ( ( file ) => ! ( file . endsWith ( '.d.ts' ) || file . endsWith ( '.js.map' ) ) ) . forEach ( ( file ) => { if ( file . replace ( /(?:Plugin)?\.js$/i , '' ) . match ( config . reDisablePlugins ) ) { logger . info ( `Plugin ${ file } not installed because it is disabled` ) ; return ; } let plugin ; const pluginFile = path . join ( this . pluginDir , file ) ; try { plugin = this . require ( pluginFile ) . default as SwPlugin ; const { isSupported , version } = this . checkModuleVersion ( plugin ) ; if ( ! isSupported ) { logger . info ( `Plugin ${ plugin . module } ${ version } doesn't satisfy the supported version ${ plugin . versions }` ) ; return ; } logger . info ( `Installing plugin ${ plugin . module } ${ plugin . versions }` ) ; plugin . install ( this ) ; } catch ( e ) { if ( plugin ) { logger . error ( `Error installing plugin ${ plugin . module } ${ plugin . versions }` ) ; } else { logger . error ( `Error processing plugin ${ pluginFile }` ) ; } } } ) ; } }