small cleanput and switch to sentinel

This commit is contained in:
Zoe
2025-05-16 03:23:47 +00:00
parent c31f070b46
commit a6f4782518
11 changed files with 69 additions and 213 deletions

View File

@@ -1,3 +1,2 @@
DISABLE_GLOOMI=false PRELOAD_PLUGINS='[{"file": "gloomi.so", "domains": ["localhost"]}]' # make sure gloomi.so is in the $PLUGINS_DIR
GLOOMI_HOSTNAME=localhost
PLUGINS_DIR=plugs PLUGINS_DIR=plugs

View File

@@ -60,7 +60,7 @@ type PluginUpload struct {
## GLoomI ## 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: 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 localhost as the hostname, but you con configure it to use a different hostname by changing the `PRELOADED_PLUGINS` environment variable, as describe in the [README](README.md). The endpoints for GLoomI are as follows:
- `GET /api/plugins` - This endpoint returns a list of all registered plugins and their domains. - `GET /api/plugins` - This endpoint returns a list of all registered plugins and their domains.
- `POST /api/plugins` - This endpoint uploads a plugin to GLoom. it takes a multipart/form-data request with the following fields: - `POST /api/plugins` - This endpoint uploads a plugin to GLoom. it takes a multipart/form-data request with the following fields:

View File

@@ -1,6 +1,6 @@
# GLoom # GLoom
GLoom is a plugin-based web app manager written in Go (perhaps a pico-paas). 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, and now even supports unloading plugins, and gracefully handles plugins that crash, but it is not yet ready for production use, and may not ever be. GLoom is still in early development, so expect some rough edges and bugs and at its heart, GLoom is just a proof of concept, fun to write, and fun to use, but not production ready. GLoom is a plugin-based web app manager written in Go (perhaps a pico-paas). 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, and now even supports unloading plugins, and gracefully handles plugins that crash, but it is not yet ready for production use, and may not ever be. GLoom is still in early development, so expect some rough edges and bugs and at its heart, GLoom is just a proof of concept, fun to write, and fun to use, but not production ready. If you want a more stable and production ready web app manager, check out my other project, [Flux](https://github.com/juls0730/flux) ;).
## Features ## Features
@@ -15,6 +15,8 @@ GLoom is a plugin-based web app manager written in Go (perhaps a pico-paas). GLo
- Go 1.20 or higher - Go 1.20 or higher
- [zqdgr](https://github.com/juls0730/zqdgr) - [zqdgr](https://github.com/juls0730/zqdgr)
This project is primarily written for Linux, and has only been tested on Linux, you might have luck with other operating systems, but it is not guaranteed to work, feel free to open an issue if you encounter any problems.
### Installation ### Installation
1. Clone the repository: 1. Clone the repository:
@@ -32,9 +34,9 @@ GLoom is a plugin-based web app manager written in Go (perhaps a pico-paas). GLo
zqdgr build zqdgr build
``` ```
and if you want to build the project without the GLoom management Interface (you will not be able to manage plugins wunless you have another interface like GLoomI): and if you want to build the project without the GLoom management Interface (you will not be able to manage plugins wunless you have another interface like GLoomI or mark all the plugins you want to use as preloaded):
```bash ```bash
zqdgr build:no-gloomi zqdgr build:gloom
``` ```
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. 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.
@@ -48,6 +50,7 @@ GLoom is configured using environment variables. The following environment varia
```json ```json
[{"file": "gloomi.so", "domains": ["localhost"]}] [{"file": "gloomi.so", "domains": ["localhost"]}]
``` ```
It is not recommended to preload any plugin other than a management interface, this is because preloaded plugins are protected and cannot be updated in an green-blue fashion.
- `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`. - `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 ## Usage
@@ -60,4 +63,4 @@ Contributions are welcome!
## License ## License
GLoom is licensed under the MIT License. GLoom is licensed under the MIT License and ever file is licensed under it unless otherwise specified.

View File

@@ -1,9 +1,9 @@
{ {
"name": "Go Project", "name": "GLoomI",
"version": "0.0.1", "version": "0.0.1",
"description": "Example description", "description": "GLoomI is the included plugin management interface for GLoom",
"author": "you", "author": "juls0730",
"license": "BSL-1.0", "license": "MIT",
"scripts": { "scripts": {
"build": "go build -buildmode=plugin -o ../plugs/gloomi.so main.go" "build": "go build -buildmode=plugin -o ../plugs/gloomi.so main.go"
}, },

10
go.mod
View File

@@ -1,15 +1,11 @@
module github.com/juls0730/gloom module github.com/juls0730/gloom
go 1.23.4 go 1.24.2
require ( require (
github.com/joho/godotenv v1.5.1 github.com/joho/godotenv v1.5.1
github.com/juls0730/sentinel v0.0.0-20250515154110-2e7e6586cacd
github.com/mattn/go-sqlite3 v1.14.24 github.com/mattn/go-sqlite3 v1.14.24
) )
require ( require golang.org/x/sync v0.14.0 // indirect
github.com/mattn/go-colorable v0.1.14 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect
golang.org/x/sys v0.29.0 // indirect
)

13
go.sum
View File

@@ -1,13 +1,8 @@
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= github.com/juls0730/sentinel v0.0.0-20250515154110-2e7e6586cacd h1:JNazPdlAs307Gtaqmb+wfCjcOzO3MRXxg9nf0bAKAnc=
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= github.com/juls0730/sentinel v0.0.0-20250515154110-2e7e6586cacd/go.mod h1:CnRvcleiS2kvK1N2PeQmeoRP5EXpBDpHPkg72vAUaSg=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-sqlite3 v1.14.24 h1:tpSp2G2KyMnnQu99ngJ47EIkWVmliIizyZBfPrBWDRM= github.com/mattn/go-sqlite3 v1.14.24 h1:tpSp2G2KyMnnQu99ngJ47EIkWVmliIizyZBfPrBWDRM=
github.com/mattn/go-sqlite3 v1.14.24/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= github.com/mattn/go-sqlite3 v1.14.24/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d h1:5PJl274Y63IEHC+7izoQE9x6ikvDFZS2mDVS3drnohI= golang.org/x/sync v0.14.0 h1:woo0S4Yywslg6hp4eUFjTVOyKt0RookbpAHG4c1HmhQ=
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=

View File

@@ -1,4 +1,6 @@
// Copyright (c) 2024 @tarampampam
// https://gist.github.com/tarampampam/f96538257ff125ab71785710d48b3118 // https://gist.github.com/tarampampam/f96538257ff125ab71785710d48b3118
package libs package libs
import "sync" import "sync"

221
main.go
View File

@@ -11,9 +11,7 @@ import (
"math/rand/v2" "math/rand/v2"
"net" "net"
"net/http" "net/http"
"net/http/httputil"
"net/rpc" "net/rpc"
"net/url"
"os" "os"
"os/exec" "os/exec"
"path" "path"
@@ -21,11 +19,11 @@ import (
"strconv" "strconv"
"strings" "strings"
"sync" "sync"
"sync/atomic"
"time" "time"
"github.com/joho/godotenv" "github.com/joho/godotenv"
"github.com/juls0730/gloom/libs" "github.com/juls0730/gloom/libs"
"github.com/juls0730/sentinel"
_ "github.com/mattn/go-sqlite3" _ "github.com/mattn/go-sqlite3"
) )
@@ -54,10 +52,10 @@ type GLoom struct {
hostMap libs.SyncMap[string, bool] hostMap libs.SyncMap[string, bool]
DB *sql.DB DB *sql.DB
ProxyManager *ProxyManager ProxyManager *sentinel.ProxyManager
} }
func NewGloom(proxyManager *ProxyManager) (*GLoom, error) { func NewGloom(proxyManager *sentinel.ProxyManager) (*GLoom, error) {
pluginsDir := os.Getenv("PLUGINS_DIR") pluginsDir := os.Getenv("PLUGINS_DIR")
if pluginsDir == "" { if pluginsDir == "" {
pluginsDir = "plugs" pluginsDir = "plugs"
@@ -132,11 +130,11 @@ func NewGloom(proxyManager *ProxyManager) (*GLoom, error) {
} }
func (gloom *GLoom) LoadInitialPlugins() error { func (gloom *GLoom) LoadInitialPlugins() error {
slog.Debug("Loading initial plugins") slog.Info("Loading initial plugins")
for _, plugin := range gloom.preloadPlugins { for _, plugin := range gloom.preloadPlugins {
if err := gloom.RegisterPlugin(filepath.Join(gloom.pluginDir, plugin.File), plugin.File, plugin.Domains); err != nil { 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) panic(fmt.Errorf("failed to load preload plugin %s: %w (make sure its in %s)", plugin.File, err, gloom.pluginDir))
} }
} }
@@ -164,6 +162,8 @@ func (gloom *GLoom) LoadInitialPlugins() error {
} }
} }
slog.Info("Loaded initial plugins")
return nil return nil
} }
@@ -233,7 +233,15 @@ func (gloom *GLoom) RegisterPlugin(pluginPath string, name string, domains []str
} }
process := cmd.Process process := cmd.Process
timeout := time.After(5 * time.Second)
for { for {
select {
case <-timeout:
_ = process.Signal(os.Interrupt)
return fmt.Errorf("timed out waiting for pluginHost to start (this is likely a GLoom bug)")
default:
}
_, err := os.Stat(controlPath) _, err := os.Stat(controlPath)
if err == nil { if err == nil {
break break
@@ -276,16 +284,22 @@ func (gloom *GLoom) RegisterPlugin(pluginPath string, name string, domains []str
} }
} }
proxy, err := NewDeploymentProxy(socketPath) proxy, err := sentinel.NewDeploymentProxy(socketPath, NewUnixSocketTransport)
if err != nil { if err != nil {
return err return err
} }
var oldProxy *Proxy var oldProxy *sentinel.Proxy
for _, domain := range domains { for _, domain := range domains {
var ok bool var ok bool
oldProxy, ok = gloom.ProxyManager.Load(domain) if value, exists := gloom.ProxyManager.Load(domain); exists {
// there can only be one in a set of domains. If a is the domains already attached to the proxy, and b is oldProxy = value.(*sentinel.Proxy)
ok = true
} else {
ok = false
}
// there can only be one proxy in a set of domains. If a is the domains already attached to the proxy, and b is
// a superset of a, but the new members of b are not in any other set, then we can be sure there is just one // a superset of a, but the new members of b are not in any other set, then we can be sure there is just one
if ok { if ok {
break break
@@ -307,7 +321,11 @@ func (gloom *GLoom) RegisterPlugin(pluginPath string, name string, domains []str
if oldProxy != nil { if oldProxy != nil {
go func() { go func() {
oldProxy.GracefulShutdown(nil) slog.Debug("Gracefully shutting down old proxy")
err := oldProxy.GracefulShutdown(nil)
if err != nil {
slog.Warn("Failed to gracefully shutdown old proxy", "error", err)
}
}() }()
} }
@@ -352,7 +370,7 @@ func (gloom *GLoom) StartRPCServer() error {
return err return err
} }
fmt.Printf("RPC server running on port 7143\n") slog.Info("RPC server running on port 7143\n")
go func() { go func() {
for { for {
conn, err := listener.Accept() conn, err := listener.Accept()
@@ -439,7 +457,6 @@ func (rpc *GloomRPC) UploadPlugin(plugin PluginUpload, reply *string) error {
} }
var plugExists bool var plugExists bool
// TODO: make name a consistent identifier
slog.Debug("Checking if plugin exists", "pluginPath", pluginPath, "pluginName", plugin.Name) slog.Debug("Checking if plugin exists", "pluginPath", pluginPath, "pluginName", plugin.Name)
rpc.gloom.DB.QueryRow("SELECT 1 FROM plugins WHERE name = ?", plugin.Name).Scan(&plugExists) rpc.gloom.DB.QueryRow("SELECT 1 FROM plugins WHERE name = ?", plugin.Name).Scan(&plugExists)
slog.Debug("Plugin exists", "pluginExists", plugExists) slog.Debug("Plugin exists", "pluginExists", plugExists)
@@ -515,7 +532,7 @@ func (rpc *GloomRPC) UploadPlugin(plugin PluginUpload, reply *string) error {
return err return err
} }
fmt.Println("Plugin uploaded successfully") slog.Debug("Plugin uploaded successfully")
if err := rpc.gloom.RegisterPlugin(pluginPath, plugin.Name, domains); err != nil { if err := rpc.gloom.RegisterPlugin(pluginPath, plugin.Name, domains); err != nil {
os.Remove(pluginPath) os.Remove(pluginPath)
@@ -524,26 +541,23 @@ func (rpc *GloomRPC) UploadPlugin(plugin PluginUpload, reply *string) error {
return err return err
} }
if !plugExists { if plugExists {
_, err = rpc.gloom.DB.Exec("INSERT INTO plugins (path, name, domains) VALUES (?, ?, ?)", pluginPath, plugin.Name, strings.Join(plugin.Domains, ","))
if err != nil {
*reply = fmt.Sprintf("Plugin upload failed: %v", err)
return err
}
} else {
_, err = rpc.gloom.DB.Exec("UPDATE plugins SET domains = ?, path = ? WHERE name = ?", strings.Join(plugin.Domains, ","), pluginPath, plugin.Name) _, err = rpc.gloom.DB.Exec("UPDATE plugins SET domains = ?, path = ? WHERE name = ?", strings.Join(plugin.Domains, ","), pluginPath, plugin.Name)
if err != nil { if err != nil {
*reply = fmt.Sprintf("Plugin upload failed: %v", err) *reply = fmt.Sprintf("Plugin upload failed: %v", err)
return err return err
} }
}
if plugExists {
// exit out early otherwise we risk creating multiple of the same plugin and causing undefined behavior
*reply = "Plugin updated successfully" *reply = "Plugin updated successfully"
return nil return nil
} }
_, err = rpc.gloom.DB.Exec("INSERT INTO plugins (path, name, domains) VALUES (?, ?, ?)", pluginPath, plugin.Name, strings.Join(plugin.Domains, ","))
if err != nil {
*reply = fmt.Sprintf("Plugin upload failed: %v", err)
return err
}
*reply = "Plugin uploaded successfully" *reply = "Plugin uploaded successfully"
return nil return nil
} }
@@ -594,7 +608,7 @@ func main() {
logger := slog.New(slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{Level: level})) logger := slog.New(slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{Level: level}))
slog.SetDefault(logger) slog.SetDefault(logger)
proxyManager := NewProxyManager() proxyManager := sentinel.NewProxyManager(RequestLogger{})
gloom, err := NewGloom(proxyManager) gloom, err := NewGloom(proxyManager)
if err != nil { if err != nil {
@@ -607,89 +621,15 @@ func main() {
gloom.LoadInitialPlugins() gloom.LoadInitialPlugins()
fmt.Println("Server running at http://localhost:3000") slog.Info("Server running at http://localhost:3000")
if err := gloom.ProxyManager.ListenAndServe("127.0.0.1:3000"); err != nil { if err := gloom.ProxyManager.ListenAndServe("127.0.0.1:3000"); err != nil {
panic(err) panic(err)
} }
} }
// this is the object that oversees the proxying of requests to the correct deployment type RequestLogger struct{}
type ProxyManager struct {
libs.SyncMap[string, *Proxy]
}
func NewProxyManager() *ProxyManager { func (RequestLogger) LogRequest(app string, status int, latency time.Duration, ip, method, path string) {
return &ProxyManager{}
}
func (proxyManager *ProxyManager) ListenAndServe(host string) error {
slog.Info("Proxy server starting", "url", host)
if err := http.ListenAndServe(host, proxyManager); err != nil && err != http.ErrServerClosed {
return fmt.Errorf("failed to start proxy server: %v", err)
}
return nil
}
// Stops forwarding traffic to a deployment
func (proxyManager *ProxyManager) RemoveDeployment(host string) {
slog.Info("Removing proxy", "host", host)
proxyManager.Delete(host)
}
// Starts forwarding traffic to a deployment. The deployment must be ready to recieve requests before this is called.
func (proxyManager *ProxyManager) AddProxy(host string, proxy *Proxy) {
slog.Debug("Adding proxy", "host", host)
proxyManager.Store(host, proxy)
}
// This function is responsible for taking an http request and forwarding it to the correct deployment
func (proxyManager *ProxyManager) ServeHTTP(w http.ResponseWriter, r *http.Request) {
start := time.Now()
host := r.Host
path := r.URL.Path
method := r.Method
ip := getClientIP(r)
slog.Debug("Proxying request", "host", host, "path", path, "method", method, "ip", ip)
proxy, ok := proxyManager.Load(host)
if !ok {
http.Error(w, "Not found", http.StatusNotFound)
logRequest(host, http.StatusNotFound, time.Since(start), ip, method, path)
return
}
// Create a custom ResponseWriter to capture the status code
rw := &ResponseWriterInterceptor{ResponseWriter: w, statusCode: http.StatusOK}
proxy.proxyFunc.ServeHTTP(rw, r)
latency := time.Since(start)
statusCode := rw.statusCode
logRequest(host, statusCode, latency, ip, method, path)
}
// getClientIP retrieves the client's IP address from the request.
// It handles cases where the IP might be forwarded by proxies.
func getClientIP(r *http.Request) string {
if forwarded := r.Header.Get("X-Forwarded-For"); forwarded != "" {
return forwarded
}
return r.RemoteAddr
}
// ResponseWriterInterceptor is a custom http.ResponseWriter that captures the status code.
type ResponseWriterInterceptor struct {
http.ResponseWriter
statusCode int
}
func (rw *ResponseWriterInterceptor) WriteHeader(code int) {
rw.statusCode = code
rw.ResponseWriter.WriteHeader(code)
}
func logRequest(app string, status int, latency time.Duration, ip, method, path string) {
slog.Info("Proxy Request", slog.Info("Proxy Request",
slog.String("time", time.Now().Format(time.RFC3339)), slog.String("time", time.Now().Format(time.RFC3339)),
slog.Int("status", status), slog.Int("status", status),
@@ -710,85 +650,12 @@ func (d *unixDialer) DialContext(ctx context.Context, network, address string) (
return net.Dial("unix", d.socketPath) return net.Dial("unix", d.socketPath)
} }
func NewUnixSocketTransport(socketPath string) *http.Transport { func NewUnixSocketTransport(socket string) *http.Transport {
return &http.Transport{ return &http.Transport{
DialContext: (&unixDialer{socketPath: socketPath}).DialContext,
}
}
type Proxy struct {
socket string
proxyFunc *httputil.ReverseProxy
shutdownTimeout time.Duration
activeRequests int64
}
const PROXY_SHUTDOWN_TIMEOUT = 30 * time.Second
// Creates a proxy for a given deployment
func NewDeploymentProxy(socket string) (*Proxy, error) {
proxy := &Proxy{
socket: socket,
shutdownTimeout: PROXY_SHUTDOWN_TIMEOUT,
activeRequests: 0,
}
transport := &http.Transport{
DialContext: (&unixDialer{socketPath: socket}).DialContext, DialContext: (&unixDialer{socketPath: socket}).DialContext,
MaxIdleConns: 100, MaxIdleConns: 100,
IdleConnTimeout: 90 * time.Second, IdleConnTimeout: 90 * time.Second,
MaxIdleConnsPerHost: 100, MaxIdleConnsPerHost: 100,
ForceAttemptHTTP2: false, ForceAttemptHTTP2: false,
} }
proxy.proxyFunc = &httputil.ReverseProxy{
Director: func(req *http.Request) {
req.URL = &url.URL{
Scheme: "http",
Host: req.Host,
Path: req.URL.Path,
}
atomic.AddInt64(&proxy.activeRequests, 1)
},
Transport: transport,
ModifyResponse: func(resp *http.Response) error {
atomic.AddInt64(&proxy.activeRequests, -1)
return nil
},
ErrorHandler: func(w http.ResponseWriter, r *http.Request, err error) {
slog.Error("Proxy error", "error", err)
atomic.AddInt64(&proxy.activeRequests, -1)
w.WriteHeader(http.StatusInternalServerError)
},
}
return proxy, nil
}
func (p *Proxy) GracefulShutdown(shutdownFunc func()) {
slog.Debug("Shutting down proxy", "socket", p.socket)
ctx, cancel := context.WithTimeout(context.Background(), p.shutdownTimeout)
defer cancel()
done := false
for !done {
select {
case <-ctx.Done():
slog.Debug("Proxy shutdown timed out", "socket", p.socket)
done = true
default:
if atomic.LoadInt64(&p.activeRequests) == 0 {
slog.Debug("Proxy shutdown completed successfully", "socket", p.socket)
done = true
}
time.Sleep(time.Second)
}
}
if shutdownFunc != nil {
shutdownFunc()
}
} }

View File

@@ -33,7 +33,6 @@ func init() {
type Plugin interface { type Plugin interface {
Init() (*fiber.Config, error) Init() (*fiber.Config, error)
RegisterRoutes(app fiber.Router) RegisterRoutes(app fiber.Router)
// Name() string
} }
type PluginInstance struct { type PluginInstance struct {
@@ -43,12 +42,6 @@ type PluginInstance struct {
Router *fiber.App Router *fiber.App
} }
// Init is the entry point for a container process
func (p *PluginInstance) Run(pluginName string) {
log.Printf("Starting container with plugin %s", pluginName)
// Load and initialize the plugin here
}
func main() { func main() {
signalChan := make(chan os.Signal, 1) signalChan := make(chan os.Signal, 1)
signal.Notify(signalChan, os.Interrupt) signal.Notify(signalChan, os.Interrupt)

View File

@@ -2,5 +2,6 @@ CREATE TABLE IF NOT EXISTS plugins (
id INTEGER PRIMARY KEY AUTOINCREMENT, id INTEGER PRIMARY KEY AUTOINCREMENT,
path TEXT NOT NULL UNIQUE, path TEXT NOT NULL UNIQUE,
name TEXT NOT NULL UNIQUE, name TEXT NOT NULL UNIQUE,
/* domains is a comma-separated list of domains */
domains TEXT NOT NULL domains TEXT NOT NULL
); );

View File

@@ -5,10 +5,10 @@
"author": "juls0730", "author": "juls0730",
"license": "MIT", "license": "MIT",
"scripts": { "scripts": {
"build": "zqdgr build:gloomi && zqdgr build:pluginHost && go build", "build": "zqdgr build:gloomi && zqdgr build:gloom",
"build:pluginHost": "sh -c \"cd pluginHost; go build -o ../host main.go\"", "build:pluginHost": "sh -c \"cd pluginHost; go build -o ../host main.go\"",
"build:gloomi": "sh -c \"cd gloomi; zqdgr build\"", "build:gloomi": "sh -c \"cd gloomi; zqdgr build\"",
"build:no-gloomi": "go build", "build:gloom": "zqdgr build:pluginHost && go build",
"clean": "rm -rf plugs && rm -rf host && rm -rf gloom.db && rm -rf plugin/plugin.so && rm -rf gloom", "clean": "rm -rf plugs && rm -rf host && rm -rf gloom.db && rm -rf plugin/plugin.so && rm -rf gloom",
"dev": "zqdgr build && ./gloom" "dev": "zqdgr build && ./gloom"
}, },