|
- package http
-
- import (
- "bytes"
- "context"
- "crypto/tls"
- "net/http"
-
- "github.com/gin-gonic/gin"
- "gitlink.org.cn/cloudream/common/pkgs/async"
- "gitlink.org.cn/cloudream/common/pkgs/logger"
- "gitlink.org.cn/cloudream/jcs-pub/client/internal/cluster"
- "gitlink.org.cn/cloudream/jcs-pub/client/internal/http/auth"
- "gitlink.org.cn/cloudream/jcs-pub/client/internal/http/proxy"
- "gitlink.org.cn/cloudream/jcs-pub/client/internal/http/types"
- v1 "gitlink.org.cn/cloudream/jcs-pub/client/internal/http/v1"
- "gitlink.org.cn/cloudream/jcs-pub/client/internal/services"
- clirpc "gitlink.org.cn/cloudream/jcs-pub/common/pkgs/rpc/client"
- "golang.org/x/net/http2"
- )
-
- type ServerEventChan = async.UnboundChannel[ServerEvent]
-
- type ServerEvent interface {
- IsServerEvent() bool
- }
-
- type ExitEvent struct {
- ServerEvent
- Err error
- }
-
- type Server struct {
- cfg types.Config
- httpSrv *http.Server
- svc *services.Service
- clster *cluster.Cluster
- eventChan *ServerEventChan
- auth *auth.Auth
- proxy *proxy.ClusterProxy
- v1Svr *v1.Server
- }
-
- func NewServer(cfg types.Config, svc *services.Service, clster *cluster.Cluster) *Server {
- return &Server{
- cfg: cfg,
- svc: svc,
- clster: clster,
- eventChan: async.NewUnboundChannel[ServerEvent](),
- v1Svr: v1.NewServer(&cfg, svc),
- }
- }
-
- func (s *Server) Start() *ServerEventChan {
- go func() {
- if !s.cfg.Enabled {
- return
- }
-
- engine := gin.New()
- s.httpSrv = &http.Server{
- Addr: s.cfg.Listen,
- Handler: engine,
- }
- s.auth = auth.New(&s.cfg)
- s.proxy = proxy.NewClusterProxy(s.clster)
- s.httpSrv.TLSConfig = &tls.Config{
- GetConfigForClient: s.auth.TLSConfigSelector,
- }
- http2.ConfigureServer(s.httpSrv, &http2.Server{})
-
- s.v1Svr.InitRouters(engine.Group("/v1"), s.auth, s.proxy)
-
- logger.Infof("start serving http at: %s", s.cfg.Listen)
-
- err := s.httpSrv.ListenAndServeTLS("", "")
- s.eventChan.Send(ExitEvent{Err: err})
- }()
- return s.eventChan
- }
-
- func (s *Server) Stop() {
- if s.httpSrv == nil {
- s.eventChan.Send(ExitEvent{})
- return
- }
-
- s.httpSrv.Shutdown(context.Background())
- }
-
- func (s *Server) ServeHTTP(ctx context.Context, req *clirpc.HTTPProxyRequest) (*clirpc.HTTPProxyResponse, error) {
- ctx2 := context.WithValue(ctx, auth.ClusterProxyRequest, true)
-
- r, err := http.NewRequestWithContext(ctx2, req.Method, req.URI, bytes.NewReader(req.Body))
- if err != nil {
- return nil, err
- }
-
- for _, v := range req.Header {
- r.Header.Add(v.Key, v.Value)
- }
-
- resp := proxyRespWriter{
- header: make(http.Header),
- }
- s.httpSrv.Handler.ServeHTTP(&resp, r)
-
- var header []*clirpc.HeaderKV
- for k, v := range resp.header {
- for _, vv := range v {
- header = append(header, &clirpc.HeaderKV{
- Key: k,
- Value: vv,
- })
- }
- }
-
- return &clirpc.HTTPProxyResponse{
- StatusCode: int32(resp.statusCode),
- Header: header,
- Body: resp.body.Bytes(),
- }, nil
- }
-
- type proxyRespWriter struct {
- statusCode int
- header http.Header
- body bytes.Buffer
- }
-
- func (w *proxyRespWriter) Header() http.Header {
- return w.header
- }
-
- func (w *proxyRespWriter) Write(b []byte) (int, error) {
- return w.body.Write(b)
- }
-
- func (w *proxyRespWriter) WriteHeader(statusCode int) {
- w.statusCode = statusCode
- }
|