add get symbol repository

This commit is contained in:
王性驊 2025-08-04 22:02:01 +08:00
parent d587e95442
commit 436996d25d
16 changed files with 471 additions and 31 deletions

View File

@ -14,10 +14,16 @@ import (
)
type (
NoneReq = app_cloudep_blockchain.NoneReq
OKResp = app_cloudep_blockchain.OKResp
ListSymbolsRequest = app_cloudep_blockchain.ListSymbolsRequest
ListSymbolsResponse = app_cloudep_blockchain.ListSymbolsResponse
NoneReq = app_cloudep_blockchain.NoneReq
OKResp = app_cloudep_blockchain.OKResp
Symbol = app_cloudep_blockchain.Symbol
BlockchainService interface {
// ListSymbols retrieves all available trading symbols.
ListSymbols(ctx context.Context, in *ListSymbolsRequest, opts ...grpc.CallOption) (*ListSymbolsResponse, error)
// Ping is a health-check endpoint.
Ping(ctx context.Context, in *NoneReq, opts ...grpc.CallOption) (*OKResp, error)
}
@ -32,6 +38,13 @@ func NewBlockchainService(cli zrpc.Client) BlockchainService {
}
}
// ListSymbols retrieves all available trading symbols.
func (m *defaultBlockchainService) ListSymbols(ctx context.Context, in *ListSymbolsRequest, opts ...grpc.CallOption) (*ListSymbolsResponse, error) {
client := app_cloudep_blockchain.NewBlockchainServiceClient(m.cli.Conn())
return client.ListSymbols(ctx, in, opts...)
}
// Ping is a health-check endpoint.
func (m *defaultBlockchainService) Ping(ctx context.Context, in *NoneReq, opts ...grpc.CallOption) (*OKResp, error) {
client := app_cloudep_blockchain.NewBlockchainServiceClient(m.cli.Conn())
return client.Ping(ctx, in, opts...)

View File

@ -2,9 +2,13 @@ Name: blockchain.rpc
ListenOn: 0.0.0.0:8888
Etcd:
Hosts:
- 127.0.0.1:2379
- 10.0.0.19:2379
Key: blockchain.rpc
Binance:
Key: ""
Secret: ""
TestMode: true
TestMode: true
RedisCluster:
Host: 127.0.0.1:6379
Type: node

View File

@ -95,6 +95,174 @@ func (*NoneReq) Descriptor() ([]byte, []int) {
return file_generate_rpc_blockchain_proto_rawDescGZIP(), []int{1}
}
// ListSymbolsRequest is the request for the ListSymbols RPC.
// It is currently empty but can be extended with filtering or pagination fields in the future.
type ListSymbolsRequest struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ListSymbolsRequest) Reset() {
*x = ListSymbolsRequest{}
mi := &file_generate_rpc_blockchain_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ListSymbolsRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ListSymbolsRequest) ProtoMessage() {}
func (x *ListSymbolsRequest) ProtoReflect() protoreflect.Message {
mi := &file_generate_rpc_blockchain_proto_msgTypes[2]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ListSymbolsRequest.ProtoReflect.Descriptor instead.
func (*ListSymbolsRequest) Descriptor() ([]byte, []int) {
return file_generate_rpc_blockchain_proto_rawDescGZIP(), []int{2}
}
// ListSymbolsResponse contains a list of symbols.
type ListSymbolsResponse struct {
state protoimpl.MessageState `protogen:"open.v1"`
Symbols []*Symbol `protobuf:"bytes,1,rep,name=symbols,proto3" json:"symbols,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ListSymbolsResponse) Reset() {
*x = ListSymbolsResponse{}
mi := &file_generate_rpc_blockchain_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ListSymbolsResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ListSymbolsResponse) ProtoMessage() {}
func (x *ListSymbolsResponse) ProtoReflect() protoreflect.Message {
mi := &file_generate_rpc_blockchain_proto_msgTypes[3]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ListSymbolsResponse.ProtoReflect.Descriptor instead.
func (*ListSymbolsResponse) Descriptor() ([]byte, []int) {
return file_generate_rpc_blockchain_proto_rawDescGZIP(), []int{3}
}
func (x *ListSymbolsResponse) GetSymbols() []*Symbol {
if x != nil {
return x.Symbols
}
return nil
}
// Symbol represents information about a trading pair.
type Symbol struct {
state protoimpl.MessageState `protogen:"open.v1"`
Symbol string `protobuf:"bytes,1,opt,name=symbol,proto3" json:"symbol,omitempty"` // 交易對名稱 BTCUSDT
Status string `protobuf:"bytes,2,opt,name=status,proto3" json:"status,omitempty"` // 狀態(如 "TRADING" 表示可交易)
BaseAsset string `protobuf:"bytes,3,opt,name=base_asset,json=baseAsset,proto3" json:"base_asset,omitempty"` // 主幣種(如 BTCUSDT 的 BTC
BaseAssetPrecision int32 `protobuf:"varint,4,opt,name=base_asset_precision,json=baseAssetPrecision,proto3" json:"base_asset_precision,omitempty"` // 主幣的小數點精度
QuoteAsset string `protobuf:"bytes,5,opt,name=quote_asset,json=quoteAsset,proto3" json:"quote_asset,omitempty"` // 報價幣種(如 BTCUSDT 的 USDT
QuoteAssetPrecision int32 `protobuf:"varint,6,opt,name=quote_asset_precision,json=quoteAssetPrecision,proto3" json:"quote_asset_precision,omitempty"` // 報價資產顯示的小數位數
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *Symbol) Reset() {
*x = Symbol{}
mi := &file_generate_rpc_blockchain_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *Symbol) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Symbol) ProtoMessage() {}
func (x *Symbol) ProtoReflect() protoreflect.Message {
mi := &file_generate_rpc_blockchain_proto_msgTypes[4]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Symbol.ProtoReflect.Descriptor instead.
func (*Symbol) Descriptor() ([]byte, []int) {
return file_generate_rpc_blockchain_proto_rawDescGZIP(), []int{4}
}
func (x *Symbol) GetSymbol() string {
if x != nil {
return x.Symbol
}
return ""
}
func (x *Symbol) GetStatus() string {
if x != nil {
return x.Status
}
return ""
}
func (x *Symbol) GetBaseAsset() string {
if x != nil {
return x.BaseAsset
}
return ""
}
func (x *Symbol) GetBaseAssetPrecision() int32 {
if x != nil {
return x.BaseAssetPrecision
}
return 0
}
func (x *Symbol) GetQuoteAsset() string {
if x != nil {
return x.QuoteAsset
}
return ""
}
func (x *Symbol) GetQuoteAssetPrecision() int32 {
if x != nil {
return x.QuoteAssetPrecision
}
return 0
}
var File_generate_rpc_blockchain_proto protoreflect.FileDescriptor
const file_generate_rpc_blockchain_proto_rawDesc = "" +
@ -102,8 +270,21 @@ const file_generate_rpc_blockchain_proto_rawDesc = "" +
"\x1dgenerate/rpc/blockchain.proto\x12\n" +
"blockchain\"\b\n" +
"\x06OKResp\"\t\n" +
"\aNoneReq2D\n" +
"\x11BlockchainService\x12/\n" +
"\aNoneReq\"\x14\n" +
"\x12ListSymbolsRequest\"C\n" +
"\x13ListSymbolsResponse\x12,\n" +
"\asymbols\x18\x01 \x03(\v2\x12.blockchain.SymbolR\asymbols\"\xde\x01\n" +
"\x06Symbol\x12\x16\n" +
"\x06symbol\x18\x01 \x01(\tR\x06symbol\x12\x16\n" +
"\x06status\x18\x02 \x01(\tR\x06status\x12\x1d\n" +
"\n" +
"base_asset\x18\x03 \x01(\tR\tbaseAsset\x120\n" +
"\x14base_asset_precision\x18\x04 \x01(\x05R\x12baseAssetPrecision\x12\x1f\n" +
"\vquote_asset\x18\x05 \x01(\tR\n" +
"quoteAsset\x122\n" +
"\x15quote_asset_precision\x18\x06 \x01(\x05R\x13quoteAssetPrecision2\x94\x01\n" +
"\x11BlockchainService\x12N\n" +
"\vListSymbols\x12\x1e.blockchain.ListSymbolsRequest\x1a\x1f.blockchain.ListSymbolsResponse\x12/\n" +
"\x04Ping\x12\x13.blockchain.NoneReq\x1a\x12.blockchain.OKRespB.Z,code.30cm.net/digimon/app-cloudep-blockchainb\x06proto3"
var (
@ -118,19 +299,25 @@ func file_generate_rpc_blockchain_proto_rawDescGZIP() []byte {
return file_generate_rpc_blockchain_proto_rawDescData
}
var file_generate_rpc_blockchain_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
var file_generate_rpc_blockchain_proto_msgTypes = make([]protoimpl.MessageInfo, 5)
var file_generate_rpc_blockchain_proto_goTypes = []any{
(*OKResp)(nil), // 0: blockchain.OKResp
(*NoneReq)(nil), // 1: blockchain.NoneReq
(*OKResp)(nil), // 0: blockchain.OKResp
(*NoneReq)(nil), // 1: blockchain.NoneReq
(*ListSymbolsRequest)(nil), // 2: blockchain.ListSymbolsRequest
(*ListSymbolsResponse)(nil), // 3: blockchain.ListSymbolsResponse
(*Symbol)(nil), // 4: blockchain.Symbol
}
var file_generate_rpc_blockchain_proto_depIdxs = []int32{
1, // 0: blockchain.BlockchainService.Ping:input_type -> blockchain.NoneReq
0, // 1: blockchain.BlockchainService.Ping:output_type -> blockchain.OKResp
1, // [1:2] is the sub-list for method output_type
0, // [0:1] is the sub-list for method input_type
0, // [0:0] is the sub-list for extension type_name
0, // [0:0] is the sub-list for extension extendee
0, // [0:0] is the sub-list for field type_name
4, // 0: blockchain.ListSymbolsResponse.symbols:type_name -> blockchain.Symbol
2, // 1: blockchain.BlockchainService.ListSymbols:input_type -> blockchain.ListSymbolsRequest
1, // 2: blockchain.BlockchainService.Ping:input_type -> blockchain.NoneReq
3, // 3: blockchain.BlockchainService.ListSymbols:output_type -> blockchain.ListSymbolsResponse
0, // 4: blockchain.BlockchainService.Ping:output_type -> blockchain.OKResp
3, // [3:5] is the sub-list for method output_type
1, // [1:3] is the sub-list for method input_type
1, // [1:1] is the sub-list for extension type_name
1, // [1:1] is the sub-list for extension extendee
0, // [0:1] is the sub-list for field type_name
}
func init() { file_generate_rpc_blockchain_proto_init() }
@ -144,7 +331,7 @@ func file_generate_rpc_blockchain_proto_init() {
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_generate_rpc_blockchain_proto_rawDesc), len(file_generate_rpc_blockchain_proto_rawDesc)),
NumEnums: 0,
NumMessages: 2,
NumMessages: 5,
NumExtensions: 0,
NumServices: 1,
},

View File

@ -19,13 +19,17 @@ import (
const _ = grpc.SupportPackageIsVersion9
const (
BlockchainService_Ping_FullMethodName = "/blockchain.BlockchainService/Ping"
BlockchainService_ListSymbols_FullMethodName = "/blockchain.BlockchainService/ListSymbols"
BlockchainService_Ping_FullMethodName = "/blockchain.BlockchainService/Ping"
)
// BlockchainServiceClient is the client API for BlockchainService service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
type BlockchainServiceClient interface {
// ListSymbols retrieves all available trading symbols.
ListSymbols(ctx context.Context, in *ListSymbolsRequest, opts ...grpc.CallOption) (*ListSymbolsResponse, error)
// Ping is a health-check endpoint.
Ping(ctx context.Context, in *NoneReq, opts ...grpc.CallOption) (*OKResp, error)
}
@ -37,6 +41,16 @@ func NewBlockchainServiceClient(cc grpc.ClientConnInterface) BlockchainServiceCl
return &blockchainServiceClient{cc}
}
func (c *blockchainServiceClient) ListSymbols(ctx context.Context, in *ListSymbolsRequest, opts ...grpc.CallOption) (*ListSymbolsResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(ListSymbolsResponse)
err := c.cc.Invoke(ctx, BlockchainService_ListSymbols_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *blockchainServiceClient) Ping(ctx context.Context, in *NoneReq, opts ...grpc.CallOption) (*OKResp, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(OKResp)
@ -51,6 +65,9 @@ func (c *blockchainServiceClient) Ping(ctx context.Context, in *NoneReq, opts ..
// All implementations must embed UnimplementedBlockchainServiceServer
// for forward compatibility.
type BlockchainServiceServer interface {
// ListSymbols retrieves all available trading symbols.
ListSymbols(context.Context, *ListSymbolsRequest) (*ListSymbolsResponse, error)
// Ping is a health-check endpoint.
Ping(context.Context, *NoneReq) (*OKResp, error)
mustEmbedUnimplementedBlockchainServiceServer()
}
@ -62,6 +79,9 @@ type BlockchainServiceServer interface {
// pointer dereference when methods are called.
type UnimplementedBlockchainServiceServer struct{}
func (UnimplementedBlockchainServiceServer) ListSymbols(context.Context, *ListSymbolsRequest) (*ListSymbolsResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method ListSymbols not implemented")
}
func (UnimplementedBlockchainServiceServer) Ping(context.Context, *NoneReq) (*OKResp, error) {
return nil, status.Errorf(codes.Unimplemented, "method Ping not implemented")
}
@ -86,6 +106,24 @@ func RegisterBlockchainServiceServer(s grpc.ServiceRegistrar, srv BlockchainServ
s.RegisterService(&BlockchainService_ServiceDesc, srv)
}
func _BlockchainService_ListSymbols_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(ListSymbolsRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(BlockchainServiceServer).ListSymbols(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: BlockchainService_ListSymbols_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(BlockchainServiceServer).ListSymbols(ctx, req.(*ListSymbolsRequest))
}
return interceptor(ctx, in, info, handler)
}
func _BlockchainService_Ping_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(NoneReq)
if err := dec(in); err != nil {
@ -111,6 +149,10 @@ var BlockchainService_ServiceDesc = grpc.ServiceDesc{
ServiceName: "blockchain.BlockchainService",
HandlerType: (*BlockchainServiceServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "ListSymbols",
Handler: _BlockchainService_ListSymbols_Handler,
},
{
MethodName: "Ping",
Handler: _BlockchainService_Ping_Handler,

View File

@ -8,6 +8,27 @@ message OKResp {}
// NoneReq
message NoneReq {}
// ListSymbolsRequest is the request for the ListSymbols RPC.
// It is currently empty but can be extended with filtering or pagination fields in the future.
message ListSymbolsRequest {}
// ListSymbolsResponse contains a list of symbols.
message ListSymbolsResponse {
repeated Symbol symbols = 1;
}
// Symbol represents information about a trading pair.
message Symbol {
string symbol = 1; // BTCUSDT
string status = 2; // "TRADING"
string base_asset = 3; // BTCUSDT BTC
int32 base_asset_precision = 4; //
string quote_asset = 5; // BTCUSDT USDT
int32 quote_asset_precision = 6; //
}
service BlockchainService{
// ListSymbols retrieves all available trading symbols.
rpc ListSymbols(ListSymbolsRequest) returns(ListSymbolsResponse);
// Ping is a health-check endpoint.
rpc Ping(NoneReq) returns(OKResp);
}
}

1
go.mod
View File

@ -18,6 +18,7 @@ require (
)
require (
code.30cm.net/digimon/library-go/errs v1.2.14
github.com/adshao/go-binance/v2 v2.8.3
github.com/beorn7/perks v1.0.1 // indirect
github.com/cenkalti/backoff/v4 v4.3.0 // indirect

2
go.sum
View File

@ -1,3 +1,5 @@
code.30cm.net/digimon/library-go/errs v1.2.14 h1:Un9wcIIjjJW8D2i0ISf8ibzp9oNT4OqLsaSKW0T4RJU=
code.30cm.net/digimon/library-go/errs v1.2.14/go.mod h1:Hs4v7SbXNggDVBGXSYsFMjkii1qLF+rugrIpWePN4/o=
github.com/adshao/go-binance/v2 v2.8.3 h1:jwPRcX2u7FIO1pPoXgocyXpXhBI81A41kcmSDzS6uzo=
github.com/adshao/go-binance/v2 v2.8.3/go.mod h1:XkkuecSyJKPolaCGf/q4ovJYB3t0P+7RUYTbGr+LMGM=
github.com/alicebob/miniredis/v2 v2.35.0 h1:QwLphYqCEAo1eu1TqPRN2jgVMPBweeQcR21jeqDCONI=

View File

@ -1,10 +1,15 @@
package config
import "github.com/zeromicro/go-zero/zrpc"
import (
"github.com/zeromicro/go-zero/core/stores/redis"
"github.com/zeromicro/go-zero/zrpc"
)
type Config struct {
zrpc.RpcServerConf
Binance
Binance Binance
// Redis Cluster
RedisCluster redis.RedisConf
}
type Binance struct {

View File

@ -0,0 +1,7 @@
package blockchain
import "code.30cm.net/digimon/library-go/errs"
const CodeBlockchain uint32 = 10
const FailedToGetSymbolFormBinanceErrorCode errs.ErrorCode = 1

View File

@ -6,5 +6,5 @@ import (
)
type DataSourceRepository interface {
GetSymbols(ctx context.Context) ([]entity.Symbol, error)
GetSymbols(ctx context.Context) ([]*entity.Symbol, error)
}

View File

@ -0,0 +1,19 @@
package usecase
import (
"context"
)
type DataSourceUseCase interface {
GetSymbols(ctx context.Context) ([]*Symbol, error)
}
// Symbol 代表交易對資訊
type Symbol struct {
Symbol string `json:"symbol"` // 交易對名稱 BTCUSDT
Status string `json:"status"` // 狀態(如 "TRADING" 表示可交易)
BaseAsset string `json:"base_asset"` // 主幣種(如 BTCUSDT 的 BTC
BaseAssetPrecision int `json:"base_asset_precision"` // 主幣的小數點精度
QuoteAsset string `json:"quote_asset"` // 報價幣種(如 BTCUSDT 的 USDT
QuoteAssetPrecision int `json:"quote_asset_precision"` // 報價資產顯示的小數位數
}

View File

@ -0,0 +1,49 @@
package blockchainservicelogic
import (
"context"
app_cloudep_blockchain "blockchain/gen_result/pb/code.30cm.net/digimon/app-cloudep-blockchain"
"blockchain/internal/svc"
"github.com/zeromicro/go-zero/core/logx"
)
type ListSymbolsLogic struct {
ctx context.Context
svcCtx *svc.ServiceContext
logx.Logger
}
func NewListSymbolsLogic(ctx context.Context, svcCtx *svc.ServiceContext) *ListSymbolsLogic {
return &ListSymbolsLogic{
ctx: ctx,
svcCtx: svcCtx,
Logger: logx.WithContext(ctx),
}
}
// ListSymbols retrieves all available trading symbols.
func (l *ListSymbolsLogic) ListSymbols(in *app_cloudep_blockchain.ListSymbolsRequest) (*app_cloudep_blockchain.ListSymbolsResponse, error) {
result, err := l.svcCtx.BinanceDataSource.GetSymbols(l.ctx)
if err != nil {
return nil, err
}
rpy := make([]*app_cloudep_blockchain.Symbol, 0, len(result))
for _, item := range result {
rpy = append(rpy, &app_cloudep_blockchain.Symbol{
Symbol: item.Symbol,
Status: item.Status,
BaseAsset: item.BaseAsset,
BaseAssetPrecision: int32(item.BaseAssetPrecision),
QuoteAsset: item.QuoteAsset,
QuoteAssetPrecision: int32(item.QuoteAssetPrecision),
})
}
return &app_cloudep_blockchain.ListSymbolsResponse{
Symbols: rpy,
}, nil
}

View File

@ -41,16 +41,16 @@ func MustBinanceRepository(param BinanceRepositoryParam) repository.DataSourceRe
}
}
func (repo *BinanceRepository) GetSymbols(ctx context.Context) ([]entity.Symbol, error) {
func (repo *BinanceRepository) GetSymbols(ctx context.Context) ([]*entity.Symbol, error) {
// 優先從 redis hash 拿
cached, err := repo.rds.Hgetall(blockchain.RedisKeySymbolList)
if err == nil && len(cached) > 0 {
symbols := make([]entity.Symbol, 0, len(cached))
symbols := make([]*entity.Symbol, 0, len(cached))
canUseCache := true
for _, v := range cached {
var symbol entity.Symbol
if err := json.Unmarshal([]byte(v), &symbol); err == nil {
symbols = append(symbols, symbol)
symbols = append(symbols, &symbol)
} else {
// 如果任何一個反序列化失敗,代表快取可能已損壞,最好是回源重新拉取
canUseCache = false
@ -68,11 +68,11 @@ func (repo *BinanceRepository) GetSymbols(ctx context.Context) ([]entity.Symbol,
if err != nil {
return nil, err
}
result := make([]entity.Symbol, 0, len(srcSymbols))
result := make([]*entity.Symbol, 0, len(srcSymbols))
hashData := make(map[string]string, len(srcSymbols))
for _, s := range srcSymbols {
// 只挑目前需要的欄位
symbolEntity := entity.Symbol{
symbolEntity := &entity.Symbol{
Symbol: s.Symbol,
Status: s.Status,
BaseAsset: s.BaseAsset,
@ -106,7 +106,7 @@ func (repo *BinanceRepository) GetSymbols(ctx context.Context) ([]entity.Symbol,
return nil, err
}
return val.([]entity.Symbol), nil
return val.([]*entity.Symbol), nil
}
func (repo *BinanceRepository) getSymbolsFromSource(ctx context.Context) ([]binance.Symbol, error) {

View File

@ -23,6 +23,13 @@ func NewBlockchainServiceServer(svcCtx *svc.ServiceContext) *BlockchainServiceSe
}
}
// ListSymbols retrieves all available trading symbols.
func (s *BlockchainServiceServer) ListSymbols(ctx context.Context, in *app_cloudep_blockchain.ListSymbolsRequest) (*app_cloudep_blockchain.ListSymbolsResponse, error) {
l := blockchainservicelogic.NewListSymbolsLogic(ctx, s.svcCtx)
return l.ListSymbols(in)
}
// Ping is a health-check endpoint.
func (s *BlockchainServiceServer) Ping(ctx context.Context, in *app_cloudep_blockchain.NoneReq) (*app_cloudep_blockchain.OKResp, error) {
l := blockchainservicelogic.NewPingLogic(ctx, s.svcCtx)
return l.Ping(in)

View File

@ -1,13 +1,37 @@
package svc
import "blockchain/internal/config"
import (
"blockchain/internal/config"
"blockchain/internal/domain/repository"
"blockchain/internal/domain/usecase"
repo "blockchain/internal/repository"
uc "blockchain/internal/usecase"
"github.com/zeromicro/go-zero/core/stores/redis"
)
type ServiceContext struct {
Config config.Config
Config config.Config
BinanceDataSource usecase.DataSourceUseCase
BinanceRepo repository.DataSourceRepository
}
func NewServiceContext(c config.Config) *ServiceContext {
newRedis, err := redis.NewRedis(c.RedisCluster)
if err != nil {
panic(err)
}
binanceRepo := repo.MustBinanceRepository(repo.BinanceRepositoryParam{
Conf: &c.Binance,
Redis: newRedis,
})
return &ServiceContext{
Config: c,
Config: c,
BinanceRepo: binanceRepo,
BinanceDataSource: uc.MustBinanceUseCase(uc.BinanceUseCaseParam{
BinanceRepo: binanceRepo,
}),
}
}

View File

@ -0,0 +1,59 @@
package usecase
import (
"blockchain/internal/domain/blockchain"
"blockchain/internal/domain/repository"
"blockchain/internal/domain/usecase"
"context"
"code.30cm.net/digimon/library-go/errs"
"github.com/zeromicro/go-zero/core/logx"
)
type BinanceUseCaseParam struct {
BinanceRepo repository.DataSourceRepository
}
type BinanceUseCase struct {
BinanceUseCaseParam
}
func MustBinanceUseCase(param BinanceUseCaseParam) usecase.DataSourceUseCase {
return &BinanceUseCase{
BinanceUseCaseParam: param,
}
}
// GetSymbols implements usecase.DataSourceUseCase.
func (use *BinanceUseCase) GetSymbols(ctx context.Context) ([]*usecase.Symbol, error) {
result, err := use.BinanceRepo.GetSymbols(ctx)
if err != nil {
// 錯誤代碼 20-201-04
e := errs.ThirdPartyErrorL(
blockchain.CodeBlockchain,
blockchain.FailedToGetSymbolFormBinanceErrorCode,
logx.WithContext(ctx),
[]logx.LogField{
{Key: "func", Value: "BinanceUseCase.ThirdPartyErrorL"},
{Key: "err", Value: err.Error()},
},
"failed to get symbols from binance").Wrap(err)
return nil, e
}
rpy := make([]*usecase.Symbol, len(result))
for _, item := range result {
rpy = append(rpy, &usecase.Symbol{
Symbol: item.Symbol,
Status: item.Status,
BaseAsset: item.BaseAsset,
BaseAssetPrecision: item.BaseAssetPrecision,
QuoteAsset: item.QuoteAsset,
QuoteAssetPrecision: item.QuoteAssetPrecision,
})
}
return rpy, nil
}