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.
 
 

204 lines
6.0 KiB

package exchange
import (
"context"
"fmt"
"io"
"math"
"sig-pub/api/pb"
"sig-pub/pkg/publish"
"sig-pub/pkg/types"
"sig-pub/pkg/types/decimals"
"sig-pub/pkg/zlog"
"sync/atomic"
"google.golang.org/grpc"
)
type ExchangeGrpcServer struct {
pb.UnimplementedExchangeServiceServer
exchangeService *ExchangeService
klineStreamId int64
klineSubscriber *publish.Publisher[int64, grpc.BidiStreamingServer[pb.ReqStreamSubscribeKline, pb.RspStreamSubscribeKline]]
}
// exchanges: 支持的数据源交易所
func NewExchangeGrpcServer(exchangeService *ExchangeService) *ExchangeGrpcServer {
return &ExchangeGrpcServer{
exchangeService: exchangeService,
}
}
func (svr *ExchangeGrpcServer) Init() (err error) {
svr.klineSubscriber = svr.exchangeService.GetKlineSubscriber()
return
}
// SubscribeKline 订阅k线stream
func (svr *ExchangeGrpcServer) SubscribeKline(stream grpc.BidiStreamingServer[pb.ReqStreamSubscribeKline, pb.RspStreamSubscribeKline]) (err0 error) {
streamId := atomic.AddInt64(&svr.klineStreamId, 1)
// subKey = /kline/exchange/instId/interval/confirm -> /kline/OKX/DOGE-USDT-SWAP/1s/1
// 接收消息的goroutine
recvChan := make(chan *pb.ReqStreamSubscribeKline)
go func() {
for {
msg, err := stream.Recv()
if err == io.EOF {
zlog.Infof("recv close EOF")
close(recvChan)
return
}
if err != nil {
zlog.Infof("recv error: %v", err)
close(recvChan)
return
}
zlog.Infof("recv stream msg: %#v", msg)
recvChan <- msg
}
}()
// 发送和处理消息
for {
select {
case <-stream.Context().Done():
// 客户端断开连接
svr.klineSubscriber.UnsubscribeAll(streamId)
return stream.Context().Err()
case msg, ok := <-recvChan:
if !ok {
// 接收通道关闭,结束流
svr.klineSubscriber.UnsubscribeAll(streamId)
return
}
if msg.SubType == pb.SubscribeType_UNSUB_ALL {
svr.klineSubscriber.UnsubscribeAll(streamId)
continue
}
for _, exchange := range msg.Exchanges {
for _, instId := range msg.InstIds {
for _, interval := range msg.Intervals {
confirms := []int{1}
if !msg.OnlyConfirm {
confirms = append(confirms, 0)
}
for _, confirm := range confirms {
subKey := fmt.Sprintf("/kline/%s/%s/%s/%d", exchange.String(), instId, interval, confirm)
zlog.Debugf("stream: id=%d, sub %s", streamId, subKey)
switch msg.SubType {
case pb.SubscribeType_SUB:
svr.klineSubscriber.Subscribe(subKey, streamId, stream)
case pb.SubscribeType_UNSUB:
svr.klineSubscriber.Unsubscribe(subKey, streamId)
}
}
}
}
}
}
}
}
// Exchanges 获取支持的交易所列表
func (svr *ExchangeGrpcServer) Exchanges(ctx context.Context, req *pb.ReqExchanges) (rsp *pb.RspExchanges, err error) {
exchanges, err := svr.exchangeService.Exchanges()
if err != nil {
return
}
return &pb.RspExchanges{Exchanges: exchanges}, nil
}
// ExchangeInstanceState 获取交易产品系统状态
func (svr *ExchangeGrpcServer) ExchangeInstanceState(ctx context.Context, req *pb.ReqExchangeInstanceState) (rsp *pb.RspExchangeInstanceState, err error) {
states, err := svr.exchangeService.ExchangeInstanceState(req)
if err != nil {
return
}
return &pb.RspExchangeInstanceState{InstsState: states}, nil
}
// 查询SeriesRange时间范围
func (svr *ExchangeGrpcServer) SeriesRange(ctx context.Context, req *pb.ReqSeriesRange) (rsp *pb.RspSeriesRange, err error) {
rsp = new(pb.RspSeriesRange)
rsp.After, rsp.Before, rsp.Total, err = svr.exchangeService.CalcSeriesRange(req.Series)
return
}
// HistoryKline 获取交易产品历史k线 (before < klines... < after)
func (svr *ExchangeGrpcServer) HistoryKline(ctx context.Context, req *pb.ReqHistoryKline) (rsp *pb.RspHistoryKline, err error) {
if req.Series == nil {
err = fmt.Errorf("series arg is required")
return
}
// 查询范围数据条数检查
_, _, total, err := svr.exchangeService.CalcSeriesRange(req.Series)
if err != nil {
return
}
if total > MaxHistoryKlines {
err = fmt.Errorf("time range too large max %d", MaxHistoryKlines)
return
}
rsp = new(pb.RspHistoryKline)
rsp = &pb.RspHistoryKline{
Exchange: req.Series.Exchange,
InstId: req.Series.InstId,
Interval: req.Series.Interval,
}
kSeries := &pb.KlineSeries{
Interval: req.Series.Interval,
Time: make([]int64, 0, total),
Open: make([]float64, 0, total),
High: make([]float64, 0, total),
Low: make([]float64, 0, total),
Close: make([]float64, 0, total),
Vol: make([]float64, 0, total),
VolQuote: make([]float64, 0, total),
}
live, err := svr.exchangeService.HistoryKline(req.Series, math.MaxInt, func(liveK *types.Kline, klines []*types.Kline) error {
for _, kline := range klines {
kSeries.Time = append(kSeries.Time, kline.Ts)
kSeries.Open = append(kSeries.Open, decimals.MustToFloat64(kline.Open))
kSeries.High = append(kSeries.High, decimals.MustToFloat64(kline.High))
kSeries.Low = append(kSeries.Low, decimals.MustToFloat64(kline.Low))
kSeries.Close = append(kSeries.Close, decimals.MustToFloat64(kline.Close))
kSeries.Vol = append(kSeries.Vol, decimals.MustToFloat64(kline.Vol))
kSeries.VolQuote = append(kSeries.VolQuote, decimals.MustToFloat64(kline.VolQuote))
if liveK != nil {
kSeries.Live = liveK.ToPBKline()
}
}
return nil
})
if err != nil {
return
}
rsp.Live = live
rsp.Klines = kSeries
return
}
// HistoryKlineStream 获取交易产品历史k线(流式返回)
func (svr *ExchangeGrpcServer) HistoryKlineStream(req *pb.ReqHistoryKlineStream, stream grpc.ServerStreamingServer[pb.RspHistoryKlineStream]) (err error) {
if req.Series == nil {
err = fmt.Errorf("series arg is required")
return
}
_, err = svr.exchangeService.HistoryKline(req.Series, 200, func(_ *types.Kline, klines []*types.Kline) error {
rsp := &pb.RspHistoryKlineStream{}
rsp.Klines = make([]*pb.Kline, 0, len(klines))
for _, kline := range klines {
rsp.Klines = append(rsp.Klines, kline.ToPBKline())
}
return stream.Send(rsp)
})
if err != nil {
return
}
return
}