diff --git a/DOCUMENTATION.md b/DOCUMENTATION.md index f03d373..510c1d3 100644 --- a/DOCUMENTATION.md +++ b/DOCUMENTATION.md @@ -2,14 +2,14 @@ ## Plugins -Plugins are the core of GLoom, they are responsible for handling requests and providing routes. +Plugins are the core of GLoom, they are responsible for handling requests and providing routes. When building a plugin, it's expected that all the assets you need will be bundled with the plugin. However, you are allowed to create directories for assets like file uploads, but we urge you to create a specific directory for assets (ie a database or a public directory) to avoid cluttering the root directory of gloom. ### Plugin Interface The `Plugin` interface is the main interface for plugins to implement. It has three methods: -- `Init()` - This method is called when the plugin is loaded. It is the function that is initially called when the plugin is loaded. -- `Name()` - This method returns the name of the plugin. +- `Init() (*fiber.Config, error)` - This method is called when the plugin is loaded. It is the function that is initially called when the plugin is loaded. +- `Name() string` - This method returns the name of the plugin. - `RegisterRoutes(router fiber.Router)` - This method is called when the plugin is loaded and is responsible for registering routes to the router. Furthermore, your plugin should export a symbol named `Plugin` that implements the `Plugin` interface. The easiest way to do this in Go is simply diff --git a/README.md b/README.md index 4eee454..b8c655c 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,11 @@ # GLoom -GLoom is a plugin-based web app manager written in Go. GLoom's focus is to provide and simple and efficient way to host micro-web apps easily. +GLoom is a plugin-based web app manager written in Go. GLoom's focus is to provide and simple and efficient way to host micro-web apps easily. Currently, GLoom is a fun little proof of concept, but it suffers from a few issues: + +- Incorrectly confgiured plugins will cause GLoom to crash +- GLoom plugins are cannot be reloaded when they are updated + +As far as I see it, these issues are unfixable currently, Go Plugins __cannot__ be unloaded, and there's no way to separate GLoom plugins from the host proces, thus meaning if a plugin crashes, GLoom will crash as well. ## Features @@ -46,4 +51,4 @@ Contributions are welcome! ## License -GLoom is licensed under the MIT License. \ No newline at end of file +GLoom is licensed under the MIT License. diff --git a/gloomi/main.go b/gloomi/main.go index 39e9b79..adcb3e6 100644 --- a/gloomi/main.go +++ b/gloomi/main.go @@ -14,14 +14,14 @@ type GLoomI struct { client *rpc.Client } -func (p *GLoomI) Init() error { +func (p *GLoomI) Init() (*fiber.Config, error) { // Connect to the RPC server client, err := rpc.Dial("tcp", "localhost:7143") if err != nil { - return fmt.Errorf("failed to connect to Gloom RPC server: %w", err) + return nil, fmt.Errorf("failed to connect to Gloom RPC server: %w", err) } p.client = client - return nil + return nil, nil } func (p *GLoomI) Name() string { @@ -46,6 +46,7 @@ func (p *GLoomI) RegisterRoutes(router fiber.Router) { apiRouter.Get("/plugins", func(c fiber.Ctx) error { plugins, err := GetPlugins(p.client) if err != nil { + fmt.Printf("plugs: %+v\n", plugins) return c.Status(fiber.StatusInternalServerError).SendString("Failed to list plugins: " + err.Error()) } diff --git a/main.go b/main.go index caa75db..ead9677 100644 --- a/main.go +++ b/main.go @@ -22,9 +22,9 @@ import ( var embeddedAssets embed.FS type Plugin interface { - Init() error - Name() string + Init() (*fiber.Config, error) RegisterRoutes(app fiber.Router) + Name() string } type PluginInstance struct { @@ -70,9 +70,13 @@ func NewGloom(app *fiber.App) (*GLoom, error) { fiber: app, } - plugins, err := db.Query("SELECT path, domains FROM plugins") + return gloom, nil +} + +func (gloom *GLoom) LoadInitialPlugins() error { + plugins, err := gloom.DB.Query("SELECT path, domains FROM plugins") if err != nil { - return nil, err + return err } defer plugins.Close() @@ -83,40 +87,47 @@ func NewGloom(app *fiber.App) (*GLoom, error) { } if err := plugins.Scan(&plugin.Path, &plugin.Domain); err != nil { - return nil, err + return err } domains := strings.Split(plugin.Domain, ",") - gloom.RegisterPlugin(plugin.Path, domains) + if err := gloom.RegisterPlugin(plugin.Path, domains); err != nil { + slog.Warn("Failed to register plugin", "pluginPath", plugin.Path, "error", err) + } } - return gloom, nil + return nil } -func (gloom *GLoom) RegisterPlugin(pluginPath string, domains []string) { +func (gloom *GLoom) RegisterPlugin(pluginPath string, domains []string) error { slog.Info("Registering plugin", "pluginPath", pluginPath, "domains", domains) + p, err := plugin.Open(pluginPath) if err != nil { - panic(err) + return err } symbol, err := p.Lookup("Plugin") if err != nil { - panic(err) + return err } pluginLib, ok := symbol.(Plugin) if !ok { - panic("Plugin is not a Plugin") + return fmt.Errorf("plugin is not a Plugin") } - err = pluginLib.Init() + fiberConfig, err := pluginLib.Init() if err != nil { - panic(err) + return err } - router := fiber.New() + if fiberConfig == nil { + fiberConfig = &fiber.Config{} + } + + router := fiber.New(*fiberConfig) pluginLib.RegisterRoutes(router) pluginInstance := PluginInstance{ @@ -131,6 +142,8 @@ func (gloom *GLoom) RegisterPlugin(pluginPath string, domains []string) { for _, domain := range domains { gloom.domainMap.Store(domain, pluginPtr) } + + return nil } func (gloom *GLoom) DeletePlugin(pluginName string) { @@ -178,7 +191,6 @@ type PluginData struct { Domains []string `json:"domains"` } -// Example RPC method: List all registered plugins func (rpc *GloomRPC) ListPlugins(_ struct{}, reply *[]PluginData) error { var plugins []PluginData = make([]PluginData, 0) var domains map[string][]string = make(map[string][]string) @@ -260,8 +272,12 @@ func (rpc *GloomRPC) UploadPlugin(plugin PluginUpload, reply *string) error { return nil } + if err := rpc.gloom.RegisterPlugin("plugs/"+plugin.Name, plugin.Domains); err != nil { + slog.Warn("Failed to register uplaoded plguin", "pluginPath", "plugs/"+plugin.Name, "error", err) + *reply = "Plugin upload failed" + return nil + } rpc.gloom.DB.Exec("INSERT INTO plugins (path, domains) VALUES (?, ?)", "plugs/"+plugin.Name, strings.Join(plugin.Domains, ",")) - rpc.gloom.RegisterPlugin("plugs/"+plugin.Name, plugin.Domains) *reply = "Plugin uploaded successfully" return nil } @@ -333,13 +349,17 @@ func main() { panic("Failed to start RPC server: " + err.Error()) } + gloom.LoadInitialPlugins() + if os.Getenv("DISABLE_GLOOMI") != "true" { hostname := os.Getenv("GLOOMI_HOSTNAME") if hostname == "" { hostname = "127.0.0.1" } - gloom.RegisterPlugin("plugs/gloomi.so", []string{hostname}) + if err := gloom.RegisterPlugin("plugs/gloomi.so", []string{hostname}); err != nil { + panic("Failed to register GLoomI: " + err.Error()) + } } fmt.Println("Server running at http://localhost:3000") diff --git a/plugin/main.go b/plugin/main.go index c7cf8e2..fc18dee 100644 --- a/plugin/main.go +++ b/plugin/main.go @@ -4,8 +4,8 @@ import "github.com/gofiber/fiber/v3" type MyPlugin struct{} -func (p *MyPlugin) Init() error { - return nil +func (p *MyPlugin) Init() (*fiber.Config, error) { + return nil, nil } func (p *MyPlugin) Name() string {