Commit 73f9c58a authored by Cranky Kernel's avatar Cranky Kernel

binance: move AccountInfo request to server

Instead of the web UI making the authenticated request to Binance,
create a handler that takes care of authenticating the request
and send the result back to the UI.
parent f88af8e2
// Copyright (C) 2019 Cranky Kernel
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package server
import (
"github.com/crankykernel/binanceapi-go"
"github.com/gorilla/mux"
"gitlab.com/crankykernel/maker/go/binanceex"
"gitlab.com/crankykernel/maker/go/log"
"net/http"
)
type BinanceProxyHandlers struct {
client *binanceapi.RestClient
}
func NewBinanceProxyHandlers() *BinanceProxyHandlers {
return &BinanceProxyHandlers{
client: binanceex.GetBinanceRestClient(),
}
}
func (h *BinanceProxyHandlers) RegisterHandlers(router *mux.Router) {
router.HandleFunc("/api/binance/proxy/getAccount", h.GetAccount)
}
func (h *BinanceProxyHandlers) GetAccount(w http.ResponseWriter, r *http.Request) {
response, err := h.client.GetAccount()
if err != nil {
log.WithError(err).Errorf("Binance GetAccount request failed")
}
WriteJsonResponse(w, http.StatusOK, response)
}
......@@ -268,6 +268,10 @@ func ServerMain() {
router.HandleFunc("/api/binance/trade/{tradeId}/abandon",
abandonTradeHandler(tradeService)).Methods("POST")
// Handlers that proxy requests to Binance.
binanceProxyHandlers := NewBinanceProxyHandlers()
binanceProxyHandlers.RegisterHandlers(router)
router.HandleFunc("/api/trade/query", queryTradesHandler).
Methods("GET")
router.HandleFunc("/api/trade/{tradeId}",
......
......@@ -15,8 +15,6 @@
import {Injectable} from "@angular/core";
import {HttpHeaders, HttpParams} from "@angular/common/http";
import * as hmacSHA256 from "crypto-js/hmac-sha256";
import * as hex from "crypto-js/enc-hex";
import {catchError, map} from "rxjs/operators";
import {Observable} from "rxjs";
import {throwError} from "rxjs/internal/observable/throwError";
......@@ -30,21 +28,9 @@ const STREAM_ROOT = "wss://stream.binance.com:9443";
@Injectable()
export class BinanceApiService {
private _apiKey: string = null;
private _apiSecret: string = null;
constructor(private makerApi: MakerApiService) {
}
set apiKey(key: string) {
this._apiKey = key;
}
set apiSecret(secret: string) {
this._apiSecret = secret;
}
private get(path: string, params: HttpParams = null): Observable<Object> {
const url = `${API_ROOT}${path}`;
......@@ -57,29 +43,6 @@ export class BinanceApiService {
});
}
private authenticateGet(path: string, params: HttpParams = null): Observable<Object> {
const url = `${API_ROOT}${path}`;
if (params == null) {
params = new HttpParams();
}
let headers = new HttpHeaders();
const timestamp = new Date().getTime();
params = params.set("timestamp", `${timestamp}`);
const hmacDigest = hmacSHA256(params.toString(), this._apiSecret);
params = params.set("signature", hex.stringify(hmacDigest));
headers = headers.append("X-MBX-APIKEY", this._apiKey);
return this.makerApi.get(url, {
headers: headers,
params: params,
});
}
private post(path: string, options?: {
params?: HttpParams;
headers?: HttpHeaders;
......@@ -106,11 +69,12 @@ export class BinanceApiService {
});
}
getAccountInfo(): Observable<AccountInfo> {
const endpoint = "/api/v3/account";
return this.authenticateGet(endpoint, null)
.pipe(map((raw: RawRestAccountInfo) => {
return AccountInfo.fromRest(raw);
getAccountInfo(): Observable<BinanceAccountInfo> {
return this.makerApi.get("/api/binance/proxy/getAccount")
.pipe(map((restResponse: BinanceRestAccountInfoResrponse) => {
const accountInfo = BinanceAccountInfo.fromRest(restResponse);
console.log(accountInfo);
return accountInfo;
}));
}
......@@ -202,36 +166,28 @@ export class Balance {
}
}
export interface RawRestAccountInfo {
makeCommission: number;
takerCommission: number;
buyerCommission: number;
sellerCommission: number;
canTrade: boolean;
canWithdraw: boolean;
canDeposit: boolean;
updateTime: number;
export interface BinanceRestAccountInfoResrponse {
balances: RestBalance[];
}
export interface RawStreamAccountInfo {
export interface BinanceStreamAccountInfoResponse {
B: StreamBalance[];
}
export class AccountInfo {
export class BinanceAccountInfo {
balances: Balance[] = null;
static fromRest(raw: RawRestAccountInfo): AccountInfo {
const accountInfo = new AccountInfo();
static fromRest(raw: BinanceRestAccountInfoResrponse): BinanceAccountInfo {
const accountInfo = new BinanceAccountInfo();
accountInfo.balances = raw.balances.map((b): Balance => {
return Balance.fromRest(b);
});
return accountInfo;
}
static fromStream(raw: RawStreamAccountInfo): AccountInfo {
const accountInfo = new AccountInfo();
static fromStream(raw: BinanceStreamAccountInfoResponse): BinanceAccountInfo {
const accountInfo = new BinanceAccountInfo();
accountInfo.balances = raw.B.map((b): Balance => {
return Balance.fromStream(b);
});
......
......@@ -99,8 +99,6 @@ export class BinanceService {
console.log("BinanceServer.init()");
// Get config then do initialization that depends on config.
this.makerApi.getConfig().subscribe((config) => {
this.api.apiKey = config["binance.api.key"];
this.api.apiSecret = config["binance.api.secret"];
this.updateExchangeInfo().subscribe(() => {
this.isReadySubject.next(true);
});
......
......@@ -17,12 +17,12 @@ import {Injectable} from "@angular/core";
import {BehaviorSubject} from "rxjs/BehaviorSubject";
import {Subject} from "rxjs/Subject";
import {
AccountInfo,
BinanceAccountInfo,
AggTrade,
BinanceApiService,
buildAggTradeFromStream,
CancelOrderResponse,
RawStreamAccountInfo,
BinanceStreamAccountInfoResponse,
StreamAggTrade
} from "./binance-api.service";
import {HttpParams} from "@angular/common/http";
......@@ -54,7 +54,7 @@ export class MakerService {
public binanceAggTrades$: Subject<AggTrade> = new Subject();
public binanceAccountInfo$: Subject<AccountInfo> = new Subject();
public binanceAccountInfo$: Subject<BinanceAccountInfo> = new Subject();
private logger: Logger = null;
......@@ -94,7 +94,7 @@ export class MakerService {
this.tradeMap$.next(this.tradeMap);
break;
case MakerMessageType.BINANCE_OUTBOUND_ACCOUNT_INFO:
const accountInfo = AccountInfo.fromStream(
const accountInfo = BinanceAccountInfo.fromStream(
message.binanceOutboundAccountInfo);
this.binanceAccountInfo$.next(accountInfo);
break;
......@@ -326,7 +326,7 @@ export interface MakerMessage {
trade?: TradeState;
binanceAggTrade?: StreamAggTrade;
tradeId?: string;
binanceOutboundAccountInfo: RawStreamAccountInfo;
binanceOutboundAccountInfo: BinanceStreamAccountInfoResponse;
notice?: any;
}
......
......@@ -14,7 +14,7 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
import {AfterViewInit, Component, OnDestroy, OnInit, ViewChild} from "@angular/core";
import {AccountInfo, AggTrade, Balance, BinanceApiService} from "../binance-api.service";
import {BinanceAccountInfo, AggTrade, Balance, BinanceApiService} from "../binance-api.service";
import {Observable} from "rxjs";
import {BinanceService, LimitSellType, OpenTradeOptions, PriceSource} from "../binance.service";
import {switchMap, tap} from "rxjs/operators";
......@@ -280,7 +280,7 @@ export class TradeComponent implements OnInit, OnDestroy, AfterViewInit {
}
}
private updateAccountInfo(): Observable<AccountInfo> {
private updateAccountInfo(): Observable<BinanceAccountInfo> {
return this.api.getAccountInfo().pipe(tap((accountInfo) => {
console.log("Updating account info.");
this.updateBalances(accountInfo);
......@@ -318,7 +318,7 @@ export class TradeComponent implements OnInit, OnDestroy, AfterViewInit {
}
}
private updateBalances(accountInfo: AccountInfo) {
private updateBalances(accountInfo: BinanceAccountInfo) {
for (const balance of accountInfo.balances) {
this.balances[balance.asset] = balance;
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment