enable and apply eslint rules

This commit is contained in:
woodser 2022-05-01 13:30:11 -04:00
parent c2a466b4be
commit d7492e96b2
11 changed files with 5729 additions and 6095 deletions

16
.editorconfig Normal file
View file

@ -0,0 +1,16 @@
See http://EditorConfig.org
# top-most EditorConfig file
root = true
# defaults
[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
indent_size = 2
indent_style = space
[*.md]
trim_trailing_whitespace = false

3
.eslintignore Normal file
View file

@ -0,0 +1,3 @@
*.css
*.svg
*.png

26
.eslintrc.json Normal file
View file

@ -0,0 +1,26 @@
{
"root": true,
"env": {
"es2021": true,
"node": true,
"browser": false
},
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/recommended"
],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaVersion": 12,
"sourceType": "module"
},
"plugins": ["@typescript-eslint"],
"ignorePatterns": ["node_modules/**", "**/dist/**", "src/protobuf/**"],
"rules": {
"@typescript-eslint/no-unused-vars": "error",
"@typescript-eslint/no-var-requires": "off",
"@typescript-eslint/no-non-null-assertion": "off",
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/no-non-null-asserted-optional-chain": "off"
}
}

10788
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -7,7 +7,7 @@
"@testing-library/react": "^11.2.6", "@testing-library/react": "^11.2.6",
"@testing-library/user-event": "^12.8.3", "@testing-library/user-event": "^12.8.3",
"@types/jest": "^26.0.22", "@types/jest": "^26.0.22",
"@types/node": "^12.20.10", "@types/node": "^17.0.30",
"@types/react": "^17.0.3", "@types/react": "^17.0.3",
"@types/react-dom": "^17.0.3", "@types/react-dom": "^17.0.3",
"console": "^0.7.2", "console": "^0.7.2",
@ -26,16 +26,9 @@
"eject": "react-scripts eject", "eject": "react-scripts eject",
"prepare": "bin/build_protobuf.sh", "prepare": "bin/build_protobuf.sh",
"pretest": "bin/build_protobuf.sh", "pretest": "bin/build_protobuf.sh",
"generate:docs": "typedoc ./src/haveno.ts --exclude **/*.test.ts --excludeNotDocumented" "lint": "eslint .",
}, "eslintfix": "eslint src/* --fix",
"eslintConfig": { "typedoc": "typedoc ./src/haveno.ts --exclude **/*.test.ts --excludeNotDocumented"
"extends": [
"react-app",
"react-app/jest"
],
"ignorePatterns": [
"**/*_pb.js"
]
}, },
"browserslist": { "browserslist": {
"production": [ "production": [
@ -50,6 +43,13 @@
] ]
}, },
"devDependencies": { "devDependencies": {
"@typescript-eslint/eslint-plugin": "5.12.1",
"@typescript-eslint/parser": "^5.19.0",
"eslint": "^7.32.0",
"eslint-config-prettier": "^8.5.0",
"eslint-import-resolver-typescript": "^2.7.1",
"eslint-plugin-import": "^2.26.0",
"eslint-plugin-jsx-a11y": "^6.5.1",
"monero-javascript": "^0.6.4", "monero-javascript": "^0.6.4",
"typedoc": "^0.22.15" "typedoc": "^0.22.15"
} }

View file

@ -1,7 +1,7 @@
import React from 'react'; import React from 'react';
import logo from './logo.png'; import logo from './logo.png';
import './App.css'; import './App.css';
import {HavenoClient} from './haveno'; import HavenoClient from './haveno';
const HAVENO_DAEMON_URL = "http://localhost:8080"; const HAVENO_DAEMON_URL = "http://localhost:8080";
const HAVENO_DAEMON_PASSWORD = "apitest"; const HAVENO_DAEMON_PASSWORD = "apitest";

File diff suppressed because it is too large Load diff

View file

