better error checking and small api change

This commit is contained in:
Zoe
2025-01-09 16:30:30 +00:00
parent d2e37617d4
commit ad0e949070
5 changed files with 53 additions and 27 deletions

View File

@@ -2,14 +2,14 @@
## Plugins ## 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 ### Plugin Interface
The `Plugin` interface is the main interface for plugins to implement. It has three methods: 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. - `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()` - This method returns the name of the plugin. - `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. - `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 Furthermore, your plugin should export a symbol named `Plugin` that implements the `Plugin` interface. The easiest way to do this in Go is simply

View File

@@ -1,6 +1,11 @@
# GLoom # 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 ## Features

View File

@@ -14,14 +14,14 @@ type GLoomI struct {
client *rpc.Client client *rpc.Client
} }
func (p *GLoomI) Init() error { func (p *GLoomI) Init() (*fiber.Config, error) {
// Connect to the RPC server // Connect to the RPC server
client, err := rpc.Dial("tcp", "localhost:7143") client, err := rpc.Dial("tcp", "localhost:7143")
if err != nil { 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 p.client = client
return nil return nil, nil
} }
func (p *GLoomI) Name() string { func (p *GLoomI) Name() string {
@@ -46,6 +46,7 @@ func (p *GLoomI) RegisterRoutes(router fiber.Router) {
apiRouter.Get("/plugins", func(c fiber.Ctx) error { apiRouter.Get("/plugins", func(c fiber.Ctx) error {
plugins, err := GetPlugins(p.client) plugins, err := GetPlugins(p.client)
if err != nil { if err != nil {
fmt.Printf("plugs: %+v\n", plugins)
return c.Status(fiber.StatusInternalServerError).SendString("Failed to list plugins: " + err.Error()) return c.Status(fiber.StatusInternalServerError).SendString("Failed to list plugins: " + err.Error())
} }

54
main.go
View File

@@ -22,9 +22,9 @@ import (
var embeddedAssets embed.FS var embeddedAssets embed.FS
type Plugin interface { type Plugin interface {
Init() error Init() (*fiber.Config, error)
Name() string
RegisterRoutes(app fiber.Router) RegisterRoutes(app fiber.Router)
Name() string
} }
type PluginInstance struct { type PluginInstance struct {
@@ -70,9 +70,13 @@ func NewGloom(app *fiber.App) (*GLoom, error) {
fiber: app, 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 { if err != nil {
return nil, err return err
} }
defer plugins.Close() defer plugins.Close()
@@ -83,40 +87,47 @@ func NewGloom(app *fiber.App) (*GLoom, error) {
} }
if err := plugins.Scan(&plugin.Path, &plugin.Domain); err != nil { if err := plugins.Scan(&plugin.Path, &plugin.Domain); err != nil {
return nil, err return err
} }
domains := strings.Split(plugin.Domain, ",") 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) slog.Info("Registering plugin", "pluginPath", pluginPath, "domains", domains)
p, err := plugin.Open(pluginPath) p, err := plugin.Open(pluginPath)
if err != nil { if err != nil {
panic(err) return err
} }
symbol, err := p.Lookup("Plugin") symbol, err := p.Lookup("Plugin")
if err != nil { if err != nil {
panic(err) return err
} }
pluginLib, ok := symbol.(Plugin) pluginLib, ok := symbol.(Plugin)
if !ok { 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 { if err != nil {
panic(err) return err
} }
router := fiber.New() if fiberConfig == nil {
fiberConfig = &fiber.Config{}
}
router := fiber.New(*fiberConfig)
pluginLib.RegisterRoutes(router) pluginLib.RegisterRoutes(router)
pluginInstance := PluginInstance{ pluginInstance := PluginInstance{
@@ -131,6 +142,8 @@ func (gloom *GLoom) RegisterPlugin(pluginPath string, domains []string) {
for _, domain := range domains { for _, domain := range domains {
gloom.domainMap.Store(domain, pluginPtr) gloom.domainMap.Store(domain, pluginPtr)
} }
return nil
} }
func (gloom *GLoom) DeletePlugin(pluginName string) { func (gloom *GLoom) DeletePlugin(pluginName string) {
@@ -178,7 +191,6 @@ type PluginData struct {
Domains []string `json:"domains"` Domains []string `json:"domains"`
} }
// Example RPC method: List all registered plugins
func (rpc *GloomRPC) ListPlugins(_ struct{}, reply *[]PluginData) error { func (rpc *GloomRPC) ListPlugins(_ struct{}, reply *[]PluginData) error {
var plugins []PluginData = make([]PluginData, 0) var plugins []PluginData = make([]PluginData, 0)
var domains map[string][]string = make(map[string][]string) var domains map[string][]string = make(map[string][]string)
@@ -260,8 +272,12 @@ func (rpc *GloomRPC) UploadPlugin(plugin PluginUpload, reply *string) error {
return nil 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.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" *reply = "Plugin uploaded successfully"
return nil return nil
} }
@@ -333,13 +349,17 @@ func main() {
panic("Failed to start RPC server: " + err.Error()) panic("Failed to start RPC server: " + err.Error())
} }
gloom.LoadInitialPlugins()
if os.Getenv("DISABLE_GLOOMI") != "true" { if os.Getenv("DISABLE_GLOOMI") != "true" {
hostname := os.Getenv("GLOOMI_HOSTNAME") hostname := os.Getenv("GLOOMI_HOSTNAME")
if hostname == "" { if hostname == "" {
hostname = "127.0.0.1" 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") fmt.Println("Server running at http://localhost:3000")

View File

@@ -4,8 +4,8 @@ import "github.com/gofiber/fiber/v3"
type MyPlugin struct{} type MyPlugin struct{}
func (p *MyPlugin) Init() error { func (p *MyPlugin) Init() (*fiber.Config, error) {
return nil return nil, nil
} }
func (p *MyPlugin) Name() string { func (p *MyPlugin) Name() string {