add pocketbase
This commit is contained in:
121
backend/custom/proxy/proxy.go
Normal file
121
backend/custom/proxy/proxy.go
Normal file
@ -0,0 +1,121 @@
|
||||
package proxy
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/http/httputil"
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
"github.com/pocketbase/pocketbase"
|
||||
"github.com/pocketbase/pocketbase/core"
|
||||
"github.com/pocketbase/pocketbase/tools/router"
|
||||
)
|
||||
|
||||
var Logger *slog.Logger
|
||||
|
||||
func ServeProxyPassingToNuxt(app *pocketbase.PocketBase, se *core.ServeEvent) *router.Route[*core.RequestEvent] {
|
||||
Logger = app.Logger()
|
||||
|
||||
proxyUrl, _ := app.RootCmd.Flags().GetString("proxy")
|
||||
|
||||
if len(proxyUrl) > 0 {
|
||||
target, _ := url.Parse(proxyUrl) // Node.js app
|
||||
|
||||
proxy := httputil.NewSingleHostReverseProxy(target)
|
||||
|
||||
originalDirector := proxy.Director
|
||||
proxy.Director = func(req *http.Request) {
|
||||
originalDirector(req)
|
||||
req.Host = target.Host
|
||||
}
|
||||
proxy.Transport = &loggingTransport{http.DefaultTransport}
|
||||
|
||||
proxy.ErrorHandler = func(rw http.ResponseWriter, req *http.Request, err error) {
|
||||
if errors.Is(err, context.Canceled) {
|
||||
return
|
||||
}
|
||||
app.Logger().Error(fmt.Sprintf("Proxy error: %v for %s %s", err, req.Method, req.URL.Path), "type", "proxy")
|
||||
http.Error(rw, "Proxy error", http.StatusBadGateway)
|
||||
}
|
||||
|
||||
return se.Router.Any("/", func(e *core.RequestEvent) error {
|
||||
// Ping the backend with a HEAD request (or TCP dial)
|
||||
backendUp := isBackendAlive(target)
|
||||
if !backendUp {
|
||||
app.Logger().Error(fmt.Sprintf("Backend %s is unreachable, sending 502", target), "type", "proxy", "path", e.Request.URL.Path, "remoteIP", e.Request.RemoteAddr)
|
||||
e.Response.WriteHeader(http.StatusBadGateway)
|
||||
e.Response.Write([]byte("502 Backend is unavailable"))
|
||||
return nil
|
||||
}
|
||||
|
||||
// Forward to Node.js
|
||||
proxy.ServeHTTP(e.Response, e.Request)
|
||||
return nil
|
||||
})
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func isBackendAlive(target *url.URL) bool {
|
||||
conn, err := net.DialTimeout("tcp", target.Host, 500*time.Millisecond)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
conn.Close()
|
||||
return true
|
||||
}
|
||||
|
||||
type loggingTransport struct {
|
||||
rt http.RoundTripper
|
||||
}
|
||||
|
||||
func (t *loggingTransport) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
start := time.Now()
|
||||
|
||||
// Do the actual request
|
||||
resp, err := t.rt.RoundTrip(req)
|
||||
duration := time.Since(start)
|
||||
|
||||
// Prepare fields
|
||||
remoteAddr := req.RemoteAddr
|
||||
if ip := req.Header.Get("X-Real-IP"); len(ip) > 0 {
|
||||
remoteAddr = ip
|
||||
}
|
||||
method := req.Method
|
||||
uri := req.URL.RequestURI()
|
||||
// proto := req.Proto
|
||||
status := 0
|
||||
size := 0
|
||||
|
||||
if resp != nil {
|
||||
status = resp.StatusCode
|
||||
if resp.ContentLength > 0 {
|
||||
size = int(resp.ContentLength)
|
||||
}
|
||||
}
|
||||
|
||||
referer := req.Referer()
|
||||
ua := req.UserAgent()
|
||||
// timestamp := time.Now().Format("02/Jan/2006:15:04:05 -0700")
|
||||
|
||||
Logger.Info(
|
||||
fmt.Sprintf("%s %s", method, uri),
|
||||
"type", "proxy",
|
||||
// "method", method,
|
||||
// "url", uri,
|
||||
"referer", referer,
|
||||
"remoteIP", remoteAddr,
|
||||
"userAgent", ua,
|
||||
"execTime", fmt.Sprintf("%.4fms", float64(duration.Milliseconds())),
|
||||
"status", status,
|
||||
"size", size,
|
||||
)
|
||||
|
||||
return resp, err
|
||||
}
|
Reference in New Issue
Block a user