Plugin Manager
The PluginManager
deals with activation and deactivation of other plugins. It also manages the permission layer between two plugins.
You can use it with a very loose permissions, or inherit from it to create a custom set of permission rules.
class RemixManager extends PluginManager {
remixPlugins = ['manager', 'solidity', 'fileManager', 'udapp']
// Create custom method
isFromRemix(name: string) {
return this.remixPlugins.includes(name)
}
canActivate(from: Profile, to: Profile) {
return this.isFromRemix(from.name)
}
}
Events
profileAdded
this.on('manager', 'profileAdded', (profile: Profile) => { ... })
Emitted when a plugin has been registered by the Engine
.
profileUpdated
this.on('manager', 'profileUpdated', (profile: Profile) => { ... })
Emitted when a plugin updates its profile through the updateProfile
method.
pluginActivated
this.on('manager', 'pluginActivated', (profile: Profile) => { ... })
Emitted when a plugin has been activated, either with activatePlugin
or toggleActive
.
If the plugin was already active, the event won’t be triggered.
pluginDeactivated
this.on('manager', 'pluginDeactivated', (profile: Profile) => { ... })
Emitted when a plugin has been deactivated, either with deactivatePlugin
or toggleActive
.
If the plugin was already deactivated, the event won’t be triggered.
Constructor
Used to create a new instance of PluginManager
. You can specify the profile of the manager to extend the default one.
The property name
of the profile must be manager
.
const profile = { name: 'manager', methods: [...managerMethods, 'isFromRemiw' ] }
const manager = new RemixManager(profile)
Properties
requestFrom
Return the name of the caller. If no request was provided, it means that the method has been called from the IDE - so we use “manager”.
Use this method when you expose custom methods from the Plugin Manager.
Methods
getProfile
Get the profile if its registered.
const profile = manager.getProfile('solidity')
updateProfile
Update the profile of the plugin. This method is used to lazy load services in plugins.
Only the caller plugn can update its profile.
The properties “name” and “url” cannot be updated.
const methods = [ ...solidity.methods, 'serviceMethod' ]
await solidity.call('manager', 'updateProfile', { methods })
isActive
Verify if a plugin is currently active.
const isActive = await manager.isActive('solidity')
activatePlugin
Check if caller can activate a plugin and activate it if authorized.
This method call canActivate
under the hood.
It can be called directly on the PluginManager
:
manager.activatePlugin('solidity')
Or from another plugin (for dependancy for example) :
class EthDoc extends Plugin {
onActivation() {
return this.call('manager', 'activatePlugin', ['solidity', 'remix-tests'])
}
}
deactivatePlugin
Check if caller can deactivate plugin and deactivate it if authorized.
This method call canDeactivate
under the hood.
It can be called directly on the PluginManager
:
manager.deactivatePlugin('solidity')
Or from another plugin :
class EthDoc extends Plugin {
onDeactivation() {
return this.call('manager', 'deactivatePlugin', ['solidity', 'remix-tests'])
}
}
Deactivating a plugin can have side effect on other plugins that depend on it. We recommend limiting the access to this method to a small set of plugins -if any (see
canDeactivate
).
toggleActive
Activate or deactivate by bypassing permission.
This method should ONLY be used by the IDE. Do not expose this method to other plugins.
manager.toggleActive('solidity') // Toggle One
manager.toggleActive(['solidity', 'remix-tests']) // Toggle Many
Permission
By extending the PluginManager
you can override the permission methods to create your own rules.
canActivate
Check if a plugin can activate another.
Params
from
: The profile of the caller plugin.to
: The profile of the target plugin.
class RemixManager extends PluginManager {
// Ask permission to user if it's not a plugin from Remix
async canActivate(from: Profile, to: Profile) {
if (this.isFromRemix(from.name)) {
return true
} else {
return confirm(`Can ${from.name} activates ${to.name}`)
}
}
}
Don’t forget to let ‘manager’ activate plugins if you’re not using
toggleActivate
.
canDeactivate
Check if a plugin can deactivate another.
Params
from
: The profile of the caller plugin.to
: The profile of the target plugin.
class RemixManager extends PluginManager {
// Only "manager" can deactivate plugins
async canDeactivate(from: Profile, to: Profile) {
return from.name === 'manager'
}
}
Don’t forget to let ‘manager’ deactivate plugins if you’re not using
toggleActivate
.
canCall
Check if a plugin can call a method of another plugin.
Params
from
: Name of the caller pluginto
: Name of the target pluginmethod
: Method targeted by the callermessage
: Optional Message to display to the user
This method can be called from a plugin to protect the access to one of its methods.
Every plugin implements a helper function that takes care of from
& to
class SensitivePlugin extends Plugin {
async sensitiveMethod() {
const canCall = await this.askUserPermission('sensitiveMethod', 'This method give access to sensitvie information')
if (canCall) {
// continue sensitive method
}
}
}
Then the IDE defines how to handle this call :
class RemixManager extends PluginManager {
// Keep track of the permissions
permissions: {
[name: string]: {
[methods: name]: string[]
}
} = {}
// Remember user preference
async canCall(from: Profile, to: Profile, method: string) {
// Make sure the caller of this methods is the target plugin
if (to.name !== this.currentRequest) {
return false
}
// Check if preference exist, else ask the user
if (!this.permissions[from.name]) {
this.permissions[from.name] = {}
}
if (!this.permissions[from.name][method]) {
this.permissions[from.name][method] = []
}
if (this.permissions[from.name][method].includes(to.name)) {
return true
} else {
confirm(`Can ${from.to} call method ${method} of ${to.name} ?`)
? !!this.permissions[from.name][method].push(to.name)
: false
}
}
}
Consider keeping the preferences in the localstorage for a better user experience.
Activation Hooks
PluginManager
provides an interface to react to changes of its state.
protected onPluginActivated?(profile: Profile): any protected onPluginDeactivated?(profile: Profile): any protected onProfileAdded?(profile: Profile): any
onPluginActivated
Triggered whenever a plugin has been activated.
class RemixManager extends PluginManager {
onPluginActivated(profile: Profile) {
updateMyUI('activate', profile.name)
}
}
onPluginDeactivated
Triggered whenever a plugin has been deactivated.
class RemixManager extends PluginManager {
onPluginDeactivated(profile: Profile) {
updateMyUI('deactivate', profile.name)
}
}
onProfileAdded
Triggered whenever a plugin has been registered (profile is added to the manager).
class RemixManager extends PluginManager {
onPluginDeactivated(profile: Profile) {
updateMyUI('add', profile)
}
}