mirror of
https://github.com/ilyakooo0/urbit.git
synced 2025-01-01 19:46:36 +03:00
btc-wallet: update build, fix routing
This commit is contained in:
parent
c992421366
commit
6b5942b59a
@ -1,6 +1,6 @@
|
||||
const path = require('path');
|
||||
const webpack = require('webpack');
|
||||
// const HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||
// const { CleanWebpackPlugin } = require('clean-webpack-plugin');
|
||||
const urbitrc = require('./urbitrc');
|
||||
const fs = require('fs-extra');
|
||||
@ -33,6 +33,7 @@ let devServer = {
|
||||
host: '0.0.0.0',
|
||||
disableHostCheck: true,
|
||||
historyApiFallback: true,
|
||||
publicPath: '/apps/bitcoin/',
|
||||
};
|
||||
|
||||
const router = _.mapKeys(urbitrc.FLEET || {}, (value, key) => `${key}.localhost:9000`);
|
||||
@ -40,22 +41,19 @@ const router = _.mapKeys(urbitrc.FLEET || {}, (value, key) => `${key}.localhost:
|
||||
if(urbitrc.URL) {
|
||||
devServer = {
|
||||
...devServer,
|
||||
index: '',
|
||||
proxy: {
|
||||
'/~btc/js/bundle/index.*.js': {
|
||||
target: 'http://localhost:9000',
|
||||
pathRewrite: (req, path) => {
|
||||
return '/index.js'
|
||||
index: 'index.html',
|
||||
proxy: [{
|
||||
target: 'http://localhost:9000',
|
||||
changeOrigin: true,
|
||||
target: urbitrc.URL,
|
||||
router,
|
||||
context: path => {
|
||||
if(path === '/apps/bitcoin/desk.js') {
|
||||
return true;
|
||||
}
|
||||
},
|
||||
'**': {
|
||||
changeOrigin: true,
|
||||
target: urbitrc.URL,
|
||||
router,
|
||||
// ensure proxy doesn't timeout channels
|
||||
proxyTimeout: 0
|
||||
return !path.startsWith('/apps/bitcoin')
|
||||
}
|
||||
}
|
||||
}]
|
||||
};
|
||||
}
|
||||
|
||||
@ -107,7 +105,12 @@ module.exports = {
|
||||
devtool: 'inline-source-map',
|
||||
devServer: devServer,
|
||||
plugins: [
|
||||
new UrbitShipPlugin(urbitrc)
|
||||
new UrbitShipPlugin(urbitrc),
|
||||
new HtmlWebpackPlugin({
|
||||
title: 'Bitcoin Wallet',
|
||||
template: './public/index.html'
|
||||
})
|
||||
|
||||
],
|
||||
watch: true,
|
||||
watchOptions: {
|
||||
@ -118,7 +121,7 @@ module.exports = {
|
||||
filename: 'index.js',
|
||||
chunkFilename: 'index.js',
|
||||
path: path.resolve(__dirname, '../dist'),
|
||||
publicPath: '/',
|
||||
publicPath: '/apps/bitcoin/',
|
||||
globalObject: 'this'
|
||||
},
|
||||
optimization: {
|
||||
|
@ -1,5 +1,6 @@
|
||||
const path = require('path');
|
||||
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
|
||||
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||
// const urbitrc = require('./urbitrc');
|
||||
|
||||
module.exports = {
|
||||
@ -44,14 +45,18 @@ module.exports = {
|
||||
},
|
||||
devtool: 'source-map',
|
||||
plugins: [
|
||||
new CleanWebpackPlugin()
|
||||
new CleanWebpackPlugin(),
|
||||
new HtmlWebpackPlugin({
|
||||
title: 'Bitcoin Wallet',
|
||||
template: './public/index.html'
|
||||
})
|
||||
],
|
||||
output: {
|
||||
filename: (pathData) => {
|
||||
return pathData.chunk.name === 'app' ? 'index.[contenthash].js' : '[name].js';
|
||||
},
|
||||
path: path.resolve(__dirname, `../../arvo/app/btc-wallet/js/bundle`),
|
||||
publicPath: '/',
|
||||
path: path.resolve(__dirname, 'dist'),
|
||||
publicPath: '/apps/bitcoin/',
|
||||
},
|
||||
optimization: {
|
||||
minimize: true,
|
||||
|
30
pkg/btc-wallet/public/index.html
Normal file
30
pkg/btc-wallet/public/index.html
Normal file
@ -0,0 +1,30 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Wallet</title>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport"
|
||||
content="width=device-width, initial-scale=1, shrink-to-fit=no,maximum-scale=1"/>
|
||||
<meta name="apple-mobile-web-app-capable" content="yes" />
|
||||
<meta name="apple-touch-fullscreen" content="yes" />
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="default" />
|
||||
<!--
|
||||
<link rel="apple-touch-icon" href="/~btc/img/touch_icon.png">
|
||||
<link rel="icon" type="image/png" href="/~btc/img/Favicon.png">
|
||||
-->
|
||||
<link rel="manifest"
|
||||
href='data:application/manifest+json,{
|
||||
"name": "Wallet",
|
||||
"short_name": "Wallet",
|
||||
"description": "A%20bitcoin%20wallet%20for%20urbit",
|
||||
"display": "standalone",
|
||||
"background_color": "%23FFFFFF",
|
||||
"theme_color": "%23000000"}' />
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<div id="portal-root"></div>
|
||||
<script src="/apps/btc/desk.js"></script>
|
||||
<script src="/session.js"></script>
|
||||
</body>
|
||||
</html>
|
@ -2,7 +2,7 @@ import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import { Root } from './js/components/root.js';
|
||||
import { api } from './js/api.js';
|
||||
import { subscription } from "./js/subscription.js";
|
||||
import Channel from './js/channel';
|
||||
|
||||
import './css/indigo-static.css';
|
||||
import './css/fonts.css';
|
||||
@ -10,7 +10,7 @@ import './css/custom.css';
|
||||
|
||||
// rebuild x3
|
||||
|
||||
const channel = new window.channel();
|
||||
const channel = new Channel();
|
||||
api.setChannel(window.ship, channel);
|
||||
|
||||
|
||||
|
290
pkg/btc-wallet/src/js/channel.js
Normal file
290
pkg/btc-wallet/src/js/channel.js
Normal file
@ -0,0 +1,290 @@
|
||||
export default class Channel {
|
||||
constructor() {
|
||||
this.init();
|
||||
this.deleteOnUnload();
|
||||
|
||||
// a way to handle channel errors
|
||||
//
|
||||
//
|
||||
this.onChannelError = (err) => {
|
||||
console.error('event source error: ', err);
|
||||
};
|
||||
this.onChannelOpen = (e) => {
|
||||
console.log('open', e);
|
||||
};
|
||||
}
|
||||
|
||||
init() {
|
||||
this.debounceInterval = 500;
|
||||
// unique identifier: current time and random number
|
||||
//
|
||||
this.uid =
|
||||
new Date().getTime().toString() +
|
||||
"-" +
|
||||
Math.random().toString(16).slice(-6);
|
||||
|
||||
this.requestId = 1;
|
||||
|
||||
// the currently connected EventSource
|
||||
//
|
||||
this.eventSource = null;
|
||||
|
||||
// the id of the last EventSource event we received
|
||||
//
|
||||
this.lastEventId = 0;
|
||||
|
||||
// this last event id acknowledgment sent to the server
|
||||
//
|
||||
this.lastAcknowledgedEventId = 0;
|
||||
|
||||
// a registry of requestId to successFunc/failureFunc
|
||||
//
|
||||
// These functions are registered during a +poke and are executed
|
||||
// in the onServerEvent()/onServerError() callbacks. Only one of
|
||||
// the functions will be called, and the outstanding poke will be
|
||||
// removed after calling the success or failure function.
|
||||
//
|
||||
|
||||
this.outstandingPokes = new Map();
|
||||
|
||||
// a registry of requestId to subscription functions.
|
||||
//
|
||||
// These functions are registered during a +subscribe and are
|
||||
// executed in the onServerEvent()/onServerError() callbacks. The
|
||||
// event function will be called whenever a new piece of data on this
|
||||
// subscription is available, which may be 0, 1, or many times. The
|
||||
// disconnect function may be called exactly once.
|
||||
//
|
||||
this.outstandingSubscriptions = new Map();
|
||||
|
||||
this.outstandingJSON = [];
|
||||
|
||||
this.debounceTimer = null;
|
||||
}
|
||||
|
||||
resetDebounceTimer() {
|
||||
if (this.debounceTimer) {
|
||||
clearTimeout(this.debounceTimer);
|
||||
this.debounceTimer = null;
|
||||
}
|
||||
this.debounceTimer = setTimeout(() => {
|
||||
this.sendJSONToChannel();
|
||||
}, this.debounceInterval)
|
||||
}
|
||||
|
||||
setOnChannelError(onError = (err) => {}) {
|
||||
this.onChannelError = onError;
|
||||
}
|
||||
|
||||
setOnChannelOpen(onOpen = (e) => {}) {
|
||||
this.onChannelOpen = onOpen;
|
||||
}
|
||||
|
||||
deleteOnUnload() {
|
||||
window.addEventListener("beforeunload", (event) => {
|
||||
this.delete();
|
||||
});
|
||||
}
|
||||
|
||||
clearQueue() {
|
||||
clearTimeout(this.debounceTimer);
|
||||
this.debounceTimer = null;
|
||||
this.sendJSONToChannel();
|
||||
}
|
||||
|
||||
// sends a poke to an app on an urbit ship
|
||||
//
|
||||
poke(ship, app, mark, json, successFunc, failureFunc) {
|
||||
let id = this.nextId();
|
||||
this.outstandingPokes.set(
|
||||
id,
|
||||
{
|
||||
success: successFunc,
|
||||
fail: failureFunc
|
||||
}
|
||||
);
|
||||
|
||||
const j = {
|
||||
id,
|
||||
action: "poke",
|
||||
ship,
|
||||
app,
|
||||
mark,
|
||||
json
|
||||
};
|
||||
|
||||
this.sendJSONToChannel(j);
|
||||
}
|
||||
|
||||
// subscribes to a path on an specific app and ship.
|
||||
//
|
||||
// Returns a subscription id, which is the same as the same internal id
|
||||
// passed to your Urbit.
|
||||
subscribe(
|
||||
ship,
|
||||
app,
|
||||
path,
|
||||
connectionErrFunc = () => {},
|
||||
eventFunc = () => {},
|
||||
quitFunc = () => {},
|
||||
subAckFunc = () => {},
|
||||
) {
|
||||
let id = this.nextId();
|
||||
this.outstandingSubscriptions.set(
|
||||
id,
|
||||
{
|
||||
err: connectionErrFunc,
|
||||
event: eventFunc,
|
||||
quit: quitFunc,
|
||||
subAck: subAckFunc
|
||||
}
|
||||
);
|
||||
|
||||
const json = {
|
||||
id,
|
||||
action: "subscribe",
|
||||
ship,
|
||||
app,
|
||||
path
|
||||
}
|
||||
|
||||
this.resetDebounceTimer();
|
||||
|
||||
this.outstandingJSON.push(json);
|
||||
return id;
|
||||
}
|
||||
|
||||
// quit the channel
|
||||
//
|
||||
delete() {
|
||||
let id = this.nextId();
|
||||
clearInterval(this.ackTimer);
|
||||
navigator.sendBeacon(this.channelURL(), JSON.stringify([{
|
||||
id,
|
||||
action: "delete"
|
||||
}]));
|
||||
if (this.eventSource) {
|
||||
this.eventSource.close();
|
||||
}
|
||||
}
|
||||
|
||||
// unsubscribe to a specific subscription
|
||||
//
|
||||
unsubscribe(subscription) {
|
||||
let id = this.nextId();
|
||||
this.sendJSONToChannel({
|
||||
id,
|
||||
action: "unsubscribe",
|
||||
subscription
|
||||
});
|
||||
}
|
||||
|
||||
// sends a JSON command command to the server.
|
||||
//
|
||||
sendJSONToChannel(j) {
|
||||
let req = new XMLHttpRequest();
|
||||
req.open("PUT", this.channelURL());
|
||||
req.setRequestHeader("Content-Type", "application/json");
|
||||
|
||||
if (this.lastEventId == this.lastAcknowledgedEventId) {
|
||||
if (j) {
|
||||
this.outstandingJSON.push(j);
|
||||
}
|
||||
|
||||
if (this.outstandingJSON.length > 0) {
|
||||
let x = JSON.stringify(this.outstandingJSON);
|
||||
req.send(x);
|
||||
}
|
||||
} else {
|
||||
// we add an acknowledgment to clear the server side queue
|
||||
//
|
||||
// The server side puts messages it sends us in a queue until we
|
||||
// acknowledge that we received it.
|
||||
//
|
||||
let payload = [
|
||||
...this.outstandingJSON,
|
||||
{action: "ack", "event-id": this.lastEventId}
|
||||
];
|
||||
if (j) {
|
||||
payload.push(j)
|
||||
}
|
||||
let x = JSON.stringify(payload);
|
||||
req.send(x);
|
||||
|
||||
this.lastAcknowledgedEventId = this.lastEventId;
|
||||
}
|
||||
this.outstandingJSON = [];
|
||||
|
||||
this.connectIfDisconnected();
|
||||
}
|
||||
|
||||
// connects to the EventSource if we are not currently connected
|
||||
//
|
||||
connectIfDisconnected() {
|
||||
if (this.eventSource) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.eventSource = new EventSource(this.channelURL(), {withCredentials:true});
|
||||
this.eventSource.onmessage = e => {
|
||||
this.lastEventId = parseInt(e.lastEventId, 10);
|
||||
|
||||
let obj = JSON.parse(e.data);
|
||||
let pokeFuncs = this.outstandingPokes.get(obj.id);
|
||||
let subFuncs = this.outstandingSubscriptions.get(obj.id);
|
||||
|
||||
if (obj.response == "poke" && !!pokeFuncs) {
|
||||
let funcs = pokeFuncs;
|
||||
if (obj.hasOwnProperty("ok")) {
|
||||
funcs["success"]();
|
||||
} else if (obj.hasOwnProperty("err")) {
|
||||
funcs["fail"](obj.err);
|
||||
} else {
|
||||
console.error("Invalid poke response: ", obj);
|
||||
}
|
||||
this.outstandingPokes.delete(obj.id);
|
||||
|
||||
} else if (obj.response == "subscribe" ||
|
||||
(obj.response == "poke" && !!subFuncs)) {
|
||||
let funcs = subFuncs;
|
||||
|
||||
if (obj.hasOwnProperty("err")) {
|
||||
funcs["err"](obj.err);
|
||||
this.outstandingSubscriptions.delete(obj.id);
|
||||
} else if (obj.hasOwnProperty("ok")) {
|
||||
funcs["subAck"](obj);
|
||||
}
|
||||
} else if (obj.response == "diff") {
|
||||
// ensure we ack before channel clogs
|
||||
if((this.lastEventId - this.lastAcknowledgedEventId) > 30) {
|
||||
this.clearQueue();
|
||||
}
|
||||
|
||||
let funcs = subFuncs;
|
||||
funcs["event"](obj.json);
|
||||
} else if (obj.response == "quit") {
|
||||
let funcs = subFuncs;
|
||||
funcs["quit"](obj);
|
||||
this.outstandingSubscriptions.delete(obj.id);
|
||||
} else {
|
||||
console.log("Unrecognized response: ", e);
|
||||
}
|
||||
}
|
||||
|
||||
this.eventSource.onopen = this.onChannelOpen;
|
||||
|
||||
this.eventSource.onerror = e => {
|
||||
this.delete();
|
||||
this.init();
|
||||
this.onChannelError(e);
|
||||
}
|
||||
}
|
||||
|
||||
channelURL() {
|
||||
return "/~/channel/" + this.uid;
|
||||
}
|
||||
|
||||
nextId() {
|
||||
return this.requestId++;
|
||||
}
|
||||
}
|
@ -40,7 +40,7 @@ export default class Body extends Component {
|
||||
} else {
|
||||
return (
|
||||
<Switch>
|
||||
<Route path="/~btc/settings">
|
||||
<Route path="/settings">
|
||||
<Col
|
||||
display='flex'
|
||||
flexDirection='column'
|
||||
@ -53,7 +53,7 @@ export default class Body extends Component {
|
||||
/>
|
||||
</Col>
|
||||
</Route>
|
||||
<Route path="/~btc">
|
||||
<Route path="/">
|
||||
<Col
|
||||
display='flex'
|
||||
flexDirection='column'
|
||||
|
@ -16,7 +16,7 @@ export default class Header extends Component {
|
||||
render() {
|
||||
let icon = this.props.settings ? "X" : "Adjust";
|
||||
let iconColor = this.props.settings ? "black" : "orange";
|
||||
let iconLink = this.props.settings ? "/~btc" : "/~btc/settings";
|
||||
let iconLink = this.props.settings ? "/" : "/settings";
|
||||
|
||||
let connection = null;
|
||||
let badge = null;
|
||||
|
@ -33,7 +33,7 @@ export class Root extends Component {
|
||||
const blur = !loaded ? false : !(this.state.wallet && this.state.provider);
|
||||
|
||||
return (
|
||||
<BrowserRouter>
|
||||
<BrowserRouter basename="/apps/bitcoin">
|
||||
<ThemeProvider theme={light}>
|
||||
<Reset />
|
||||
{loaded ? (
|
||||
|
@ -7,7 +7,7 @@ class Store {
|
||||
constructor() {
|
||||
this.state = {
|
||||
loadedBtc: false,
|
||||
loadedSettings: false,
|
||||
loadedSettings: true,
|
||||
loaded: false,
|
||||
providerPerms: {},
|
||||
shipWallets: {},
|
||||
@ -23,7 +23,7 @@ class Store {
|
||||
BTC: { last: 1, symbol: 'BTC' }
|
||||
},
|
||||
denomination: 'BTC',
|
||||
showWarning: true,
|
||||
showWarning: false,
|
||||
error: '',
|
||||
broadcastSuccess: false,
|
||||
};
|
||||
|
@ -19,6 +19,7 @@ export class Subscription {
|
||||
}
|
||||
|
||||
initializeSettings() {
|
||||
return;
|
||||
let app = 'settings-store';
|
||||
let path = '/bucket/btc-wallet';
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user