From 0e82059e44fdc2f56dd5fd6ae2ec4d94ef70b9a8 Mon Sep 17 00:00:00 2001 From: lbank Date: Mon, 1 Apr 2024 21:08:39 +0800 Subject: [PATCH] init --- .gitignore | 3 + README.md | 0 examples/account/hmac/account.go | 77 +++++++++ examples/account/rsa/account.go | 77 +++++++++ examples/base/hmac/base.go | 27 +++ examples/base/rsa/base.go | 26 +++ examples/market/rsa/market.go | 26 +++ examples/order/rsa/order.go | 26 +++ examples/spot/rsa/spot.go | 29 ++++ examples/wallet/rsa/wallet.go | 26 +++ examples/withdraw/rsa/withdraw.go | 26 +++ examples/wsapi/market/market.go | 15 ++ go.mod | 21 +++ go.sum | 31 ++++ pkg/log.go | 55 ++++++ pkg/utils.go | 161 +++++++++++++++++ sve/account.go | 42 +++++ sve/base.go | 72 ++++++++ sve/client.go | 73 ++++++++ sve/httpservice.go | 277 ++++++++++++++++++++++++++++++ sve/market.go | 27 +++ sve/order.go | 60 +++++++ sve/settings.go | 82 +++++++++ sve/spot.go | 53 ++++++ sve/wallet.go | 60 +++++++ sve/withdraw.go | 24 +++ sve/ws.go | 73 ++++++++ sve/wsapimarket.go.go | 26 +++ sve/wsclient.go | 47 +++++ version.go | 5 + 30 files changed, 1547 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 examples/account/hmac/account.go create mode 100644 examples/account/rsa/account.go create mode 100644 examples/base/hmac/base.go create mode 100644 examples/base/rsa/base.go create mode 100644 examples/market/rsa/market.go create mode 100644 examples/order/rsa/order.go create mode 100644 examples/spot/rsa/spot.go create mode 100644 examples/wallet/rsa/wallet.go create mode 100644 examples/withdraw/rsa/withdraw.go create mode 100644 examples/wsapi/market/market.go create mode 100644 go.mod create mode 100644 go.sum create mode 100644 pkg/log.go create mode 100644 pkg/utils.go create mode 100644 sve/account.go create mode 100644 sve/base.go create mode 100644 sve/client.go create mode 100644 sve/httpservice.go create mode 100644 sve/market.go create mode 100644 sve/order.go create mode 100644 sve/settings.go create mode 100644 sve/spot.go create mode 100644 sve/wallet.go create mode 100644 sve/withdraw.go create mode 100644 sve/ws.go create mode 100644 sve/wsapimarket.go.go create mode 100644 sve/wsclient.go create mode 100644 version.go diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ad07450 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +.idea/* +*.log +logs/* \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..e69de29 diff --git a/examples/account/hmac/account.go b/examples/account/hmac/account.go new file mode 100644 index 0000000..34cf948 --- /dev/null +++ b/examples/account/hmac/account.go @@ -0,0 +1,77 @@ +package main + +import ( + "lbank_connector_go/sve" +) + +// rsa +const ( + apiKey = "44b9cdf2-6c66-4f57-a551-a80dbc42542d" + secretKey = "71CE6CF6E03A51C61AA6F94A453443E8" +) + +var client = sve.NewClient(apiKey, secretKey) + +func TestUserInfo() { + client.Debug = true + client.SetHost(sve.LbankApiHost) + data := map[string]string{} + client.NewAccountService().UserInfo(data) +} + +func TestSubscribeGetKey() { + client.Debug = true + client.SetHost(sve.LbankApiHost) + data := map[string]string{} + client.NewAccountService().SubscribeGetKey(data) +} + +func TestSubscribeRefreshKey() { + client.Debug = true + client.SetHost(sve.LbankApiHost) + data := map[string]string{ + "subscribeKey": "32a6ece19c591f1791cc07ba570db4dd00a4ab7bb32f0f3adc7969b4c9e2e2f0", + } + client.NewAccountService().SubscribeRefreshKey(data) +} + +func TestSubscribeDestroyKey() { + client.Debug = true + client.SetHost(sve.LbankApiHost) + data := map[string]string{ + "subscribeKey": "32a6ece19c591f1791cc07ba570db4dd00a4ab7bb32f0f3adc7969b4c9e2e2f0", + } + client.NewAccountService().SubscribeDestroyKey(data) +} + +func TestGetDepositAddress() { + client.Debug = true + client.SetHost(sve.LbankApiHost) + data := map[string]string{ + "assetCode": "BTC", + "netWork": "", + } + client.NewAccountService().GetDepositAddress(data) +} + +func TestDepositHistory() { + client.Debug = true + client.SetHost(sve.LbankApiHost) + data := map[string]string{ + "assetCode": "", + "startTime": "", + "endTime": "", + "pageNo": "1", + "pageSize": "10", + } + client.NewAccountService().DepositHistory(data) +} + +func main() { + TestUserInfo() + //TestSubscribeGetKey() + //TestSubscribeRefreshKey() + //TestSubscribeDestroyKey() + //TestGetDepositAddress() + //TestDepositHistory() +} diff --git a/examples/account/rsa/account.go b/examples/account/rsa/account.go new file mode 100644 index 0000000..38e97ed --- /dev/null +++ b/examples/account/rsa/account.go @@ -0,0 +1,77 @@ +package main + +import ( + "lbank_connector_go/sve" +) + +// rsa +const ( + apiKey = "1cc62cfb-2f36-4ac9-b5fb-2c40138db8ab" + secretKey = "MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBAILOdckXVqiMcLEdpockDZ1bLQc/XDlFxBSXMenZaok1PGljO6j2f45+PRH4X1tls78FHLBjCE4uizJb9kcd6uQTDCV9mMU4Tqyy9hflI1xt4K+u2Oxi+2z+NgrIOQXBazaZ+SJ1t1NMK5DhR7QUMPqMUg+JX7e2Xv89xOTiSfU1AgMBAAECgYB+OtcXs9oA1WZ6xW5Kw9QPokkV0WMiMd1DMZUNYq6YsjMWUJjmONpnnBM7IECFZuPK1xgUb704FVpmwrAreQeOpkS8i8PegP0yB/uaQAw1RYmnhOVpeJJPpHaLBwgSNP+EBBzi8/2ZYJPNbXaQm19QC0Y2grYMz35Z8Ro8zdF4gQJBAMvV5LRS1mSDpn6GG6APv/DjEblgaOAV4RWE1OJNxM3o8FeP41XPJMal6mX6YqwNVIvUFEv9ukiOiWmxrwrwRkkCQQCkSCINnWOQFRpsRkSIZ/ZgAz9PhdRcyIfqKCMstfaYu9SMubBD/rsJZSV27i+bmGwTR/Gmm4T51vadq/NwzUeNAkEAjnIYlKe7KZ0S8iJ4FcBL62RT0497WvYPSQF93/RnD1q08wwb27CZy7TQ/Jkg8YmTRvBbistyrhfmEZXZdLR6+QJBAIlKIvM/0cHKcQ+FVaatQy+P5yvdCtETYMpmCqdF1jRj3EhSsiTQz5wVZE7U1QJySfd/C0sR8vocFHNGDSb61s0CQQDLhsj7WLHTxZKiBvhxuXIwebQOVoqFomeAPloAMs2JUgIKqGXgVcByII2WiROmpWWx/W1ZfRxtHdD62v2BYBEI" +) + +var client = sve.NewClient(apiKey, secretKey) + +func TestUserInfo() { + client.Debug = true + client.SetHost(sve.LbankApiHost) + data := map[string]string{} + client.NewAccountService().UserInfo(data) +} + +func TestSubscribeGetKey() { + client.Debug = true + client.SetHost(sve.LbankApiHost) + data := map[string]string{} + client.NewAccountService().SubscribeGetKey(data) +} + +func TestSubscribeRefreshKey() { + client.Debug = true + client.SetHost(sve.LbankApiHost) + data := map[string]string{ + "subscribeKey": "32a6ece19c591f1791cc07ba570db4dd00a4ab7bb32f0f3adc7969b4c9e2e2f0", + } + client.NewAccountService().SubscribeRefreshKey(data) +} + +func TestSubscribeDestroyKey() { + client.Debug = true + client.SetHost(sve.LbankApiHost) + data := map[string]string{ + "subscribeKey": "32a6ece19c591f1791cc07ba570db4dd00a4ab7bb32f0f3adc7969b4c9e2e2f0", + } + client.NewAccountService().SubscribeDestroyKey(data) +} + +func TestGetDepositAddress() { + client.Debug = true + client.SetHost(sve.LbankApiHost) + data := map[string]string{ + "assetCode": "BTC", + "netWork": "", + } + client.NewAccountService().GetDepositAddress(data) +} + +func TestDepositHistory() { + client.Debug = true + client.SetHost(sve.LbankApiHost) + data := map[string]string{ + "assetCode": "", + "startTime": "", + "endTime": "", + "pageNo": "1", + "pageSize": "10", + } + client.NewAccountService().DepositHistory(data) +} + +func main() { + TestUserInfo() + //TestSubscribeGetKey() + //TestSubscribeRefreshKey() + //TestSubscribeDestroyKey() + //TestGetDepositAddress() + //TestDepositHistory() +} diff --git a/examples/base/hmac/base.go b/examples/base/hmac/base.go new file mode 100644 index 0000000..1a6ca56 --- /dev/null +++ b/examples/base/hmac/base.go @@ -0,0 +1,27 @@ +package main + +import ( + "lbank_connector_go/sve" +) + +// SHA256 +const ( + apiKey = "44b9cdf2-6c66-4f57-a551-a80dbc42542d" + secretKey = "71CE6CF6E03A51C61AA6F94A453443E8" +) + +var client = sve.NewClient(apiKey, secretKey) + +func TestAccuracy() { + client.Debug = true + client.SetHost(sve.LbankApiHost) + data := map[string]string{ + "symbol": "lbk_usdt", + "size": "1", + } + client.NewBaseService().Accuracy(data) +} + +func main() { + TestAccuracy() +} diff --git a/examples/base/rsa/base.go b/examples/base/rsa/base.go new file mode 100644 index 0000000..6a980bb --- /dev/null +++ b/examples/base/rsa/base.go @@ -0,0 +1,26 @@ +package main + +import ( + "lbank_connector_go/sve" +) + +const ( + apiKey = "1cc62cfb-2f36-4ac9-b5fb-2c40138db8ab" + secretKey = "MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBAILOdckXVqiMcLEdpockDZ1bLQc/XDlFxBSXMenZaok1PGljO6j2f45+PRH4X1tls78FHLBjCE4uizJb9kcd6uQTDCV9mMU4Tqyy9hflI1xt4K+u2Oxi+2z+NgrIOQXBazaZ+SJ1t1NMK5DhR7QUMPqMUg+JX7e2Xv89xOTiSfU1AgMBAAECgYB+OtcXs9oA1WZ6xW5Kw9QPokkV0WMiMd1DMZUNYq6YsjMWUJjmONpnnBM7IECFZuPK1xgUb704FVpmwrAreQeOpkS8i8PegP0yB/uaQAw1RYmnhOVpeJJPpHaLBwgSNP+EBBzi8/2ZYJPNbXaQm19QC0Y2grYMz35Z8Ro8zdF4gQJBAMvV5LRS1mSDpn6GG6APv/DjEblgaOAV4RWE1OJNxM3o8FeP41XPJMal6mX6YqwNVIvUFEv9ukiOiWmxrwrwRkkCQQCkSCINnWOQFRpsRkSIZ/ZgAz9PhdRcyIfqKCMstfaYu9SMubBD/rsJZSV27i+bmGwTR/Gmm4T51vadq/NwzUeNAkEAjnIYlKe7KZ0S8iJ4FcBL62RT0497WvYPSQF93/RnD1q08wwb27CZy7TQ/Jkg8YmTRvBbistyrhfmEZXZdLR6+QJBAIlKIvM/0cHKcQ+FVaatQy+P5yvdCtETYMpmCqdF1jRj3EhSsiTQz5wVZE7U1QJySfd/C0sR8vocFHNGDSb61s0CQQDLhsj7WLHTxZKiBvhxuXIwebQOVoqFomeAPloAMs2JUgIKqGXgVcByII2WiROmpWWx/W1ZfRxtHdD62v2BYBEI" +) + +var client = sve.NewClient(apiKey, secretKey) + +func TestAccuracy() { + client.Debug = true + client.SetHost(sve.LbankApiHost) + data := map[string]string{ + "symbol": "lbk_usdt", + "size": "1", + } + client.NewBaseService().Accuracy(data) +} + +func main() { + TestAccuracy() +} diff --git a/examples/market/rsa/market.go b/examples/market/rsa/market.go new file mode 100644 index 0000000..c09e947 --- /dev/null +++ b/examples/market/rsa/market.go @@ -0,0 +1,26 @@ +package main + +import ( + "lbank_connector_go/sve" +) + +const ( + apiKey = "1cc62cfb-2f36-4ac9-b5fb-2c40138db8ab" + secretKey = "MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBAILOdckXVqiMcLEdpockDZ1bLQc/XDlFxBSXMenZaok1PGljO6j2f45+PRH4X1tls78FHLBjCE4uizJb9kcd6uQTDCV9mMU4Tqyy9hflI1xt4K+u2Oxi+2z+NgrIOQXBazaZ+SJ1t1NMK5DhR7QUMPqMUg+JX7e2Xv89xOTiSfU1AgMBAAECgYB+OtcXs9oA1WZ6xW5Kw9QPokkV0WMiMd1DMZUNYq6YsjMWUJjmONpnnBM7IECFZuPK1xgUb704FVpmwrAreQeOpkS8i8PegP0yB/uaQAw1RYmnhOVpeJJPpHaLBwgSNP+EBBzi8/2ZYJPNbXaQm19QC0Y2grYMz35Z8Ro8zdF4gQJBAMvV5LRS1mSDpn6GG6APv/DjEblgaOAV4RWE1OJNxM3o8FeP41XPJMal6mX6YqwNVIvUFEv9ukiOiWmxrwrwRkkCQQCkSCINnWOQFRpsRkSIZ/ZgAz9PhdRcyIfqKCMstfaYu9SMubBD/rsJZSV27i+bmGwTR/Gmm4T51vadq/NwzUeNAkEAjnIYlKe7KZ0S8iJ4FcBL62RT0497WvYPSQF93/RnD1q08wwb27CZy7TQ/Jkg8YmTRvBbistyrhfmEZXZdLR6+QJBAIlKIvM/0cHKcQ+FVaatQy+P5yvdCtETYMpmCqdF1jRj3EhSsiTQz5wVZE7U1QJySfd/C0sR8vocFHNGDSb61s0CQQDLhsj7WLHTxZKiBvhxuXIwebQOVoqFomeAPloAMs2JUgIKqGXgVcByII2WiROmpWWx/W1ZfRxtHdD62v2BYBEI" +) + +var client = sve.NewClient(apiKey, secretKey) + +func TestDepth() { + client.Debug = true + client.SetHost(sve.LbankApiHost) + data := map[string]string{ + "symbol": "lbk_usdt", + "size": "1", + } + client.NewMarketService().Depth(data) +} + +func main() { + TestDepth() +} diff --git a/examples/order/rsa/order.go b/examples/order/rsa/order.go new file mode 100644 index 0000000..db2daeb --- /dev/null +++ b/examples/order/rsa/order.go @@ -0,0 +1,26 @@ +package main + +import ( + "lbank_connector_go/sve" +) + +const ( + apiKey = "1cc62cfb-2f36-4ac9-b5fb-2c40138db8ab" + secretKey = "MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBAILOdckXVqiMcLEdpockDZ1bLQc/XDlFxBSXMenZaok1PGljO6j2f45+PRH4X1tls78FHLBjCE4uizJb9kcd6uQTDCV9mMU4Tqyy9hflI1xt4K+u2Oxi+2z+NgrIOQXBazaZ+SJ1t1NMK5DhR7QUMPqMUg+JX7e2Xv89xOTiSfU1AgMBAAECgYB+OtcXs9oA1WZ6xW5Kw9QPokkV0WMiMd1DMZUNYq6YsjMWUJjmONpnnBM7IECFZuPK1xgUb704FVpmwrAreQeOpkS8i8PegP0yB/uaQAw1RYmnhOVpeJJPpHaLBwgSNP+EBBzi8/2ZYJPNbXaQm19QC0Y2grYMz35Z8Ro8zdF4gQJBAMvV5LRS1mSDpn6GG6APv/DjEblgaOAV4RWE1OJNxM3o8FeP41XPJMal6mX6YqwNVIvUFEv9ukiOiWmxrwrwRkkCQQCkSCINnWOQFRpsRkSIZ/ZgAz9PhdRcyIfqKCMstfaYu9SMubBD/rsJZSV27i+bmGwTR/Gmm4T51vadq/NwzUeNAkEAjnIYlKe7KZ0S8iJ4FcBL62RT0497WvYPSQF93/RnD1q08wwb27CZy7TQ/Jkg8YmTRvBbistyrhfmEZXZdLR6+QJBAIlKIvM/0cHKcQ+FVaatQy+P5yvdCtETYMpmCqdF1jRj3EhSsiTQz5wVZE7U1QJySfd/C0sR8vocFHNGDSb61s0CQQDLhsj7WLHTxZKiBvhxuXIwebQOVoqFomeAPloAMs2JUgIKqGXgVcByII2WiROmpWWx/W1ZfRxtHdD62v2BYBEI" +) + +var client = sve.NewClient(apiKey, secretKey) + +func TestCreateOrder() { + client.Debug = true + client.SetHost(sve.LbankApiHost) + data := map[string]string{ + "symbol": "lbk_usdt", + "size": "1", + } + client.NewOrderService().CreateOrder(data) +} + +func main() { + TestCreateOrder() +} diff --git a/examples/spot/rsa/spot.go b/examples/spot/rsa/spot.go new file mode 100644 index 0000000..6c642ee --- /dev/null +++ b/examples/spot/rsa/spot.go @@ -0,0 +1,29 @@ +package main + +import ( + "lbank_connector_go/sve" +) + +const ( + apiKey = "1cc62cfb-2f36-4ac9-b5fb-2c40138db8ab" + secretKey = "MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBAILOdckXVqiMcLEdpockDZ1bLQc/XDlFxBSXMenZaok1PGljO6j2f45+PRH4X1tls78FHLBjCE4uizJb9kcd6uQTDCV9mMU4Tqyy9hflI1xt4K+u2Oxi+2z+NgrIOQXBazaZ+SJ1t1NMK5DhR7QUMPqMUg+JX7e2Xv89xOTiSfU1AgMBAAECgYB+OtcXs9oA1WZ6xW5Kw9QPokkV0WMiMd1DMZUNYq6YsjMWUJjmONpnnBM7IECFZuPK1xgUb704FVpmwrAreQeOpkS8i8PegP0yB/uaQAw1RYmnhOVpeJJPpHaLBwgSNP+EBBzi8/2ZYJPNbXaQm19QC0Y2grYMz35Z8Ro8zdF4gQJBAMvV5LRS1mSDpn6GG6APv/DjEblgaOAV4RWE1OJNxM3o8FeP41XPJMal6mX6YqwNVIvUFEv9ukiOiWmxrwrwRkkCQQCkSCINnWOQFRpsRkSIZ/ZgAz9PhdRcyIfqKCMstfaYu9SMubBD/rsJZSV27i+bmGwTR/Gmm4T51vadq/NwzUeNAkEAjnIYlKe7KZ0S8iJ4FcBL62RT0497WvYPSQF93/RnD1q08wwb27CZy7TQ/Jkg8YmTRvBbistyrhfmEZXZdLR6+QJBAIlKIvM/0cHKcQ+FVaatQy+P5yvdCtETYMpmCqdF1jRj3EhSsiTQz5wVZE7U1QJySfd/C0sR8vocFHNGDSb61s0CQQDLhsj7WLHTxZKiBvhxuXIwebQOVoqFomeAPloAMs2JUgIKqGXgVcByII2WiROmpWWx/W1ZfRxtHdD62v2BYBEI" +) + +var client = sve.NewClient(apiKey, secretKey) + +func TestCreateOrder() { + client.Debug = true + client.SetHost(sve.LbankApiHost) + data := map[string]string{ + "symbol": "lbk_usdt", + "type": "buy", + "price": "0.01", + "amount": "1", + "custom_id": "test", + } + client.NewSpotService().CreateOrder(data) +} + +func main() { + TestCreateOrder() +} diff --git a/examples/wallet/rsa/wallet.go b/examples/wallet/rsa/wallet.go new file mode 100644 index 0000000..7c16b95 --- /dev/null +++ b/examples/wallet/rsa/wallet.go @@ -0,0 +1,26 @@ +package main + +import ( + "lbank_connector_go/sve" +) + +const ( + apiKey = "1cc62cfb-2f36-4ac9-b5fb-2c40138db8ab" + secretKey = "MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBAILOdckXVqiMcLEdpockDZ1bLQc/XDlFxBSXMenZaok1PGljO6j2f45+PRH4X1tls78FHLBjCE4uizJb9kcd6uQTDCV9mMU4Tqyy9hflI1xt4K+u2Oxi+2z+NgrIOQXBazaZ+SJ1t1NMK5DhR7QUMPqMUg+JX7e2Xv89xOTiSfU1AgMBAAECgYB+OtcXs9oA1WZ6xW5Kw9QPokkV0WMiMd1DMZUNYq6YsjMWUJjmONpnnBM7IECFZuPK1xgUb704FVpmwrAreQeOpkS8i8PegP0yB/uaQAw1RYmnhOVpeJJPpHaLBwgSNP+EBBzi8/2ZYJPNbXaQm19QC0Y2grYMz35Z8Ro8zdF4gQJBAMvV5LRS1mSDpn6GG6APv/DjEblgaOAV4RWE1OJNxM3o8FeP41XPJMal6mX6YqwNVIvUFEv9ukiOiWmxrwrwRkkCQQCkSCINnWOQFRpsRkSIZ/ZgAz9PhdRcyIfqKCMstfaYu9SMubBD/rsJZSV27i+bmGwTR/Gmm4T51vadq/NwzUeNAkEAjnIYlKe7KZ0S8iJ4FcBL62RT0497WvYPSQF93/RnD1q08wwb27CZy7TQ/Jkg8YmTRvBbistyrhfmEZXZdLR6+QJBAIlKIvM/0cHKcQ+FVaatQy+P5yvdCtETYMpmCqdF1jRj3EhSsiTQz5wVZE7U1QJySfd/C0sR8vocFHNGDSb61s0CQQDLhsj7WLHTxZKiBvhxuXIwebQOVoqFomeAPloAMs2JUgIKqGXgVcByII2WiROmpWWx/W1ZfRxtHdD62v2BYBEI" +) + +var client = sve.NewClient(apiKey, secretKey) + +func TestSupplementApiRestrictions() { + client.Debug = true + client.SetHost(sve.LbankApiHost) + data := map[string]string{ + "symbol": "lbk_usdt", + "size": "1", + } + client.NewWalletService().SupplementApiRestrictions(data) +} + +func main() { + TestSupplementApiRestrictions() +} diff --git a/examples/withdraw/rsa/withdraw.go b/examples/withdraw/rsa/withdraw.go new file mode 100644 index 0000000..b320bed --- /dev/null +++ b/examples/withdraw/rsa/withdraw.go @@ -0,0 +1,26 @@ +package main + +import ( + "lbank_connector_go/sve" +) + +const ( + apiKey = "1cc62cfb-2f36-4ac9-b5fb-2c40138db8ab" + secretKey = "MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBAILOdckXVqiMcLEdpockDZ1bLQc/XDlFxBSXMenZaok1PGljO6j2f45+PRH4X1tls78FHLBjCE4uizJb9kcd6uQTDCV9mMU4Tqyy9hflI1xt4K+u2Oxi+2z+NgrIOQXBazaZ+SJ1t1NMK5DhR7QUMPqMUg+JX7e2Xv89xOTiSfU1AgMBAAECgYB+OtcXs9oA1WZ6xW5Kw9QPokkV0WMiMd1DMZUNYq6YsjMWUJjmONpnnBM7IECFZuPK1xgUb704FVpmwrAreQeOpkS8i8PegP0yB/uaQAw1RYmnhOVpeJJPpHaLBwgSNP+EBBzi8/2ZYJPNbXaQm19QC0Y2grYMz35Z8Ro8zdF4gQJBAMvV5LRS1mSDpn6GG6APv/DjEblgaOAV4RWE1OJNxM3o8FeP41XPJMal6mX6YqwNVIvUFEv9ukiOiWmxrwrwRkkCQQCkSCINnWOQFRpsRkSIZ/ZgAz9PhdRcyIfqKCMstfaYu9SMubBD/rsJZSV27i+bmGwTR/Gmm4T51vadq/NwzUeNAkEAjnIYlKe7KZ0S8iJ4FcBL62RT0497WvYPSQF93/RnD1q08wwb27CZy7TQ/Jkg8YmTRvBbistyrhfmEZXZdLR6+QJBAIlKIvM/0cHKcQ+FVaatQy+P5yvdCtETYMpmCqdF1jRj3EhSsiTQz5wVZE7U1QJySfd/C0sR8vocFHNGDSb61s0CQQDLhsj7WLHTxZKiBvhxuXIwebQOVoqFomeAPloAMs2JUgIKqGXgVcByII2WiROmpWWx/W1ZfRxtHdD62v2BYBEI" +) + +var client = sve.NewClient(apiKey, secretKey) + +func TestWithdraw() { + client.Debug = true + client.SetHost(sve.LbankApiHost) + data := map[string]string{ + "symbol": "lbk_usdt", + "size": "1", + } + client.NewWithDrawService().Withdraw(data) +} + +func main() { + TestWithdraw() +} diff --git a/examples/wsapi/market/market.go b/examples/wsapi/market/market.go new file mode 100644 index 0000000..0a6e601 --- /dev/null +++ b/examples/wsapi/market/market.go @@ -0,0 +1,15 @@ +package main + +import "lbank_connector_go/sve" + +var client = sve.NewWsClient("", "") + +func TestKbar() { + client.Debug = true + //client.SetHost(sve.LbankApiHost) + client.NewWsMarketService().Kbar("kbar", "usdt_btc") +} + +func main() { + TestKbar() +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..107d61f --- /dev/null +++ b/go.mod @@ -0,0 +1,21 @@ +module lbank_connector_go + +go 1.20 + +require ( + github.com/google/uuid v1.6.0 + github.com/gorilla/websocket v1.5.1 + github.com/natefinch/lumberjack v2.0.0+incompatible + github.com/tidwall/gjson v1.17.0 + go.uber.org/zap v1.26.0 +) + +require ( + github.com/BurntSushi/toml v1.3.2 // indirect + github.com/tidwall/match v1.1.1 // indirect + github.com/tidwall/pretty v1.2.1 // indirect + go.uber.org/multierr v1.11.0 // indirect + golang.org/x/net v0.17.0 // indirect + gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..1832a2a --- /dev/null +++ b/go.sum @@ -0,0 +1,31 @@ +github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8= +github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY= +github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY= +github.com/natefinch/lumberjack v2.0.0+incompatible h1:4QJd3OLAMgj7ph+yZTuX13Ld4UpgHp07nNdFX7mqFfM= +github.com/natefinch/lumberjack v2.0.0+incompatible/go.mod h1:Wi9p2TTF5DG5oU+6YfsmYQpsTIOm0B1VNzQg9Mw6nPk= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= +github.com/tidwall/gjson v1.17.0 h1:/Jocvlh98kcTfpN2+JzGQWQcqrPQwDrVEMApx/M5ZwM= +github.com/tidwall/gjson v1.17.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= +github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= +github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= +github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4= +github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= +go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk= +go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= +go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= +go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so= +golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= +golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= +gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= diff --git a/pkg/log.go b/pkg/log.go new file mode 100644 index 0000000..06364d8 --- /dev/null +++ b/pkg/log.go @@ -0,0 +1,55 @@ +package pkg + +import ( + "os" + + "github.com/natefinch/lumberjack" + "go.uber.org/zap" + "go.uber.org/zap/zapcore" +) + +func genEncoder() zapcore.Encoder { + encoderConfig := zap.NewDevelopmentEncoderConfig() + encoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder + encoderConfig.EncodeTime = zapcore.TimeEncoderOfLayout("2006-01-02 15:04:05.000") + encoderConfig.EncodeLevel = zapcore.CapitalColorLevelEncoder + return zapcore.NewConsoleEncoder(encoderConfig) +} + +func genInfoWrite() zapcore.WriteSyncer { + infoLumberIO := &lumberjack.Logger{ + Filename: "./logs/info.log", + MaxSize: 10, // megabytes + MaxBackups: 100, + MaxAge: 7, // days + Compress: false, + } + return zapcore.AddSync(infoLumberIO) +} + +func genErrorWrite() zapcore.WriteSyncer { + lumberWriteSyncer := &lumberjack.Logger{ + Filename: "./logs/error.log", + MaxSize: 10, // megabytes + MaxBackups: 100, + MaxAge: 7, // days + Compress: false, + } + return zapcore.AddSync(lumberWriteSyncer) +} + +func InitLogger() *zap.SugaredLogger { + encoder := genEncoder() + + info := genInfoWrite() + err := genErrorWrite() + + core := zapcore.NewTee( + zapcore.NewCore(encoder, zapcore.NewMultiWriteSyncer(info, zapcore.AddSync(os.Stdout)), zap.DebugLevel), + zapcore.NewCore(encoder, zapcore.NewMultiWriteSyncer(err, zapcore.AddSync(os.Stdout)), zap.WarnLevel), + ) + logger := zap.New(core, zap.AddCaller()) + zap.ReplaceGlobals(logger) + defer logger.Sync() + return logger.Sugar() +} diff --git a/pkg/utils.go b/pkg/utils.go new file mode 100644 index 0000000..0432872 --- /dev/null +++ b/pkg/utils.go @@ -0,0 +1,161 @@ +package pkg + +import ( + "bytes" + "crypto" + "crypto/hmac" + "crypto/md5" + "crypto/rand" + "crypto/rsa" + "crypto/sha256" + "crypto/x509" + "encoding/base64" + "encoding/hex" + "encoding/json" + "encoding/pem" + "errors" + mrand "math/rand" + "sort" + "strconv" + "strings" + "time" + + "github.com/google/uuid" +) + +func HmacHashing(s string) string { + d := []byte(s) + h := md5.New() + h.Write(d) + return strings.ToUpper(hex.EncodeToString(h.Sum(nil))) +} + +func HmacSHA256(paramStr, secretKey string) string { + h := hmac.New(sha256.New, []byte(secretKey)) + h.Write([]byte(paramStr)) + return hex.EncodeToString(h.Sum(nil)) +} + +func PrettyPrint(str []byte) (string, error) { + var buf bytes.Buffer + if err := json.Indent(&buf, str, "", " "); err != nil { + return string(str), err + } + return strings.TrimSuffix(buf.String(), "\n"), nil +} + +//func PrettyPrint(i interface{}) string { +// s, _ := json.MarshalIndent(i, "", "\t") +// return string(s) +//} + +func Map2JsonString(param map[string]interface{}) string { + data, _ := json.Marshal(param) + return string(data) +} + +func CurrentTimestamp() int64 { + return FormatTimestamp(time.Now()) +} + +func FormatTimestamp(t time.Time) int64 { + return t.UnixNano() / int64(time.Millisecond) +} + +func Timestamp() string { + return strconv.Itoa(int(time.Now().UnixMilli())) +} + +func RandomStr() string { + s := "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" + arr := strings.Split(s, "") + mrand.Shuffle(len(s), func(i, j int) { + arr[i], arr[j] = arr[j], arr[i] + }) + return strings.Join(arr[:35], "") +} + +func Interface2Str(i interface{}) string { + switch i.(type) { + case string: + return i.(string) + case int: + return strconv.Itoa(i.(int)) + case int64: + return strconv.FormatInt(i.(int64), 10) + case float32: + return strconv.FormatFloat(i.(float64), 'f', -1, 32) + case float64: + return strconv.FormatFloat(i.(float64), 'f', -1, 64) + default: + return "" + } +} + +func ParsePKCS1PrivateKey(secret []byte) (*rsa.PrivateKey, error) { + block, _ := pem.Decode(secret) + if block == nil { + return nil, errors.New("secret key error") + } + privateKey, err := x509.ParsePKCS8PrivateKey(block.Bytes) + if err != nil { + return nil, err + } + + return privateKey.(*rsa.PrivateKey), err +} + +func FormatStringBySign(kwargs map[string]string) string { + var keys []string + + for k := range kwargs { + keys = append(keys, k) + } + sort.Strings(keys) + paramsSortStr := "" + for _, key := range keys { + paramsSortStr += key + "=" + kwargs[key] + "&" + } + paramsSortStr = paramsSortStr[:len(paramsSortStr)-1] + + return paramsSortStr +} + +func RSASign(params string, privateKey *rsa.PrivateKey) string { + md5Hash := md5.Sum([]byte(params)) + md5String := strings.ToUpper(hex.EncodeToString(md5Hash[:])) + + paramsSha256 := sha256.New() + paramsSha256.Write([]byte(md5String)) + sha256Hash := paramsSha256.Sum(nil) + + sigMsg, err := rsa.SignPKCS1v15(rand.Reader, privateKey, crypto.SHA256, sha256Hash) + if err != nil { + panic(err) + } + + return base64.StdEncoding.EncodeToString(sigMsg) +} + +func HmacSha256Base64Signer(params string, secretKey string) (string, error) { + md5Hash := md5.Sum([]byte(params)) + md5String := strings.ToUpper(hex.EncodeToString(md5Hash[:])) + + mac := hmac.New(sha256.New, []byte(secretKey)) + _, err := mac.Write([]byte(md5String)) + if err != nil { + return "", err + } + + return hex.EncodeToString(mac.Sum(nil)), nil +} + +func Now() string { + return time.Now().Format("2006-01-02 15:04:05") +} + +func RandomUUID() string { + id := uuid.New() + strID := id.String() + return strID +} diff --git a/sve/account.go b/sve/account.go new file mode 100644 index 0000000..6fd1af4 --- /dev/null +++ b/sve/account.go @@ -0,0 +1,42 @@ +package sve + +type AccountService struct { + c *Client + hs *HttpService +} + +func (a *AccountService) UserInfo(data map[string]string) { + url := a.c.Host + PathUserInfo + params := a.hs.BuildSignBody(data) + a.hs.Post(url, params) +} + +func (a *AccountService) SubscribeGetKey(data map[string]string) { + url := a.c.Host + PathSubscribeGetKey + params := a.hs.BuildSignBody(data) + a.hs.Post(url, params) +} + +func (a *AccountService) SubscribeRefreshKey(data map[string]string) { + url := a.c.Host + PathSubscribeRefreshKey + params := a.hs.BuildSignBody(data) + a.hs.Post(url, params) +} + +func (a *AccountService) SubscribeDestroyKey(data map[string]string) { + url := a.c.Host + PathSubscribeDestroyKey + params := a.hs.BuildSignBody(data) + a.hs.Post(url, params) +} + +func (a *AccountService) GetDepositAddress(data map[string]string) { + url := a.c.Host + PathGetDepositAddress + params := a.hs.BuildSignBody(data) + a.hs.Post(url, params) +} + +func (a *AccountService) DepositHistory(data map[string]string) { + url := a.c.Host + PathDepositHistory + params := a.hs.BuildSignBody(data) + a.hs.Post(url, params) +} diff --git a/sve/base.go b/sve/base.go new file mode 100644 index 0000000..c9d4324 --- /dev/null +++ b/sve/base.go @@ -0,0 +1,72 @@ +package sve + +type BaseService struct { + c *Client + hs *HttpService +} + +func (b *BaseService) CurrencyPairs(data map[string]string) { + url := b.c.Host + PathCurrencyPairs + params := b.hs.BuildSignBody(data) + b.hs.Get(url, params) +} + +func (b *BaseService) Accuracy(data map[string]string) { + url := b.c.Host + PathAccuracy + params := b.hs.BuildSignBody(data) + b.hs.Get(url, params) +} + +func (b *BaseService) UsdToCny(data map[string]string) { + url := b.c.Host + PathUsdToCny + params := b.hs.BuildSignBody(data) + b.hs.Get(url, params) +} + +func (b *BaseService) WithdrawConfigs(data map[string]string) { + url := b.c.Host + PathWithdrawConfigs + params := b.hs.BuildSignBody(data) + b.hs.Get(url, params) +} + +func (b *BaseService) Timestamp(data map[string]string) { + url := b.c.Host + PathTimestamp + params := b.hs.BuildSignBody(data) + b.hs.Get(url, params) +} + +func (b *BaseService) Ticker24hr(data map[string]string) { + url := b.c.Host + PathTicker24hr + params := b.hs.BuildSignBody(data) + b.hs.Get(url, params) +} + +func (b *BaseService) EtfTicker24hr(data map[string]string) { + url := b.c.Host + PathEtfTicker24hr + params := b.hs.BuildSignBody(data) + b.hs.Get(url, params) +} + +func (b *BaseService) Ticker(data map[string]string) { + url := b.c.Host + PathTicker + params := b.hs.BuildSignBody(data) + b.hs.Get(url, params) +} + +func (b *BaseService) IncrDepth(data map[string]string) { + url := b.c.Host + PathIncrDepth + params := b.hs.BuildSignBody(data) + b.hs.Get(url, params) +} + +func (b *BaseService) Trades(data map[string]string) { + url := b.c.Host + PathTrades + params := b.hs.BuildSignBody(data) + b.hs.Get(url, params) +} + +func (b *BaseService) Kline(data map[string]string) { + url := b.c.Host + PathKline + params := b.hs.BuildSignBody(data) + b.hs.Get(url, params) +} diff --git a/sve/client.go b/sve/client.go new file mode 100644 index 0000000..239f07b --- /dev/null +++ b/sve/client.go @@ -0,0 +1,73 @@ +package sve + +import ( + "go.uber.org/zap" + + "lbank_connector_go/pkg" +) + +type Client struct { + ApiKey string + SecretKey string + Host string + Debug bool + Logger *zap.SugaredLogger +} + +var host = "https://www.lbkex.net" + +func NewClient(apiKey, secretKey string) *Client { + devLogger := pkg.InitLogger() + c := &Client{ + ApiKey: apiKey, + SecretKey: secretKey, + Host: host, + Logger: devLogger, + } + return c +} + +func (c *Client) debug(msg string, args ...interface{}) { + if c.Debug { + c.Logger.Debugf(msg, args...) + } +} + +func (c *Client) SetHost(host string) { + c.Host = host +} + +func (c *Client) NewSpotService() *SpotService { + hs := c.NewHttpService() + return &SpotService{c: c, hs: hs} +} +func (c *Client) NewMarketService() *MarketService { + hs := c.NewHttpService() + return &MarketService{c: c, hs: hs} +} +func (c *Client) NewWalletService() *WalletService { + hs := c.NewHttpService() + return &WalletService{c: c, hs: hs} +} +func (c *Client) NewBaseService() *BaseService { + hs := c.NewHttpService() + return &BaseService{c: c, hs: hs} +} +func (c *Client) NewAccountService() *AccountService { + hs := c.NewHttpService() + return &AccountService{c: c, hs: hs} +} + +func (c *Client) NewOrderService() *OrderService { + hs := c.NewHttpService() + return &OrderService{c: c, hs: hs} +} + +func (c *Client) NewWithDrawService() *WithDrawService { + hs := c.NewHttpService() + return &WithDrawService{c: c, hs: hs} +} + +func (c *Client) NewHttpService() *HttpService { + return &HttpService{c: c} +} diff --git a/sve/httpservice.go b/sve/httpservice.go new file mode 100644 index 0000000..c0c5d67 --- /dev/null +++ b/sve/httpservice.go @@ -0,0 +1,277 @@ +package sve + +import ( + "bytes" + "crypto/tls" + "encoding/json" + "errors" + "fmt" + "io" + "net/http" + "net/url" + "strings" + "time" + + "github.com/tidwall/gjson" + + "lbank_connector_go/pkg" +) + +type HttpService struct { + c *Client + ReqObj *http.Request + RespObj *http.Response + Body string + CostTime int64 + Method string + Headers map[string]string + Text string + Content []byte + IsEchoReq bool + isDebug bool + + Error error + + EchoStr string `json:"echostr"` + Timestamp string `json:"timestamp"` + SignatureMethod string `json:"signature_method"` +} + +var defaultHeaders = map[string]string{ + "Content-Type": "application/x-www-form-urlencoded", +} + +var tr = &http.Transport{ + TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, + MaxIdleConnsPerHost: 2000, +} + +type KwArgs func(hs *HttpService) + +func WithHeaders(headers map[string]string) KwArgs { + return func(hs *HttpService) { + hs.Headers = headers + } +} +func WithDebug(debug bool) KwArgs { + return func(hs *HttpService) { + hs.isDebug = debug + } +} + +func WithParams(params map[string]string) KwArgs { + urlParams := url.Values{} + for k, v := range params { + urlParams.Add(k, v) + } + return func(hs *HttpService) { + hs.ReqObj.URL.RawQuery = urlParams.Encode() + } +} + +func NewHttpService() *HttpService { + return &HttpService{} +} + +func (hs *HttpService) Get(url, data string, kwargs ...KwArgs) *http.Response { + var newUrl string + if len(data) > 0 { + newUrl = fmt.Sprintf("%s?%s", url, data) + } else { + newUrl = url + } + text, err := hs.DoHttpRequest("GET", newUrl, "", kwargs...) + hs.Error = err + hs.Text = text + if err != nil { + hs.c.debug("[reqErr] %s\n" + err.Error()) + } + return hs.RespObj +} + +func (hs *HttpService) Post(url, json string, kwargs ...KwArgs) *http.Response { + text, err := hs.DoHttpRequest("POST", url, json, kwargs...) + hs.Text = text + if err != nil { + hs.c.Logger.Error("[reqErr] %s\n" + err.Error()) + } + return hs.RespObj +} + +func (hs *HttpService) IsPrintReq(isEchoReq bool) *HttpService { + hs.IsEchoReq = isEchoReq + return hs +} + +func (hs *HttpService) DoHttpRequest(method, url, body string, kwargs ...KwArgs) (string, error) { + hs.BuildHeader() + client := hs.BuildClient() + req, err := hs.BuildRequest(method, url, body) + if err != nil { + return "", err + } + hs.ReqObj = req + + for _, kw := range kwargs { + kw(hs) + } + + if len(hs.Headers) > 0 { + hs.BuildRequestHeaders(hs.ReqObj, hs.Headers) + } else { + hs.BuildRequestHeaders(hs.ReqObj, defaultHeaders) + } + startTime := time.Now() + respObj, err := client.Do(hs.ReqObj) + hs.RespObj = respObj + elapsed := time.Since(startTime).Nanoseconds() / int64(time.Millisecond) + hs.CostTime = elapsed + if hs.IsEchoReq || hs.isDebug || hs.c.Debug { + hs.PrintReqInfo(hs.ReqObj) + } + if err != nil { + hs.c.Logger.Error("[reqErr] %s\n" + err.Error()) + hs.PrintReqInfo(hs.ReqObj) + return "", err + } + defer respObj.Body.Close() + content, err := io.ReadAll(respObj.Body) + hs.Content = content + if err != nil { + hs.c.Logger.Error("[RespErr]%s\n" + err.Error()) + hs.PrintReqInfo(hs.ReqObj) + hs.PrintRespInfo(content, elapsed) + return "", err + } + if hs.isDebug || hs.c.Debug { + hs.PrintRespInfo(content, elapsed) + } + return string(content), nil +} + +func (hs *HttpService) BuildRequest(method, url string, body string) (req *http.Request, err error) { + hs.Body = body + b := hs.BuildBody(body) + req, err = http.NewRequest(method, url, b) + if err != nil { + hs.c.Logger.Error("BuildRequestErr" + err.Error()) + return nil, err + } + return req, nil +} + +func (hs *HttpService) BuildClient() *http.Client { + client := &http.Client{Timeout: 3 * 60 * time.Second, Transport: tr} + return client +} + +func (hs *HttpService) BuildRequestHeaders(req *http.Request, headers map[string]string) *HttpService { + for k, v := range headers { + req.Header.Set(k, v) + } + return hs + //{"Content-Type": 'application/x-www-form-urlencoded', + // "signature_method": self.sign_method, + // 'timestamp': self.timestamp, + // 'echostr': self.random_str} +} + +func (hs *HttpService) PrintReqInfo(req *http.Request) { + s := fmt.Sprintf("\n [ReqHeaders]:%v", req.Header) + fmt.Sprintf("\n [ReqMethod]:%s", req.Method) + + fmt.Sprintf("\n [ReqUrl]:%s", req.URL) + fmt.Sprintf("\n [ReqBody]:%s", hs.Body) + hs.c.debug(s) +} + +func (hs *HttpService) BuildBody(body string) *strings.Reader { + hs.Body = body + return strings.NewReader(body) +} + +func (hs *HttpService) PrintRespInfo(resInfo []byte, costTime int64) *HttpService { + costFloat := float64(costTime) / 1.0e9 + formatCostTime := fmt.Sprintf("%.3f", costFloat) + hs.CostTime = costTime / 1e6 + r, _ := pkg.PrettyPrint(resInfo) + s := fmt.Sprintf("\n [RespHttpCode]:%d", hs.RespObj.StatusCode) + fmt.Sprintf("\n [RespCost]:%sSecond", + formatCostTime) + fmt.Sprintf("\n [RespBody]:%s", r) + hs.c.debug(s) + return hs +} + +func (hs *HttpService) PrettyPrint(resInfo []byte) (string, error) { + var buf bytes.Buffer + if err := json.Indent(&buf, resInfo, "", " "); err != nil { + return string(resInfo), err + } + return strings.TrimSuffix(buf.String(), "\n"), nil +} + +func (hs *HttpService) Map2String(body map[string]interface{}) string { + return pkg.Map2JsonString(body) +} + +// Json https://github.com/tidwall/gjson +func (hs *HttpService) Json() gjson.Result { + return gjson.Parse(hs.Text) +} + +func (hs *HttpService) InitTsAndStr() { + hs.Timestamp = pkg.Timestamp() + hs.EchoStr = pkg.RandomStr() +} +func (hs *HttpService) BuildHeader() *HttpService { + hd := map[string]string{ + "Content-Type": "application/x-www-form-urlencoded", + "signature_method": "RSA", + "timestamp": hs.Timestamp, + "echostr": hs.EchoStr} + hs.Headers = hd + return hs +} + +func (hs *HttpService) BuildSignBody(kwargs map[string]string) string { + hs.InitTsAndStr() + kwargs["api_key"] = hs.c.ApiKey + kwargs["timestamp"] = hs.Timestamp + if len(hs.c.SecretKey) > 0 { + kwargs["signature_method"] = "RSA" + } else { + kwargs["signature_method"] = "HmacSHA256" + } + kwargs["echostr"] = hs.EchoStr + + paramsSortStr := pkg.FormatStringBySign(kwargs) + var sign string + if len(hs.c.SecretKey) > 0 { + sign, _ = hs.BuildRsaSignV2(paramsSortStr, hs.c.SecretKey) + } else { + sign, _ = hs.BuildHmacSignV2(paramsSortStr, hs.c.SecretKey) + } + kwargs["sign"] = sign + postData := url.Values{} + for k, v := range kwargs { + postData.Add(k, v) + } + postData.Del("echostr") + postData.Del("timestamp") + postData.Del("signature_method") + hs.Body = postData.Encode() + return postData.Encode() +} + +// BuildRsaSignV2 +func (hs *HttpService) BuildRsaSignV2(params, secret string) (string, error) { + if len(secret) == 0 { + return "", errors.New("secret is empty") + } + b := []byte("-----BEGIN RSA PRIVATE KEY-----\n" + secret + "\n-----END RSA PRIVATE KEY-----") + privateKey, err := pkg.ParsePKCS1PrivateKey(b) + if err != nil { + return "", err + } + return pkg.RSASign(params, privateKey), nil +} + +func (hs *HttpService) BuildHmacSignV2(params, secret string) (string, error) { + return pkg.HmacSha256Base64Signer(params, secret) +} \ No newline at end of file diff --git a/sve/market.go b/sve/market.go new file mode 100644 index 0000000..2e951ce --- /dev/null +++ b/sve/market.go @@ -0,0 +1,27 @@ +package sve + +type MarketService struct { + c *Client + hs *HttpService +} + +func (m *MarketService) Depth(data map[string]string) { + url := m.c.Host + PathDepth + params := m.hs.BuildSignBody(data) + m.hs.Get(url, params) +} +func (m *MarketService) SupplementTrades(data map[string]string) { + url := m.c.Host + PathSupplementTrades + params := m.hs.BuildSignBody(data) + m.hs.Get(url, params) +} +func (m *MarketService) SupplementTickerPrice(data map[string]string) { + url := m.c.Host + PathSupplementTickerPrice + params := m.hs.BuildSignBody(data) + m.hs.Get(url, params) +} +func (m *MarketService) SupplementTickerBookTicker(data map[string]string) { + url := m.c.Host + PathSupplementTickerBookTicker + params := m.hs.BuildSignBody(data) + m.hs.Get(url, params) +} diff --git a/sve/order.go b/sve/order.go new file mode 100644 index 0000000..5dc3f53 --- /dev/null +++ b/sve/order.go @@ -0,0 +1,60 @@ +package sve + +type OrderService struct { + c *Client + hs *HttpService +} + +func (o *OrderService) CreateOrder(data map[string]string) { + url := o.c.Host + PathCreateOrder + params := o.hs.BuildSignBody(data) + o.hs.Post(url, params) +} + +func (o *OrderService) BatchCreateOrder(data map[string]string) { + url := o.c.Host + PathBatchCreateOrder + params := o.hs.BuildSignBody(data) + o.hs.Post(url, params) +} + +func (o *OrderService) CancelOrder(data map[string]string) { + url := o.c.Host + PathCancelOrder + params := o.hs.BuildSignBody(data) + o.hs.Post(url, params) +} + +func (o *OrderService) CancelClientOrders(data map[string]string) { + url := o.c.Host + PathCancelClientOrders + params := o.hs.BuildSignBody(data) + o.hs.Post(url, params) +} + +func (o *OrderService) OrdersInfo(data map[string]string) { + url := o.c.Host + PathOrdersInfo + params := o.hs.BuildSignBody(data) + o.hs.Post(url, params) +} + +func (o *OrderService) OrdersInfoHistory(data map[string]string) { + url := o.c.Host + PathOrdersInfoHistory + params := o.hs.BuildSignBody(data) + o.hs.Post(url, params) +} + +func (o *OrderService) OrderTransactionDetail(data map[string]string) { + url := o.c.Host + PathOrderTransactionDetail + params := o.hs.BuildSignBody(data) + o.hs.Post(url, params) +} + +func (o *OrderService) TransactionHistory(data map[string]string) { + url := o.c.Host + PathTransactionHistory + params := o.hs.BuildSignBody(data) + o.hs.Post(url, params) +} + +func (o *OrderService) OrdersInfoNoDeal(data map[string]string) { + url := o.c.Host + PathOrdersInfoNoDeal + params := o.hs.BuildSignBody(data) + o.hs.Post(url, params) +} diff --git a/sve/settings.go b/sve/settings.go new file mode 100644 index 0000000..32d8d81 --- /dev/null +++ b/sve/settings.go @@ -0,0 +1,82 @@ +package sve + +const ( + //LbankApiHost = "https://api.lbkex.com" + LbankApiHost = "https://www.lbkex.net" + LbankWsApiHost = "" +) + +const ( + PathSupplementCreatOrder = "/v2/supplement/create_order.do" + PathSupplementCancelOrder = "/v2/supplement/cancel_order.do" + PathSupplementCancelOrderBySymbol = "/v2/supplement/cancel_order_by_symbol.do" + PathSupplementOrdersInfo = "/v2/supplement/orders_info.do" + PathSupplementOrdersInfoNoDeal = "/v2/supplement/orders_info_no_deal.do" + PathSupplementOrdersInfoHistory = "/v2/supplement/orders_info_history.do" + PathSupplementUserInfoAccount = "/v2/supplement/user_info_account.do" + PathSupplementTransactionHistory = "/v2/supplement/transaction_history.do" +) + +const ( + PathDepth = "/v2/depth.do" + PathSupplementTrades = "/v2/supplement/trades.do" + PathSupplementTickerPrice = "/v2/supplement/ticker/price.do" + PathSupplementTickerBookTicker = "/v2/supplement/ticker/bookTicker.do" +) + +const ( + PathSupplementSystemStatus = "/v2/supplement/system_status.do" + PathSupplementUserInfo = "/v2/supplement/user_info.do" + PathSupplementWithdraw = "/v2/supplement/withdraw.do" + PathSupplementDepositHistory = "/v2/supplement/deposit_history.do" + PathSupplementWithdraws = "/v2/supplement/withdraws.do" + PathSupplementGetDepositAddress = "/v2/supplement/get_deposit_address.do" + PathSupplementAssetDetail = "/v2/supplement/asset_detail.do" + PathSupplementCustomerTradeFee = "/v2/supplement/customer_trade_fee.do" + PathSupplementApiRestrictions = "/v2/supplement/api_Restrictions.do" +) + +const ( + PathCurrencyPairs = "/v2/currencyPairs.do" + PathAccuracy = "/v2/accuracy.do" + PathUsdToCny = "/v2/usdToCny.do" + PathWithdrawConfigs = "/v2/withdrawConfigs.do" + PathTimestamp = "/v2/timestamp.do" + PathTicker24hr = "/v2/ticker/24hr.do" + PathEtfTicker24hr = "/v2/etfTicker/24hr.do" + PathTicker = "/v2/ticker.do" + PathIncrDepth = "/v2/incrDepth.do" + PathTrades = "/v2/trades.do" + PathKline = "/v2/kline.do" +) + +const ( + PathUserInfo = "/v2/user_info.do" + PathSubscribeGetKey = "/v2/subscribe/get_key.do" + PathSubscribeRefreshKey = "/v2/subscribe/refresh_key.do" + PathSubscribeDestroyKey = "/v2/subscribe/destroy_key.do" + PathGetDepositAddress = "/v2/get_deposit_address.do" + PathDepositHistory = "/v2/deposit_history.do" +) + +const ( + PathCreateOrder = "/v2/create_order.do" + PathBatchCreateOrder = "/v2/batch_create_order.do" + PathCancelOrder = "/v2/cancel_order.do" + PathCancelClientOrders = "/v2/cancel_clientOrders.do" + PathOrdersInfo = "/v2/orders_info.do" + PathOrdersInfoHistory = "/v2/orders_info_history.do" + PathOrderTransactionDetail = "/v2/order_transaction_detail.do" + PathTransactionHistory = "/v2/transaction_history.do" + PathOrdersInfoNoDeal = "/v2/orders_info_no_deal.do" +) + +const ( + PathWithdraw = "/v2/withdraw.do" + PathWithdrawCancel = "/v2/withdrawCancel.do" + PathWithdraws = "/v2/withdraws.do" +) + +const ( + PathWs = "wss://www.lbkex.net/ws/V2/" +) diff --git a/sve/spot.go b/sve/spot.go new file mode 100644 index 0000000..721f230 --- /dev/null +++ b/sve/spot.go @@ -0,0 +1,53 @@ +package sve + +type SpotService struct { + c *Client + hs *HttpService +} + +func (s *SpotService) CreateOrder(data map[string]string) { + url := s.c.Host + PathSupplementCreatOrder + params := s.hs.BuildSignBody(data) + s.hs.Post(url, params) +} + +func (s *SpotService) CancelOrder(data map[string]string) { + url := s.c.Host + PathSupplementCancelOrder + params := s.hs.BuildSignBody(data) + s.hs.Post(url, params) +} + +func (s *SpotService) CancelOrderBySymbol(data map[string]string) { + url := s.c.Host + PathSupplementCancelOrderBySymbol + params := s.hs.BuildSignBody(data) + s.hs.Post(url, params) +} + +func (s *SpotService) OrdersInfo(data map[string]string) { + url := s.c.Host + PathSupplementOrdersInfo + params := s.hs.BuildSignBody(data) + s.hs.Post(url, params) +} + +func (s *SpotService) OrdersInfoNoDeal(data map[string]string) { + url := s.c.Host + PathSupplementOrdersInfoNoDeal + params := s.hs.BuildSignBody(data) + s.hs.Post(url, params) +} + +func (s *SpotService) OrdersInfoHistory(data map[string]string) { + url := s.c.Host + PathSupplementOrdersInfoHistory + params := s.hs.BuildSignBody(data) + s.hs.Post(url, params) +} + +func (s *SpotService) UserInfoAccount(data map[string]string) { + url := s.c.Host + PathSupplementUserInfoAccount + params := s.hs.BuildSignBody(data) + s.hs.Post(url, params) +} +func (s *SpotService) TransactionHistory(data map[string]string) { + url := s.c.Host + PathSupplementTransactionHistory + params := s.hs.BuildSignBody(data) + s.hs.Post(url, params) +} diff --git a/sve/wallet.go b/sve/wallet.go new file mode 100644 index 0000000..79ed3dd --- /dev/null +++ b/sve/wallet.go @@ -0,0 +1,60 @@ +package sve + +type WalletService struct { + c *Client + hs *HttpService +} + +func (w *WalletService) SupplementSystemStatus(data map[string]string) { + url := w.c.Host + PathSupplementSystemStatus + params := w.hs.BuildSignBody(data) + w.hs.Post(url, params) +} + +func (w *WalletService) SupplementUserInfo(data map[string]string) { + url := w.c.Host + PathSupplementUserInfo + params := w.hs.BuildSignBody(data) + w.hs.Post(url, params) +} + +func (w *WalletService) SupplementWithdraw(data map[string]string) { + url := w.c.Host + PathSupplementWithdraw + params := w.hs.BuildSignBody(data) + w.hs.Post(url, params) +} + +func (w *WalletService) SupplementDepositHistory(data map[string]string) { + url := w.c.Host + PathSupplementDepositHistory + params := w.hs.BuildSignBody(data) + w.hs.Post(url, params) +} + +func (w *WalletService) SupplementWithdraws(data map[string]string) { + url := w.c.Host + PathSupplementWithdraws + params := w.hs.BuildSignBody(data) + w.hs.Post(url, params) +} + +func (w *WalletService) SupplementGetDepositAddress(data map[string]string) { + url := w.c.Host + PathSupplementGetDepositAddress + params := w.hs.BuildSignBody(data) + w.hs.Post(url, params) +} + +func (w *WalletService) SupplementAssetDetail(data map[string]string) { + url := w.c.Host + PathSupplementAssetDetail + params := w.hs.BuildSignBody(data) + w.hs.Post(url, params) +} + +func (w *WalletService) SupplementCustomerTradeFee(data map[string]string) { + url := w.c.Host + PathSupplementCustomerTradeFee + params := w.hs.BuildSignBody(data) + w.hs.Post(url, params) +} + +func (w *WalletService) SupplementApiRestrictions(data map[string]string) { + url := w.c.Host + PathSupplementApiRestrictions + params := w.hs.BuildSignBody(data) + w.hs.Post(url, params) +} diff --git a/sve/withdraw.go b/sve/withdraw.go new file mode 100644 index 0000000..6402b4b --- /dev/null +++ b/sve/withdraw.go @@ -0,0 +1,24 @@ +package sve + +type WithDrawService struct { + c *Client + hs *HttpService +} + +func (w *WithDrawService) Withdraw(data map[string]string) { + url := w.c.Host + PathWithdraw + params := w.hs.BuildSignBody(data) + w.hs.Post(url, params) +} + +func (w *WithDrawService) WithdrawCancel(data map[string]string) { + url := w.c.Host + PathWithdrawCancel + params := w.hs.BuildSignBody(data) + w.hs.Post(url, params) +} + +func (w *WithDrawService) Withdraws(data map[string]string) { + url := w.c.Host + PathWithdraws + params := w.hs.BuildSignBody(data) + w.hs.Post(url, params) +} diff --git a/sve/ws.go b/sve/ws.go new file mode 100644 index 0000000..12224d8 --- /dev/null +++ b/sve/ws.go @@ -0,0 +1,73 @@ +package sve + +import ( + "encoding/json" + "fmt" + "log" + "net/url" + "time" + + "github.com/gorilla/websocket" + + "lbank_connector_go/pkg" +) + +type WsService struct { + conn *websocket.Conn + Wc *WsClient +} + +func (w *WsService) KeepAlive(timeout time.Duration) { + ticker := time.NewTicker(timeout) + go func() { + defer ticker.Stop() + for { + pingMap := map[string]string{ + "ping": pkg.RandomUUID(), + "action": "ping", + } + msg, _ := json.Marshal(pingMap) + w.SendMsg(msg) + <-ticker.C + } + }() +} + +func (w *WsService) CreateWsConn() (*websocket.Conn, error) { + u := url.URL{Scheme: "wss", Host: "www.lbkex.net", Path: "/ws/V2/"} + if w.Wc.Debug { + w.Wc.debug("CreateWsConn: %s", u.String()) + } + dialer := websocket.DefaultDialer + conn, _, err := dialer.Dial(u.String(), nil) + if err != nil { + w.Wc.Logger.Fatal("dial:", err) + } + w.conn = conn + return conn, err +} + +func (w *WsService) SendMsg(content []byte) { + err := w.conn.WriteMessage(websocket.TextMessage, content) + if err != nil { + w.Wc.Logger.Fatal("SendMsg:", err) + return + } + if w.Wc.Debug { + w.Wc.debug("Sent: %s", content) + + } + log.Printf("Sent: %s", content) +} + +func (w *WsService) ReceiveMsg() { + for { + _, message, err := w.conn.ReadMessage() + if err != nil { + w.Wc.Logger.Fatal("read:", err) + return + } + w.Wc.debug("Received: %s", message) + fmt.Printf("Received: %s", message) + } +} diff --git a/sve/wsapimarket.go.go b/sve/wsapimarket.go.go new file mode 100644 index 0000000..80b3362 --- /dev/null +++ b/sve/wsapimarket.go.go @@ -0,0 +1,26 @@ +package sve + +import ( + "time" +) + +type WsMarketService struct { + Ws *WsService +} + +func (w *WsMarketService) Kbar(kbar, pair string) { + conn, _ := w.Ws.CreateWsConn() + defer conn.Close() + //payloay := map[string]string{ + // "action": "subscribe", + // "subscribe": "kbar", + // "kbar": kbar, + // "pair": pair, + //} + w.Ws.KeepAlive(10 * time.Second) + //msg, _ := json.Marshal(payloay) + msg := []byte(`{"action":"subscribe","subscribe":"kbar","kbar":"5min","pair":"btc_usdt"}`) + go w.Ws.SendMsg(msg) + go w.Ws.ReceiveMsg() + select {} +} diff --git a/sve/wsclient.go b/sve/wsclient.go new file mode 100644 index 0000000..18e5fcf --- /dev/null +++ b/sve/wsclient.go @@ -0,0 +1,47 @@ +package sve + +import ( + "go.uber.org/zap" + + "lbank_connector_go/pkg" +) + +type WsClient struct { + ApiKey string + SecretKey string + Host string + Debug bool + Logger *zap.SugaredLogger +} + +//var host = "https://www.lbkex.net" + +func NewWsClient(apiKey, secretKey string) *WsClient { + devLogger := pkg.InitLogger() + wsClient := &WsClient{ + ApiKey: apiKey, + SecretKey: secretKey, + Host: host, + Logger: devLogger, + } + return wsClient +} + +func (wc *WsClient) debug(msg string, args ...interface{}) { + if wc.Debug { + wc.Logger.Debugf(msg, args...) + } +} + +func (wc *WsClient) SetHost(host string) { + wc.Host = host +} + +func (wc *WsClient) NewWsService() *WsService { + return &WsService{Wc: wc} +} + +func (wc *WsClient) NewWsMarketService() *WsMarketService { + ws := wc.NewWsService() + return &WsMarketService{ws} +} diff --git a/version.go b/version.go new file mode 100644 index 0000000..c1f2057 --- /dev/null +++ b/version.go @@ -0,0 +1,5 @@ +package lbank_connector_go + +const Version = "0.1.0" + +const Name = "lbank-connector-go"