The PluginManager
deals with activation and deactivation of other plugins. It also manage the permission layer between two plugins.
You can use it as it with a very loose permission, 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)
}
}
this.on('manager', 'profileAdded', (profile: Profile) => { ... })
Emitted when a plugin have been registered by the Engine
.
this.on('manager', 'profileUpdated', (profile: Profile) => { ... })
Emitted when a plugin update it's profile through the updateProfile
method.
this.on('manager', 'pluginActivated', (profile: Profile) => { ... })
Emitted when a plugin have been activated, either with activatePlugin
or toggleActive
.
If the plugin was already active, the event won't be triggered.
this.on('manager', 'pluginDeactivated', (profile: Profile) => { ... })
Emitted when a plugin have been deactivated, either with deactivatePlugin
or toggleActive
.
If the plugin was already deactivated, the event won't be triggered.
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)
Return the name of the caller. If no request provided, this mean 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.
Get the profile if it's registered.
const profile = manager.getProfile('solidity')
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 })
Verify if a plugin is currently active.
const isActive = await manager.isActive('solidity')
Check if caller can activate 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'])
}
}
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. We recommand to limit the access to this methods to a small set of plugins if any (see
canDeactivate
).
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
By extending the PluginManager
you can override the permission methods to create your own rules.
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
.
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
.
Check if a plugin can call a method of another.
Params
from
: Name of the caller pluginto
: Name of the target pluginmethod
: Method targetted 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 it's method.
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
}
}
}
You might consider keep the preferences in the localstorage for a better user experience.
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
Triggered whenever a plugin has been activated.
class RemixManager extends PluginManager {
onPluginActivated(profile: Profile) {
updateMyUI('activate', profile.name)
}
}
Triggered whenever a plugin has been deactivated.
class RemixManager extends PluginManager {
onPluginDeactivated(profile: Profile) {
updateMyUI('deactivate', profile.name)
}
}
Triggered whenever a plugin has been registered (profile is added to the manager).
class RemixManager extends PluginManager {
onPluginDeactivated(profile: Profile) {
updateMyUI('add', profile)
}
}