Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/aperturerobotics/controllerbus

Modular application framework for Go.
https://github.com/aperturerobotics/controllerbus

controllers dynamic-configuration go plugin webassembly yaml

Last synced: 3 months ago
JSON representation

Modular application framework for Go.

Awesome Lists containing this project

README

        

![Controller Bus](./doc/img/controller-bus-logo.png)

## Introduction

[![GoDoc Widget]][GoDoc] [![Go Report Card Widget]][Go Report Card]

[GoDoc]: https://godoc.org/github.com/aperturerobotics/controllerbus
[GoDoc Widget]: https://godoc.org/github.com/aperturerobotics/controllerbus?status.svg
[Go Report Card Widget]: https://goreportcard.com/badge/github.com/aperturerobotics/controllerbus
[Go Report Card]: https://goreportcard.com/report/github.com/aperturerobotics/controllerbus

**ControllerBus** is a framework for **communicating control loops**:

- **Configurable**: flexible self-documenting config with Protobuf and YAML.
- **Cross-platform**: supports web browsers, servers, desktop, mobile, ...
- **Hot-loadable**: plugins and IPC dynamically add controllers at runtime.
- **Modular**: easily combine together application components w/o glue code.
- **Declarative**: de-duplicated declarative requests between controllers.

The primary concepts are:

- **Config**: configuration for a controller or process.
- **Controller**: goroutine which can create & handle Directives.
- **Directive**: a cross-controller request or declaration of target state.
- **Bus**: communication channel between running Controllers.
- **Factory**: constructor for controller and configuration objects.

Controller Bus provides a pattern for structuring modular Go projects.

## Examples

[![Support Server](https://img.shields.io/discord/803825858599059487.svg?label=Discord&logo=Discord&colorB=7289da&style=for-the-badge)](https://discord.gg/ZAZSt8CweP)

[![asciicast](https://asciinema.org/a/418275.svg)](https://asciinema.org/a/418275)

Basic demo of the controllerbus daemon and ConfigSet format:

```sh
cd ./cmd/controllerbus
go build -v
./controllerbus daemon
```

This will load `controllerbus_daemon.yaml` and execute the boilerplate demo:

```
added directive directive="LoadControllerWithConfig"
added directive directive="ExecController `ExecControllerWithConfig`: with a directive.
- yaml/json: resolving human-readable configuration to Config objects.

Config objects are Protobuf messages with attached validation functions. They
can be hand written in YAML and parsed to Protobuf or be created as Go objects.

### Protobuf Configuration

The [boilerplate](./example/boilerplate/controller/config.proto) example has the
following configuration proto:

```protobuf
// Config is the boilerplate configuration.
message Config {
// ExampleField is an example configuration field.
string example_field = 1;
}
```

This is an example YAML configuration for this controller:

```yaml
exampleField: "Hello world!"
```

With the Go API, we can use the **LoadControllerWithConfig** directive to
execute the controller with a configuration object:

```go
bus.ExecOneOff(
ctx,
cb,
resolver.NewLoadControllerWithConfig(&boilerplate_controller.Config{
ExampleField: "Hello World!",
}),
nil,
)
```

## Daemon and API

The [example daemon](./cmd/controllerbus) has an associated client and CLI for
the [Bus API](./bus/api), for example:

```sh
$ controllerbus client exec -f controllerbus_daemon.yaml
```

```json
{
"controllerInfo": {
"version": "0.0.1",
"id": "controllerbus/example/boilerplate"
},
"status": "ControllerStatus_RUNNING",
"id": "boilerplate-example-0"
}
```

The bus service has the following API:

```protobuf
// ControllerBusService is a generic controller bus lookup api.
service ControllerBusService {
// GetBusInfo requests information about the controller bus.
rpc GetBusInfo(GetBusInfoRequest) returns (GetBusInfoResponse) {}
// ExecController executes a controller configuration on the bus.
rpc ExecController(controller.exec.ExecControllerRequest) returns (stream controller.exec.ExecControllerResponse) {}
}
```

The RPC API is itself implemented as a controller, which can be configured:

```yaml
grpc-api:
config:
listenAddr: ":5000"
busApiConfig:
enableExecController: true
id: controllerbus/bus/api
rev: 1
```

For security, the default value of `enableExecController` is `false` to disallow
executing controllers via the API.

The structure under `cmd/controllerbus` and `example/boilerplate` are examples
which are intended to be copied to other projects, which reference the core
`controllerbus` controllers. A minimal program is as follows:

```go
ctx := context.Background()
log := logrus.New()
log.SetLevel(logrus.DebugLevel)
le := logrus.NewEntry(log)

b, sr, err := core.NewCoreBus(ctx, le)
if err != nil {
t.Fatal(err.Error())
}
sr.AddFactory(NewFactory(b))

execDir := resolver.NewLoadControllerWithConfig(&Config{
ExampleField: "testing",
})
_, ctrlRef, err := bus.ExecOneOff(ctx, b, execDir, nil)
if err != nil {
t.Fatal(err.Error())
}
defer ctrlRef.Release()
```

This provides logging, context cancelation. A single Factory is attached which
provides support for the Config type, (see the boilerplate example).

## Daemon and Client CLIs

Plugins can be bundled together with a set of root configurations into a CLI.
This can be used to bundle modules into a daemon and/or client for an
application - similar to the [controllerbus cli](./cmd/controllerbus).

## Testing

An in-memory Bus can be created for testing, an
[example](./example/boilerplate/controller/controller_test.go) is provided in
the boilerplate package.

## Plugins

[![asciicast](https://asciinema.org/a/I4LOCViLwzRlztYc1rytgAxWp.svg)](./example/plugin-demo)

**⚠ Plugins are experimental and not yet feature-complete.**

The [plugin](./plugin) system and compiler scans a set of Go packages for
ControllerBus factories and bundles them together into a hashed Plugin bundle.
The compiler CLI can watch code files for changes and re-build automatically.
Multiple plugin loaders and binary formats are supported.

```
USAGE:
controllerbus hot compile - compile packages specified as arguments once

OPTIONS:
--build-prefix value prefix to prepend to import paths, generated on default [$CONTROLLER_BUS_PLUGIN_BUILD_PREFIX]
--codegen-dir value path to directory to create/use for codegen, if empty uses tmpdir [$CONTROLLER_BUS_CODEGEN_DIR]
--output PATH, -o PATH write the output plugin to PATH - accepts {buildHash} [$CONTROLLER_BUS_OUTPUT]
--plugin-binary-id value binary id for the output plugin [$CONTROLLER_BUS_PLUGIN_BINARY_ID]
--plugin-binary-version value binary version for the output plugin, accepts {buildHash} [$CONTROLLER_BUS_PLUGIN_BINARY_VERSION]
--no-cleanup disable cleaning up the codegen dirs [$CONTROLLER_BUS_NO_CLEANUP]
--help, -h show help
```

The CLI will analyze a list of Go package paths, discover all Factories
available in the packages, generate a Go module for importing all of the
factories into a single Plugin, and compile that package to a .so library.

## Projects

List of projects known to use Controller Bus:

- [Bifrost]: networking and p2p library + daemon

[Bifrost]: https://github.com/aperturerobotics/bifrost

Open a PR to add your project to this list!

## Support

Please open a [GitHub issue] with any questions / issues.

[GitHub issue]: https://github.com/aperturerobotics/controllerbus/issues/new

... or feel free to reach out on [Matrix Chat] or [Discord].

[Discord]: https://discord.gg/ZAZSt8CweP
[Matrix Chat]: https://matrix.to/#/#aperturerobotics:matrix.org

## License

MIT