gohttp/server/manager.go

209 lines
4.1 KiB
Go

package server
import (
"context"
"errors"
"fmt"
"net"
"net/http"
"strings"
"time"
"bufio"
"io"
"git.pyer.club/kingecg/gohttpd/model"
logger "git.pyer.club/kingecg/gologger"
"git.pyer.club/kingecg/cmux"
)
var ServerManager map[string]*ServerListener = make(map[string]*ServerListener)
func makeMatcher(name string, s *ServerListener) cmux.Matcher {
return func(r io.Reader) bool {
if s.ServerCount() == 1 {
return true
}
req, err := http.ReadRequest(bufio.NewReader(r))
if err != nil {
return false
}
return strings.HasPrefix(req.Host, name)
}
}
type sl struct {
net.Listener
closed bool
}
func (sl *sl) Accept() (net.Conn, error) {
if sl.closed {
return nil, errors.New("closed")
}
return sl.Listener.Accept()
}
func (sl *sl) Close() error {
sl.closed = true
return nil
}
type Server struct {
Conf *model.HttpServerConfig
Closed bool
*http.Server
l *sl
}
func (s *Server) Renew() {
s.Server = &http.Server{
Handler: s.Handler,
}
}
type ServerListener struct {
port int
listener cmux.CMux
servers map[string]*Server
}
func (s *ServerListener) AddServer(name string, server *Server) {
s.servers[name] = server
}
func (s *ServerListener) ServerCount() int {
return len(s.servers)
}
func (s *ServerListener) StartServer(name string) {
server, ok := s.servers[name]
serverName := server.Conf.ServerName
if !ok {
panic("No named server")
}
go func() {
var err error
defer func() {
l := logger.GetLogger("ServerListener")
if err != nil {
if err == http.ErrServerClosed {
server.Closed = true
} else {
l.Error("Server error:", err)
}
}
l.Info("Server stopped:", name)
}()
if server.Closed {
server.Renew()
}
if server.l == nil {
server.l = &sl{
Listener: s.listener.Match(makeMatcher(serverName, s)),
}
}
if server.Conf.CertFile != "" && server.Conf.KeyFile != "" {
err = server.ServeTLS(server.l, server.Conf.CertFile, server.Conf.KeyFile)
} else {
err = server.Serve(server.l)
}
}()
// return server.Serve(l)
}
func (s *ServerListener) StopServer(name string) error {
server, ok := s.servers[name]
if !ok {
return nil
}
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
return server.Shutdown(ctx)
}
// Start 方法用于并发启动 ServerListener 中所有注册的服务器。
// 它会为每个服务器创建一个新的 goroutine 来启动,以确保各个服务器可以独立运行。
func (s *ServerListener) Start() {
// 遍历 ServerListener 中所有注册的服务器
for name, _ := range s.servers {
// 为每个服务器启动一个新的 goroutine 来执行启动操作
s.StartServer(name)
}
}
func (s *ServerListener) ShutDown() {
// may need add wait group
for _, server := range s.servers {
server.Shutdown(context.Background())
}
s.listener.Close()
}
func (s *ServerListener) Serve() {
l := logger.GetLogger("Listener")
l.Debug("listen on :", s.port)
go s.listener.Serve()
}
func NewServerListener(port int) *ServerListener {
listenStr := fmt.Sprintf(":%d", port)
l, err := net.Listen("tcp", listenStr)
if err != nil {
l := logger.GetLogger("ServerListener")
l.Error("Listen error:", err)
}
muxer := cmux.New(l)
s := &ServerListener{port: port, listener: muxer, servers: make(map[string]*Server)}
return s
}
func AddServer(name string, server *Server, port int) {
listenStr := fmt.Sprintf(":%d", port)
listener, ok := ServerManager[listenStr]
if !ok {
listener = NewServerListener(port)
ServerManager[listenStr] = listener
}
listener.AddServer(name, server)
}
func AddServerWithConfig(conf *model.HttpServerConfig) {
mux := NewServeMux(conf)
s := &http.Server{
Handler: mux,
}
name := conf.Name
port := conf.Port
ss := &Server{
Server: s,
Conf: conf,
}
AddServer(name, ss, port)
}
func StopServer(name string, port int) {
listenStr := fmt.Sprintf(":%d", port)
listener, ok := ServerManager[listenStr]
if !ok {
return
}
listener.StopServer(name)
}
func StartServer(name string, port int) {
listenStr := fmt.Sprintf(":%d", port)
listener, ok := ServerManager[listenStr]
if !ok {
return
}
listener.StartServer(name)
}