ethereum / remix-plugin

157 stars 101 forks source link

Docs - plugin system sequence diagrams #144

Open loredanacirstea opened 4 years ago

loredanacirstea commented 4 years ago

I went through the code and made some diagrams of the plugin system. Let me know if you think these would be useful for you or others and I can make a PR.

SVGs are also available. Diagrams were made with http://nomnoml.com and https://bramp.github.io/js-sequence-diagrams - source code below.

Plugin System classes

RemixPluginUML

[AbstractPluginEngine
    |
    methods: ExposedMethods
    events: ExposedEvents
    listeners: EventRecord
    permissionHandler: IPermissionHandler
    |
    register(plugins: Plugin/Array): void
    activate(names: string/Array): void
    deactivate(names: string/Array): void
    setSettings(settings: PluginEngineSettings): void
    |
    onRegistration?(plugin: Plugin): void
    onActivated?(plugin: Plugin): void
    onDeactivated?(plugin: Plugin): void
]
[PluginEngine
    |
    settings: PluginEngineSettings
    plugins: PluginMap
    actives: stringArray
    |
    isRegistered(name: string): boolean
    isActive(name: string): boolean
    isNative(profile: IframeProfile)
    |
    registerOne(plugin: Plugin)
    activateOne(name: string)
    deactivateOne(name: string)
]
[RemixAppManager
    |
    event: EventEmitter
    donotAutoReload: stringArray
    registered: object
    pluginsDirectory: string
    |
    getAll()
    getOne(name)
    getIds()
    ensureActivated(apiName)
    ensureDeactivated(apiName)
    isRequired(name)
    registeredPlugins()
]

[Plugin
    |
    profile: Profile
    requestQueue: Array<() => Promise>
    currentRequest: PluginRequest
    app: PluginApi<App>
    |
    activate()
    deactivate()
    callPluginMethod(method: string, args Array)
    addRequest(request: PluginRequest, method, args)
    |
    (injected by PluginEngine:)
    call(pluginName: string, key: string, ...payload)
    on(pluginName: string, event: string, cb: (...payload) => void) 
    emit(event: string, ...payload)
    |
    onRegistation?(): void
    onActivation?(): void
    onDeactivation?(): void
]
[IframePlugin
    |
    |
    getMessage(event: MessageEvent)
    postMessage(message: Partial<Message>)
    render()
]

[PluginManagerComponent
    |
    event: EventEmitter
    appManager: RemixAppManager
    views: object
    localPlugin: LocalPlugin
    filter: string
    |
    renderItem(name)
    openLocalPlugin()
    render()
    reRender()
    filterPlugins({target})
]

[PluginClient
    |
    id: number
    isLoaded: boolean
    events: EventEmitter
    currentRequest: PluginRequest
    options: PluginOptions<App>
    methods: stringArray
    |
    onload(cb?: () => void): Promise<void>
    call(pluginName: string, method: string, ...payload)
    on(pluginName: string, method: string, callb: function)
    emit(method: string, ...payload)
]

[AbstractPluginEngine]<:-[PluginEngine]

[Plugin]<:-[ViewPlugin]
[ViewPlugin]<:-[IframePlugin]

[PluginEngine]+-> 0..*[Plugin]

[PluginEngine]<:-[RemixAppManager]
[ViewPlugin]<:-[PluginManagerComponent]

[PluginManagerComponent]->[RemixAppManager]
[RemixAppManager]+->[PluginManagerComponent]
[RemixAppManager]+-> 0..*[IframePlugin]

Plugin Client initialization

RemixPluginConnectSequence

participant client_PluginClient
participant client_connectIframe
participant engine_IframePlugin

client_connectIframe -> engine_IframePlugin: postMessage \n request, handshake
client_connectIframe -> client_connectIframe: addEventListener message, getMessage

engine_IframePlugin -> engine_IframePlugin: add \n pendingRequest
engine_IframePlugin -> client_connectIframe: postMessage \n request, handshake
client_connectIframe -> client_PluginClient: emit loaded
client_PluginClient -> client_PluginClient: on loaded \n isLoaded=true
client_connectIframe -> engine_IframePlugin: postMessage \n response, handshake
engine_IframePlugin -> engine_IframePlugin: process \n pendingRequest

Plugin Client call to another plugin

(Plugin this[method](...args) needs to be expanded)

RemixPluginCallSequence

participant dApp
participant client_PluginClient
participant client_connectIframe
participant engine_IframePlugin

dApp -> client_PluginClient: call(name, key, ...payload)
client_PluginClient -> client_PluginClient: on `[${name}] ${key}-${id}`
client_PluginClient -> client_connectIframe: emit send, request \n name, key, payload, id
client_connectIframe -> engine_IframePlugin: postMessage request \n name, key, payload, id

engine_IframePlugin -> engine_IframePlugin: call \n (name, key, ...payload)
engine_IframePlugin -> engine_IframePlugin: check permissions
engine_IframePlugin -> engine_IframePlugin: check plugin active
engine_IframePlugin -> Plugin: addRequest \n (request, method, args)
Plugin -> Plugin: callPluginMethod \n (method, args)
Plugin -> Plugin: this[method](...args)
Plugin -> engine_IframePlugin: reject/resolve

engine_IframePlugin -> client_connectIframe: postMessage response \n name, key, payload, id

client_connectIframe -> client_PluginClient: emit `[${name}] ${key}-${id}`
client_PluginClient -> dApp: resolve/reject
GrandSchtroumpf commented 4 years ago

Wow it looks nice :) RemixAppManager and PluginManagerComponent are not part of @remixproject/engine. As we want to promote the fact that the library is agnostic of the IDE, I would prefer not to mention it here. Also, the LibraryPlugin is missing here (if you want to be exhaustif). Do you want to do a PR on the doc folder ?

Concerning the sequence diagrams, what the public you're targeting ? Developers who wants to contribute to the engine/client or developers who want to use it ?