change how plugin preloading works and change gloomi plugin uploading
This commit is contained in:
@@ -55,6 +55,9 @@ type PluginUpload struct {
|
||||
}
|
||||
```
|
||||
|
||||
> [!IMPORTANT]
|
||||
> The Name field can only contain alphanumeric characters and underscores and dashes.
|
||||
|
||||
## GLoomI
|
||||
|
||||
GLoomI is the included plugin management interface for GLoom, it utilizes the GLoom RPC, much like you would if you wanted to make your own management interface. By default, GLoomI is configured to use 127.0.0.1 as the hostname, but you con configure it to use a different hostname by setting the `GLOOMI_HOSTNAME` environment variable. The endpoints for GLoomI are as follows:
|
||||
|
||||
@@ -37,14 +37,17 @@ GLoom is a plugin-based web app manager written in Go (perhaps a pico-paas). GLo
|
||||
zqdgr build:no-gloomi
|
||||
```
|
||||
|
||||
and make sure to set the `DISABLE_GLOOMI` environment variable to `true` in the `.env` file.
|
||||
and make sure to clear the `PRELOAD_PLUGINS` environment variable and set it to your preferred management interface, or nothing at all if you don't want to use a management interface.
|
||||
|
||||
## Configuring
|
||||
|
||||
GLoom is configured using environment variables. The following environment variables are supported:
|
||||
|
||||
- `DEBUG` - Enables debug logging. This is a boolean value, so you can set it to any truthy value to enable debug logging.
|
||||
- `DISABLE_GLOOMI` - Disables the GLoomI plugin. This is a boolean value, so you can set it to any truthy value to disable the GLoomI plugin.
|
||||
- `PRELOAD_PLUGINS` - A json array of plugins to preload. The default value of this is `gloomi`, this is how GLoomI is loaded by default, and how replacement interfaces can be loaded. The format is in json, and the default value is:
|
||||
```json
|
||||
[{"file": "gloomi.so", "domains": ["localhost"]}]
|
||||
```
|
||||
- `PLUGINS_DIR` - The directory where plugins are stored. This is a string value, so you can set it to any directory path you want. The default value is `plugs`.
|
||||
|
||||
## Usage
|
||||
|
||||
@@ -52,6 +52,7 @@ func (p *GLoomI) RegisterRoutes(router fiber.Router) {
|
||||
})
|
||||
|
||||
type UploadRequest struct {
|
||||
Name string `form:"name"`
|
||||
Domains string `form:"domains"`
|
||||
}
|
||||
|
||||
@@ -65,6 +66,17 @@ func (p *GLoomI) RegisterRoutes(router fiber.Router) {
|
||||
return c.Status(fiber.StatusBadRequest).SendString("No domains provided")
|
||||
}
|
||||
|
||||
if pluginUpload.Name == "" {
|
||||
return c.Status(fiber.StatusBadRequest).SendString("No name provided")
|
||||
}
|
||||
|
||||
// check if string is alphanumeric
|
||||
for _, char := range pluginUpload.Name {
|
||||
if !((char >= 'a' && char <= 'z') || (char >= 'A' && char <= 'Z') || (char >= '0' && char <= '9') || char == '-' || char == '_') {
|
||||
return c.Status(fiber.StatusBadRequest).SendString("Invalid name provided")
|
||||
}
|
||||
}
|
||||
|
||||
domains := make([]string, 0)
|
||||
for _, domain := range strings.Split(pluginUpload.Domains, ",") {
|
||||
domains = append(domains, strings.TrimSpace(domain))
|
||||
@@ -86,7 +98,7 @@ func (p *GLoomI) RegisterRoutes(router fiber.Router) {
|
||||
Name string `json:"name"`
|
||||
Data []byte `json:"data"`
|
||||
}
|
||||
pluginUploadStruct.Name = pluginFile.Filename
|
||||
pluginUploadStruct.Name = pluginUpload.Name
|
||||
pluginUploadStruct.Domains = domains
|
||||
pluginUploadStruct.Data, err = io.ReadAll(pluginData)
|
||||
if err != nil {
|
||||
|
||||
93
main.go
93
main.go
@@ -5,6 +5,7 @@ import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"embed"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"math/rand/v2"
|
||||
@@ -37,11 +38,18 @@ type PluginHost struct {
|
||||
Domains []string
|
||||
}
|
||||
|
||||
type PreloadPlugin struct {
|
||||
File string `json:"file"`
|
||||
Domains []string `json:"domains"`
|
||||
}
|
||||
|
||||
type GLoom struct {
|
||||
// path to the pluginHost binary
|
||||
tmpDir string
|
||||
pluginDir string
|
||||
|
||||
preloadPlugins []PreloadPlugin
|
||||
|
||||
plugins libs.SyncMap[string, *PluginHost]
|
||||
hostMap libs.SyncMap[string, bool]
|
||||
|
||||
@@ -95,12 +103,29 @@ func NewGloom(proxyManager *ProxyManager) (*GLoom, error) {
|
||||
}
|
||||
slog.Debug("Wrote pluginHost", "dir", tmpDir+"/pluginHost")
|
||||
|
||||
var preloadPlugins []PreloadPlugin
|
||||
preloadPluginsEnv, ok := os.LookupEnv("PRELOAD_PLUGINS")
|
||||
if ok {
|
||||
err = json.Unmarshal([]byte(preloadPluginsEnv), &preloadPlugins)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
} else {
|
||||
preloadPlugins = []PreloadPlugin{
|
||||
{
|
||||
File: "gloomi.so",
|
||||
Domains: []string{"localhost"},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
gloom := &GLoom{
|
||||
tmpDir: tmpDir,
|
||||
pluginDir: pluginsDir,
|
||||
plugins: libs.SyncMap[string, *PluginHost]{},
|
||||
DB: db,
|
||||
ProxyManager: proxyManager,
|
||||
tmpDir: tmpDir,
|
||||
pluginDir: pluginsDir,
|
||||
preloadPlugins: preloadPlugins,
|
||||
plugins: libs.SyncMap[string, *PluginHost]{},
|
||||
DB: db,
|
||||
ProxyManager: proxyManager,
|
||||
}
|
||||
|
||||
return gloom, nil
|
||||
@@ -109,6 +134,12 @@ func NewGloom(proxyManager *ProxyManager) (*GLoom, error) {
|
||||
func (gloom *GLoom) LoadInitialPlugins() error {
|
||||
slog.Debug("Loading initial plugins")
|
||||
|
||||
for _, plugin := range gloom.preloadPlugins {
|
||||
if err := gloom.RegisterPlugin(filepath.Join(gloom.pluginDir, plugin.File), plugin.File, plugin.Domains); err != nil {
|
||||
slog.Warn("Failed to register plugin", "pluginPath", plugin.File, "error", err)
|
||||
}
|
||||
}
|
||||
|
||||
plugins, err := gloom.DB.Query("SELECT path, domains, name FROM plugins")
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -272,7 +303,7 @@ func (gloom *GLoom) RegisterPlugin(pluginPath string, name string, domains []str
|
||||
Domains: domains,
|
||||
}
|
||||
|
||||
gloom.plugins.Store(pluginPath, plugHost)
|
||||
gloom.plugins.Store(name, plugHost)
|
||||
|
||||
if oldProxy != nil {
|
||||
go func() {
|
||||
@@ -367,6 +398,32 @@ type PluginUpload struct {
|
||||
}
|
||||
|
||||
func (rpc *GloomRPC) UploadPlugin(plugin PluginUpload, reply *string) error {
|
||||
for _, preloadPlugin := range rpc.gloom.preloadPlugins {
|
||||
if plugin.Name == preloadPlugin.File {
|
||||
*reply = "Plugin is preloaded"
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
if plugin.Name == "" {
|
||||
*reply = "Plugin name cannot be empty"
|
||||
return fmt.Errorf("plugin name cannot be empty")
|
||||
}
|
||||
|
||||
for _, char := range plugin.Name {
|
||||
if !((char >= 'a' && char <= 'z') || (char >= 'A' && char <= 'Z') || (char >= '0' && char <= '9') || char == '-' || char == '_') {
|
||||
*reply = "Invalid plugin name"
|
||||
return fmt.Errorf("invalid plugin name")
|
||||
}
|
||||
}
|
||||
|
||||
for _, domain := range plugin.Domains {
|
||||
if domain == "" {
|
||||
*reply = "Domain cannot be empty"
|
||||
return fmt.Errorf("domain cannot be empty")
|
||||
}
|
||||
}
|
||||
|
||||
_, err := deploymentLock.Lock(plugin.Name, context.Background())
|
||||
if err != nil && err == ErrLocked {
|
||||
*reply = "Plugin is already being updated"
|
||||
@@ -492,9 +549,11 @@ func (rpc *GloomRPC) UploadPlugin(plugin PluginUpload, reply *string) error {
|
||||
}
|
||||
|
||||
func (rpc *GloomRPC) DeletePlugin(pluginName string, reply *string) error {
|
||||
if pluginName == "GLoomI" {
|
||||
*reply = "GLoomI cannot be deleted since it is not a plugin that is loaded by a user. If you wish to disable GLoomI, set DISABLE_GLOOMI=true in your .env file"
|
||||
return nil
|
||||
for _, preloadPlugin := range rpc.gloom.preloadPlugins {
|
||||
if pluginName == preloadPlugin.File {
|
||||
*reply = "Plugin is preloaded"
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
_, ok := rpc.gloom.plugins.Load(pluginName)
|
||||
@@ -548,22 +607,6 @@ func main() {
|
||||
|
||||
gloom.LoadInitialPlugins()
|
||||
|
||||
enableGloomi, err := strconv.ParseBool(os.Getenv("ENABLE_GLOOMI"))
|
||||
if err != nil {
|
||||
enableGloomi = true
|
||||
}
|
||||
|
||||
if enableGloomi {
|
||||
hostname := os.Getenv("GLOOMI_HOSTNAME")
|
||||
if hostname == "" {
|
||||
hostname = "127.0.0.1"
|
||||
}
|
||||
|
||||
if err := gloom.RegisterPlugin("plugs/gloomi.so", "GLoomI", []string{hostname}); err != nil {
|
||||
panic("Failed to register GLoomI: " + err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Println("Server running at http://localhost:3000")
|
||||
if err := gloom.ProxyManager.ListenAndServe("127.0.0.1:3000"); err != nil {
|
||||
panic(err)
|
||||
|
||||
Reference in New Issue
Block a user