95 lines
2.1 KiB
Go
95 lines
2.1 KiB
Go
package service
|
||
|
||
import (
|
||
"context"
|
||
"errors"
|
||
"fmt"
|
||
"log"
|
||
"net/http"
|
||
"sync"
|
||
"time"
|
||
)
|
||
|
||
// HTTPServer 封装HTTP服务器功能
|
||
type HTTPServer struct {
|
||
server *http.Server
|
||
wg sync.WaitGroup
|
||
}
|
||
|
||
// NewServer 创建一个新的HTTP服务器实例
|
||
func NewServer(addr string, handler http.Handler) *HTTPServer {
|
||
return &HTTPServer{
|
||
server: &http.Server{
|
||
Addr: addr,
|
||
Handler: handler,
|
||
},
|
||
}
|
||
}
|
||
|
||
// Start 启动HTTP服务器(在协程中),支持context
|
||
func (s *HTTPServer) Start(ctx context.Context) error {
|
||
log.Printf("HTTP服务器正在启动,监听地址: %s", s.server.Addr)
|
||
|
||
// 监听context取消信号
|
||
shutdownChan := make(chan struct{})
|
||
go func() {
|
||
<-ctx.Done()
|
||
log.Println("接收到context取消信号,开始关闭服务器...")
|
||
close(shutdownChan)
|
||
}()
|
||
|
||
s.wg.Add(1)
|
||
go func() {
|
||
defer s.wg.Done()
|
||
|
||
if err := s.server.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) {
|
||
log.Printf("服务器启动失败: %v", err)
|
||
return
|
||
}
|
||
}()
|
||
|
||
// 给服务器一点启动时间
|
||
time.Sleep(100 * time.Millisecond)
|
||
|
||
// 等待服务器启动完成或context取消
|
||
select {
|
||
case <-shutdownChan:
|
||
// 如果context在启动过程中被取消,立即关闭服务器
|
||
if err := s.Stop(); err != nil {
|
||
log.Printf("启动过程中关闭服务器失败: %v", err)
|
||
}
|
||
return ctx.Err()
|
||
default:
|
||
log.Println("HTTP服务器启动成功")
|
||
return nil
|
||
}
|
||
}
|
||
|
||
// Stop 优雅关闭HTTP服务器
|
||
func (s *HTTPServer) Stop() error {
|
||
log.Println("正在关闭HTTP服务器...")
|
||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||
defer cancel()
|
||
|
||
if err := s.server.Shutdown(ctx); err != nil {
|
||
return fmt.Errorf("服务器关闭失败: %v", err)
|
||
}
|
||
|
||
// 等待服务器协程结束
|
||
s.wg.Wait()
|
||
log.Println("HTTP服务器已成功关闭")
|
||
return nil
|
||
}
|
||
|
||
// StartWithContext 可选:提供一个更简洁的启动方法(如果你需要)
|
||
func (s *HTTPServer) StartWithContext(ctx context.Context) <-chan error {
|
||
errChan := make(chan error, 1)
|
||
|
||
go func() {
|
||
errChan <- s.Start(ctx)
|
||
close(errChan)
|
||
}()
|
||
|
||
return errChan
|
||
}
|