167 lines
4.3 KiB
Go
167 lines
4.3 KiB
Go
package http
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"mime"
|
|
"net/http"
|
|
"strings"
|
|
"time"
|
|
|
|
"wpw-common/internal"
|
|
"wpw-common/public"
|
|
|
|
"github.com/apache/thrift/lib/go/thrift"
|
|
"github.com/gofiber/fiber/v2"
|
|
"github.com/gofiber/fiber/v2/middleware/cors"
|
|
"github.com/gofiber/fiber/v2/middleware/filesystem"
|
|
"github.com/gofiber/fiber/v2/middleware/recover"
|
|
"github.com/gofiber/fiber/v2/middleware/session"
|
|
"go.uber.org/zap"
|
|
)
|
|
|
|
var (
|
|
defaultServer = newServer()
|
|
Session = session.New(session.Config{
|
|
KeyLookup: "header:X-Hub-Track-Token",
|
|
})
|
|
|
|
thriftContentType = []byte("application/x-thrift")
|
|
|
|
contextKeyFiber contextKey = "fiber-app"
|
|
|
|
hubHeader = []string{
|
|
"X-Hub-Env",
|
|
"X-Hub-App",
|
|
"X-Hub-Version",
|
|
"X-Hub-App",
|
|
"X-Hub-Track-Token",
|
|
"X-Hub-Auth-Token",
|
|
}
|
|
)
|
|
|
|
type contextKey string
|
|
|
|
type server struct {
|
|
pCtx context.Context
|
|
app *fiber.App
|
|
logger *zap.SugaredLogger
|
|
}
|
|
|
|
func newServer() *server {
|
|
app := fiber.New()
|
|
|
|
app.Use(recover.New())
|
|
|
|
app.Use(cors.New(cors.Config{
|
|
// AllowOrigins: "https://gofiber.io, https://gofiber.net",
|
|
AllowOrigins: "*",
|
|
AllowHeaders: strings.Join(append([]string{
|
|
"Origin",
|
|
"Content-Type",
|
|
"Accept",
|
|
}, hubHeader...), ", "),
|
|
ExposeHeaders: strings.Join(hubHeader, ", "),
|
|
}))
|
|
|
|
app.Use(filesystem.New(filesystem.Config{
|
|
Root: http.FS(public.FS),
|
|
Browse: false,
|
|
Index: "index.html",
|
|
MaxAge: 3000,
|
|
NotFoundFile: "index.html",
|
|
}))
|
|
|
|
srv := &server{app: app}
|
|
return srv
|
|
}
|
|
|
|
func (s *server) registerService(path string, p thrift.TProcessor) {
|
|
processorFactory := thrift.NewTProcessorFactory(p)
|
|
protocolFactory := thrift.NewTCompactProtocolFactoryConf(&thrift.TConfiguration{})
|
|
contentTypeResp := mime.FormatMediaType(string(thriftContentType), map[string]string{
|
|
"charset": "utf-8",
|
|
"protocol": "TCOMPACT",
|
|
})
|
|
|
|
s.app.Post(path, func(c *fiber.Ctx) error {
|
|
mBegin := time.Now()
|
|
var mDur time.Duration
|
|
|
|
c.Response().Header.Set("Content-Type", contentTypeResp)
|
|
if !bytes.HasPrefix(c.Request().Header.ContentType(), thriftContentType) {
|
|
c.Response().Header.Set("x-error-type", "bad-request")
|
|
c.Response().Header.Set("x-error-message", "bad request")
|
|
return c.SendStatus(400)
|
|
}
|
|
|
|
body := c.Context().Request.Body()
|
|
transport := thrift.NewStreamTransport(bytes.NewReader(body), c)
|
|
protocol := protocolFactory.GetProtocol(transport)
|
|
|
|
// put fiber ctx to the context
|
|
ctx := WithFiberContext(s.pCtx, c)
|
|
|
|
// process method
|
|
handled, err := processorFactory.GetProcessor(transport).Process(ctx, protocol, protocol)
|
|
if err != nil {
|
|
s.logger.Errorw("process method", "err", err)
|
|
switch err.(type) {
|
|
case thrift.TTransportException:
|
|
c.Response().Header.Set("x-error-type", "transport-exception")
|
|
c.Response().Header.Set("x-error-message", err.Error())
|
|
goto internal_error
|
|
case thrift.TProtocolException:
|
|
c.Response().Header.Set("x-error-type", "protocol-exception")
|
|
c.Response().Header.Set("x-error-message", err.Error())
|
|
goto internal_error
|
|
case thrift.TApplicationException:
|
|
c.Response().Header.Set("x-error-type", "application-exception")
|
|
c.Response().Header.Set("x-error-message", err.Error())
|
|
default:
|
|
c.Response().Header.Set("x-error-type", "exception")
|
|
c.Response().Header.Set("x-error-message", err.Error())
|
|
}
|
|
}
|
|
|
|
mDur = time.Since(mBegin)
|
|
c.Response().Header.Set("x-trace-duration", mDur.String())
|
|
|
|
_ = handled
|
|
if err := protocol.Flush(c.Context()); err != nil {
|
|
return err
|
|
}
|
|
return c.SendStatus(200)
|
|
internal_error:
|
|
// do something!
|
|
return c.SendStatus(200)
|
|
})
|
|
}
|
|
|
|
func (s *server) run(appCtx *internal.AppContext, addr string) error {
|
|
s.pCtx = internal.WithAppContext(context.Background(), appCtx)
|
|
s.logger = appCtx.Logger.Sugar().Named("httpsrv")
|
|
s.logger.Infow("starting server",
|
|
"addr", addr)
|
|
return s.app.Listen(addr)
|
|
}
|
|
|
|
func Router() *fiber.App {
|
|
return defaultServer.app
|
|
}
|
|
|
|
func GetFiberFromContext(ctx context.Context) *fiber.Ctx {
|
|
return ctx.Value(contextKeyFiber).(*fiber.Ctx)
|
|
}
|
|
|
|
func WithFiberContext(ctx context.Context, c *fiber.Ctx) context.Context {
|
|
return context.WithValue(ctx, contextKeyFiber, c)
|
|
}
|
|
|
|
func RegisterService(path string, p thrift.TProcessor) {
|
|
defaultServer.registerService(path, p)
|
|
}
|
|
|
|
func Run(appCtx *internal.AppContext, addr string) error {
|
|
return defaultServer.run(appCtx, addr)
|
|
}
|