209 lines
4.1 KiB
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)
|
|
}
|