Skip to content
This repository has been archived by the owner on Feb 8, 2024. It is now read-only.

DataProvider.watchTransfers #115

Merged
merged 5 commits into from
Oct 25, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@stellar/wallet-sdk",
"version": "0.0.6-rc.12",
"version": "0.0.6-rc.13",
"description": "Libraries to help you write Stellar-enabled wallets in Javascript",
"main": "dist/index.js",
"types": "dist/index.d.ts",
Expand Down
1 change: 1 addition & 0 deletions playground/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"dependencies": {
"@stellar/elements": "^0.0.0",
"lodash": "^4.17.14",
"moment": "^2.24.0",
"react": "^16.8.5",
"react-dom": "^16.8.5",
"react-json-view": "^1.19.1",
Expand Down
71 changes: 41 additions & 30 deletions playground/src/components/Transfers.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import React, { Component } from "react";
import moment from "moment";
import Json from "react-json-view";

class Transfers extends Component {
state = {
Expand Down Expand Up @@ -42,45 +44,54 @@ class Transfers extends Component {
streamEnder: null,
});

// const streamEnder = dataProvider.watchTransfers({
// onMessage: (transfer) => {
// this.setState({
// transfers: [
// { transfer, updateTime: new Date() },
// ...this.state.transfers,
// ],
// });
// },
// onError: (err) => {
// console.log("error: ", err);
// this.setState({ err });
// streamEnder();
// },
// });
const streamEnder = dataProvider.watchTransfers({
onMessage: (transfer) => {
this.setState({
transfers: [
{ transfer, updateTime: new Date() },
...this.state.transfers,
],
});
},
onError: (err) => {
console.log("error: ", err);
this.setState({ err });
streamEnder();
},
});

// this.setState({
// streamEnder,
// });
this.setState({
streamEnder,
});
};

render() {
const { transfers, err } = this.state;
return (
<div>
<h2>Transfers</h2>

<p>
<em>not implemented yet</em>
</p>

<ul>
{transfers.map(({ transfer, updateTime }) => (
<li key={updateTime.toString()}>
Updated: {updateTime.toString()}
<br />
<pre>{JSON.stringify(transfer, null, 2)}</pre>
</li>
))}
{transfers
.sort((a, b) => b.transfer.timestamp - a.transfer.timestamp)
.map(({ transfer, updateTime }) => (
<li key={transfer.id}>
Updated: {updateTime.toString()}
<br />
<ul>
<li>{moment.unix(transfer.timestamp).format("LLL")}</li>
{transfer.isInitialFunding && <li>First funding</li>}
<li>
{transfer.isRecipient ? "Received" : "Sent"}{" "}
{transfer.amount.toString()} {transfer.token.code}
</li>
<li>
{transfer.isRecipient ? "From" : "To"}{" "}
{transfer.otherAccount.publicKey}
</li>
</ul>
{/* <Json src={transfer} /> */}
</li>
))}
</ul>

{err && <p>Error: {err.toString()}</p>}
Expand Down
5 changes: 5 additions & 0 deletions playground/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -6598,6 +6598,11 @@ [email protected], [email protected], mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.1:
dependencies:
minimist "0.0.8"

moment@^2.24.0:
version "2.24.0"
resolved "https://registry.yarnpkg.com/moment/-/moment-2.24.0.tgz#0d055d53f5052aa653c9f6eb68bb5d12bf5c2b5b"
integrity sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg==

move-concurrently@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/move-concurrently/-/move-concurrently-1.0.1.tgz#be2c005fda32e0b29af1f05d7c4b33214c701f92"
Expand Down
88 changes: 77 additions & 11 deletions src/data/DataProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,16 +30,22 @@ function isAccount(obj: any): obj is Account {

interface CallbacksObject {
accountDetails?: () => void;
transfers?: () => void;
}

interface ErrorHandlersObject {
accountDetails?: (error: any) => void;
transfers?: (error: any) => void;
}

interface WatcherTimeoutsObject {
[name: string]: ReturnType<typeof setTimeout>;
}

export class DataProvider {
private accountKey: string;
private serverUrl: string;
private unfundedWatcherTimeout: any;
private _watcherTimeouts: WatcherTimeoutsObject;

private effectStreamEnder?: () => void;
private callbacks: CallbacksObject;
Expand Down Expand Up @@ -69,7 +75,7 @@ export class DataProvider {
this.errorHandlers = {};
this.serverUrl = params.serverUrl;
this.accountKey = accountKey;
this.unfundedWatcherTimeout = null;
this._watcherTimeouts = {};
}

/**
Expand Down Expand Up @@ -209,7 +215,7 @@ export class DataProvider {
// otherwise, if it's a 404, try again in a bit.
.catch((err) => {
if (err.isUnfunded) {
this.unfundedWatcherTimeout = setTimeout(() => {
this._watcherTimeouts.watchAccountDetails = setTimeout(() => {
this.watchAccountDetails(params);
}, 2000);
} else {
Expand All @@ -219,8 +225,68 @@ export class DataProvider {

// if they exec this function, don't make the balance callback do anything
return () => {
if (this.unfundedWatcherTimeout) {
clearTimeout(this.unfundedWatcherTimeout);
if (this._watcherTimeouts.watchAccountDetails) {
clearTimeout(this._watcherTimeouts.watchAccountDetails);
}

delete this.callbacks.accountDetails;
delete this.errorHandlers.accountDetails;
};
}

/**
* Fetch transfers, then re-fetch whenever the details update.
* Returns a function you can execute to stop the watcher.
*/
public watchTransfers(params: WatcherParams<Transfer>): () => void {
const { onMessage, onError } = params;

let getNextTransfers: () => Promise<Collection<Transfer>>;

this.fetchTransfers()

// if the account is funded, watch for effects.
.then((res) => {
// reset the transfer cache
getNextTransfers = res.prev;

// onMessage each transfer separately
res.records.forEach(onMessage);

this.callbacks.transfers = debounce(() => {
getNextTransfers()
.then((nextRes) => {
getNextTransfers = nextRes.prev;

// get new things
if (nextRes.records.length) {
nextRes.records.forEach(onMessage);
}
})
.catch(onError);
}, 2000);
this.errorHandlers.transfers = onError;

this._startEffectWatcher().catch((err) => {
onError(err);
});
})

// otherwise, if it's a 404, try again in a bit.
.catch((err) => {
if (err.isUnfunded) {
this._watcherTimeouts.watchTransfers = setTimeout(() => {
this.watchTransfers(params);
}, 2000);
} else {
onError(err);
}
});

// if they exec this function, don't make the balance callback do anything
return () => {
if (this._watcherTimeouts.watchTransfers) {
clearTimeout(this._watcherTimeouts.watchTransfers);
}

delete this.callbacks.accountDetails;
Expand All @@ -244,8 +310,8 @@ export class DataProvider {
const tradeResponses = await Promise.all(tradeRequests);

return {
next: () => offers.next().then(this._processOpenOffers),
prev: () => offers.prev().then(this._processOpenOffers),
next: () => offers.next().then((res) => this._processOpenOffers(res)),
prev: () => offers.prev().then((res) => this._processOpenOffers(res)),
records: makeDisplayableOffers(
{ publicKey: this.accountKey },
{
Expand All @@ -263,8 +329,8 @@ export class DataProvider {
trades: ServerApi.CollectionPage<ServerApi.TradeRecord>,
): Promise<Collection<Trade>> {
return {
next: () => trades.next().then(this._processTrades),
prev: () => trades.prev().then(this._processTrades),
next: () => trades.next().then((res) => this._processTrades(res)),
prev: () => trades.prev().then((res) => this._processTrades(res)),
records: makeDisplayableTrades(
{ publicKey: this.accountKey },
trades.records,
Expand All @@ -280,8 +346,8 @@ export class DataProvider {
>,
): Promise<Collection<Transfer>> {
return {
next: () => transfers.next().then(this._processTransfers),
prev: () => transfers.prev().then(this._processTransfers),
next: () => transfers.next().then((res) => this._processTransfers(res)),
prev: () => transfers.prev().then((res) => this._processTransfers(res)),
records: makeDisplayableTransfers(
{ publicKey: this.accountKey },
transfers.records,
Expand Down