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) }