168 lines
4.4 KiB
Go
168 lines
4.4 KiB
Go
// server.go - Simplified HTTP server
|
|
package http
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
"time"
|
|
|
|
"Moonshark/config"
|
|
"Moonshark/metadata"
|
|
"Moonshark/runner"
|
|
"Moonshark/utils"
|
|
|
|
"github.com/goccy/go-json"
|
|
"github.com/valyala/bytebufferpool"
|
|
"github.com/valyala/fasthttp"
|
|
)
|
|
|
|
func NewHttpServer(cfg *config.Config, handler fasthttp.RequestHandler, dbg bool) *fasthttp.Server {
|
|
return &fasthttp.Server{
|
|
Handler: handler,
|
|
Name: "Moonshark/" + metadata.Version,
|
|
ReadTimeout: 30 * time.Second,
|
|
WriteTimeout: 30 * time.Second,
|
|
IdleTimeout: 120 * time.Second,
|
|
MaxRequestBodySize: 16 << 20,
|
|
TCPKeepalive: true,
|
|
ReduceMemoryUsage: true,
|
|
StreamRequestBody: true,
|
|
NoDefaultServerHeader: true,
|
|
}
|
|
}
|
|
|
|
func NewPublicHandler(pubDir, prefix string) fasthttp.RequestHandler {
|
|
if !strings.HasPrefix(prefix, "/") {
|
|
prefix = "/" + prefix
|
|
}
|
|
if !strings.HasSuffix(prefix, "/") {
|
|
prefix += "/"
|
|
}
|
|
|
|
fs := &fasthttp.FS{
|
|
Root: pubDir,
|
|
IndexNames: []string{"index.html"},
|
|
AcceptByteRange: true,
|
|
Compress: true,
|
|
CompressedFileSuffix: ".gz",
|
|
CompressBrotli: true,
|
|
PathRewrite: fasthttp.NewPathPrefixStripper(len(prefix) - 1),
|
|
}
|
|
return fs.NewRequestHandler()
|
|
}
|
|
|
|
func Send404(ctx *fasthttp.RequestCtx) {
|
|
ctx.SetContentType("text/html; charset=utf-8")
|
|
ctx.SetStatusCode(fasthttp.StatusNotFound)
|
|
ctx.SetBody([]byte(utils.NotFoundPage(ctx.URI().String())))
|
|
}
|
|
|
|
func Send500(ctx *fasthttp.RequestCtx, err error) {
|
|
ctx.SetContentType("text/html; charset=utf-8")
|
|
ctx.SetStatusCode(fasthttp.StatusInternalServerError)
|
|
|
|
if err == nil {
|
|
ctx.SetBody([]byte(utils.InternalErrorPage(string(ctx.Path()), "")))
|
|
} else {
|
|
ctx.SetBody([]byte(utils.InternalErrorPage(string(ctx.Path()), err.Error())))
|
|
}
|
|
}
|
|
|
|
// ApplyResponse applies a Response to a fasthttp.RequestCtx
|
|
func ApplyResponse(resp *runner.Response, ctx *fasthttp.RequestCtx) {
|
|
// Set status code
|
|
ctx.SetStatusCode(resp.Status)
|
|
|
|
// Set headers
|
|
for name, value := range resp.Headers {
|
|
ctx.Response.Header.Set(name, value)
|
|
}
|
|
|
|
// Set cookies
|
|
for _, cookie := range resp.Cookies {
|
|
ctx.Response.Header.SetCookie(cookie)
|
|
}
|
|
|
|
// Process the body based on its type
|
|
if resp.Body == nil {
|
|
return
|
|
}
|
|
|
|
// Check if Content-Type was manually set
|
|
contentTypeSet := false
|
|
for name := range resp.Headers {
|
|
if strings.ToLower(name) == "content-type" {
|
|
contentTypeSet = true
|
|
break
|
|
}
|
|
}
|
|
|
|
// Get a buffer from the pool
|
|
buf := bytebufferpool.Get()
|
|
defer bytebufferpool.Put(buf)
|
|
|
|
// Set body based on type
|
|
switch body := resp.Body.(type) {
|
|
case string:
|
|
if !contentTypeSet {
|
|
ctx.Response.Header.SetContentType("text/plain; charset=utf-8")
|
|
}
|
|
ctx.SetBodyString(body)
|
|
case []byte:
|
|
if !contentTypeSet {
|
|
ctx.Response.Header.SetContentType("text/plain; charset=utf-8")
|
|
}
|
|
ctx.SetBody(body)
|
|
case map[string]any, map[any]any, []any, []float64, []string, []int, []map[string]any:
|
|
// Marshal JSON
|
|
if err := json.NewEncoder(buf).Encode(body); err == nil {
|
|
if !contentTypeSet {
|
|
ctx.Response.Header.SetContentType("application/json")
|
|
}
|
|
ctx.SetBody(buf.Bytes())
|
|
} else {
|
|
// Fallback to string representation
|
|
if !contentTypeSet {
|
|
ctx.Response.Header.SetContentType("text/plain; charset=utf-8")
|
|
}
|
|
ctx.SetBodyString(fmt.Sprintf("%v", body))
|
|
}
|
|
default:
|
|
// Check if it's any other map or slice type
|
|
typeStr := fmt.Sprintf("%T", body)
|
|
if typeStr[0] == '[' || (len(typeStr) > 3 && typeStr[:3] == "map") {
|
|
if err := json.NewEncoder(buf).Encode(body); err == nil {
|
|
if !contentTypeSet {
|
|
ctx.Response.Header.SetContentType("application/json")
|
|
}
|
|
ctx.SetBody(buf.Bytes())
|
|
} else {
|
|
if !contentTypeSet {
|
|
ctx.Response.Header.SetContentType("text/plain; charset=utf-8")
|
|
}
|
|
ctx.SetBodyString(fmt.Sprintf("%v", body))
|
|
}
|
|
} else {
|
|
// Default to string representation
|
|
if !contentTypeSet {
|
|
ctx.Response.Header.SetContentType("text/plain; charset=utf-8")
|
|
}
|
|
ctx.SetBodyString(fmt.Sprintf("%v", body))
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
func HandleDebugStats(ctx *fasthttp.RequestCtx) {
|
|
stats := utils.CollectSystemStats(s.cfg)
|
|
stats.Components = utils.ComponentStats{
|
|
RouteCount: 0, // TODO: Get from router
|
|
BytecodeBytes: 0, // TODO: Get from router
|
|
SessionStats: s.sessionManager.GetCacheStats(),
|
|
}
|
|
ctx.SetContentType("text/html; charset=utf-8")
|
|
ctx.SetStatusCode(fasthttp.StatusOK)
|
|
ctx.SetBody([]byte(utils.DebugStatsPage(stats)))
|
|
}
|
|
*/
|