How it would be: will be solved by moving the interface for the interaction of the plugin-consumer
with theplugin-supplier
into a separate library that will be hosted somewhere.
Plugin-supplier API:
There is interface that will be implemented by plugin-supplier
and used by plugin-consumer
.
This interface and linked objects will be separately in jar that will be hosted on codee maven.
interface PluginA {
fun foo(): Foo
fun bar(foo: Foo): Bar
}
Somewhere in script:
@file:DependsOn("there path to artifact with PluginA interface")
...
plugins.api.register<PluginA>(object : PluginA {
override fun foo(): Foo = MyFoo()
override fun bar(foo: Foo): Bar = foo.toBar()
}, CompatibilitySettings(version = 1))
Plugin-consumer
Plugin-consumer takes interface and calls some function.
plugins.api.withType<PluginA>(version = 1).onSuccess {
foo().apply { /* some stuff */ }
}.onError {
throw RuntimeException("Stub!")
}
Also, it can be used to provide some handlers from the app in new updates to keep back compatibility.
Synchronization of executions
Since a situation may occur when the plugin-consumer
is executed before theplugin-supplier
, I propose the following solution in the form of a callback:
plugins.afterEvaluation {
plugins.api.withType<PluginA>(version = 1) {
foo()
}
}
Action / Value dependence
Then imagine the following case: we have plugin-A, which depends on plugin-B. We also have plugin-C, which is awaiting some actions from plugin-A (which cannot perform them until it receives some value from plugin-B).
All this can be solved by providing plugin-C some kind of callback, for example:
plugin-C
In separated library:
interface PluginCCallbacks {
val value: String get() {
runBlocking { delay(10000L) }
return "value"
}
}
In script:
plugins.api.register<PluginCCallbacks>(object : PluginCCallbacks, CompatibilitySettings(currentVersion = 1))
plugin-A
In separated library:
interface PluginACallbacks {
fun setOnActionFinished(handler: () -> Unit)
}
In script:
val callbacks = object : PluginCCallbacks {...}
plugins.api.register<PluginACallbacks>(callbacks, CompatibilitySettings(...))
plugins.afterEvaluation {
plugins.withType<PluginCCallbacks>(version = 1) {
var _ = value
// lets notify all subscribers that action finished (pseudo-method)
callbacks.notifyOnActionFinished()
}
}
plugin-C
In script:
plugins.afterEvaluation {
plugins.withType<PluginACallbacks>(version = 1) {
setOnActionFinished {
// plugin-A finished it's work
}
}
}
Backward compatibility
To ensure the stability of the plugins when interacting, you must use CompatibilitySettings:
val settings = CompatibilitySettings(
minVersion = 1, maxVersion = 3, currentVersion = 2
)
// and apply it while registering:
plugins.api.register(IApi, settings)
enhancement priority:normal