feat: add web-socket to mempool; & replace UI mappings

This commit is contained in:
Vlad Stan 2022-07-07 14:21:30 +03:00
parent d74b48b0b6
commit 912a7e1c4b
2 changed files with 109 additions and 45 deletions

View File

@ -3,7 +3,9 @@
<q-card class="my-card"> <q-card class="my-card">
<div class="column"> <div class="column">
<center> <center>
<div class="col theHeading">{{ charge.description }}</div> <div class="col theHeading">
<span v-text="charge.description"></span>
</div>
</center> </center>
<div class="col"> <div class="col">
<div <div
@ -39,18 +41,32 @@
</div> </div>
</div> </div>
<div class="col" style="margin: 2px 15px; max-height: 100px"> <div class="col" style="margin: 2px 15px; max-height: 100px">
<center> <div class="row items-center q-mt-md">
<q-btn flat dense outline @click="copyText('{{ charge.id }}')" <div class="col-4 q-pr-lg">Charge Id:</div>
>Charge ID: {{ charge.id }}</q-btn <div class="col-8 q-pr-lg">
> <q-btn flat dense outline @click="copyText(charge.id)"
</center> ><span v-text="charge.id"></span
<span ></q-btn>
><small </div>
>{% raw %} Total to pay: {{ charge.amount }}sats<br /> </div>
Amount paid: {{ charge.balance }}</small <div class="row items-center q-mt-md">
><br /> <div class="col-4 q-pr-lg">Total to pay:</div>
Amount due: {{ charge.amount - charge.balance }}sats {% endraw %} <div class="col-8 q-pr-lg">
</span> <span v-text="charge.amount"></span> sats
</div>
</div>
<div class="row items-center q-mt-md">
<div class="col-4 q-pr-lg">Amount paid:</div>
<div class="col-8 q-pr-lg">
<span v-text="charge.balance"></span> sats
</div>
</div>
<div class="row items-center q-mt-md">
<div class="col-4 q-pr-lg">Amount due:</div>
<div class="col-8 q-pr-lg">
<span v-text="charge.amount - charge.balance"></span> sats
</div>
</div>
</div> </div>
<q-separator></q-separator> <q-separator></q-separator>
<div class="col"> <div class="col">
@ -119,23 +135,22 @@
></q-icon> ></q-icon>
<q-btn <q-btn
outline outline
v-if="'{{ charge.webhook }}' != 'None'" v-if="charge.webhook"
type="a" type="a"
href="{{ charge.completelink }}" :href="charge.completelink"
label="{{ charge.completelinktext }}" :label="charge.completelinktext"
></q-btn> ></q-btn>
</div> </div>
<div v-else> <div v-else>
<center> <span class="text-subtitle2"
<span class="text-subtitle2" >Pay this lightning-network invoice:</span
>Pay this <br /> >
lightning-network invoice</span <br />
>
</center> <a :href="'lightning:'+charge.payment_request">
<a href="lightning:{{ charge.payment_request }}">
<q-responsive :ratio="1" class="q-mx-md"> <q-responsive :ratio="1" class="q-mx-md">
<qrcode <qrcode
:value="'{{ charge.payment_request }}'" :value="charge.payment_request"
:options="{width: 800}" :options="{width: 800}"
class="rounded-borders" class="rounded-borders"
></qrcode> ></qrcode>
@ -145,7 +160,7 @@
<q-btn <q-btn
outline outline
color="grey" color="grey"
@click="copyText('{{ charge.payment_request }}')" @click="copyText(charge.payment_request)"
>Copy invoice</q-btn >Copy invoice</q-btn
> >
</div> </div>
@ -169,23 +184,23 @@
></q-icon> ></q-icon>
<q-btn <q-btn
outline outline
v-if="'{{ charge.webhook }}' != None" v-if="charge.webhook "
type="a" type="a"
href="{{ charge.completelink }}" :href="charge.completelink"
label="{{ charge.completelinktext }}" :label="charge.completelinktext"
></q-btn> ></q-btn>
</div> </div>
<div v-else> <div v-else>
<center> <span class="text-subtitle2"
<span class="text-subtitle2" >Send
>Send {{ charge.amount }}sats<br /> <span v-text="charge.amount"></span>
to this onchain address</span sats to this onchain address</span
> >
</center>
<a href="bitcoin:{{ charge.onchainaddress }}"> <a :href="'bitcoin:'+charge.onchainaddress">
<q-responsive :ratio="1" class="q-mx-md"> <q-responsive :ratio="1" class="q-mx-md">
<qrcode <qrcode
:value="'{{ charge.onchainaddress }}'" :value="charge.onchainaddress"
:options="{width: 800}" :options="{width: 800}"
class="rounded-borders" class="rounded-borders"
></qrcode> ></qrcode>
@ -195,7 +210,7 @@
<q-btn <q-btn
outline outline
color="grey" color="grey"
@click="copyText('{{ charge.onchainaddress }}')" @click="copyText(charge.onchainaddress)"
>Copy address</q-btn >Copy address</q-btn
> >
</div> </div>
@ -210,7 +225,7 @@
<style> <style>
.theCard { .theCard {
width: 360px; width: 30%;
margin: 10px auto; margin: 10px auto;
} }
.theHeading { .theHeading {
@ -220,6 +235,7 @@
</style> </style>
<!-- todo: use config mempool --> <!-- todo: use config mempool -->
<script src="https://mempool.space/mempool.js"></script> <script src="https://mempool.space/mempool.js"></script>
<script src="{{ url_for('satspay_static', path='js/utils.js') }}"></script>
<script> <script>
Vue.component(VueQrcode.name, VueQrcode) Vue.component(VueQrcode.name, VueQrcode)
@ -228,7 +244,8 @@
mixins: [windowMixin], mixins: [windowMixin],
data() { data() {
return { return {
charge: JSON.parse('{{charge | tojson}}'), charge: JSON.parse('{{charge_data | tojson}}'),
ws: null,
newProgress: 0.4, newProgress: 0.4,
counter: 1, counter: 1,
newTimeLeft: '', newTimeLeft: '',
@ -277,11 +294,13 @@
const fn = async () => const fn = async () =>
addressesAPI.getAddressTxsUtxo({ addressesAPI.getAddressTxsUtxo({
address: charge.onchainaddress address: this.charge.onchainaddress
}) })
const utxos = await retryWithDelay(fn) const utxos = await retryWithDelay(fn)
charge.balance = utxos.reduce((t, u) => t + u.value, 0) console.log('### utxos', utxos)
this.charge.balance = utxos.reduce((t, u) => t + u.value, 0)
console.log('### utxos', utxos)
}, },
payInvoice: function () { payInvoice: function () {
this.lnbtc = true this.lnbtc = true
@ -293,8 +312,8 @@
}, },
refreshExpirationTime: function () { refreshExpirationTime: function () {
this.timetoComplete = this.timetoComplete =
parseInt('{{ charge.time }}') * 60 - parseInt(this.charge.time) * 60 -
(Date.now() / 1000 - parseInt('{{ charge.timestamp }}')) (Date.now() / 1000 - parseInt(this.charge.timestamp))
this.newTimeLeft = Quasar.utils.date.formatDate( this.newTimeLeft = Quasar.utils.date.formatDate(
new Date((this.timeToComplete - 3600) * 1000), new Date((this.timeToComplete - 3600) * 1000),
@ -304,7 +323,7 @@
refreshProgres: function () { refreshProgres: function () {
this.refreshExpirationTime() this.refreshExpirationTime()
this.newProgress = this.newProgress =
1 - this.timeToComplete / (parseInt('{{ charge.time }}') * 60) 1 - this.timeToComplete / (parseInt(this.charge.time) * 60)
}, },
loopRefresh: function () { loopRefresh: function () {
// invoice only // invoice only
@ -320,9 +339,50 @@
if (this.charge.onchainaddress) this.checkAddressBalance() if (this.charge.onchainaddress) this.checkAddressBalance()
} }
}, 1000) }, 1000)
},
initWs: async function () {
const {
bitcoin: {websocket}
} = mempoolJS({
hostname: 'mempool.space'
})
this.ws = new WebSocket('wss://mempool.space/api/v1/ws')
this.ws.addEventListener('open', x => {
console.log('### open ws', x)
})
this.ws.addEventListener('close', x => {
console.log('### close ws', x)
})
this.ws.addEventListener('message', ({data}) => {
const res = JSON.parse(data.toString())
console.log('### socker mempool res', res)
if (res['address-transactions']) {
this.checkAddressBalance()
}
})
},
loopPingWs: function () {
setInterval(() => {
if (!this.ws || this.ws.readyState !== WebSocket.OPEN) this.initWs()
this.ws.send(JSON.stringify({action: 'ping'}))
}, 30 * 1000)
},
trackAddress: async function (address, retry = 0) {
try {
if (!this.ws || this.ws.readyState !== WebSocket.OPEN) this.initWs()
console.log('### start to track: ', address)
this.ws.send(JSON.stringify({'track-address': address}))
} catch (error) {
await sleep(1000)
if (retry > 10) throw error
this.trackAddress(address, retry + 1)
}
} }
}, },
created: function () { created: function () {
console.log('### charge', this.charge)
if (this.charge.lnbitswallet) this.payInvoice() if (this.charge.lnbitswallet) this.payInvoice()
else this.payOnchain() else this.payOnchain()
@ -334,6 +394,10 @@
this.loopRefresh() this.loopRefresh()
} }
this.startPaymentNotifier() this.startPaymentNotifier()
if (this.charge.onchainaddress) {
this.loopPingWs()
this.trackAddress(this.charge.onchainaddress)
}
} }
}) })
</script> </script>

View File

@ -34,5 +34,5 @@ async def display(request: Request, charge_id: str):
inkey = wallet.inkey if wallet else None inkey = wallet.inkey if wallet else None
return satspay_renderer().TemplateResponse( return satspay_renderer().TemplateResponse(
"satspay/display.html", "satspay/display.html",
{"request": request, "charge": charge.dict(), "wallet_inkey": inkey}, {"request": request, "charge_data": charge.dict(), "wallet_inkey": inkey},
) )