DNF90 服务端与启动器完整源码(含 GM 工具功能增强)
服务端(Go): - GM 塞背包/带属性装备发放:在线角色推送 op14 增量物品行,背包实时刷新,无需回角色选择界面 - GM 改金币/改等级:去掉在线拒绝,落库后推送 op14 钱包/op37 等级状态,在线实时刷新 - 等级端点统一切换到新版 GMSetCharacterLevel(自带在线刷新) - 无限/锁死疲劳模式 + 燃烧疲劳:每房间消耗 2 点、打怪与通关经验双倍 - 燃烧疲劳开关时给所有在线角色推送系统提示(op12 mode 0) - 深渊史诗掉率:GM 全局倍率 + 城镇增益药剂窗口倍率,真实接入掉落结算 启动器(Python/JS): - 标题栏自绘、窗口 1204x717、禁止拖拽改大小、仅最小化/关闭 - GM 工具:疲劳与燃烧、深渊史诗掉率、拍卖行上架(单一定价对齐) - 拍卖行上架前端对齐服务端单一价格语义,修复 400 报错
This commit is contained in:
commit
645b64fe21
4388 files changed
+1405457
No files matched your search
@@ -0,0 +1,371 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"longheng.io/server/internal/platform/admincmdqueue"
|
||||
"longheng.io/server/internal/platform/cluster"
|
||||
"longheng.io/server/internal/platform/config"
|
||||
"longheng.io/server/internal/platform/discovery"
|
||||
"longheng.io/server/internal/platform/reload"
|
||||
rpckit "longheng.io/server/internal/platform/rpc"
|
||||
"longheng.io/server/internal/platform/servergroup"
|
||||
"longheng.io/server/internal/platform/topology"
|
||||
"longheng.io/server/internal/platform/workerpool"
|
||||
)
|
||||
|
||||
// New 创建只装配不运行的 Application,适合测试或上层进程自行托管生命周期。
|
||||
func New(serviceName, configPath string, builder Builder) (*Application, error) {
|
||||
return NewWithManifest(serviceName, configPath, ServiceManifest{Components: builder})
|
||||
}
|
||||
|
||||
// Run 创建并运行基于 Builder 的服务,直到传入 context 或系统信号触发停服。
|
||||
func Run(ctx context.Context, serviceName, configPath string, builder Builder) error {
|
||||
return RunWithManifest(ctx, serviceName, configPath, ServiceManifest{Components: builder})
|
||||
}
|
||||
|
||||
// RunWithManifest 创建并运行基于 ServiceManifest 的服务,统一复用平台基础设施装配。
|
||||
func RunWithManifest(ctx context.Context, serviceName, configPath string, manifest ServiceManifest) error {
|
||||
if ctx == nil {
|
||||
ctx = context.Background()
|
||||
}
|
||||
application, err := NewWithManifest(serviceName, configPath, manifest)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return application.Run(ctx)
|
||||
}
|
||||
|
||||
// NewWithManifest 创建 Application 并完成平台、runtime、admin 与业务组件的统一装配。
|
||||
func NewWithManifest(serviceName, configPath string, manifest ServiceManifest) (*Application, error) {
|
||||
foundation, err := newPlatformBase(serviceName, configPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cfg := foundation.cfg
|
||||
logger := foundation.logger
|
||||
otelShutdown := foundation.otelShutdown
|
||||
pvfArchive := foundation.pvfArchive
|
||||
dataTables := foundation.dataTables
|
||||
dataTableViews := foundation.dataTableViews
|
||||
stateSyncStore := foundation.stateSyncStore
|
||||
serverGroupManager := foundation.serverGroupManager
|
||||
serverGroupStore := foundation.serverGroupStore
|
||||
auditLogger := foundation.auditLogger
|
||||
logicLogger := foundation.logicLogger
|
||||
biLogger := foundation.biLogger
|
||||
healthSvc := foundation.healthSvc
|
||||
metricsRegistry := foundation.metricsRegistry
|
||||
tracer := foundation.tracer
|
||||
rateLimiter := foundation.rateLimiter
|
||||
adminTimeouts := foundation.adminTimeouts
|
||||
adminServer := foundation.adminServer
|
||||
schedulerSvc := foundation.schedulerSvc
|
||||
var application *Application
|
||||
configProvider := func() config.ServiceConfig {
|
||||
if application != nil {
|
||||
return application.configSnapshot()
|
||||
}
|
||||
return cfg
|
||||
}
|
||||
adminGuard := newAdminSecurity(configProvider, auditLogger, logger, rateLimiter)
|
||||
storageObjects, err := newStorageObjSvc(cfg, adminServer.Mux(), adminGuard.wrap, adminGuard.wrapDangerous)
|
||||
if err != nil {
|
||||
_ = foundation.close(context.Background())
|
||||
return nil, err
|
||||
}
|
||||
accountCenter, err := newAccountCenter(cfg, adminServer.Mux(), adminGuard.wrap, adminGuard.wrapDangerous)
|
||||
if err != nil {
|
||||
_ = storageObjects.Close()
|
||||
_ = foundation.close(context.Background())
|
||||
return nil, err
|
||||
}
|
||||
|
||||
reg, err := newRegistry(cfg, logger)
|
||||
if err != nil {
|
||||
_ = foundation.close(context.Background())
|
||||
return nil, err
|
||||
}
|
||||
eventBus, err := newBus(cfg, logger)
|
||||
if err != nil {
|
||||
_ = reg.Close()
|
||||
_ = foundation.close(context.Background())
|
||||
return nil, err
|
||||
}
|
||||
attachBusMetrics(eventBus, metricsRegistry, cfg)
|
||||
cacheStore, err := newCache(cfg, metricsRegistry)
|
||||
if err != nil {
|
||||
_ = eventBus.Close()
|
||||
_ = reg.Close()
|
||||
_ = foundation.close(context.Background())
|
||||
return nil, err
|
||||
}
|
||||
lockManager, err := newLockManager(cfg, metricsRegistry)
|
||||
if err != nil {
|
||||
_ = cacheStore.Close()
|
||||
_ = eventBus.Close()
|
||||
_ = reg.Close()
|
||||
_ = foundation.close(context.Background())
|
||||
return nil, err
|
||||
}
|
||||
presenceRuntime, err := newPresenceRuntime(cfg)
|
||||
if err != nil {
|
||||
_ = lockManager.Close()
|
||||
_ = cacheStore.Close()
|
||||
_ = eventBus.Close()
|
||||
_ = reg.Close()
|
||||
_ = foundation.close(context.Background())
|
||||
return nil, err
|
||||
}
|
||||
regPresenceMetrics(metricsRegistry, presenceRuntime, cfg)
|
||||
onlinePush, err := newOnlinePushService(eventBus, presenceRuntime, adminServer.Mux(), adminGuard.wrap, adminGuard.wrapDangerous)
|
||||
if err != nil {
|
||||
if closer, ok := presenceRuntime.(interface{ Close() error }); ok {
|
||||
_ = closer.Close()
|
||||
}
|
||||
_ = lockManager.Close()
|
||||
_ = cacheStore.Close()
|
||||
_ = eventBus.Close()
|
||||
_ = reg.Close()
|
||||
_ = foundation.close(context.Background())
|
||||
return nil, err
|
||||
}
|
||||
eventLog, eventLogWorker, err := newEventLog(cfg, eventBus, adminServer.Mux(), adminGuard.wrap, logger)
|
||||
if err != nil {
|
||||
if closer, ok := presenceRuntime.(interface{ Close() error }); ok {
|
||||
_ = closer.Close()
|
||||
}
|
||||
_ = lockManager.Close()
|
||||
_ = cacheStore.Close()
|
||||
_ = eventBus.Close()
|
||||
_ = reg.Close()
|
||||
_ = foundation.close(context.Background())
|
||||
return nil, err
|
||||
}
|
||||
var adminCommands *admincmdqueue.Executor
|
||||
if eventLog != nil {
|
||||
adminCommands, err = admincmdqueue.NewExecutor(admincmdqueue.ExecutorOptions{Log: eventLog})
|
||||
if err != nil {
|
||||
_ = eventLog.Close()
|
||||
if closer, ok := presenceRuntime.(interface{ Close() error }); ok {
|
||||
_ = closer.Close()
|
||||
}
|
||||
_ = lockManager.Close()
|
||||
_ = cacheStore.Close()
|
||||
_ = eventBus.Close()
|
||||
_ = reg.Close()
|
||||
_ = foundation.close(context.Background())
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
hotUpdateManager, err := newHotUpdateManager(cfg, dataTables, dataTableViews, eventLog, logger)
|
||||
if err != nil {
|
||||
if eventLog != nil {
|
||||
_ = eventLog.Close()
|
||||
}
|
||||
if closer, ok := presenceRuntime.(interface{ Close() error }); ok {
|
||||
_ = closer.Close()
|
||||
}
|
||||
_ = lockManager.Close()
|
||||
_ = cacheStore.Close()
|
||||
_ = eventBus.Close()
|
||||
_ = reg.Close()
|
||||
_ = foundation.close(context.Background())
|
||||
return nil, err
|
||||
}
|
||||
workers := workerpool.New("worker-pool", cfg.Worker.Size, cfg.Worker.Queue, logger)
|
||||
rpcEndpoint := rpckit.NewEndpoint(cfg.Service.Name, cfg.Service.NodeID, eventBus, logger)
|
||||
rpcEndpoint.SetOptionsExact(rpckit.Options{
|
||||
CallTimeout: time.Duration(cfg.RPC.CallTimeoutSeconds) * time.Second,
|
||||
MaxPending: cfg.RPC.MaxPending,
|
||||
MaxPayloadBytes: cfg.RPC.MaxPayloadBytes,
|
||||
})
|
||||
discoveryResolver := discovery.NewResolver(
|
||||
reg,
|
||||
time.Duration(cfg.Discovery.CacheTTLSeconds)*time.Second,
|
||||
time.Duration(cfg.Discovery.FailureTTLSeconds)*time.Second,
|
||||
!cfg.Discovery.AllowMaintaining,
|
||||
)
|
||||
discoveryResolver.SetFailureThreshold(cfg.Discovery.FailureThreshold)
|
||||
discoveryResolver.SetStrategy(discovery.Strategy(cfg.Discovery.Strategy))
|
||||
rpcEndpoint.SetDiscoveryResolver(discoveryResolver)
|
||||
rpcEndpoint.SetTracer(tracer)
|
||||
registerRPCMetrics(metricsRegistry, rpcEndpoint, cfg)
|
||||
topologyManager := topology.New(topologyConfig(cfg), reg, logger)
|
||||
clusterCoord := cluster.New(cfg, reg, eventBus, healthSvc, adminServer.Mux(), cfg.Admin.Token, logger, func(next http.HandlerFunc) http.HandlerFunc {
|
||||
return adminGuard.wrap("cluster", next)
|
||||
})
|
||||
application = &Application{
|
||||
cfg: cfg,
|
||||
configPath: configPath,
|
||||
logger: logger,
|
||||
bus: eventBus,
|
||||
cache: cacheStore,
|
||||
lockManager: lockManager,
|
||||
presence: presenceRuntime,
|
||||
registry: reg,
|
||||
cluster: clusterCoord,
|
||||
health: healthSvc,
|
||||
metrics: metricsRegistry,
|
||||
rateLimiter: rateLimiter,
|
||||
discovery: discoveryResolver,
|
||||
rpc: rpcEndpoint,
|
||||
topology: topologyManager,
|
||||
scheduler: schedulerSvc,
|
||||
tracer: tracer,
|
||||
pvfArchive: pvfArchive,
|
||||
dataTables: dataTables,
|
||||
dataTableViews: dataTableViews,
|
||||
audit: auditLogger,
|
||||
logicLog: logicLogger,
|
||||
biLog: biLogger,
|
||||
eventLog: eventLog,
|
||||
adminCommands: adminCommands,
|
||||
accountCenter: accountCenter,
|
||||
onlinePush: onlinePush,
|
||||
otelShutdown: otelShutdown,
|
||||
workers: workers,
|
||||
admin: adminServer,
|
||||
hotUpdate: hotUpdateManager,
|
||||
stateSync: stateSyncStore,
|
||||
storageObjects: storageObjects,
|
||||
serverGroup: serverGroupManager,
|
||||
serverGroupStore: serverGroupStore,
|
||||
serverGroupArchives: foundation.serverGroupArchives,
|
||||
}
|
||||
reloadManager := reload.New("config-reloader", reloadConfig(cfg), application.applyRuntimeReload, logger)
|
||||
application.reloader = reloadManager
|
||||
registerCommonRoutes(commonRouteContext{
|
||||
Mux: adminServer.Mux(),
|
||||
ConfigProvider: application.configSnapshot,
|
||||
Health: healthSvc,
|
||||
Metrics: metricsRegistry,
|
||||
RateLimiter: rateLimiter,
|
||||
Discovery: discoveryResolver,
|
||||
RPC: rpcEndpoint,
|
||||
Topology: topologyManager,
|
||||
Scheduler: schedulerSvc,
|
||||
Tracer: tracer,
|
||||
PVF: pvfArchive,
|
||||
DataTables: dataTables,
|
||||
DataTableViews: dataTableViews,
|
||||
Audit: auditLogger,
|
||||
LogicLog: logicLogger,
|
||||
BILog: biLogger,
|
||||
Reload: reloadManager,
|
||||
Logger: logger,
|
||||
})
|
||||
regUpdateStateRoutes(adminServer.Mux(), adminGuard.wrapDangerous, adminCommands, hotUpdateManager, stateSyncStore, time.Duration(cfg.StateSync.TTLSeconds)*time.Second)
|
||||
if serverGroupManager != nil {
|
||||
servergroup.RegisterAdminRoutes(adminServer.Mux(), serverGroupManager, servergroup.AdminOptions{
|
||||
Prefix: cfg.ServerGroup.AdminPrefix,
|
||||
Store: serverGroupStore,
|
||||
Archives: foundation.serverGroupArchives,
|
||||
WarZoneInZoneDelaySecs: cfg.ServerGroup.InZoneDelaySeconds,
|
||||
WarZoneNoticeLeadSecs: cfg.ServerGroup.NoticeLeadSeconds,
|
||||
Wrap: adminGuard.wrap,
|
||||
WrapDangerous: adminGuard.wrapDangerous,
|
||||
})
|
||||
}
|
||||
|
||||
env := &Env{
|
||||
Config: cfg,
|
||||
ConfigPath: configPath,
|
||||
Logger: logger,
|
||||
Bus: eventBus,
|
||||
Cache: cacheStore,
|
||||
Lock: lockManager,
|
||||
Presence: presenceRuntime,
|
||||
Cluster: clusterCoord,
|
||||
Registry: reg,
|
||||
Health: healthSvc,
|
||||
Metrics: metricsRegistry,
|
||||
RateLimiter: rateLimiter,
|
||||
Discovery: discoveryResolver,
|
||||
RPC: rpcEndpoint,
|
||||
Topology: topologyManager,
|
||||
Scheduler: schedulerSvc,
|
||||
Tracer: tracer,
|
||||
PVF: pvfArchive,
|
||||
DataTables: dataTables,
|
||||
DataTableViews: dataTableViews,
|
||||
Audit: auditLogger,
|
||||
LogicLog: logicLogger,
|
||||
BILog: biLogger,
|
||||
EventLog: eventLog,
|
||||
AdminCommands: adminCommands,
|
||||
AccountCenter: accountCenter,
|
||||
OnlinePush: onlinePush,
|
||||
Reload: reloadManager,
|
||||
HotUpdate: hotUpdateManager,
|
||||
StateSync: stateSyncStore,
|
||||
StorageObjects: storageObjects,
|
||||
ServerGroup: serverGroupManager,
|
||||
ServerGroupStore: serverGroupStore,
|
||||
ServerGroupArchives: foundation.serverGroupArchives,
|
||||
Workers: workers,
|
||||
AdminMux: adminServer.Mux(),
|
||||
AdminTimeouts: adminTimeouts,
|
||||
AdminAuth: adminGuard.wrap,
|
||||
AdminDangerous: adminGuard.wrapDangerous,
|
||||
ConfigProvider: application.configSnapshot,
|
||||
}
|
||||
|
||||
components := []Component{workers, schedulerSvc, rpcEndpoint, reloadManager}
|
||||
if hotUpdateManager != nil {
|
||||
components = append(components, hotUpdateManager)
|
||||
}
|
||||
if stateSyncSweeper := newStateSyncSweeper(stateSyncStore, time.Duration(cfg.StateSync.CleanupIntervalSeconds)*time.Second, logger); stateSyncSweeper != nil {
|
||||
components = append(components, stateSyncSweeper)
|
||||
}
|
||||
if eventLogWorker != nil {
|
||||
components = append(components, eventLogWorker)
|
||||
}
|
||||
extra, err := manifest.Build(env)
|
||||
if err != nil {
|
||||
_ = cleanupComponents(context.Background(), healthSvc, extra)
|
||||
closeHotCtl(hotUpdateManager)
|
||||
if closer, ok := presenceRuntime.(interface{ Close() error }); ok {
|
||||
_ = closer.Close()
|
||||
}
|
||||
_ = lockManager.Close()
|
||||
_ = cacheStore.Close()
|
||||
_ = eventBus.Close()
|
||||
_ = reg.Close()
|
||||
if eventLog != nil {
|
||||
_ = eventLog.Close()
|
||||
}
|
||||
_ = foundation.close(context.Background())
|
||||
return nil, err
|
||||
}
|
||||
application.i18nCatalog = env.I18N
|
||||
if cfg.DataTables.Enabled {
|
||||
if _, err := dataTableViews.RefreshAll(context.Background(), dataTables); err != nil {
|
||||
_ = cleanupComponents(context.Background(), healthSvc, extra)
|
||||
closeHotCtl(hotUpdateManager)
|
||||
if closer, ok := presenceRuntime.(interface{ Close() error }); ok {
|
||||
_ = closer.Close()
|
||||
}
|
||||
_ = lockManager.Close()
|
||||
_ = cacheStore.Close()
|
||||
_ = eventBus.Close()
|
||||
_ = reg.Close()
|
||||
if eventLog != nil {
|
||||
_ = eventLog.Close()
|
||||
}
|
||||
_ = foundation.close(context.Background())
|
||||
return nil, fmt.Errorf("refresh data table views: %w", err)
|
||||
}
|
||||
}
|
||||
components = append(components, extra...)
|
||||
components = append(components, adminServer)
|
||||
components = append(components, clusterCoord)
|
||||
components = append(components, topologyManager)
|
||||
|
||||
application.components = components
|
||||
application.constructed = extra
|
||||
return application, nil
|
||||
}
|
||||
Reference in new issue
Block a user