Initial commit: 可转债轮动分析系统
- 实时行情:东财push2主源 + 腾讯批量报价备用源(自动切换) - 历史K线:东财push2his主源 + 腾讯web子域备用源(含熔断机制) - 增量同步:支持 -incr/-since 参数按存档日期增量入库 - 策略回测:净值曲线/10指标/基准对比,含基本面过滤 - 用户认证:用户名密码 + 邮箱验证码双登录方式 - 前端:三Tab SPA(实时行情/策略回测/数据管理)
This commit is contained in:
87
cmd/server/main.go
Normal file
87
cmd/server/main.go
Normal file
@@ -0,0 +1,87 @@
|
||||
// server 是可转债轮动分析系统的 B/S 服务入口。
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/signal"
|
||||
"path/filepath"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"stock-analysis/internal/controller"
|
||||
"stock-analysis/internal/datasource/eastmoney"
|
||||
"stock-analysis/internal/datasource/fallback"
|
||||
"stock-analysis/internal/datasource/tencent"
|
||||
"stock-analysis/internal/router"
|
||||
"stock-analysis/internal/service"
|
||||
"stock-analysis/internal/storage/sqlite"
|
||||
)
|
||||
|
||||
func main() {
|
||||
addr := ":8080"
|
||||
if p := os.Getenv("PORT"); p != "" {
|
||||
addr = ":" + p
|
||||
}
|
||||
webDir := "web"
|
||||
dbPath := defaultDBPath()
|
||||
|
||||
// 东财为主数据源(实时行情+历史K线),腾讯为历史K线备用源(东财失败时自动切换)
|
||||
ds := fallback.New(eastmoney.NewClient(), tencent.NewClient())
|
||||
svc := service.NewMarketService(ds)
|
||||
mc := controller.NewMarketController(svc, dbPath)
|
||||
|
||||
store, err := sqlite.Open(dbPath)
|
||||
if err != nil {
|
||||
log.Fatalf("open sqlite: %v", err)
|
||||
}
|
||||
defer store.Close()
|
||||
authSvc := service.NewAuthService(store)
|
||||
if err := authSvc.EnsureAdmin(context.Background()); err != nil {
|
||||
log.Printf("ensure admin: %v", err)
|
||||
}
|
||||
ac := controller.NewAuthController(authSvc)
|
||||
|
||||
handler := router.New(mc, ac, webDir)
|
||||
|
||||
server := &http.Server{
|
||||
Addr: addr,
|
||||
Handler: handler,
|
||||
ReadHeaderTimeout: 5 * time.Second,
|
||||
}
|
||||
|
||||
// 优雅退出:收到信号后关闭服务。
|
||||
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
|
||||
defer stop()
|
||||
|
||||
go func() {
|
||||
log.Printf("stock-analysis server listening on http://localhost%s", addr)
|
||||
if err := server.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) {
|
||||
log.Fatalf("server: %v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
<-ctx.Done()
|
||||
log.Println("shutting down server...")
|
||||
shutdownCtx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
defer cancel()
|
||||
if err := server.Shutdown(shutdownCtx); err != nil {
|
||||
log.Printf("shutdown: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// defaultDBPath 返回默认数据库路径。
|
||||
// 默认使用项目目录下的 stock.db,避免 OneDrive/AppData 的 I/O 限制。
|
||||
func defaultDBPath() string {
|
||||
if env := os.Getenv("STOCK_DB_PATH"); env != "" {
|
||||
return env
|
||||
}
|
||||
exe, err := os.Executable()
|
||||
if err != nil {
|
||||
return "stock.db"
|
||||
}
|
||||
return filepath.Join(filepath.Dir(exe), "stock.db")
|
||||
}
|
||||
Reference in New Issue
Block a user