Merge remote-tracking branch 'refs/remotes/origin/main'
This commit is contained in:
commit
4591d0eff8
|
@ -99,8 +99,8 @@ issues:
|
||||||
- gocognit
|
- gocognit
|
||||||
- contextcheck
|
- contextcheck
|
||||||
|
|
||||||
# exclude-dirs:
|
exclude-dirs:
|
||||||
# - internal/logic
|
- internal/lib/cassandra
|
||||||
|
|
||||||
exclude-files:
|
exclude-files:
|
||||||
- .*_test.go
|
- .*_test.go
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
version: '3'
|
|
||||||
|
|
||||||
services:
|
services:
|
||||||
docker-etcd:
|
docker-etcd:
|
||||||
hostname: etcd
|
hostname: etcd
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
Name: blockchain.rpc
|
Name: blockchain.rpc
|
||||||
ListenOn: 0.0.0.0:8888
|
ListenOn: 0.0.0.0:8888
|
||||||
|
Timeout: 10000
|
||||||
Etcd:
|
Etcd:
|
||||||
Hosts:
|
Hosts:
|
||||||
- localhost:2379
|
- localhost:2379
|
||||||
|
@ -8,7 +9,7 @@ Binance:
|
||||||
Key: ""
|
Key: ""
|
||||||
Secret: ""
|
Secret: ""
|
||||||
TestMode: true
|
TestMode: true
|
||||||
WorkerSize: 10
|
WorkerSize: 20
|
||||||
|
|
||||||
RedisCluster:
|
RedisCluster:
|
||||||
Host: 127.0.0.1:6379
|
Host: 127.0.0.1:6379
|
||||||
|
@ -18,7 +19,7 @@ Cassandra:
|
||||||
Hosts:
|
Hosts:
|
||||||
- 127.0.0.1
|
- 127.0.0.1
|
||||||
Port: 9042
|
Port: 9042
|
||||||
Keyspace: sccflex
|
Keyspace: digimon
|
||||||
UseAuth: true
|
UseAuth: true
|
||||||
Username: cassandra
|
Username: cassandra
|
||||||
Password: cassandra
|
Password: cassandra
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
create keyspace kline with replication = {'class': 'SimpleStrategy', 'replication_factor': 1};
|
|
@ -1,9 +1,10 @@
|
||||||
package config
|
package config
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/zeromicro/go-zero/core/stores/redis"
|
"github.com/zeromicro/go-zero/core/stores/redis"
|
||||||
"github.com/zeromicro/go-zero/zrpc"
|
"github.com/zeromicro/go-zero/zrpc"
|
||||||
"time"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
|
|
|
@ -4,4 +4,7 @@ import "code.30cm.net/digimon/library-go/errs"
|
||||||
|
|
||||||
const CodeBlockchain uint32 = 10
|
const CodeBlockchain uint32 = 10
|
||||||
|
|
||||||
const FailedToGetSymbolFormBinanceErrorCode errs.ErrorCode = 1
|
const (
|
||||||
|
FailedToGetSymbolFormBinanceErrorCode errs.ErrorCode = 1
|
||||||
|
FailedToUpsertBinanceErrorCode errs.ErrorCode = 2
|
||||||
|
)
|
||||||
|
|
|
@ -13,9 +13,12 @@ type Kline struct {
|
||||||
TakerBuyBaseAssetVolume string `csv:"taker_buy_base_asset_volume" db:"taker_buy_base_asset_volume" cql:"taker_buy_base_asset_volume"` // 主動買入成交量
|
TakerBuyBaseAssetVolume string `csv:"taker_buy_base_asset_volume" db:"taker_buy_base_asset_volume" cql:"taker_buy_base_asset_volume"` // 主動買入成交量
|
||||||
TakerBuyQuoteAssetVolume string `csv:"taker_buy_quote_asset_volume" db:"taker_buy_quote_asset_volume" cql:"taker_buy_quote_asset_volume"` // 主動買入成交額
|
TakerBuyQuoteAssetVolume string `csv:"taker_buy_quote_asset_volume" db:"taker_buy_quote_asset_volume" cql:"taker_buy_quote_asset_volume"` // 主動買入成交額
|
||||||
Symbol string `db:"symbol" partition_key:"true" cql:"symbol"` // 交易對,partition key
|
Symbol string `db:"symbol" partition_key:"true" cql:"symbol"` // 交易對,partition key
|
||||||
Interval string `db:"interval" partition_key:"true" cql:"interval"` // K 線時間區間,partition key // 12h,15m,1d,1h,1m,1s,2h,30m,3m,4h,5m,6h,8h
|
// K 線時間區間,partition key // 12h,15m,1d,1h,1m,1s,2h,30m,3m,4h,5m,6h,8h
|
||||||
|
Interval string `db:"interval" partition_key:"true" cql:"interval"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Kline) TableName() string {
|
func (s *Kline) TableName() string {
|
||||||
return "symbol"
|
return "kline"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// todo 未來在分表,每一個交易幣兌一個表
|
||||||
|
|
|
@ -7,10 +7,10 @@ import (
|
||||||
|
|
||||||
type DataSourceRepository interface {
|
type DataSourceRepository interface {
|
||||||
GetSymbols(ctx context.Context) ([]*entity.Symbol, error)
|
GetSymbols(ctx context.Context) ([]*entity.Symbol, error)
|
||||||
KlineDownloader
|
Downloader
|
||||||
}
|
}
|
||||||
|
|
||||||
type KlineDownloader interface {
|
type Downloader interface {
|
||||||
// FetchHistoryKline 抓歷史 K 線資料
|
// FetchHistoryKline 抓歷史 K 線資料
|
||||||
FetchHistoryKline(ctx context.Context, param QueryKline) ([]*entity.Kline, error)
|
FetchHistoryKline(ctx context.Context, param QueryKline) ([]*entity.Kline, error)
|
||||||
SaveHistoryKline(ctx context.Context, data []*entity.Kline) error
|
SaveHistoryKline(ctx context.Context, data []*entity.Kline) error
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
|
|
||||||
type DataSourceUseCase interface {
|
type DataSourceUseCase interface {
|
||||||
GetSymbols(ctx context.Context) ([]*Symbol, error)
|
GetSymbols(ctx context.Context) ([]*Symbol, error)
|
||||||
|
UpsertKline(ctx context.Context, data QueryKline) error
|
||||||
}
|
}
|
||||||
|
|
||||||
// Symbol 代表交易對資訊
|
// Symbol 代表交易對資訊
|
||||||
|
@ -17,3 +18,10 @@ type Symbol struct {
|
||||||
QuoteAsset string `json:"quote_asset"` // 報價幣種(如 BTCUSDT 的 USDT)
|
QuoteAsset string `json:"quote_asset"` // 報價幣種(如 BTCUSDT 的 USDT)
|
||||||
QuoteAssetPrecision int `json:"quote_asset_precision"` // 報價資產顯示的小數位數
|
QuoteAssetPrecision int `json:"quote_asset_precision"` // 報價資產顯示的小數位數
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type QueryKline struct {
|
||||||
|
Symbol string
|
||||||
|
Interval string
|
||||||
|
StartUnixNano int64
|
||||||
|
EndUnixNano int64
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
package websocket_manager
|
|
@ -1,7 +1,9 @@
|
||||||
package blockchainservicelogic
|
package blockchainservicelogic
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"blockchain/internal/domain/usecase"
|
||||||
"context"
|
"context"
|
||||||
|
"time"
|
||||||
|
|
||||||
app_cloudep_blockchain "blockchain/gen_result/pb/code.30cm.net/digimon/app-cloudep-blockchain"
|
app_cloudep_blockchain "blockchain/gen_result/pb/code.30cm.net/digimon/app-cloudep-blockchain"
|
||||||
"blockchain/internal/svc"
|
"blockchain/internal/svc"
|
||||||
|
@ -24,5 +26,15 @@ func NewPingLogic(ctx context.Context, svcCtx *svc.ServiceContext) *PingLogic {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *PingLogic) Ping(_ *app_cloudep_blockchain.NoneReq) (*app_cloudep_blockchain.OKResp, error) {
|
func (l *PingLogic) Ping(_ *app_cloudep_blockchain.NoneReq) (*app_cloudep_blockchain.OKResp, error) {
|
||||||
|
err := l.svcCtx.BinanceDataSource.UpsertKline(l.ctx, usecase.QueryKline{
|
||||||
|
Symbol: "BTCUSDT",
|
||||||
|
Interval: "1m",
|
||||||
|
StartUnixNano: time.Date(2024, 8, 1, 0, 0, 0, 0, time.UTC).UnixNano(),
|
||||||
|
EndUnixNano: time.Date(2025, 8, 2, 0, 0, 0, 0, time.UTC).UnixNano(),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
return &app_cloudep_blockchain.OKResp{}, nil
|
return &app_cloudep_blockchain.OKResp{}, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,9 +30,10 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type BinanceRepositoryParam struct {
|
type BinanceRepositoryParam struct {
|
||||||
Conf *config.Binance
|
Conf *config.Binance
|
||||||
Redis *redis.Redis
|
Redis *redis.Redis
|
||||||
DB *cassandra.CassandraDB
|
DB *cassandra.CassandraDB
|
||||||
|
KeySpace string
|
||||||
}
|
}
|
||||||
|
|
||||||
type BinanceRepository struct {
|
type BinanceRepository struct {
|
||||||
|
@ -61,6 +62,7 @@ func MustBinanceRepository(param BinanceRepositoryParam) repository.DataSourceRe
|
||||||
barrier: syncx.NewSingleFlight(),
|
barrier: syncx.NewSingleFlight(),
|
||||||
workerSize: param.Conf.WorkerSize,
|
workerSize: param.Conf.WorkerSize,
|
||||||
workers: workers,
|
workers: workers,
|
||||||
|
KeySpace: param.KeySpace,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -173,11 +175,32 @@ func (repo *BinanceRepository) FetchHistoryKline(ctx context.Context, param repo
|
||||||
}
|
}
|
||||||
|
|
||||||
func (repo *BinanceRepository) SaveHistoryKline(ctx context.Context, data []*entity.Kline) error {
|
func (repo *BinanceRepository) SaveHistoryKline(ctx context.Context, data []*entity.Kline) error {
|
||||||
|
ch := make(chan struct{}, repo.workerSize)
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
var errList []error
|
||||||
|
var mu sync.Mutex
|
||||||
|
|
||||||
for _, item := range data {
|
for _, item := range data {
|
||||||
err := repo.db.Insert(ctx, item, repo.KeySpace)
|
wg.Add(1)
|
||||||
if err != nil {
|
ch <- struct{}{} // block if max concurrency reached
|
||||||
logx.Errorf("failed to insert data: %v", item)
|
|
||||||
}
|
go func(k *entity.Kline) {
|
||||||
|
defer wg.Done()
|
||||||
|
defer func() { <-ch }()
|
||||||
|
|
||||||
|
if err := repo.db.Insert(ctx, k, repo.KeySpace); err != nil {
|
||||||
|
mu.Lock()
|
||||||
|
errList = append(errList, err)
|
||||||
|
mu.Unlock()
|
||||||
|
logx.Errorf("failed to insert data: %v", err)
|
||||||
|
}
|
||||||
|
}(item)
|
||||||
|
}
|
||||||
|
|
||||||
|
wg.Wait()
|
||||||
|
|
||||||
|
if len(errList) > 0 {
|
||||||
|
return fmt.Errorf("insert errors: %v", errList)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -28,9 +28,10 @@ func NewServiceContext(c config.Config) *ServiceContext {
|
||||||
}
|
}
|
||||||
|
|
||||||
binanceRepo := repo.MustBinanceRepository(repo.BinanceRepositoryParam{
|
binanceRepo := repo.MustBinanceRepository(repo.BinanceRepositoryParam{
|
||||||
Conf: &c.Binance,
|
Conf: &c.Binance,
|
||||||
Redis: newRedis,
|
Redis: newRedis,
|
||||||
DB: cassandra,
|
DB: cassandra,
|
||||||
|
KeySpace: c.Cassandra.Keyspace,
|
||||||
})
|
})
|
||||||
|
|
||||||
return &ServiceContext{
|
return &ServiceContext{
|
||||||
|
|
|
@ -28,7 +28,6 @@ func MustBinanceUseCase(param BinanceUseCaseParam) usecase.DataSourceUseCase {
|
||||||
func (use *BinanceUseCase) GetSymbols(ctx context.Context) ([]*usecase.Symbol, error) {
|
func (use *BinanceUseCase) GetSymbols(ctx context.Context) ([]*usecase.Symbol, error) {
|
||||||
result, err := use.BinanceRepo.GetSymbols(ctx)
|
result, err := use.BinanceRepo.GetSymbols(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// 錯誤代碼 20-201-04
|
|
||||||
e := errs.ThirdPartyErrorL(
|
e := errs.ThirdPartyErrorL(
|
||||||
blockchain.CodeBlockchain,
|
blockchain.CodeBlockchain,
|
||||||
blockchain.FailedToGetSymbolFormBinanceErrorCode,
|
blockchain.FailedToGetSymbolFormBinanceErrorCode,
|
||||||
|
@ -56,3 +55,42 @@ func (use *BinanceUseCase) GetSymbols(ctx context.Context) ([]*usecase.Symbol, e
|
||||||
|
|
||||||
return rpy, nil
|
return rpy, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (use *BinanceUseCase) UpsertKline(ctx context.Context, data usecase.QueryKline) error {
|
||||||
|
origianData, err := use.BinanceRepo.FetchHistoryKline(ctx, repository.QueryKline{
|
||||||
|
Symbol: data.Symbol,
|
||||||
|
Interval: data.Interval,
|
||||||
|
StartUnixNano: data.StartUnixNano,
|
||||||
|
EndUnixNano: data.EndUnixNano,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
e := errs.ThirdPartyErrorL(
|
||||||
|
blockchain.CodeBlockchain,
|
||||||
|
blockchain.FailedToUpsertBinanceErrorCode,
|
||||||
|
logx.WithContext(ctx),
|
||||||
|
[]logx.LogField{
|
||||||
|
{Key: "func", Value: "BinanceRepo.FetchHistoryKline"},
|
||||||
|
{Key: "err", Value: err.Error()},
|
||||||
|
},
|
||||||
|
"failed to get kline history from binance").Wrap(err)
|
||||||
|
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
|
||||||
|
err = use.BinanceRepo.SaveHistoryKline(ctx, origianData)
|
||||||
|
if err != nil {
|
||||||
|
e := errs.DatabaseErrorWithScopeL(
|
||||||
|
blockchain.CodeBlockchain,
|
||||||
|
blockchain.FailedToUpsertBinanceErrorCode,
|
||||||
|
logx.WithContext(ctx),
|
||||||
|
[]logx.LogField{
|
||||||
|
{Key: "func", Value: "BinanceRepo.SaveHistoryKline"},
|
||||||
|
{Key: "err", Value: err.Error()},
|
||||||
|
},
|
||||||
|
"failed save data from binance").Wrap(err)
|
||||||
|
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue