mirror of
https://github.com/GlueOps/autoglue.git
synced 2026-02-13 12:50:05 +01:00
feat: adding embedded db-studio
Signed-off-by: allanice001 <allanice001@gmail.com>
This commit is contained in:
106
internal/web/pgweb_proxy.go
Normal file
106
internal/web/pgweb_proxy.go
Normal file
@@ -0,0 +1,106 @@
|
||||
package web
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/http/httputil"
|
||||
"net/url"
|
||||
"os"
|
||||
"os/exec"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Pgweb struct {
|
||||
cmd *exec.Cmd
|
||||
host string
|
||||
port string
|
||||
bin string
|
||||
}
|
||||
|
||||
func StartPgweb(dbURL, host, port string, readonly bool, user, pass string) (*Pgweb, error) {
|
||||
// pick random port if 0/empty
|
||||
if port == "" || port == "0" {
|
||||
l, err := net.Listen("tcp", net.JoinHostPort(host, "0"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer l.Close()
|
||||
_, p, _ := net.SplitHostPort(l.Addr().String())
|
||||
port = p
|
||||
}
|
||||
|
||||
args := []string{
|
||||
"--url", dbURL,
|
||||
"--bind", host,
|
||||
"--listen", port,
|
||||
"--skip-open",
|
||||
}
|
||||
if readonly {
|
||||
args = append(args, "--readonly")
|
||||
}
|
||||
if user != "" && pass != "" {
|
||||
args = append(args, "--auth-user", user, "--auth-pass", pass)
|
||||
}
|
||||
|
||||
pgwebBinary, err := ExtractPgweb()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("pgweb extract: %w", err)
|
||||
}
|
||||
|
||||
cmd := exec.Command(pgwebBinary, args...)
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
|
||||
if err := cmd.Start(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// wait for port to be ready
|
||||
deadline := time.Now().Add(4 * time.Second)
|
||||
for time.Now().Before(deadline) {
|
||||
c, err := net.DialTimeout("tcp", net.JoinHostPort(host, port), 200*time.Millisecond)
|
||||
if err == nil {
|
||||
_ = c.Close()
|
||||
return &Pgweb{cmd: cmd, host: host, port: port}, nil
|
||||
}
|
||||
time.Sleep(120 * time.Millisecond)
|
||||
}
|
||||
// still return object so caller can Stop()
|
||||
//return &Pgweb{cmd: cmd, host: host, port: port, bin: pgwebBinary}, nil
|
||||
return nil, fmt.Errorf("pgweb did not become ready on %s:%s", host, port)
|
||||
}
|
||||
|
||||
func (p *Pgweb) Proxy() http.HandlerFunc {
|
||||
target, _ := url.Parse("http://" + net.JoinHostPort(p.host, p.port))
|
||||
proxy := httputil.NewSingleHostReverseProxy(target)
|
||||
proxy.FlushInterval = 100 * time.Millisecond
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
r.Host = target.Host
|
||||
// Let pgweb handle its paths; we mount it at a prefix.
|
||||
proxy.ServeHTTP(w, r)
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Pgweb) Stop(ctx context.Context) error {
|
||||
if p == nil || p.cmd == nil || p.cmd.Process == nil {
|
||||
return nil
|
||||
}
|
||||
_ = p.cmd.Process.Kill()
|
||||
done := make(chan struct{})
|
||||
go func() { _, _ = p.cmd.Process.Wait(); close(done) }()
|
||||
select {
|
||||
case <-done:
|
||||
if p.bin != "" {
|
||||
_ = CleanupPgweb(p.bin)
|
||||
}
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Pgweb) Port() string {
|
||||
return p.port
|
||||
}
|
||||
Reference in New Issue
Block a user