@ -1,19 +1,18 @@
import {HavenoUtils} from "./utils/HavenoUtils"; import console from "console";
import {TaskLooper} from "./utils/TaskLooper"; import HavenoUtils from "./utils/HavenoUtils";
import * as grpcWeb from 'grpc-web'; import TaskLooper from "./utils/TaskLooper";
import {GetVersionClient, AccountClient, MoneroConnectionsClient, DisputesClient, DisputeAgentsClient, NotificationsClient, WalletsClient, PriceClient, OffersClient, PaymentAccountsClient, TradesClient, ShutdownServerClient, MoneroNodeClient} from './protobuf/GrpcServiceClientPb'; import type * as grpcWeb from "grpc-web";
import {GetVersionRequest, GetVersionReply, IsAppInitializedRequest, IsAppInitializedReply, RegisterDisputeAgentRequest, MarketPriceRequest, MarketPriceReply, MarketPricesRequest, MarketPricesReply, MarketPriceInfo, MarketDepthRequest, MarketDepthReply, MarketDepthInfo, GetBalancesRequest, GetBalancesReply, XmrBalanceInfo, GetMyOfferRequest, GetMyOfferReply, GetOffersRequest, GetOffersReply, OfferInfo, GetPaymentMethodsRequest, GetPaymentMethodsReply, GetPaymentAccountFormRequest, CreatePaymentAccountRequest, CreatePaymentAccountReply, GetPaymentAccountFormReply, GetPaymentAccountsRequest, GetPaymentAccountsReply, CreateCryptoCurrencyPaymentAccountRequest, CreateCryptoCurrencyPaymentAccountReply, CreateOfferRequest, CreateOfferReply, CancelOfferRequest, TakeOfferRequest, TakeOfferReply, TradeInfo, GetTradeRequest, GetTradeReply, GetTradesRequest, GetTradesReply, GetNewDepositAddressRequest, GetNewDepositAddressReply, ConfirmPaymentStartedRequest, ConfirmPaymentReceivedRequest, XmrTx, GetXmrTxsRequest, GetXmrTxsReply, XmrDestination, CreateXmrTxRequest, CreateXmrTxReply, RelayXmrTxRequest, RelayXmrTxReply, CreateAccountRequest, AccountExistsRequest, AccountExistsReply, DeleteAccountRequest, OpenAccountRequest, IsAccountOpenRequest, IsAccountOpenReply, CloseAccountRequest, ChangePasswordRequest, BackupAccountRequest, BackupAccountReply, RestoreAccountRequest, StopRequest, NotificationMessage, RegisterNotificationListenerRequest, SendNotificationRequest, UrlConnection, AddConnectionRequest, RemoveConnectionRequest, GetConnectionRequest, GetConnectionsRequest, SetConnectionRequest, CheckConnectionRequest, CheckConnectionsReply, CheckConnectionsRequest, StartCheckingConnectionsRequest, StopCheckingConnectionsRequest, GetBestAvailableConnectionRequest, SetAutoSwitchRequest, CheckConnectionReply, GetConnectionsReply, GetConnectionReply, GetBestAvailableConnectionReply, GetDisputeRequest, GetDisputeReply, GetDisputesRequest, GetDisputesReply, OpenDisputeRequest, ResolveDisputeRequest, SendDisputeChatMessageRequest, SendChatMessageRequest, GetChatMessagesRequest, GetChatMessagesReply, StartMoneroNodeRequest, StopMoneroNodeRequest, IsMoneroNodeRunningRequest, IsMoneroNodeRunningReply, GetMoneroNodeSettingsRequest, GetMoneroNodeSettingsReply} from './protobuf/grpc_pb'; import { GetVersionClient, AccountClient, MoneroConnectionsClient, DisputesClient, DisputeAgentsClient, NotificationsClient, WalletsClient, PriceClient, OffersClient, PaymentAccountsClient, TradesClient, ShutdownServerClient, MoneroNodeClient } from './protobuf/GrpcServiceClientPb';
import {PaymentMethod, PaymentAccount, AvailabilityResult, Attachment, DisputeResult, Dispute, ChatMessage, MoneroNodeSettings} from './protobuf/pb_pb'; import { GetVersionRequest, GetVersionReply, IsAppInitializedRequest, IsAppInitializedReply, RegisterDisputeAgentRequest, MarketPriceRequest, MarketPriceReply, MarketPricesRequest, MarketPricesReply, MarketPriceInfo, MarketDepthRequest, MarketDepthReply, MarketDepthInfo, GetBalancesRequest, GetBalancesReply, XmrBalanceInfo, GetMyOfferRequest, GetMyOfferReply, GetOffersRequest, GetOffersReply, OfferInfo, GetPaymentMethodsRequest, GetPaymentMethodsReply, GetPaymentAccountFormRequest, CreatePaymentAccountRequest, CreatePaymentAccountReply, GetPaymentAccountFormReply, GetPaymentAccountsRequest, GetPaymentAccountsReply, CreateCryptoCurrencyPaymentAccountRequest, CreateCryptoCurrencyPaymentAccountReply, CreateOfferRequest, CreateOfferReply, CancelOfferRequest, TakeOfferRequest, TakeOfferReply, TradeInfo, GetTradeRequest, GetTradeReply, GetTradesRequest, GetTradesReply, GetNewDepositAddressRequest, GetNewDepositAddressReply, ConfirmPaymentStartedRequest, ConfirmPaymentReceivedRequest, XmrTx, GetXmrTxsRequest, GetXmrTxsReply, XmrDestination, CreateXmrTxRequest, CreateXmrTxReply, RelayXmrTxRequest, RelayXmrTxReply, CreateAccountRequest, AccountExistsRequest, AccountExistsReply, DeleteAccountRequest, OpenAccountRequest, IsAccountOpenRequest, IsAccountOpenReply, CloseAccountRequest, ChangePasswordRequest, BackupAccountRequest, BackupAccountReply, RestoreAccountRequest, StopRequest, NotificationMessage, RegisterNotificationListenerRequest, SendNotificationRequest, UrlConnection, AddConnectionRequest, RemoveConnectionRequest, GetConnectionRequest, GetConnectionsRequest, SetConnectionRequest, CheckConnectionRequest, CheckConnectionsReply, CheckConnectionsRequest, StartCheckingConnectionsRequest, StopCheckingConnectionsRequest, GetBestAvailableConnectionRequest, SetAutoSwitchRequest, CheckConnectionReply, GetConnectionsReply, GetConnectionReply, GetBestAvailableConnectionReply, GetDisputeRequest, GetDisputeReply, GetDisputesRequest, GetDisputesReply, OpenDisputeRequest, ResolveDisputeRequest, SendDisputeChatMessageRequest, SendChatMessageRequest, GetChatMessagesRequest, GetChatMessagesReply, StartMoneroNodeRequest, StopMoneroNodeRequest, IsMoneroNodeRunningRequest, IsMoneroNodeRunningReply, GetMoneroNodeSettingsRequest, GetMoneroNodeSettingsReply } from "./protobuf/grpc_pb";
import { PaymentMethod, PaymentAccount, AvailabilityResult, Attachment, DisputeResult, Dispute, ChatMessage, MoneroNodeSettings } from "./protobuf/pb_pb";
const console = require('console');
/** /**
* Haveno daemon client using gRPC. * Haveno daemon client using gRPC.
*/ */
class HavenoClient { export default class HavenoClient {
// grpc clients // grpc clients
_appName: string|undefined; _appName: string | undefined;
_getVersionClient: GetVersionClient; _getVersionClient: GetVersionClient;
_disputeAgentsClient: DisputeAgentsClient; _disputeAgentsClient: DisputeAgentsClient;
_disputesClient: DisputesClient; _disputesClient: DisputesClient;
@ -27,25 +26,25 @@ class HavenoClient {
_tradesClient: TradesClient; _tradesClient: TradesClient;
_accountClient: AccountClient; _accountClient: AccountClient;
_shutdownServerClient: ShutdownServerClient; _shutdownServerClient: ShutdownServerClient;
// state variables // state variables
_url: string; _url: string;
_password: string; _password: string;
_process: any; _process: any;
_processLogging = false; _processLogging = false;
_walletRpcPort: number|undefined; _walletRpcPort: number | undefined;
_notificationListeners: ((notification: NotificationMessage) => void)[] = []; _notificationListeners: ((notification: NotificationMessage) => void)[] = [];
_registerNotificationListenerCalled = false; _registerNotificationListenerCalled = false;
_keepAliveLooper: any; _keepAliveLooper: any;
_keepAlivePeriodMs: number = 60000; _keepAlivePeriodMs = 60000;
// constants // constants
static readonly _fullyInitializedMessage = "Application fully initialized"; static readonly _fullyInitializedMessage = "Application fully initialized";
static readonly _loginRequiredMessage = "Interactive login required"; static readonly _loginRequiredMessage = "Interactive login required";
/** /**
* Construct a client connected to a Haveno daemon. * Construct a client connected to a Haveno daemon.
* *
* @param {string} url - Haveno daemon url * @param {string} url - Haveno daemon url
* @param {string} password - Haveno daemon password * @param {string} password - Haveno daemon password
*/ */
@ -69,10 +68,10 @@ class HavenoClient {
this._notificationsClient = new NotificationsClient(this._url); this._notificationsClient = new NotificationsClient(this._url);
this._shutdownServerClient = new ShutdownServerClient(this._url); this._shutdownServerClient = new ShutdownServerClient(this._url);
} }
/** /**
* Start a new Haveno process. * Start a new Haveno process.
* *
* @param {string} havenoPath - path to Haveno binaries * @param {string} havenoPath - path to Haveno binaries
* @param {string[]} cmd - command to start the process * @param {string[]} cmd - command to start the process
* @param {string} url - Haveno daemon url (must proxy to api port) * @param {string} url - Haveno daemon url (must proxy to api port)
@ -80,24 +79,24 @@ class HavenoClient {
* @return {haveno} a client connected to the newly started Haveno process * @return {haveno} a client connected to the newly started Haveno process
*/ */
static async startProcess(havenoPath: string, cmd: string[], url: string, enableLogging: boolean): Promise<HavenoClient> { static async startProcess(havenoPath: string, cmd: string[], url: string, enableLogging: boolean): Promise<HavenoClient> {
// return promise which resolves after starting havenod // return promise which resolves after starting havenod
return new Promise(function(resolve, reject) { return new Promise((resolve, reject) => {
HavenoUtils.log(2, "Starting Haveno process: " + cmd + " on proxy url: " + url); HavenoUtils.log(2, "Starting Haveno process: " + cmd + " on proxy url: " + url);
// state variables // state variables
let output = ""; let output = "";
let isStarted = false; let isStarted = false;
let daemon: HavenoClient|undefined = undefined; let daemon: HavenoClient | undefined = undefined;
// start process // start process
let childProcess = require('child_process').spawn(cmd[0], cmd.slice(1), {cwd: havenoPath}); const childProcess = require('child_process').spawn(cmd[0], cmd.slice(1), {cwd: havenoPath});
childProcess.stdout.setEncoding('utf8'); childProcess.stdout.setEncoding('utf8');
childProcess.stderr.setEncoding('utf8'); childProcess.stderr.setEncoding('utf8');
// handle stdout // handle stdout
childProcess.stdout.on('data', async function(data: any) { childProcess.stdout.on('data', async function(data: any) {
let line = data.toString(); const line = data.toString();
if (loggingEnabled()) process.stdout.write(line); if (loggingEnabled()) process.stdout.write(line);
output += line + '\n'; // capture output in case of error output += line + '\n'; // capture output in case of error
@ -105,12 +104,12 @@ class HavenoClient {
if (!daemon && (line.indexOf(HavenoClient._fullyInitializedMessage) >= 0 || line.indexOf(HavenoClient._loginRequiredMessage) >= 0)) { if (!daemon && (line.indexOf(HavenoClient._fullyInitializedMessage) >= 0 || line.indexOf(HavenoClient._loginRequiredMessage) >= 0)) {
// get api password // get api password
let passwordIdx = cmd.indexOf("--apiPassword"); const passwordIdx = cmd.indexOf("--apiPassword");
if (passwordIdx < 0) { if (passwordIdx < 0) {
reject("Must provide API password to start Haveno daemon"); reject("Must provide API password to start Haveno daemon");
return; return;
} }
let password = cmd[passwordIdx + 1]; const password = cmd[passwordIdx + 1];
// create client connected to internal process // create client connected to internal process
daemon = new HavenoClient(url, password); daemon = new HavenoClient(url, password);
@ -119,7 +118,7 @@ class HavenoClient {
daemon._appName = cmd[cmd.indexOf("--appName") + 1]; daemon._appName = cmd[cmd.indexOf("--appName") + 1];
// get wallet rpc port // get wallet rpc port
let walletRpcPortIdx = cmd.indexOf("--walletRpcBindPort"); const walletRpcPortIdx = cmd.indexOf("--walletRpcBindPort");
if (walletRpcPortIdx >= 0) daemon._walletRpcPort = parseInt(cmd[walletRpcPortIdx + 1]); if (walletRpcPortIdx >= 0) daemon._walletRpcPort = parseInt(cmd[walletRpcPortIdx + 1]);
// resolve promise with client connected to internal process // resolve promise with client connected to internal process
@ -217,9 +216,8 @@ class HavenoClient {
* @return {string} the Haveno daemon version * @return {string} the Haveno daemon version
*/ */
async getVersion(): Promise<string> { async getVersion(): Promise<string> {
let that = this; return new Promise((resolve, reject) => {
return new Promise(function(resolve, reject) { this._getVersionClient.getVersion(new GetVersionRequest(), {password: this._password}, function(err: grpcWeb.RpcError, response: GetVersionReply) {
that._getVersionClient.getVersion(new GetVersionRequest(), {password: that._password}, function(err: grpcWeb.RpcError, response: GetVersionReply) {
if (err) reject(err); if (err) reject(err);
else resolve(response.getVersion()); else resolve(response.getVersion());
}); });
@ -246,9 +244,8 @@ class HavenoClient {
* @return {boolean} true if the account is created, false otherwise * @return {boolean} true if the account is created, false otherwise
*/ */
async accountExists(): Promise<boolean> { async accountExists(): Promise<boolean> {
let that = this; return new Promise((resolve, reject) => {
return new Promise(function(resolve, reject) { this._accountClient.accountExists(new AccountExistsRequest(), {password: this._password}, function(err: grpcWeb.RpcError, response: AccountExistsReply) {
that._accountClient.accountExists(new AccountExistsRequest(), {password: that._password}, function(err: grpcWeb.RpcError, response: AccountExistsReply) {
if (err) reject(err); if (err) reject(err);
else resolve(response.getAccountExists()); else resolve(response.getAccountExists());
}); });
@ -261,9 +258,8 @@ class HavenoClient {
* @return {boolean} true if the account is open and authenticated, false otherwise * @return {boolean} true if the account is open and authenticated, false otherwise
*/ */
async isAccountOpen(): Promise<boolean> { async isAccountOpen(): Promise<boolean> {
let that = this; return new Promise((resolve, reject) => {
return new Promise(function(resolve, reject) { this._accountClient.isAccountOpen(new IsAccountOpenRequest(), {password: this._password}, function(err: grpcWeb.RpcError, response: IsAccountOpenReply) {
that._accountClient.isAccountOpen(new IsAccountOpenRequest(), {password: that._password}, function(err: grpcWeb.RpcError, response: IsAccountOpenReply) {
if (err) reject(err); if (err) reject(err);
else resolve(response.getIsAccountOpen()); else resolve(response.getIsAccountOpen());
}); });
@ -276,9 +272,8 @@ class HavenoClient {
* @param {string} password - the password to encrypt the account * @param {string} password - the password to encrypt the account
*/ */
async createAccount(password: string): Promise<void> { async createAccount(password: string): Promise<void> {
let that = this; await new Promise<void>((resolve, reject) => {
await new Promise(function(resolve, reject) { this._accountClient.createAccount(new CreateAccountRequest().setPassword(password), {password: this._password}, function(err: grpcWeb.RpcError) {
that._accountClient.createAccount(new CreateAccountRequest().setPassword(password), {password: that._password}, function(err: grpcWeb.RpcError) {
if (err) reject(err); if (err) reject(err);
else resolve(); else resolve();
}); });
@ -292,9 +287,8 @@ class HavenoClient {
* @param {string} password - the account password * @param {string} password - the account password
*/ */
async openAccount(password: string): Promise<void> { async openAccount(password: string): Promise<void> {
let that = this; await new Promise<void>((resolve, reject) => {
await new Promise(function(resolve, reject) { this._accountClient.openAccount(new OpenAccountRequest().setPassword(password), {password: this._password}, function(err: grpcWeb.RpcError) {
that._accountClient.openAccount(new OpenAccountRequest().setPassword(password), {password: that._password}, function(err: grpcWeb.RpcError) {
if (err) reject(err); if (err) reject(err);
else resolve(); else resolve();
}); });
@ -308,9 +302,8 @@ class HavenoClient {
* @param {string} password - the new account password * @param {string} password - the new account password
*/ */
async changePassword(password: string): Promise<void> { async changePassword(password: string): Promise<void> {
let that = this; return new Promise<void>((resolve, reject) => {
return new Promise(function(resolve, reject) { this._accountClient.changePassword(new ChangePasswordRequest().setPassword(password), {password: this._password}, function(err: grpcWeb.RpcError) {
that._accountClient.changePassword(new ChangePasswordRequest().setPassword(password), {password: that._password}, function(err: grpcWeb.RpcError) {
if (err) reject(err); if (err) reject(err);
else resolve(); else resolve();
}); });
@ -321,9 +314,8 @@ class HavenoClient {
* Close the currently open account. * Close the currently open account.
*/ */
async closeAccount(): Promise<void> { async closeAccount(): Promise<void> {
let that = this; return new Promise<void>((resolve, reject) => {
return new Promise(function(resolve, reject) { this._accountClient.closeAccount(new CloseAccountRequest(), {password: this._password}, function(err: grpcWeb.RpcError) {
that._accountClient.closeAccount(new CloseAccountRequest(), {password: that._password}, function(err: grpcWeb.RpcError) {
if (err) reject(err); if (err) reject(err);
else resolve(); else resolve();
}); });
@ -334,9 +326,8 @@ class HavenoClient {
* Permanently delete the Haveno account and shutdown the server. // TODO: possible to not shutdown server? * Permanently delete the Haveno account and shutdown the server. // TODO: possible to not shutdown server?
*/ */
async deleteAccount(): Promise<void> { async deleteAccount(): Promise<void> {
let that = this; return new Promise<void>((resolve, reject) => {
return new Promise(function(resolve, reject) { this._accountClient.deleteAccount(new DeleteAccountRequest(), {password: this._password}, async function(err: grpcWeb.RpcError) {
that._accountClient.deleteAccount(new DeleteAccountRequest(), {password: that._password}, async function(err: grpcWeb.RpcError) {
if (err) reject(err); if (err) reject(err);
else setTimeout(resolve, 5000); else setTimeout(resolve, 5000);
}); });
@ -347,16 +338,15 @@ class HavenoClient {
* Backup the account to the given stream. TODO: stream type? * Backup the account to the given stream. TODO: stream type?
*/ */
async backupAccount(stream: any): Promise<number> { async backupAccount(stream: any): Promise<number> {
let that = this; return new Promise((resolve, reject) => {
return new Promise(function(resolve, reject) {
let total = 0; let total = 0;
let response = that._accountClient.backupAccount(new BackupAccountRequest(), {password: that._password}); const response = this._accountClient.backupAccount(new BackupAccountRequest(), {password: this._password});
response.on('data', (chunk) => { response.on('data', (chunk: any) => {
let bytes = (chunk as BackupAccountReply).getZipBytes(); // TODO: right api? const bytes = (chunk as BackupAccountReply).getZipBytes(); // TODO: right api?
total += bytes.length; total += bytes.length;
stream.write(bytes); stream.write(bytes);
}); });
response.on('error', function(err) { response.on('error', function(err: any) {
if(err) reject(err); if(err) reject(err);
}); });
response.on('end', function() { response.on('end', function() {
@ -374,17 +364,18 @@ class HavenoClient {
*/ */
async restoreAccount(zipBytes: Uint8Array): Promise<void> { async restoreAccount(zipBytes: Uint8Array): Promise<void> {
if (zipBytes.length === 0) throw new Error("Zip bytes must not be empty") if (zipBytes.length === 0) throw new Error("Zip bytes must not be empty")
let totalLength = zipBytes.byteLength; const totalLength = zipBytes.byteLength;
let offset = 0; let offset = 0;
let chunkSize = 4000000; // the max frame size is 4194304 but leave room for http headers let chunkSize = 4000000; // the max frame size is 4194304 but leave room for http headers
let hasMore = true; let hasMore = true;
// eslint-disable-next-line no-constant-condition
while (true) { while (true) {
if (zipBytes.byteLength <= offset + 1) return; if (zipBytes.byteLength <= offset + 1) return;
if (zipBytes.byteLength <= offset + chunkSize) { if (zipBytes.byteLength <= offset + chunkSize) {
chunkSize = zipBytes.byteLength - offset - 1; chunkSize = zipBytes.byteLength - offset - 1;
hasMore = false; hasMore = false;
} }
let subArray = zipBytes.subarray(offset, offset + chunkSize); const subArray = zipBytes.subarray(offset, offset + chunkSize);
await this._restoreAccountChunk(subArray, offset, totalLength, hasMore); await this._restoreAccountChunk(subArray, offset, totalLength, hasMore);
offset += chunkSize; offset += chunkSize;
} }
@ -406,7 +397,7 @@ class HavenoClient {
* @param {(notification: NotificationMessage) => void} listener - the notification listener to remove * @param {(notification: NotificationMessage) => void} listener - the notification listener to remove
*/ */
async removeNotificationListener(listener: (notification: NotificationMessage) => void): Promise<void> { async removeNotificationListener(listener: (notification: NotificationMessage) => void): Promise<void> {
let idx = this._notificationListeners.indexOf(listener); const idx = this._notificationListeners.indexOf(listener);
if (idx > -1) this._notificationListeners.splice(idx, 1); if (idx > -1) this._notificationListeners.splice(idx, 1);
else throw new Error("Notification listener is not registered"); else throw new Error("Notification listener is not registered");
} }
@ -417,7 +408,7 @@ class HavenoClient {
* @return {boolean} true if connected to the Monero network, false otherwise * @return {boolean} true if connected to the Monero network, false otherwise
*/ */
async isConnectedToMonero(): Promise<boolean> { async isConnectedToMonero(): Promise<boolean> {
let connection = await this.getMoneroConnection(); const connection = await this.getMoneroConnection();
return connection !== undefined && return connection !== undefined &&
connection.getOnlineStatus()! === UrlConnection.OnlineStatus.ONLINE && connection.getOnlineStatus()! === UrlConnection.OnlineStatus.ONLINE &&
connection.getAuthenticationStatus()! !== UrlConnection.AuthenticationStatus.NOT_AUTHENTICATED; connection.getAuthenticationStatus()! !== UrlConnection.AuthenticationStatus.NOT_AUTHENTICATED;
@ -429,9 +420,8 @@ class HavenoClient {
* @param {string | UrlConnection} connection - daemon url or connection to add * @param {string | UrlConnection} connection - daemon url or connection to add
*/ */
async addMoneroConnection(connection: string | UrlConnection): Promise<void> { async addMoneroConnection(connection: string | UrlConnection): Promise<void> {
let that = this; return new Promise((resolve, reject) => {
return new Promise(function(resolve, reject) { this._moneroConnectionsClient.addConnection(new AddConnectionRequest().setConnection(typeof connection === "string" ? new UrlConnection().setUrl(connection) : connection), {password: this._password}, function(err: grpcWeb.RpcError) {
that._moneroConnectionsClient.addConnection(new AddConnectionRequest().setConnection(typeof connection === "string" ? new UrlConnection().setUrl(connection) : connection), {password: that._password}, function(err: grpcWeb.RpcError) {
if (err) reject(err); if (err) reject(err);
else resolve(); else resolve();
}); });
@ -444,9 +434,8 @@ class HavenoClient {
* @param {string} url - url of the daemon connection to remove * @param {string} url - url of the daemon connection to remove
*/ */
async removeMoneroConnection(url: string): Promise<void> { async removeMoneroConnection(url: string): Promise<void> {
let that = this; return new Promise((resolve, reject) => {
return new Promise(function(resolve, reject) { this._moneroConnectionsClient.removeConnection(new RemoveConnectionRequest().setUrl(url), {password: this._password}, function(err: grpcWeb.RpcError) {
that._moneroConnectionsClient.removeConnection(new RemoveConnectionRequest().setUrl(url), {password: that._password}, function(err: grpcWeb.RpcError) {
if (err) reject(err); if (err) reject(err);
else resolve(); else resolve();
}); });
@ -459,9 +448,8 @@ class HavenoClient {
* @return {UrlConnection | undefined} the current daemon connection, undefined if no current connection * @return {UrlConnection | undefined} the current daemon connection, undefined if no current connection
*/ */
async getMoneroConnection(): Promise<UrlConnection | undefined> { async getMoneroConnection(): Promise<UrlConnection | undefined> {
let that = this; return new Promise((resolve, reject) => {
return new Promise(function(resolve, reject) { this._moneroConnectionsClient.getConnection(new GetConnectionRequest(), {password: this._password}, function(err: grpcWeb.RpcError, response: GetConnectionReply) {
that._moneroConnectionsClient.getConnection(new GetConnectionRequest(), {password: that._password}, function(err: grpcWeb.RpcError, response: GetConnectionReply) {
if (err) reject(err); if (err) reject(err);
else resolve(response.getConnection()); else resolve(response.getConnection());
}); });
@ -474,9 +462,8 @@ class HavenoClient {
* @return {UrlConnection[]} all daemon connections * @return {UrlConnection[]} all daemon connections
*/ */
async getMoneroConnections(): Promise<UrlConnection[]> { async getMoneroConnections(): Promise<UrlConnection[]> {
let that = this; return new Promise((resolve, reject) => {
return new Promise(function(resolve, reject) { this._moneroConnectionsClient.getConnections(new GetConnectionsRequest(), {password: this._password}, function(err: grpcWeb.RpcError, response: GetConnectionsReply) {
that._moneroConnectionsClient.getConnections(new GetConnectionsRequest(), {password: that._password}, function(err: grpcWeb.RpcError, response: GetConnectionsReply) {
if (err) reject(err); if (err) reject(err);
else resolve(response.getConnectionsList()); else resolve(response.getConnectionsList());
}); });
@ -494,12 +481,11 @@ class HavenoClient {
* @param {string | UrlConnection} connection - connection to set as current * @param {string | UrlConnection} connection - connection to set as current
*/ */
async setMoneroConnection(connection?: string | UrlConnection): Promise<void> { async setMoneroConnection(connection?: string | UrlConnection): Promise<void> {
let that = this; const request = new SetConnectionRequest();
let request = new SetConnectionRequest();
if (typeof connection === "string") request.setUrl(connection); if (typeof connection === "string") request.setUrl(connection);
else request.setConnection(connection); else request.setConnection(connection);
return new Promise(function(resolve, reject) { return new Promise((resolve, reject) => {
that._moneroConnectionsClient.setConnection(request, {password: that._password}, function(err: grpcWeb.RpcError) { this._moneroConnectionsClient.setConnection(request, {password: this._password}, function(err: grpcWeb.RpcError) {
if (err) reject(err); if (err) reject(err);
else resolve(); else resolve();
}); });
@ -514,9 +500,8 @@ class HavenoClient {
* @return {UrlConnection | undefined} the current daemon connection status, undefined if no current connection * @return {UrlConnection | undefined} the current daemon connection status, undefined if no current connection
*/ */
async checkMoneroConnection(): Promise<UrlConnection | undefined> { async checkMoneroConnection(): Promise<UrlConnection | undefined> {
let that = this; return new Promise((resolve, reject) => {
return new Promise(function(resolve, reject) { this._moneroConnectionsClient.checkConnection(new CheckConnectionRequest(), {password: this._password}, function(err: grpcWeb.RpcError, response: CheckConnectionReply) {
that._moneroConnectionsClient.checkConnection(new CheckConnectionRequest(), {password: that._password}, function(err: grpcWeb.RpcError, response: CheckConnectionReply) {
if (err) reject(err); if (err) reject(err);
else resolve(response.getConnection()); else resolve(response.getConnection());
}); });
@ -529,9 +514,8 @@ class HavenoClient {
* @return {UrlConnection[]} status of all managed connections. * @return {UrlConnection[]} status of all managed connections.
*/ */
async checkMoneroConnections(): Promise<UrlConnection[]> { async checkMoneroConnections(): Promise<UrlConnection[]> {
let that = this; return new Promise((resolve, reject) => {
return new Promise(function(resolve, reject) { this._moneroConnectionsClient.checkConnections(new CheckConnectionsRequest(), {password: this._password}, function(err: grpcWeb.RpcError, response: CheckConnectionsReply) {
that._moneroConnectionsClient.checkConnections(new CheckConnectionsRequest(), {password: that._password}, function(err: grpcWeb.RpcError, response: CheckConnectionsReply) {
if (err) reject(err); if (err) reject(err);
else resolve(response.getConnectionsList()); else resolve(response.getConnectionsList());
}); });
@ -544,9 +528,8 @@ class HavenoClient {
* @param {number} refreshPeriod - time between checks in milliseconds (default 15000 ms or 15 seconds) * @param {number} refreshPeriod - time between checks in milliseconds (default 15000 ms or 15 seconds)
*/ */
async startCheckingConnection(refreshPeriod: number): Promise<void> { async startCheckingConnection(refreshPeriod: number): Promise<void> {
let that = this; return new Promise((resolve, reject) => {
return new Promise(function(resolve, reject) { this._moneroConnectionsClient.startCheckingConnections(new StartCheckingConnectionsRequest().setRefreshPeriod(refreshPeriod), {password: this._password}, function(err: grpcWeb.RpcError) {
that._moneroConnectionsClient.startCheckingConnections(new StartCheckingConnectionsRequest().setRefreshPeriod(refreshPeriod), {password: that._password}, function(err: grpcWeb.RpcError) {
if (err) reject(err); if (err) reject(err);
else resolve(); else resolve();
}); });
@ -557,9 +540,8 @@ class HavenoClient {
* Stop checking the connection status periodically. * Stop checking the connection status periodically.
*/ */
async stopCheckingConnection(): Promise<void> { async stopCheckingConnection(): Promise<void> {
let that = this; return new Promise((resolve, reject) => {
return new Promise(function(resolve, reject) { this._moneroConnectionsClient.stopCheckingConnections(new StopCheckingConnectionsRequest(), {password: this._password}, function(err: grpcWeb.RpcError) {
that._moneroConnectionsClient.stopCheckingConnections(new StopCheckingConnectionsRequest(), {password: that._password}, function(err: grpcWeb.RpcError) {
if (err) reject(err); if (err) reject(err);
else resolve(); else resolve();
}); });
@ -572,9 +554,8 @@ class HavenoClient {
* @return {UrlConnection | undefined} the best available connection in order of priority then response time, undefined if no connections available * @return {UrlConnection | undefined} the best available connection in order of priority then response time, undefined if no connections available
*/ */
async getBestAvailableConnection(): Promise<UrlConnection | undefined> { async getBestAvailableConnection(): Promise<UrlConnection | undefined> {
let that = this; return new Promise((resolve, reject) => {
return new Promise(function(resolve, reject) { this._moneroConnectionsClient.getBestAvailableConnection(new GetBestAvailableConnectionRequest(), {password: this._password}, function(err: grpcWeb.RpcError, response: GetBestAvailableConnectionReply) {
that._moneroConnectionsClient.getBestAvailableConnection(new GetBestAvailableConnectionRequest(), {password: that._password}, function(err: grpcWeb.RpcError, response: GetBestAvailableConnectionReply) {
if (err) reject(err); if (err) reject(err);
else resolve(response.getConnection()); else resolve(response.getConnection());
}); });
@ -587,9 +568,8 @@ class HavenoClient {
* @param {boolean} autoSwitch - whether auto switch is enabled or disabled * @param {boolean} autoSwitch - whether auto switch is enabled or disabled
*/ */
async setAutoSwitch(autoSwitch: boolean): Promise<void> { async setAutoSwitch(autoSwitch: boolean): Promise<void> {
let that = this; return new Promise((resolve, reject) => {
return new Promise(function(resolve, reject) { this._moneroConnectionsClient.setAutoSwitch(new SetAutoSwitchRequest().setAutoSwitch(autoSwitch), {password: this._password}, function(err: grpcWeb.RpcError) {
that._moneroConnectionsClient.setAutoSwitch(new SetAutoSwitchRequest().setAutoSwitch(autoSwitch), {password: that._password}, function(err: grpcWeb.RpcError) {
if (err) reject(err); if (err) reject(err);
else resolve(); else resolve();
}); });
@ -600,9 +580,8 @@ class HavenoClient {
* Returns whether daemon is running a local monero node. * Returns whether daemon is running a local monero node.
*/ */
async isMoneroNodeRunning(): Promise<boolean> { async isMoneroNodeRunning(): Promise<boolean> {
let that = this; return new Promise((resolve, reject) => {
return new Promise(function(resolve, reject) { this._moneroNodeClient.isMoneroNodeRunning(new IsMoneroNodeRunningRequest(), {password: this._password}, function(err: grpcWeb.RpcError, response: IsMoneroNodeRunningReply) {
that._moneroNodeClient.isMoneroNodeRunning(new IsMoneroNodeRunningRequest(), {password: that._password}, function(err: grpcWeb.RpcError, response: IsMoneroNodeRunningReply) {
if (err) reject(err); if (err) reject(err);
else resolve(response.getIsRunning()); else resolve(response.getIsRunning());
}); });
@ -613,10 +592,9 @@ class HavenoClient {
* Gets the current local monero node settings. * Gets the current local monero node settings.
*/ */
async getMoneroNodeSettings(): Promise<MoneroNodeSettings | undefined> { async getMoneroNodeSettings(): Promise<MoneroNodeSettings | undefined> {
let that = this; return new Promise((resolve, reject) => {
return new Promise(function(resolve, reject) { const request = new GetMoneroNodeSettingsRequest();
let request = new GetMoneroNodeSettingsRequest(); this._moneroNodeClient.getMoneroNodeSettings(request, {password: this._password}, function(err: grpcWeb.RpcError, response: GetMoneroNodeSettingsReply) {
that._moneroNodeClient.getMoneroNodeSettings(request, {password: that._password}, function(err: grpcWeb.RpcError, response: GetMoneroNodeSettingsReply) {
if (err) reject(err); if (err) reject(err);
else resolve(response.getSettings()); else resolve(response.getSettings());
}); });
@ -629,10 +607,9 @@ class HavenoClient {
* @param {MoneroNodeSettings} settings - the settings to start the local node with * @param {MoneroNodeSettings} settings - the settings to start the local node with
*/ */
async startMoneroNode(settings: MoneroNodeSettings): Promise<void> { async startMoneroNode(settings: MoneroNodeSettings): Promise<void> {
let that = this; return new Promise((resolve, reject) => {
return new Promise(function(resolve, reject) { const request = new StartMoneroNodeRequest().setSettings(settings);
let request = new StartMoneroNodeRequest().setSettings(settings); this._moneroNodeClient.startMoneroNode(request, {password: this._password}, function(err: grpcWeb.RpcError) {
that._moneroNodeClient.startMoneroNode(request, {password: that._password}, function(err: grpcWeb.RpcError) {
if (err) reject(err); if (err) reject(err);
else resolve(); else resolve();
}); });
@ -643,9 +620,8 @@ class HavenoClient {
* Stops the local monero node. * Stops the local monero node.
*/ */
async stopMoneroNode(): Promise<void> { async stopMoneroNode(): Promise<void> {
let that = this; return new Promise((resolve, reject) => {
return new Promise(function(resolve, reject) { this._moneroNodeClient.stopMoneroNode(new StopMoneroNodeRequest(), {password: this._password}, function(err: grpcWeb.RpcError) {
that._moneroNodeClient.stopMoneroNode(new StopMoneroNodeRequest(), {password: that._password}, function(err: grpcWeb.RpcError) {
if (err) reject(err); if (err) reject(err);
else resolve(); else resolve();
}); });
@ -659,12 +635,11 @@ class HavenoClient {
* @param {string} registrationKey - registration key * @param {string} registrationKey - registration key
*/ */
async registerDisputeAgent(disputeAgentType: string, registrationKey: string): Promise<void> { async registerDisputeAgent(disputeAgentType: string, registrationKey: string): Promise<void> {
let that = this; const request = new RegisterDisputeAgentRequest()
let request = new RegisterDisputeAgentRequest()
.setDisputeAgentType(disputeAgentType) .setDisputeAgentType(disputeAgentType)
.setRegistrationKey(registrationKey); .setRegistrationKey(registrationKey);
return new Promise(function(resolve, reject) { return new Promise((resolve, reject) => {
that._disputeAgentsClient.registerDisputeAgent(request, {password: that._password}, function(err: grpcWeb.RpcError) { this._disputeAgentsClient.registerDisputeAgent(request, {password: this._password}, function(err: grpcWeb.RpcError) {
if (err) reject(err); if (err) reject(err);
else resolve(); else resolve();
}); });
@ -677,9 +652,8 @@ class HavenoClient {
* @return {XmrBalanceInfo} the user's balances * @return {XmrBalanceInfo} the user's balances
*/ */
async getBalances(): Promise<XmrBalanceInfo> { async getBalances(): Promise<XmrBalanceInfo> {
let that = this; return new Promise((resolve, reject) => {
return new Promise(function(resolve, reject) { this._walletsClient.getBalances(new GetBalancesRequest().setCurrencyCode("XMR"), {password: this._password}, function(err: grpcWeb.RpcError, response: GetBalancesReply) {
that._walletsClient.getBalances(new GetBalancesRequest().setCurrencyCode("XMR"), {password: that._password}, function(err: grpcWeb.RpcError, response: GetBalancesReply) {
if (err) reject(err); if (err) reject(err);
else resolve(response.getBalances()!.getXmr()!); else resolve(response.getBalances()!.getXmr()!);
}); });
@ -692,9 +666,8 @@ class HavenoClient {
* @return {string} the deposit address (a subaddress in the Haveno wallet) * @return {string} the deposit address (a subaddress in the Haveno wallet)
*/ */
async getNewDepositAddress(): Promise<string> { async getNewDepositAddress(): Promise<string> {
let that = this; return new Promise((resolve, reject) => {
return new Promise(function(resolve, reject) { this._walletsClient.getNewDepositAddress(new GetNewDepositAddressRequest(), {password: this._password}, function(err: grpcWeb.RpcError, response: GetNewDepositAddressReply) {
that._walletsClient.getNewDepositAddress(new GetNewDepositAddressRequest(), {password: that._password}, function(err: grpcWeb.RpcError, response: GetNewDepositAddressReply) {
if (err) reject(err); if (err) reject(err);
else resolve(response.getSubaddress()); else resolve(response.getSubaddress());
}); });
@ -707,9 +680,8 @@ class HavenoClient {
* @return {XmrTx[]} the transactions * @return {XmrTx[]} the transactions
*/ */
async getXmrTxs(): Promise<XmrTx[]> { async getXmrTxs(): Promise<XmrTx[]> {
let that = this; return new Promise((resolve, reject) => {
return new Promise(function(resolve, reject) { this._walletsClient.getXmrTxs(new GetXmrTxsRequest(), {password: this._password}, function(err: grpcWeb.RpcError, response: GetXmrTxsReply) {
that._walletsClient.getXmrTxs(new GetXmrTxsRequest(), {password: that._password}, function(err: grpcWeb.RpcError, response: GetXmrTxsReply) {
if (err) reject(err); if (err) reject(err);
else resolve(response.getTxsList()); else resolve(response.getTxsList());
}); });
@ -723,8 +695,8 @@ class HavenoClient {
* @return {XmrTx} the transaction with the hash * @return {XmrTx} the transaction with the hash
*/ */
async getXmrTx(txHash: string): Promise<XmrTx> { async getXmrTx(txHash: string): Promise<XmrTx> {
let txs = await this.getXmrTxs(); // TODO (woodser): implement getXmrTx(hash) grpc call const txs = await this.getXmrTxs(); // TODO (woodser): implement getXmrTx(hash) grpc call
for (let tx of txs) { for (const tx of txs) {
if (tx.getHash() === txHash) return tx; if (tx.getHash() === txHash) return tx;
} }
throw new Error("No transaction with hash " + txHash); throw new Error("No transaction with hash " + txHash);
@ -736,9 +708,8 @@ class HavenoClient {
* @return {XmrTx} the created transaction * @return {XmrTx} the created transaction
*/ */
async createXmrTx(destinations: XmrDestination[]): Promise<XmrTx> { async createXmrTx(destinations: XmrDestination[]): Promise<XmrTx> {
let that = this; return new Promise((resolve, reject) => {
return new Promise(function(resolve, reject) { this._walletsClient.createXmrTx(new CreateXmrTxRequest().setDestinationsList(destinations), {password: this._password}, function(err: grpcWeb.RpcError, response: CreateXmrTxReply) {
that._walletsClient.createXmrTx(new CreateXmrTxRequest().setDestinationsList(destinations), {password: that._password}, function(err: grpcWeb.RpcError, response: CreateXmrTxReply) {
if (err) reject(err); if (err) reject(err);
else resolve(response.getTx()!); else resolve(response.getTx()!);
}); });
@ -751,9 +722,8 @@ class HavenoClient {
* @return {string} the hash of the relayed transaction * @return {string} the hash of the relayed transaction
*/ */
async relayXmrTx(metadata: string): Promise<string> { async relayXmrTx(metadata: string): Promise<string> {
let that = this; return new Promise((resolve, reject) => {
return new Promise(function(resolve, reject) { this._walletsClient.relayXmrTx(new RelayXmrTxRequest().setMetadata(metadata), {password: this._password}, function(err: grpcWeb.RpcError, response: RelayXmrTxReply) {
that._walletsClient.relayXmrTx(new RelayXmrTxRequest().setMetadata(metadata), {password: that._password}, function(err: grpcWeb.RpcError, response: RelayXmrTxReply) {
if (err) reject(err); if (err) reject(err);
else resolve(response.getHash()); else resolve(response.getHash());
}); });
@ -767,9 +737,8 @@ class HavenoClient {
* @return {number} the current market price per 1 XMR in the given currency * @return {number} the current market price per 1 XMR in the given currency
*/ */
async getPrice(currencyCode: string): Promise<number> { async getPrice(currencyCode: string): Promise<number> {
let that = this; return new Promise((resolve, reject) => {
return new Promise(function(resolve, reject) { this._priceClient.getMarketPrice(new MarketPriceRequest().setCurrencyCode(currencyCode), {password: this._password}, function(err: grpcWeb.RpcError, response: MarketPriceReply) {
that._priceClient.getMarketPrice(new MarketPriceRequest().setCurrencyCode(currencyCode), {password: that._password}, function(err: grpcWeb.RpcError, response: MarketPriceReply) {
if (err) reject(err); if (err) reject(err);
else resolve(response.getPrice()); else resolve(response.getPrice());
}); });
@ -782,9 +751,8 @@ class HavenoClient {
* @return {MarketPrice[]} price per 1 XMR in all supported currencies (fiat & crypto) * @return {MarketPrice[]} price per 1 XMR in all supported currencies (fiat & crypto)
*/ */
async getPrices(): Promise<MarketPriceInfo[]> { async getPrices(): Promise<MarketPriceInfo[]> {
let that = this; return new Promise((resolve, reject) => {
return new Promise(function(resolve, reject) { this._priceClient.getMarketPrices(new MarketPricesRequest(), {password: this._password}, function(err: grpcWeb.RpcError, response: MarketPricesReply) {
that._priceClient.getMarketPrices(new MarketPricesRequest(), {password: that._password}, function(err: grpcWeb.RpcError, response: MarketPricesReply) {
if (err) reject(err); if (err) reject(err);
else resolve(response.getMarketPriceList()); else resolve(response.getMarketPriceList());
}); });
@ -797,10 +765,9 @@ class HavenoClient {
* @param {string} assetCode - asset to get the market depth of * @param {string} assetCode - asset to get the market depth of
* @return {MarketDepthInfo} market depth of the given currency * @return {MarketDepthInfo} market depth of the given currency
*/ */
async getMarketDepth(assetCode: string): Promise<MarketDepthInfo> { async getMarketDepth(assetCode: string): Promise<MarketDepthInfo> {
let that = this; return new Promise((resolve, reject) => {
return new Promise(function(resolve, reject) { this._priceClient.getMarketDepth(new MarketDepthRequest().setCurrencyCode(assetCode), {password: this._password}, function(err: grpcWeb.RpcError, response: MarketDepthReply) {
that._priceClient.getMarketDepth(new MarketDepthRequest().setCurrencyCode(assetCode), {password: that._password}, function(err: grpcWeb.RpcError, response: MarketDepthReply) {
if (err) reject(err); if (err) reject(err);
else resolve(response.getMarketDepth()!); else resolve(response.getMarketDepth()!);
}); });
@ -813,9 +780,8 @@ class HavenoClient {
* @return {PaymentMethod[]} the payment methods * @return {PaymentMethod[]} the payment methods
*/ */
async getPaymentMethods(): Promise<PaymentMethod[]> { async getPaymentMethods(): Promise<PaymentMethod[]> {
let that = this; return new Promise((resolve, reject) => {
return new Promise(function(resolve, reject) { this._paymentAccountsClient.getPaymentMethods(new GetPaymentMethodsRequest(), {password: this._password}, function(err: grpcWeb.RpcError, response: GetPaymentMethodsReply) {
that._paymentAccountsClient.getPaymentMethods(new GetPaymentMethodsRequest(), {password: that._password}, function(err: grpcWeb.RpcError, response: GetPaymentMethodsReply) {
if (err) reject(err); if (err) reject(err);
else resolve(response.getPaymentMethodsList()); else resolve(response.getPaymentMethodsList());
}); });
@ -828,9 +794,8 @@ class HavenoClient {
* @return {PaymentAccount[]} the payment accounts * @return {PaymentAccount[]} the payment accounts
*/ */
async getPaymentAccounts(): Promise<PaymentAccount[]> { async getPaymentAccounts(): Promise<PaymentAccount[]> {
let that = this; return new Promise((resolve, reject) => {
return new Promise(function(resolve, reject) { this._paymentAccountsClient.getPaymentAccounts(new GetPaymentAccountsRequest(), {password: this._password}, function(err: grpcWeb.RpcError, response: GetPaymentAccountsReply) {
that._paymentAccountsClient.getPaymentAccounts(new GetPaymentAccountsRequest(), {password: that._password}, function(err: grpcWeb.RpcError, response: GetPaymentAccountsReply) {
if (err) reject(err); if (err) reject(err);
else resolve(response.getPaymentAccountsList()); else resolve(response.getPaymentAccountsList());
}); });
@ -844,9 +809,9 @@ class HavenoClient {
* @return {PaymentAccount} the payment account * @return {PaymentAccount} the payment account
*/ */
async getPaymentAccount(paymentAccountId: string): Promise<PaymentAccount> { async getPaymentAccount(paymentAccountId: string): Promise<PaymentAccount> {
// TODO (woodser): implement this on the backend // TODO (woodser): implement this on the backend
let paymentAccounts = await this.getPaymentAccounts(); const paymentAccounts = await this.getPaymentAccounts();
for (let paymentAccount of paymentAccounts) { for (const paymentAccount of paymentAccounts) {
if (paymentAccount.getId() === paymentAccountId) return paymentAccount; if (paymentAccount.getId() === paymentAccountId) return paymentAccount;
} }
throw new Error("No payment account with id " + paymentAccountId); throw new Error("No payment account with id " + paymentAccountId);
@ -858,9 +823,8 @@ class HavenoClient {
* @return {object} the payment account form as JSON * @return {object} the payment account form as JSON
*/ */
async getPaymentAccountForm(paymentMethodId: string): Promise<any> { async getPaymentAccountForm(paymentMethodId: string): Promise<any> {
let that = this; return new Promise((resolve, reject) => {
return new Promise(function(resolve, reject) { this._paymentAccountsClient.getPaymentAccountForm(new GetPaymentAccountFormRequest().setPaymentMethodId(paymentMethodId), {password: this._password}, function(err: grpcWeb.RpcError, response: GetPaymentAccountFormReply) {
that._paymentAccountsClient.getPaymentAccountForm(new GetPaymentAccountFormRequest().setPaymentMethodId(paymentMethodId), {password: that._password}, function(err: grpcWeb.RpcError, response: GetPaymentAccountFormReply) {
if (err) reject(err); if (err) reject(err);
else resolve(JSON.parse(response.getPaymentAccountFormJson())); else resolve(JSON.parse(response.getPaymentAccountFormJson()));
}); });
@ -874,9 +838,8 @@ class HavenoClient {
* @return {PaymentAccount} the created payment account * @return {PaymentAccount} the created payment account
*/ */
async createPaymentAccount(paymentAccountForm: any): Promise<PaymentAccount> { async createPaymentAccount(paymentAccountForm: any): Promise<PaymentAccount> {
let that = this; return new Promise((resolve, reject) => {
return new Promise(function(resolve, reject) { this._paymentAccountsClient.createPaymentAccount(new CreatePaymentAccountRequest().setPaymentAccountForm(JSON.stringify(paymentAccountForm)), {password: this._password}, function(err: grpcWeb.RpcError, response: CreatePaymentAccountReply) {
that._paymentAccountsClient.createPaymentAccount(new CreatePaymentAccountRequest().setPaymentAccountForm(JSON.stringify(paymentAccountForm)), {password: that._password}, function(err: grpcWeb.RpcError, response: CreatePaymentAccountReply) {
if (err) reject(err); if (err) reject(err);
else resolve(response.getPaymentAccount()!); else resolve(response.getPaymentAccount()!);
}); });
@ -892,14 +855,13 @@ class HavenoClient {
* @return {PaymentAccount} the created payment account * @return {PaymentAccount} the created payment account
*/ */
async createCryptoPaymentAccount(accountName: string, assetCode: string, address: string): Promise<PaymentAccount> { async createCryptoPaymentAccount(accountName: string, assetCode: string, address: string): Promise<PaymentAccount> {
let that = this; const request = new CreateCryptoCurrencyPaymentAccountRequest()
let request = new CreateCryptoCurrencyPaymentAccountRequest() .setAccountName(accountName)
.setAccountName(accountName) .setCurrencyCode(assetCode)
.setCurrencyCode(assetCode) .setAddress(address)
.setAddress(address) .setTradeInstant(false); // not using instant trades
.setTradeInstant(false); // not using instant trades return new Promise((resolve, reject) => {
return new Promise(function(resolve, reject) { this._paymentAccountsClient.createCryptoCurrencyPaymentAccount(request, {password: this._password}, function(err: grpcWeb.RpcError, response: CreateCryptoCurrencyPaymentAccountReply) {
that._paymentAccountsClient.createCryptoCurrencyPaymentAccount(request, {password: that._password}, function(err: grpcWeb.RpcError, response: CreateCryptoCurrencyPaymentAccountReply) {
if (err) reject(err); if (err) reject(err);
else resolve(response.getPaymentAccount()!); else resolve(response.getPaymentAccount()!);
}); });
@ -915,9 +877,8 @@ class HavenoClient {
*/ */
async getOffers(assetCode: string, direction?: string): Promise<OfferInfo[]> { async getOffers(assetCode: string, direction?: string): Promise<OfferInfo[]> {
if (!direction) return (await this.getOffers(assetCode, "buy")).concat(await this.getOffers(assetCode, "sell")); // TODO: implement in backend if (!direction) return (await this.getOffers(assetCode, "buy")).concat(await this.getOffers(assetCode, "sell")); // TODO: implement in backend
let that = this; return new Promise((resolve, reject) => {
return new Promise(function(resolve, reject) { this._offersClient.getOffers(new GetOffersRequest().setDirection(direction).setCurrencyCode(assetCode), {password: this._password}, function(err: grpcWeb.RpcError, response: GetOffersReply) {
that._offersClient.getOffers(new GetOffersRequest().setDirection(direction).setCurrencyCode(assetCode), {password: that._password}, function(err: grpcWeb.RpcError, response: GetOffersReply) {
if (err) reject(err); if (err) reject(err);
else resolve(response.getOffersList()); else resolve(response.getOffersList());
}); });
@ -933,9 +894,8 @@ class HavenoClient {
*/ */
async getMyOffers(assetCode: string, direction?: string): Promise<OfferInfo[]> { async getMyOffers(assetCode: string, direction?: string): Promise<OfferInfo[]> {
if (!direction) return (await this.getMyOffers(assetCode, "buy")).concat(await this.getMyOffers(assetCode, "sell")); // TODO: implement in backend if (!direction) return (await this.getMyOffers(assetCode, "buy")).concat(await this.getMyOffers(assetCode, "sell")); // TODO: implement in backend
let that = this; return new Promise((resolve, reject) => {
return new Promise(function(resolve, reject) { this._offersClient.getMyOffers(new GetOffersRequest().setDirection(direction).setCurrencyCode(assetCode), {password: this._password}, function(err: grpcWeb.RpcError, response: GetOffersReply) {
that._offersClient.getMyOffers(new GetOffersRequest().setDirection(direction).setCurrencyCode(assetCode), {password: that._password}, function(err: grpcWeb.RpcError, response: GetOffersReply) {
if (err) reject(err); if (err) reject(err);
else resolve(response.getOffersList()); else resolve(response.getOffersList());
}); });
@ -949,9 +909,8 @@ class HavenoClient {
* @return {OfferInfo} the user's created offer * @return {OfferInfo} the user's created offer
*/ */
async getMyOffer(offerId: string): Promise<OfferInfo> { async getMyOffer(offerId: string): Promise<OfferInfo> {
let that = this; return new Promise((resolve, reject) => {
return new Promise(function(resolve, reject) { this._offersClient.getMyOffer(new GetMyOfferRequest().setId(offerId), {password: this._password}, function(err: grpcWeb.RpcError, response: GetMyOfferReply) {
that._offersClient.getMyOffer(new GetMyOfferRequest().setId(offerId), {password: that._password}, function(err: grpcWeb.RpcError, response: GetMyOfferReply) {
if (err) reject(err); if (err) reject(err);
else resolve(response.getOffer()!); else resolve(response.getOffer()!);
}); });
@ -981,20 +940,19 @@ class HavenoClient {
marketPriceMargin?: number, marketPriceMargin?: number,
triggerPrice?: number, triggerPrice?: number,
minAmount?: bigint): Promise<OfferInfo> { minAmount?: bigint): Promise<OfferInfo> {
let that = this; const request = new CreateOfferRequest()
let request = new CreateOfferRequest() .setDirection(direction)
.setDirection(direction) .setAmount(amount.toString())
.setAmount(amount.toString()) .setCurrencyCode(assetCode)
.setCurrencyCode(assetCode) .setPaymentAccountId(paymentAccountId)
.setPaymentAccountId(paymentAccountId) .setBuyerSecurityDeposit(buyerSecurityDeposit)
.setBuyerSecurityDeposit(buyerSecurityDeposit) .setPrice(price ? price.toString() : "1.0") // TOOD (woodser): positive price required even if using market price?
.setPrice(price ? price.toString() : "1.0") // TOOD (woodser): positive price required even if using market price? .setUseMarketBasedPrice(price === undefined) // TODO (woodser): this field is redundant; remove from api
.setUseMarketBasedPrice(price === undefined) // TODO (woodser): this field is redundant; remove from api .setMinAmount(minAmount ? minAmount.toString() : amount.toString());
.setMinAmount(minAmount ? minAmount.toString() : amount.toString());
if (marketPriceMargin) request.setMarketPriceMargin(marketPriceMargin); if (marketPriceMargin) request.setMarketPriceMargin(marketPriceMargin);
if (triggerPrice) request.setTriggerPrice(triggerPrice.toString()); if (triggerPrice) request.setTriggerPrice(triggerPrice.toString());
return new Promise(function(resolve, reject) { return new Promise((resolve, reject) => {
that._offersClient.createOffer(request, {password: that._password}, function(err: grpcWeb.RpcError, response: CreateOfferReply) { this._offersClient.createOffer(request, {password: this._password}, function(err: grpcWeb.RpcError, response: CreateOfferReply) {
if (err) reject(err); if (err) reject(err);
else resolve(response.getOffer()!); else resolve(response.getOffer()!);
}); });
@ -1007,9 +965,8 @@ class HavenoClient {
* @param {string} offerId - the offer id to cancel * @param {string} offerId - the offer id to cancel
*/ */
async removeOffer(offerId: string): Promise<void> { async removeOffer(offerId: string): Promise<void> {
let that = this; return new Promise((resolve, reject) => {
return new Promise(function(resolve, reject) { this._offersClient.cancelOffer(new CancelOfferRequest().setId(offerId), {password: this._password}, function(err: grpcWeb.RpcError) {
that._offersClient.cancelOffer(new CancelOfferRequest().setId(offerId), {password: that._password}, function(err: grpcWeb.RpcError) {
if (err) reject(err); if (err) reject(err);
else resolve(); else resolve();
}); });
@ -1024,12 +981,11 @@ class HavenoClient {
* @return {TradeInfo} the initialized trade * @return {TradeInfo} the initialized trade
*/ */
async takeOffer(offerId: string, paymentAccountId: string): Promise<TradeInfo> { async takeOffer(offerId: string, paymentAccountId: string): Promise<TradeInfo> {
let that = this; const request = new TakeOfferRequest()
let request = new TakeOfferRequest() .setOfferId(offerId)
.setOfferId(offerId) .setPaymentAccountId(paymentAccountId);
.setPaymentAccountId(paymentAccountId); return new Promise((resolve, reject) => {
return new Promise(function(resolve, reject) { this._tradesClient.takeOffer(request, {password: this._password}, function(err: grpcWeb.RpcError, response: TakeOfferReply) {
that._tradesClient.takeOffer(request, {password: that._password}, function(err: grpcWeb.RpcError, response: TakeOfferReply) {
if (err) reject(err); if (err) reject(err);
else if (response.getFailureReason() && response.getFailureReason()!.getAvailabilityResult() !== AvailabilityResult.AVAILABLE) reject(new Error(response.getFailureReason()!.getDescription())); // TODO: api should throw grpcWeb.RpcError else if (response.getFailureReason() && response.getFailureReason()!.getAvailabilityResult() !== AvailabilityResult.AVAILABLE) reject(new Error(response.getFailureReason()!.getDescription())); // TODO: api should throw grpcWeb.RpcError
else resolve(response.getTrade()!); else resolve(response.getTrade()!);
@ -1044,9 +1000,8 @@ class HavenoClient {
* @return {TradeInfo} the trade with the given id * @return {TradeInfo} the trade with the given id
*/ */
async getTrade(tradeId: string): Promise<TradeInfo> { async getTrade(tradeId: string): Promise<TradeInfo> {
let that = this; return new Promise((resolve, reject) => {
return new Promise(function(resolve, reject) { this._tradesClient.getTrade(new GetTradeRequest().setTradeId(tradeId), {password: this._password}, function(err: grpcWeb.RpcError, response: GetTradeReply) {
that._tradesClient.getTrade(new GetTradeRequest().setTradeId(tradeId), {password: that._password}, function(err: grpcWeb.RpcError, response: GetTradeReply) {
if (err) reject(err); if (err) reject(err);
else resolve(response.getTrade()!); else resolve(response.getTrade()!);
}); });
@ -1059,9 +1014,8 @@ class HavenoClient {
* @return {TradeInfo[]} all user trades * @return {TradeInfo[]} all user trades
*/ */
async getTrades(): Promise<TradeInfo[]> { async getTrades(): Promise<TradeInfo[]> {
let that = this; return new Promise((resolve, reject) => {
return new Promise(function(resolve, reject) { this._tradesClient.getTrades(new GetTradesRequest(), {password: this._password}, function(err: grpcWeb.RpcError, response: GetTradesReply) {
that._tradesClient.getTrades(new GetTradesRequest(), {password: that._password}, function(err: grpcWeb.RpcError, response: GetTradesReply) {
if (err) reject(err); if (err) reject(err);
else resolve(response.getTradesList()); else resolve(response.getTradesList());
}); });
@ -1074,9 +1028,8 @@ class HavenoClient {
* @param {string} tradeId - the id of the trade * @param {string} tradeId - the id of the trade
*/ */
async confirmPaymentStarted(tradeId: string): Promise<void> { async confirmPaymentStarted(tradeId: string): Promise<void> {
let that = this; return new Promise((resolve, reject) => {
return new Promise(function(resolve, reject) { this._tradesClient.confirmPaymentStarted(new ConfirmPaymentStartedRequest().setTradeId(tradeId), {password: this._password}, function(err: grpcWeb.RpcError) {
that._tradesClient.confirmPaymentStarted(new ConfirmPaymentStartedRequest().setTradeId(tradeId), {password: that._password}, function(err: grpcWeb.RpcError) {
if (err) reject(err); if (err) reject(err);
else resolve(); else resolve();
}); });
@ -1089,9 +1042,8 @@ class HavenoClient {
* @param {string} tradeId - the id of the trade * @param {string} tradeId - the id of the trade
*/ */
async confirmPaymentReceived(tradeId: string): Promise<void> { async confirmPaymentReceived(tradeId: string): Promise<void> {
let that = this; return new Promise((resolve, reject) => {
return new Promise(function(resolve, reject) { this._tradesClient.confirmPaymentReceived(new ConfirmPaymentReceivedRequest().setTradeId(tradeId), {password: this._password}, function(err: grpcWeb.RpcError) {
that._tradesClient.confirmPaymentReceived(new ConfirmPaymentReceivedRequest().setTradeId(tradeId), {password: that._password}, function(err: grpcWeb.RpcError) {
if (err) reject(err); if (err) reject(err);
else resolve(); else resolve();
}); });
@ -1104,10 +1056,9 @@ class HavenoClient {
* @param {string} tradeId - the id of the trade * @param {string} tradeId - the id of the trade
*/ */
async getChatMessages(tradeId: string): Promise<ChatMessage[]> { async getChatMessages(tradeId: string): Promise<ChatMessage[]> {
let that = this; return new Promise((resolve, reject) => {
return new Promise(function(resolve, reject) { const request = new GetChatMessagesRequest().setTradeId(tradeId);
let request = new GetChatMessagesRequest().setTradeId(tradeId); this._tradesClient.getChatMessages(request, {password: this._password}, function(err: grpcWeb.RpcError, response: GetChatMessagesReply) {
that._tradesClient.getChatMessages(request, {password: that._password}, function(err: grpcWeb.RpcError, response: GetChatMessagesReply) {
if (err) reject(err); if (err) reject(err);
else resolve(response.getMessageList()); else resolve(response.getMessageList());
}); });
@ -1121,12 +1072,11 @@ class HavenoClient {
* @param {string} message - the message * @param {string} message - the message
*/ */
async sendChatMessage(tradeId: string, message: string): Promise<void> { async sendChatMessage(tradeId: string, message: string): Promise<void> {
let that = this; return new Promise((resolve, reject) => {
return new Promise(function(resolve, reject) { const request = new SendChatMessageRequest()
let request = new SendChatMessageRequest()
.setTradeId(tradeId) .setTradeId(tradeId)
.setMessage(message); .setMessage(message);
that._tradesClient.sendChatMessage(request, {password: that._password}, function(err: grpcWeb.RpcError) { this._tradesClient.sendChatMessage(request, {password: this._password}, function(err: grpcWeb.RpcError) {
if (err) reject(err); if (err) reject(err);
else resolve(); else resolve();
}); });
@ -1139,9 +1089,8 @@ class HavenoClient {
* @param {string} tradeId - the id of the trade * @param {string} tradeId - the id of the trade
*/ */
async getDispute(tradeId: string): Promise<Dispute> { async getDispute(tradeId: string): Promise<Dispute> {
let that = this; return new Promise((resolve, reject) => {
return new Promise(function(resolve, reject) { this._disputesClient.getDispute(new GetDisputeRequest().setTradeId(tradeId), {password: this._password}, function(err: grpcWeb.RpcError, response: GetDisputeReply) {
that._disputesClient.getDispute(new GetDisputeRequest().setTradeId(tradeId), {password: that._password}, function(err: grpcWeb.RpcError, response: GetDisputeReply) {
if (err) reject(err); if (err) reject(err);
else resolve(response.getDispute()!); else resolve(response.getDispute()!);
}); });
@ -1152,9 +1101,8 @@ class HavenoClient {
* Get all disputes. * Get all disputes.
*/ */
async getDisputes(): Promise<Dispute[]> { async getDisputes(): Promise<Dispute[]> {
let that = this; return new Promise((resolve, reject) => {
return new Promise(function(resolve, reject) { this._disputesClient.getDisputes(new GetDisputesRequest(), {password: this._password}, function(err: grpcWeb.RpcError, response: GetDisputesReply) {
that._disputesClient.getDisputes(new GetDisputesRequest(), {password: that._password}, function(err: grpcWeb.RpcError, response: GetDisputesReply) {
if (err) reject(err); if (err) reject(err);
else resolve(response.getDisputesList()); else resolve(response.getDisputesList());
}); });
@ -1167,9 +1115,8 @@ class HavenoClient {
* @param {string} tradeId - the id of the trade * @param {string} tradeId - the id of the trade
*/ */
async openDispute(tradeId: string): Promise<void> { async openDispute(tradeId: string): Promise<void> {
let that = this; return new Promise((resolve, reject) => {
return new Promise(function(resolve, reject) { this._disputesClient.openDispute(new OpenDisputeRequest().setTradeId(tradeId), {password: this._password}, function(err: grpcWeb.RpcError) {
that._disputesClient.openDispute(new OpenDisputeRequest().setTradeId(tradeId), {password: that._password}, function(err: grpcWeb.RpcError) {
if (err) reject(err); if (err) reject(err);
else resolve(); else resolve();
}); });
@ -1187,15 +1134,14 @@ class HavenoClient {
* @param {bigint} customWinnerAmount - custom amount to award the winner (optional) * @param {bigint} customWinnerAmount - custom amount to award the winner (optional)
*/ */
async resolveDispute(tradeId: string, winner: DisputeResult.Winner, reason: DisputeResult.Reason, summaryNotes: string, customWinnerAmount?: bigint): Promise<void> { async resolveDispute(tradeId: string, winner: DisputeResult.Winner, reason: DisputeResult.Reason, summaryNotes: string, customWinnerAmount?: bigint): Promise<void> {
let that = this; return new Promise((resolve, reject) => {
return new Promise(function(resolve, reject) { const request = new ResolveDisputeRequest()
let request = new ResolveDisputeRequest() .setTradeId(tradeId)
.setTradeId(tradeId) .setWinner(winner)
.setWinner(winner) .setReason(reason)
.setReason(reason) .setSummaryNotes(summaryNotes)
.setSummaryNotes(summaryNotes) .setCustomPayoutAmount(customWinnerAmount ? customWinnerAmount.toString() : "0");
.setCustomPayoutAmount(customWinnerAmount ? customWinnerAmount.toString() : "0"); this._disputesClient.resolveDispute(request, {password: this._password}, function(err: grpcWeb.RpcError) {
that._disputesClient.resolveDispute(request, {password: that._password}, function(err: grpcWeb.RpcError) {
if (err) reject(err); if (err) reject(err);
else resolve(); else resolve();
}); });
@ -1210,13 +1156,12 @@ class HavenoClient {
* @param {Attachment[]} attachments - attachments * @param {Attachment[]} attachments - attachments
*/ */
async sendDisputeChatMessage(disputeId: string, message: string, attachments: Attachment[]): Promise<void> { async sendDisputeChatMessage(disputeId: string, message: string, attachments: Attachment[]): Promise<void> {
let that = this; return new Promise((resolve, reject) => {
return new Promise(function(resolve, reject) { const request = new SendDisputeChatMessageRequest()
let request = new SendDisputeChatMessageRequest() .setDisputeId(disputeId)
.setDisputeId(disputeId) .setMessage(message)
.setMessage(message) .setAttachmentsList(attachments);
.setAttachmentsList(attachments); this._disputesClient.sendDisputeChatMessage(request, {password: this._password}, function(err: grpcWeb.RpcError) {
that._disputesClient.sendDisputeChatMessage(request, {password: that._password}, function(err: grpcWeb.RpcError) {
if (err) reject(err); if (err) reject(err);
else resolve(); else resolve();
}); });
@ -1228,9 +1173,8 @@ class HavenoClient {
*/ */
async shutdownServer() { async shutdownServer() {
if (this._keepAliveLooper) this._keepAliveLooper.stop(); if (this._keepAliveLooper) this._keepAliveLooper.stop();
let that = this; await new Promise<void>((resolve, reject) => {
await new Promise(function(resolve, reject) { this._shutdownServerClient.stop(new StopRequest(), {password: this._password}, function(err: grpcWeb.RpcError) { // process receives 'exit' event
that._shutdownServerClient.stop(new StopRequest(), {password: that._password}, function(err: grpcWeb.RpcError) { // process receives 'exit' event
if (err) reject(err); if (err) reject(err);
else resolve(); else resolve();
}); });
@ -1255,33 +1199,33 @@ class HavenoClient {
* Independently, gRPC createAccount() and openAccount() return after all account setup and reading from disk. * Independently, gRPC createAccount() and openAccount() return after all account setup and reading from disk.
*/ */
async _awaitAppInitialized(): Promise<void> { async _awaitAppInitialized(): Promise<void> {
let that = this; // eslint-disable-next-line no-async-promise-executor
return new Promise(async function(resolve) { return new Promise(async (resolve) => {
let isResolved = false; let isResolved = false;
let listener = async function(notification: NotificationMessage) { const resolveOnce = async () => {
if (notification.getType() === NotificationMessage.NotificationType.APP_INITIALIZED) await resolveOnce();
}
await that.addNotificationListener(listener);
if (await that._isAppInitialized()) await resolveOnce();
async function resolveOnce() {
if (isResolved) return; if (isResolved) return;
isResolved = true; isResolved = true;
await that.removeNotificationListener(listener); await this.removeNotificationListener(listener);
resolve(); resolve();
};
const listener = async function(notification: NotificationMessage) {
if (notification.getType() === NotificationMessage.NotificationType.APP_INITIALIZED) await resolveOnce();
} }
await this.addNotificationListener(listener);
if (await this._isAppInitialized()) await resolveOnce();
}); });
} }
async _isAppInitialized(): Promise<boolean> { async _isAppInitialized(): Promise<boolean> {
let that = this; return new Promise((resolve, reject) => {
return new Promise(function(resolve, reject) { this._accountClient.isAppInitialized(new IsAppInitializedRequest(), {password: this._password}, function(err: grpcWeb.RpcError, response: IsAppInitializedReply) {
that._accountClient.isAppInitialized(new IsAppInitializedRequest(), {password: that._password}, function(err: grpcWeb.RpcError, response: IsAppInitializedReply) {
if (err) reject(err); if (err) reject(err);
else resolve(response.getIsAppInitialized()); else resolve(response.getIsAppInitialized());
}); });
}); });
} }
/** /**
* Register a listener to receive notifications. * Register a listener to receive notifications.
* Due to the nature of grpc streaming, this method returns a promise * Due to the nature of grpc streaming, this method returns a promise
@ -1290,29 +1234,28 @@ class HavenoClient {
async _registerNotificationListenerOnce(): Promise<void> { async _registerNotificationListenerOnce(): Promise<void> {
if (this._registerNotificationListenerCalled) return; if (this._registerNotificationListenerCalled) return;
else this._registerNotificationListenerCalled = true; else this._registerNotificationListenerCalled = true;
let that = this; return new Promise((resolve) => {
return new Promise(function(resolve) {
// send request to register client listener // send request to register client listener
that._notificationsClient.registerNotificationListener(new RegisterNotificationListenerRequest(), {password: that._password}) this._notificationsClient.registerNotificationListener(new RegisterNotificationListenerRequest(), {password: this._password})
.on('data', (data) => { .on('data', (data) => {
if (data instanceof NotificationMessage) { if (data instanceof NotificationMessage) {
for (let listener of that._notificationListeners) listener(data); for (const listener of this._notificationListeners) listener(data);
} }
}); });
// periodically send keep alive requests // TODO (woodser): better way to keep notification stream alive? // periodically send keep alive requests // TODO (woodser): better way to keep notification stream alive?
let firstRequest = true; let firstRequest = true;
that._keepAliveLooper = new TaskLooper(async function() { this._keepAliveLooper = new TaskLooper(async () => {
if (firstRequest) { if (firstRequest) {
firstRequest = false; firstRequest = false;
return; return;
} }
await that._sendNotification(new NotificationMessage() await this._sendNotification(new NotificationMessage()
.setType(NotificationMessage.NotificationType.KEEP_ALIVE) .setType(NotificationMessage.NotificationType.KEEP_ALIVE)
.setTimestamp(Date.now())); .setTimestamp(Date.now()));
}); });
that._keepAliveLooper.start(that._keepAlivePeriodMs); this._keepAliveLooper.start(this._keepAlivePeriodMs);
setTimeout(resolve, 1000); // TODO: call returns before listener registered setTimeout(resolve, 1000); // TODO: call returns before listener registered
}); });
@ -1324,9 +1267,8 @@ class HavenoClient {
* @param {NotificationMessage} notification - notification to send * @param {NotificationMessage} notification - notification to send
*/ */
async _sendNotification(notification: NotificationMessage): Promise<void> { async _sendNotification(notification: NotificationMessage): Promise<void> {
let that = this; return new Promise((resolve, reject) => {
return new Promise(function(resolve, reject) { this._notificationsClient.sendNotification(new SendNotificationRequest().setNotification(notification), {password: this._password}, function(err: grpcWeb.RpcError) {
that._notificationsClient.sendNotification(new SendNotificationRequest().setNotification(notification), {password: that._password}, function(err: grpcWeb.RpcError) {
if (err) reject(err); if (err) reject(err);
else resolve(); else resolve();
}); });
@ -1337,19 +1279,16 @@ class HavenoClient {
* Restore an account chunk from zip bytes. * Restore an account chunk from zip bytes.
*/ */
async _restoreAccountChunk(zipBytes: Uint8Array, offset: number, totalLength: number, hasMore: boolean): Promise<void> { async _restoreAccountChunk(zipBytes: Uint8Array, offset: number, totalLength: number, hasMore: boolean): Promise<void> {
let that = this; const request = new RestoreAccountRequest()
let request = new RestoreAccountRequest()
.setZipBytes(zipBytes) .setZipBytes(zipBytes)
.setOffset(offset) .setOffset(offset)
.setTotalLength(totalLength) .setTotalLength(totalLength)
.setHasMore(hasMore); .setHasMore(hasMore);
return new Promise(function(resolve, reject) { return new Promise((resolve, reject) => {
that._accountClient.restoreAccount(request, {password: that._password}, function(err: grpcWeb.RpcError) { this._accountClient.restoreAccount(request, {password: this._password}, function(err: grpcWeb.RpcError) {
if (err) reject(err); if (err) reject(err);
else resolve(); else resolve();
}); });
}); });
} }
} }
export {HavenoClient};

View file

@ -1,10 +1,10 @@
const assert = require("assert"); import assert from "assert";
const console = require('console'); import console from 'console';
/** /**
* Collection of utilities for working with Haveno. * Collection of utilities for working with Haveno.
*/ */
class HavenoUtils { export default class HavenoUtils {
static logLevel = 0; static logLevel = 0;
static centinerosToAUMultiplier = 10000; static centinerosToAUMultiplier = 10000;
@ -40,8 +40,8 @@ class HavenoUtils {
static log(level: number, msg: string) { static log(level: number, msg: string) {
assert(level === parseInt(level + "", 10) && level >= 0, "Log level must be an integer >= 0"); assert(level === parseInt(level + "", 10) && level >= 0, "Log level must be an integer >= 0");
if (HavenoUtils.logLevel >= level) { if (HavenoUtils.logLevel >= level) {
let now = Date.now(); const now = Date.now();
let formattedTimeSinceLastLog = HavenoUtils.lastLogTimeMs ? " (+" + (now - HavenoUtils.lastLogTimeMs) + " ms)" : "\t"; const formattedTimeSinceLastLog = HavenoUtils.lastLogTimeMs ? " (+" + (now - HavenoUtils.lastLogTimeMs) + " ms)" : "\t";
HavenoUtils.lastLogTimeMs = now; HavenoUtils.lastLogTimeMs = now;
console.log(HavenoUtils.formatTimestamp(now) + formattedTimeSinceLastLog + "\t[L" + level + "] " + msg); console.log(HavenoUtils.formatTimestamp(now) + formattedTimeSinceLastLog + "\t[L" + level + "] " + msg);
} }
@ -54,7 +54,7 @@ class HavenoUtils {
* @return {string} the formatted timestamp * @return {string} the formatted timestamp
*/ */
static formatTimestamp(timestamp: number): string { static formatTimestamp(timestamp: number): string {
let date = new Date(timestamp); const date = new Date(timestamp);
return HavenoUtils.months[date.getMonth()] + "-" + date.getDate() + " " + date.getHours() + ':' + ("0" + date.getMinutes()).substr(-2) + ':' + ("0" + date.getSeconds()).substr(-2) + ':' + ("0" + date.getMilliseconds()).substr(-2); return HavenoUtils.months[date.getMonth()] + "-" + date.getDate() + " " + date.getHours() + ':' + ("0" + date.getMinutes()).substr(-2) + ':' + ("0" + date.getSeconds()).substr(-2) + ':' + ("0" + date.getMilliseconds()).substr(-2);
} }
@ -84,5 +84,3 @@ class HavenoUtils {
return BigInt(centineros) * BigInt(HavenoUtils.centinerosToAUMultiplier); return BigInt(centineros) * BigInt(HavenoUtils.centinerosToAUMultiplier);
} }
} }
export {HavenoUtils};

View file

@ -1,7 +1,7 @@
/** /**
* Run a task in a fixed period loop. * Run a task in a fixed period loop.
*/ */
class TaskLooper { export default class TaskLooper {
_fn: () => Promise<void>; _fn: () => Promise<void>;
_isStarted: boolean; _isStarted: boolean;
@ -39,12 +39,10 @@ class TaskLooper {
async _runLoop(periodInMs: number) { async _runLoop(periodInMs: number) {
this._isLooping = true; this._isLooping = true;
while (this._isStarted) { while (this._isStarted) {
let startTime = Date.now(); const startTime = Date.now();
await this._fn(); await this._fn();
if (this._isStarted) await new Promise(function(resolve) { setTimeout(resolve, periodInMs - (Date.now() - startTime)); }); if (this._isStarted) await new Promise(function(resolve) { setTimeout(resolve, periodInMs - (Date.now() - startTime)); });
} }
this._isLooping = false; this._isLooping = false;
} }
} }
export {TaskLooper};

View file

@ -1,6 +1,6 @@
{ {
"compilerOptions": { "compilerOptions": {
"target": "es5", "target": "es2021",
"lib": [ "lib": [
"dom", "dom",
"dom.iterable", "dom.iterable",