Files
hanfuit 645b64fe21 DNF90 服务端与启动器完整源码(含 GM 工具功能增强)
服务端(Go):
- GM 塞背包/带属性装备发放:在线角色推送 op14 增量物品行,背包实时刷新,无需回角色选择界面
- GM 改金币/改等级:去掉在线拒绝,落库后推送 op14 钱包/op37 等级状态,在线实时刷新
- 等级端点统一切换到新版 GMSetCharacterLevel(自带在线刷新)
- 无限/锁死疲劳模式 + 燃烧疲劳:每房间消耗 2 点、打怪与通关经验双倍
- 燃烧疲劳开关时给所有在线角色推送系统提示(op12 mode 0)
- 深渊史诗掉率:GM 全局倍率 + 城镇增益药剂窗口倍率,真实接入掉落结算

启动器(Python/JS):
- 标题栏自绘、窗口 1204x717、禁止拖拽改大小、仅最小化/关闭
- GM 工具:疲劳与燃烧、深渊史诗掉率、拍卖行上架(单一定价对齐)
- 拍卖行上架前端对齐服务端单一价格语义,修复 400 报错
2026-11-04 14:31:55 +08:00

129 lines
2.4 KiB
Go

package httpx
import (
"context"
"errors"
"log/slog"
"net"
"net/http"
"sync"
"time"
)
type Server struct {
name string
addr string
logger *slog.Logger
mux *http.ServeMux
opts Timeouts
mu sync.Mutex
listener net.Listener
server *http.Server
}
type Timeouts struct {
ReadTimeout time.Duration
ReadHeaderTimeout time.Duration
WriteTimeout time.Duration
IdleTimeout time.Duration
}
func New(name, addr string, logger *slog.Logger, opts Timeouts) *Server {
if addr == "" {
addr = ":18080"
}
return &Server{
name: name,
addr: addr,
logger: logger,
mux: http.NewServeMux(),
opts: normalizeTimeouts(opts),
}
}
func (s *Server) Name() string {
return s.name
}
func (s *Server) Mux() *http.ServeMux {
return s.mux
}
func (s *Server) Start(_ context.Context) error {
s.mu.Lock()
if s.listener != nil {
s.mu.Unlock()
return nil
}
s.mu.Unlock()
ln, err := net.Listen("tcp", s.addr)
if err != nil {
return err
}
s.mu.Lock()
s.listener = ln
s.server = NewHTTPServer(s.mux, s.opts)
server := s.server
s.mu.Unlock()
go func() {
err := server.Serve(ln)
if err != nil && !errors.Is(err, http.ErrServerClosed) && s.logger != nil {
s.logger.Error("admin http serve failed", "error", err)
}
}()
if s.logger != nil {
s.logger.Info("admin http listening", "addr", ln.Addr().String())
}
return nil
}
func NewHTTPServer(handler http.Handler, opts Timeouts) *http.Server {
opts = normalizeTimeouts(opts)
return &http.Server{
Handler: handler,
ReadTimeout: opts.ReadTimeout,
ReadHeaderTimeout: opts.ReadHeaderTimeout,
WriteTimeout: opts.WriteTimeout,
IdleTimeout: opts.IdleTimeout,
}
}
func normalizeTimeouts(opts Timeouts) Timeouts {
if opts.ReadTimeout <= 0 {
opts.ReadTimeout = 10 * time.Second
}
if opts.ReadHeaderTimeout <= 0 {
opts.ReadHeaderTimeout = 5 * time.Second
}
if opts.WriteTimeout <= 0 {
opts.WriteTimeout = 15 * time.Second
}
if opts.IdleTimeout <= 0 {
opts.IdleTimeout = 60 * time.Second
}
return opts
}
func (s *Server) Stop(ctx context.Context) error {
if ctx == nil {
ctx = context.Background()
}
s.mu.Lock()
server := s.server
s.server = nil
s.listener = nil
s.mu.Unlock()
if server == nil {
return nil
}
if s.logger != nil {
s.logger.Info("stopping admin http", "addr", s.addr)
}
return server.Shutdown(ctx)
}