You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

326 lines
7.7 KiB

// Package handler HTTP Handler实现
package handler
import (
"context"
"fmt"
"market-data-service/api"
"market-data-service/internal/service"
)
// Handler HTTP处理器实现
type Handler struct {
stockService service.StockService
futuresService service.FuturesService
adminService service.AdminService
}
// NewHandler 创建Handler
func NewHandler(
stockService service.StockService,
futuresService service.FuturesService,
adminService service.AdminService,
) *Handler {
return &Handler{
stockService: stockService,
futuresService: futuresService,
adminService: adminService,
}
}
// 确保Handler实现了api.Handler接口
var _ api.Handler = (*Handler)(nil)
// ============================================
// 股票接口实现
// ============================================
// QueryKLines 查询股票K线
func (h *Handler) QueryKLines(ctx context.Context, req *api.KLineQueryRequest) (*api.Response, error) {
// 参数校验
if err := validateKLineRequest(req); err != nil {
return nil, err
}
// 调用Service层
data, err := h.stockService.QueryKLines(ctx, req)
if err != nil {
return nil, err
}
return &api.Response{
Code: 0,
Message: "success",
Data: data,
}, nil
}
// ListSymbols 查询股票标的列表
func (h *Handler) ListSymbols(ctx context.Context, req *api.SymbolListRequest) (*api.Response, error) {
// 设置默认值
if req.Page <= 0 {
req.Page = 1
}
if req.Size <= 0 {
req.Size = 20
}
if req.Size > 100 {
req.Size = 100
}
data, err := h.stockService.ListSymbols(ctx, req)
if err != nil {
return nil, err
}
return &api.Response{
Code: 0,
Message: "success",
Data: data,
}, nil
}
// BatchQueryKLines 批量查询股票K线
func (h *Handler) BatchQueryKLines(ctx context.Context, req *api.BatchKLineRequest) (*api.Response, error) {
if err := validateBatchKLineRequest(req); err != nil {
return nil, err
}
data, err := h.stockService.BatchQueryKLines(ctx, req)
if err != nil {
return nil, err
}
return &api.Response{
Code: 0,
Message: "success",
Data: data,
}, nil
}
// ============================================
// 期货接口实现
// ============================================
// QueryKLines 查询期货K线期货Handler
func (h *Handler) QueryKLines(ctx context.Context, req *api.KLineQueryRequest) (*api.Response, error) {
if err := validateKLineRequest(req); err != nil {
return nil, err
}
data, err := h.futuresService.QueryKLines(ctx, req)
if err != nil {
return nil, err
}
return &api.Response{
Code: 0,
Message: "success",
Data: data,
}, nil
}
// ListSymbols 查询期货标的列表
func (h *Handler) ListSymbols(ctx context.Context, req *api.SymbolListRequest) (*api.Response, error) {
if req.Page <= 0 {
req.Page = 1
}
if req.Size <= 0 {
req.Size = 20
}
if req.Size > 100 {
req.Size = 100
}
data, err := h.futuresService.ListSymbols(ctx, req)
if err != nil {
return nil, err
}
return &api.Response{
Code: 0,
Message: "success",
Data: data,
}, nil
}
// BatchQueryKLines 批量查询期货K线
func (h *Handler) BatchQueryKLines(ctx context.Context, req *api.BatchKLineRequest) (*api.Response, error) {
if err := validateBatchKLineRequest(req); err != nil {
return nil, err
}
data, err := h.futuresService.BatchQueryKLines(ctx, req)
if err != nil {
return nil, err
}
return &api.Response{
Code: 0,
Message: "success",
Data: data,
}, nil
}
// QueryContinuousKLines 查询主力连续合约K线预留
func (h *Handler) QueryContinuousKLines(ctx context.Context, underlying string, req *api.KLineQueryRequest) (*api.Response, error) {
// TODO: 首期返回空数据或错误提示
return &api.Response{
Code: 0,
Message: "success",
Data: &api.KLineData{
Symbol: underlying + ".MAIN",
Name: underlying + "主力连续",
Freq: req.Freq,
Count: 0,
Items: []api.KLineItem{},
},
}, nil
}
// ============================================
// 管理接口实现
// ============================================
// GetDataSourceStatus 获取数据源状态
func (h *Handler) GetDataSourceStatus(ctx context.Context) (*api.Response, error) {
data, err := h.adminService.GetDataSourceStatus(ctx)
if err != nil {
return nil, err
}
return &api.Response{
Code: 0,
Message: "success",
Data: data,
}, nil
}
// SwitchDataSource 切换数据源
func (h *Handler) SwitchDataSource(ctx context.Context, req *api.SourceSwitchRequest) (*api.Response, error) {
if err := h.adminService.SwitchDataSource(ctx, req); err != nil {
return nil, err
}
return &api.Response{
Code: 0,
Message: "数据源切换成功",
Data: nil,
}, nil
}
// BackfillData 历史数据补录
func (h *Handler) BackfillData(ctx context.Context, req *api.BackfillRequest) (*api.Response, error) {
// 异步启动补录任务
taskID, err := h.adminService.BackfillData(ctx, req)
if err != nil {
return nil, err
}
return &api.Response{
Code: 0,
Message: "补录任务已启动",
Data: map[string]string{
"task_id": taskID,
},
}, nil
}
// HealthCheck 健康检查
func (h *Handler) HealthCheck(ctx context.Context) (*api.HealthResponse, error) {
// TODO: 检查数据库连接、数据源连通性等
return h.adminService.HealthCheck(ctx)
}
// ============================================
// 新增接口:交易日历和期货合约
// ============================================
// GetTradingDates 获取股票交易日历
func (h *Handler) GetTradingDates(ctx context.Context, req *api.TradingDatesRequest) (*api.Response, error) {
if err := validateTradingDatesRequest(req); err != nil {
return nil, err
}
// 通过请求路径判断是股票还是期货,这里简化处理
// 实际可以通过gin的context或其他方式判断
data, err := h.stockService.GetTradingDates(ctx, req)
if err != nil {
return nil, err
}
return &api.Response{
Code: 0,
Message: "success",
Data: data,
}, nil
}
// GetContractsByUnderlying 根据品种获取可交易合约
func (h *Handler) GetContractsByUnderlying(ctx context.Context, req *api.FuturesContractsRequest) (*api.Response, error) {
if req.Underlying == "" {
return nil, fmt.Errorf("underlying不能为空")
}
data, err := h.futuresService.GetContractsByUnderlying(ctx, req)
if err != nil {
return nil, err
}
return &api.Response{
Code: 0,
Message: "success",
Data: data,
}, nil
}
// ============================================
// 私有辅助函数
// ============================================
func validateKLineRequest(req *api.KLineQueryRequest) error {
if req.Symbol == "" {
return fmt.Errorf("symbol不能为空")
}
if req.Start == "" || len(req.Start) != 8 {
return fmt.Errorf("start日期格式错误应为YYYYMMDD")
}
if req.End == "" || len(req.End) != 8 {
return fmt.Errorf("end日期格式错误应为YYYYMMDD")
}
if req.Freq == "" {
req.Freq = api.Freq1D
}
return nil
}
func validateBatchKLineRequest(req *api.BatchKLineRequest) error {
if len(req.Symbols) == 0 {
return fmt.Errorf("symbols不能为空")
}
if len(req.Symbols) > 100 {
return fmt.Errorf("单次查询标的数不能超过100")
}
if req.Start == "" || len(req.Start) != 8 {
return fmt.Errorf("start日期格式错误应为YYYYMMDD")
}
if req.End == "" || len(req.End) != 8 {
return fmt.Errorf("end日期格式错误应为YYYYMMDD")
}
if req.Freq == "" {
req.Freq = api.Freq1D
}
return nil
}
func validateTradingDatesRequest(req *api.TradingDatesRequest) error {
if req.Start == "" || len(req.Start) != 8 {
return fmt.Errorf("start日期格式错误应为YYYYMMDD")
}
if req.End == "" || len(req.End) != 8 {
return fmt.Errorf("end日期格式错误应为YYYYMMDD")
}
return nil
}