add browser example.
This commit is contained in:
parent
a9dce51b3a
commit
dc436d10e2
282
browser/index.html
Normal file
282
browser/index.html
Normal file
@ -0,0 +1,282 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>bcoin</title>
|
||||||
|
<style>
|
||||||
|
html { height: 100%; }
|
||||||
|
body { height: 90%; padding: 20px; }
|
||||||
|
h1 {
|
||||||
|
font: 3em monospace;
|
||||||
|
margin: 10px;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
small {
|
||||||
|
margin: 10px;
|
||||||
|
width: 50%;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
.log {
|
||||||
|
padding: 5px;
|
||||||
|
margin-left: 10px;
|
||||||
|
overflow-y: scroll;
|
||||||
|
border: 1px solid black;
|
||||||
|
white-space: pre-wrap;
|
||||||
|
height: 40%;
|
||||||
|
width: 40%;
|
||||||
|
font: 1em monospace;
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
.wallet {
|
||||||
|
padding: 5px;
|
||||||
|
margin-left: 5px;
|
||||||
|
margin-top: 10px;
|
||||||
|
font: 1em monospace;
|
||||||
|
}
|
||||||
|
.send {
|
||||||
|
padding: 5px;
|
||||||
|
margin-left: 5px;
|
||||||
|
margin-top: 10px;
|
||||||
|
font: 1em monospace;
|
||||||
|
}
|
||||||
|
#newaddr{
|
||||||
|
display: block;
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
.tx {
|
||||||
|
float: right;
|
||||||
|
font: 1em monospace;
|
||||||
|
padding: 5px;
|
||||||
|
border: 1px solid black;
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
a {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
.floating {
|
||||||
|
font: 1em monospace;
|
||||||
|
white-space: pre-wrap;
|
||||||
|
position: absolute;
|
||||||
|
display: none;
|
||||||
|
padding: 5px;
|
||||||
|
background: white;
|
||||||
|
border: 1px solid black;
|
||||||
|
width: 40%;
|
||||||
|
height: 30%;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
margin-left: -20%;
|
||||||
|
margin-top: -15%;
|
||||||
|
overflow-y: scroll;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<script src="/bcoin.js"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>BCoin, the browser full node</h1>
|
||||||
|
<small>Welcome. Your machine is currently validating the segnet4 blockchain.
|
||||||
|
The blocks and wallet are stored on your local disk with indexed DB. You are
|
||||||
|
connecting to the actual bitcoin P2P network via a websocket->tcp proxy.
|
||||||
|
Enjoy. (See the <a href="https://github.com/bcoin-org/bcoin">bcoin repo</a> for
|
||||||
|
more bitcoin magic).</small>
|
||||||
|
<div class="tx">
|
||||||
|
Last 20 Blocks/TXs:
|
||||||
|
<div id="tx"></div>
|
||||||
|
</div>
|
||||||
|
<div id="log" class="log"></div>
|
||||||
|
<div id="wallet" class="wallet"></div>
|
||||||
|
<form id="send" class="send" action="#">
|
||||||
|
<input type="text" name="address" id="address" placeholder="Address">
|
||||||
|
<input type="text" name="amount" id="amount" placeholder="Amount (BTC)">
|
||||||
|
<input type="submit" value="Send">
|
||||||
|
</form>
|
||||||
|
<input type="button" id="newaddr" value="New Address">
|
||||||
|
<div id="floating" class="floating"></div>
|
||||||
|
<script>
|
||||||
|
;(function() {
|
||||||
|
var utils = bcoin.utils;
|
||||||
|
var body = document.getElementsByTagName('body')[0];
|
||||||
|
var log = document.getElementById('log');
|
||||||
|
var wdiv = document.getElementById('wallet');
|
||||||
|
var tdiv = document.getElementById('tx');
|
||||||
|
var floating = document.getElementById('floating');
|
||||||
|
var send = document.getElementById('send');
|
||||||
|
var newaddr = document.getElementById('newaddr');
|
||||||
|
var items = [];
|
||||||
|
var scrollback = 0;
|
||||||
|
var logger, node;
|
||||||
|
|
||||||
|
body.onmouseup = function() {
|
||||||
|
floating.style.display = 'none';
|
||||||
|
};
|
||||||
|
|
||||||
|
floating.onmouseup = function(ev) {
|
||||||
|
ev.stopPropagation();
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
function show(obj) {
|
||||||
|
floating.innerHTML = escape(utils.inspectify(obj, false));
|
||||||
|
floating.style.display = 'block';
|
||||||
|
}
|
||||||
|
|
||||||
|
logger = {
|
||||||
|
debug: function(args) {
|
||||||
|
if (++scrollback > 1000) {
|
||||||
|
log.innerHTML = '';
|
||||||
|
scrollback = 1;
|
||||||
|
}
|
||||||
|
var msg = utils.format(args, false);
|
||||||
|
log.innerHTML += '<span style="color:blue;">' + utils.now() + '</span> ';
|
||||||
|
log.innerHTML += escape(msg) + '\n';
|
||||||
|
log.scrollTop = log.scrollHeight;
|
||||||
|
},
|
||||||
|
error: function(err) {
|
||||||
|
if (++scrollback > 1000) {
|
||||||
|
log.innerHTML = '';
|
||||||
|
scrollback = 1;
|
||||||
|
}
|
||||||
|
var msg = (err.message + '').replace(/^ *Error: */, '');
|
||||||
|
log.innerHTML += '<span style="color:blue;">' + utils.now() + '</span> ';
|
||||||
|
log.innerHTML += '<span style="color:red;">[Error]</span> ';
|
||||||
|
log.innerHTML += escape(msg) + '\n';
|
||||||
|
log.scrollTop = log.scrollHeight;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
send.onsubmit = function(ev) {
|
||||||
|
var value = document.getElementById('amount').value;
|
||||||
|
var address = document.getElementById('address').value;
|
||||||
|
value = utils.satoshi(value);
|
||||||
|
node.wallet.createTX({}, [{address: address,value:value}], function(err, tx) {
|
||||||
|
if (err)
|
||||||
|
return bcoin.error(err);
|
||||||
|
node.wallet.sign(tx, function(err) {
|
||||||
|
if (err)
|
||||||
|
return bcoin.error(err);
|
||||||
|
node.sendTX(tx, function(err) {
|
||||||
|
if (err)
|
||||||
|
return bcoin.error(err);
|
||||||
|
show(tx);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
ev.preventDefault();
|
||||||
|
ev.stopPropagation();
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
newaddr.onmouseup = function() {
|
||||||
|
node.wallet.createReceive(function(err) {
|
||||||
|
if (err)
|
||||||
|
throw err;
|
||||||
|
formatWallet(node.wallet);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
function kb(size) {
|
||||||
|
size /= 1000;
|
||||||
|
return size.toFixed(2) + 'kb';
|
||||||
|
}
|
||||||
|
|
||||||
|
function create(html) {
|
||||||
|
var el = document.createElement('div');
|
||||||
|
el.innerHTML = html;
|
||||||
|
return el.firstChild;
|
||||||
|
}
|
||||||
|
|
||||||
|
function escape(html, encode) {
|
||||||
|
return html
|
||||||
|
.replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&')
|
||||||
|
.replace(/</g, '<')
|
||||||
|
.replace(/>/g, '>')
|
||||||
|
.replace(/"/g, '"')
|
||||||
|
.replace(/'/g, ''');
|
||||||
|
}
|
||||||
|
|
||||||
|
function addItem(tx) {
|
||||||
|
var el;
|
||||||
|
|
||||||
|
if (items.length === 20) {
|
||||||
|
el = items.shift();
|
||||||
|
tdiv.removeChild(el);
|
||||||
|
}
|
||||||
|
|
||||||
|
el = create('<a style="display:block;" href="#'
|
||||||
|
+ tx.rhash + '">' + tx.rhash + ' (' + tx.height
|
||||||
|
+ ' - ' + kb(tx.getSize()) + ')</a>');
|
||||||
|
tdiv.appendChild(el);
|
||||||
|
|
||||||
|
el.onmouseup = function(ev) {
|
||||||
|
show(tx);
|
||||||
|
ev.stopPropagation();
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
items.push(el);
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatWallet(wallet) {
|
||||||
|
var html = '';
|
||||||
|
var key = wallet.master.toJSON();
|
||||||
|
html += '<b>Wallet</b><br>';
|
||||||
|
html += 'Current Address (p2wpkh): <b>' + wallet.getAddress() + '</b><br>';
|
||||||
|
html += 'Current Address (p2wpkh behind p2sh): <b>' + wallet.getProgramAddress() + '</b><br>';
|
||||||
|
html += 'Extended Private Key: <b>' + key.xprivkey + '</b><br>';
|
||||||
|
html += 'Mnemonic: <b>' + key.phrase + '</b><br>';
|
||||||
|
wallet.getBalance(function(err, balance) {
|
||||||
|
if (balance) {
|
||||||
|
html += 'Confirmed Balance: <b>' + utils.btc(balance.confirmed) + '</b><br>';
|
||||||
|
html += 'Unconfirmed Balance: <b>' + utils.btc(balance.unconfirmed) + '</b><br>';
|
||||||
|
html += 'Balance: <b>' + utils.btc(balance.total) + '</b><br>';
|
||||||
|
}
|
||||||
|
wallet.getHistory(function(err, txs) {
|
||||||
|
html += 'TXs:\n';
|
||||||
|
wdiv.innerHTML = html;
|
||||||
|
if (txs) {
|
||||||
|
txs.forEach(function(tx) {
|
||||||
|
var el = create('<a style="display:block;" href="#' + tx.rhash + '">' + tx.rhash + '</a>');
|
||||||
|
wdiv.appendChild(el);
|
||||||
|
el.onclick = function(ev) {
|
||||||
|
show(tx);
|
||||||
|
ev.stopPropagation();
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
bcoin.set({
|
||||||
|
network: 'segnet4',
|
||||||
|
debug: true,
|
||||||
|
// db: 'memory',
|
||||||
|
logger: logger,
|
||||||
|
useWorkers: true
|
||||||
|
});
|
||||||
|
|
||||||
|
node = new bcoin.fullnode();
|
||||||
|
|
||||||
|
node.on('error', function(err) {
|
||||||
|
bcoin.error(err);
|
||||||
|
});
|
||||||
|
|
||||||
|
node.on('block', addItem);
|
||||||
|
node.mempool.on('tx', addItem);
|
||||||
|
|
||||||
|
node.open(function(err) {
|
||||||
|
if (err)
|
||||||
|
throw err;
|
||||||
|
|
||||||
|
node.startSync();
|
||||||
|
|
||||||
|
formatWallet(node.wallet);
|
||||||
|
|
||||||
|
node.wallet.on('update', function() {
|
||||||
|
formatWallet(node.wallet);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
136
browser/proxysocket.js
Normal file
136
browser/proxysocket.js
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
var bcoin = require('../lib/bcoin/env');
|
||||||
|
var utils = require('../lib/bcoin/utils');
|
||||||
|
var BufferWriter = require('../lib/bcoin/writer');
|
||||||
|
var assert = utils.assert;
|
||||||
|
var EventEmitter = require('events').EventEmitter;
|
||||||
|
var IOClient = require('socket.io-client');
|
||||||
|
|
||||||
|
function ProxySocket(uri) {
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
if (!(this instanceof ProxySocket))
|
||||||
|
return new ProxySocket(uri);
|
||||||
|
|
||||||
|
EventEmitter.call(this);
|
||||||
|
|
||||||
|
this.info = null;
|
||||||
|
|
||||||
|
this.socket = new IOClient(uri, { reconnection: false });
|
||||||
|
this.sendBuffer = [];
|
||||||
|
this.snonce = null;
|
||||||
|
|
||||||
|
this.closed = false;
|
||||||
|
|
||||||
|
this.socket.on('info', function(info) {
|
||||||
|
if (self.closed)
|
||||||
|
return;
|
||||||
|
|
||||||
|
self.info = info;
|
||||||
|
|
||||||
|
if (info.pow) {
|
||||||
|
self.snonce = new Buffer(info.snonce, 'hex');
|
||||||
|
self.target = new Buffer(info.target, 'hex');
|
||||||
|
}
|
||||||
|
|
||||||
|
self.emit('info', info);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.socket.on('error', function(err) {
|
||||||
|
console.error(err);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.socket.on('tcp connect', function() {
|
||||||
|
if (self.closed)
|
||||||
|
return;
|
||||||
|
self.emit('connect');
|
||||||
|
});
|
||||||
|
|
||||||
|
this.socket.on('tcp data', function(data) {
|
||||||
|
self.emit('data', new Buffer(data, 'hex'));
|
||||||
|
});
|
||||||
|
|
||||||
|
this.socket.on('tcp close', function(data) {
|
||||||
|
if (self.closed)
|
||||||
|
return;
|
||||||
|
self.closed = true;
|
||||||
|
self.emit('close');
|
||||||
|
});
|
||||||
|
|
||||||
|
this.socket.on('tcp error', function(err) {
|
||||||
|
self.emit('error', new Error(err));
|
||||||
|
});
|
||||||
|
|
||||||
|
this.socket.on('close', function() {
|
||||||
|
if (self.closed)
|
||||||
|
return;
|
||||||
|
self.closed = true;
|
||||||
|
self.emit('close');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
utils.inherits(ProxySocket, EventEmitter);
|
||||||
|
|
||||||
|
ProxySocket.prototype.connect = function connect(port, host) {
|
||||||
|
var nonce = 0;
|
||||||
|
var i, pow;
|
||||||
|
|
||||||
|
if (this.closed) {
|
||||||
|
this.sendBuffer.length = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.info)
|
||||||
|
return this.once('info', connect.bind(this, port, host));
|
||||||
|
|
||||||
|
if (this.info.pow) {
|
||||||
|
bcoin.debug(
|
||||||
|
'Solving proof of work to create socket (%d, %s) -- please wait.',
|
||||||
|
port, host);
|
||||||
|
|
||||||
|
pow = new BufferWriter();
|
||||||
|
pow.writeU32(nonce);
|
||||||
|
pow.writeBytes(this.snonce);
|
||||||
|
pow.writeU32(port);
|
||||||
|
pow.writeString(host, 'ascii');
|
||||||
|
pow = pow.render();
|
||||||
|
|
||||||
|
do {
|
||||||
|
nonce++;
|
||||||
|
assert(nonce <= 0xffffffff, 'Could not create socket.');
|
||||||
|
pow.writeUInt32LE(nonce, 0, true);
|
||||||
|
} while (utils.cmp(utils.dsha256(pow), this.target) >= 0);
|
||||||
|
|
||||||
|
bcoin.debug('Solved proof of work: %d', nonce);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.socket.emit('tcp connect', port, host, nonce);
|
||||||
|
|
||||||
|
for (i = 0; i < this.sendBuffer.length; i++)
|
||||||
|
this.write(this.sendBuffer[i]);
|
||||||
|
|
||||||
|
this.sendBuffer.length = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
ProxySocket.prototype.write = function write(data) {
|
||||||
|
if (!this.info) {
|
||||||
|
this.sendBuffer.push(data);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
this.socket.emit('tcp data', data.toString('hex'));
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
ProxySocket.prototype.destroy = function destroy() {
|
||||||
|
if (this.closed)
|
||||||
|
return;
|
||||||
|
this.closed = true;
|
||||||
|
this.socket.disconnect();
|
||||||
|
};
|
||||||
|
|
||||||
|
ProxySocket.connect = function connect(uri, port, host) {
|
||||||
|
var socket = new ProxySocket(uri);
|
||||||
|
socket.connect(port, host);
|
||||||
|
return socket;
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = ProxySocket;
|
||||||
31
browser/server.js
Normal file
31
browser/server.js
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
var HTTPBase = require('../lib/bcoin/http/base');
|
||||||
|
var fs = require('fs');
|
||||||
|
|
||||||
|
var server = new HTTPBase();
|
||||||
|
var proxy = require('./wsproxy')({
|
||||||
|
pow: process.argv.indexOf('--pow') !== -1
|
||||||
|
});
|
||||||
|
|
||||||
|
var index = fs.readFileSync(__dirname + '/index.html');
|
||||||
|
var bcoin = fs.readFileSync(__dirname + '/bcoin.js');
|
||||||
|
var worker = fs.readFileSync(__dirname + '/../lib/bcoin/worker.js');
|
||||||
|
|
||||||
|
server.get('/favicon.ico', function(req, res, next, send) {
|
||||||
|
send(404, '', 'text');
|
||||||
|
});
|
||||||
|
|
||||||
|
server.get('/', function(req, res, next, send) {
|
||||||
|
send(200, index, 'html');
|
||||||
|
});
|
||||||
|
|
||||||
|
server.get('/bcoin.js', function(req, res, next, send) {
|
||||||
|
send(200, bcoin, 'js');
|
||||||
|
});
|
||||||
|
|
||||||
|
server.get('/bcoin-worker.js', function(req, res, next, send) {
|
||||||
|
send(200, worker, 'js');
|
||||||
|
});
|
||||||
|
|
||||||
|
proxy.attach(server.server);
|
||||||
|
|
||||||
|
server.listen(8080);
|
||||||
197
browser/setimmediate.js
Normal file
197
browser/setimmediate.js
Normal file
@ -0,0 +1,197 @@
|
|||||||
|
/*!
|
||||||
|
* Copyright (c) 2012 Barnesandnoble.com, llc, Donavon West, and Domenic Denicola
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to
|
||||||
|
* deal in the Software without restriction, including without limitation the
|
||||||
|
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
* sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
(function (global, undefined) {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
if (global.setImmediate) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var nextHandle = 1; // Spec says greater than zero
|
||||||
|
var tasksByHandle = {};
|
||||||
|
var currentlyRunningATask = false;
|
||||||
|
var doc = global.document;
|
||||||
|
var setImmediate;
|
||||||
|
|
||||||
|
function addFromSetImmediateArguments(args) {
|
||||||
|
tasksByHandle[nextHandle] = partiallyApplied.apply(undefined, args);
|
||||||
|
return nextHandle++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This function accepts the same arguments as setImmediate, but
|
||||||
|
// returns a function that requires no arguments.
|
||||||
|
function partiallyApplied(handler) {
|
||||||
|
var args = [].slice.call(arguments, 1);
|
||||||
|
return function() {
|
||||||
|
if (typeof handler === "function") {
|
||||||
|
handler.apply(undefined, args);
|
||||||
|
} else {
|
||||||
|
(new Function("" + handler))();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function runIfPresent(handle) {
|
||||||
|
// From the spec: "Wait until any invocations of this algorithm started before this one have completed."
|
||||||
|
// So if we're currently running a task, we'll need to delay this invocation.
|
||||||
|
if (currentlyRunningATask) {
|
||||||
|
// Delay by doing a setTimeout. setImmediate was tried instead, but in Firefox 7 it generated a
|
||||||
|
// "too much recursion" error.
|
||||||
|
setTimeout(partiallyApplied(runIfPresent, handle), 0);
|
||||||
|
} else {
|
||||||
|
var task = tasksByHandle[handle];
|
||||||
|
if (task) {
|
||||||
|
currentlyRunningATask = true;
|
||||||
|
try {
|
||||||
|
task();
|
||||||
|
} finally {
|
||||||
|
clearImmediate(handle);
|
||||||
|
currentlyRunningATask = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function clearImmediate(handle) {
|
||||||
|
delete tasksByHandle[handle];
|
||||||
|
}
|
||||||
|
|
||||||
|
function installNextTickImplementation() {
|
||||||
|
setImmediate = function() {
|
||||||
|
var handle = addFromSetImmediateArguments(arguments);
|
||||||
|
process.nextTick(partiallyApplied(runIfPresent, handle));
|
||||||
|
return handle;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function canUsePostMessage() {
|
||||||
|
// The test against `importScripts` prevents this implementation from being installed inside a web worker,
|
||||||
|
// where `global.postMessage` means something completely different and can't be used for this purpose.
|
||||||
|
if (global.postMessage && !global.importScripts) {
|
||||||
|
var postMessageIsAsynchronous = true;
|
||||||
|
var oldOnMessage = global.onmessage;
|
||||||
|
global.onmessage = function() {
|
||||||
|
postMessageIsAsynchronous = false;
|
||||||
|
};
|
||||||
|
global.postMessage("", "*");
|
||||||
|
global.onmessage = oldOnMessage;
|
||||||
|
return postMessageIsAsynchronous;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function installPostMessageImplementation() {
|
||||||
|
// Installs an event handler on `global` for the `message` event: see
|
||||||
|
// * https://developer.mozilla.org/en/DOM/window.postMessage
|
||||||
|
// * http://www.whatwg.org/specs/web-apps/current-work/multipage/comms.html#crossDocumentMessages
|
||||||
|
|
||||||
|
var messagePrefix = "setImmediate$" + Math.random() + "$";
|
||||||
|
var onGlobalMessage = function(event) {
|
||||||
|
if (event.source === global &&
|
||||||
|
typeof event.data === "string" &&
|
||||||
|
event.data.indexOf(messagePrefix) === 0) {
|
||||||
|
runIfPresent(+event.data.slice(messagePrefix.length));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (global.addEventListener) {
|
||||||
|
global.addEventListener("message", onGlobalMessage, false);
|
||||||
|
} else {
|
||||||
|
global.attachEvent("onmessage", onGlobalMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
setImmediate = function() {
|
||||||
|
var handle = addFromSetImmediateArguments(arguments);
|
||||||
|
global.postMessage(messagePrefix + handle, "*");
|
||||||
|
return handle;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function installMessageChannelImplementation() {
|
||||||
|
var channel = new MessageChannel();
|
||||||
|
channel.port1.onmessage = function(event) {
|
||||||
|
var handle = event.data;
|
||||||
|
runIfPresent(handle);
|
||||||
|
};
|
||||||
|
|
||||||
|
setImmediate = function() {
|
||||||
|
var handle = addFromSetImmediateArguments(arguments);
|
||||||
|
channel.port2.postMessage(handle);
|
||||||
|
return handle;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function installReadyStateChangeImplementation() {
|
||||||
|
var html = doc.documentElement;
|
||||||
|
setImmediate = function() {
|
||||||
|
var handle = addFromSetImmediateArguments(arguments);
|
||||||
|
// Create a <script> element; its readystatechange event will be fired asynchronously once it is inserted
|
||||||
|
// into the document. Do so, thus queuing up the task. Remember to clean up once it's been called.
|
||||||
|
var script = doc.createElement("script");
|
||||||
|
script.onreadystatechange = function () {
|
||||||
|
runIfPresent(handle);
|
||||||
|
script.onreadystatechange = null;
|
||||||
|
html.removeChild(script);
|
||||||
|
script = null;
|
||||||
|
};
|
||||||
|
html.appendChild(script);
|
||||||
|
return handle;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function installSetTimeoutImplementation() {
|
||||||
|
setImmediate = function() {
|
||||||
|
var handle = addFromSetImmediateArguments(arguments);
|
||||||
|
setTimeout(partiallyApplied(runIfPresent, handle), 0);
|
||||||
|
return handle;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// If supported, we should attach to the prototype of global, since that is where setTimeout et al. live.
|
||||||
|
var attachTo = Object.getPrototypeOf && Object.getPrototypeOf(global);
|
||||||
|
attachTo = attachTo && attachTo.setTimeout ? attachTo : global;
|
||||||
|
|
||||||
|
// Don't get fooled by e.g. browserify environments.
|
||||||
|
if ({}.toString.call(global.process) === "[object process]") {
|
||||||
|
// For Node.js before 0.9
|
||||||
|
installNextTickImplementation();
|
||||||
|
|
||||||
|
} else if (canUsePostMessage()) {
|
||||||
|
// For non-IE10 modern browsers
|
||||||
|
installPostMessageImplementation();
|
||||||
|
|
||||||
|
} else if (global.MessageChannel) {
|
||||||
|
// For web workers, where supported
|
||||||
|
installMessageChannelImplementation();
|
||||||
|
|
||||||
|
} else if (doc && "onreadystatechange" in doc.createElement("script")) {
|
||||||
|
// For IE 6–8
|
||||||
|
installReadyStateChangeImplementation();
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// For older browsers
|
||||||
|
installSetTimeoutImplementation();
|
||||||
|
}
|
||||||
|
|
||||||
|
attachTo.setImmediate = setImmediate;
|
||||||
|
attachTo.clearImmediate = clearImmediate;
|
||||||
|
}(typeof self === "undefined" ? typeof global === "undefined" ? this : global : self));
|
||||||
132
browser/wsproxy.js
Normal file
132
browser/wsproxy.js
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
var http = require('http');
|
||||||
|
var net = require('net');
|
||||||
|
var IOServer = require('socket.io');
|
||||||
|
var utils = require('../lib/bcoin/utils');
|
||||||
|
var IP = require('../lib/bcoin/ip');
|
||||||
|
var network = require('../lib/bcoin/protocol/network');
|
||||||
|
var BufferWriter = require('../lib/bcoin/writer');
|
||||||
|
var ports = [];
|
||||||
|
var i, type;
|
||||||
|
|
||||||
|
for (i = 0; i < network.types.length; i++) {
|
||||||
|
type = network.types[i];
|
||||||
|
ports.push(network[type].port);
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = function wsproxy(options) {
|
||||||
|
var target, io;
|
||||||
|
|
||||||
|
if (!options)
|
||||||
|
options = {};
|
||||||
|
|
||||||
|
target = new Buffer(
|
||||||
|
'0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff',
|
||||||
|
'hex');
|
||||||
|
|
||||||
|
io = new IOServer();
|
||||||
|
|
||||||
|
io.on('error', function(err) {
|
||||||
|
utils.error(err.stack + '');
|
||||||
|
});
|
||||||
|
|
||||||
|
io.on('connection', function(ws) {
|
||||||
|
var snonce = utils.nonce().toArrayLike(Buffer, 'be', 8);
|
||||||
|
var socket, pow;
|
||||||
|
|
||||||
|
ws.emit('info', {
|
||||||
|
pow: !!options.pow,
|
||||||
|
snonce: snonce.toString('hex'),
|
||||||
|
target: target.toString('hex')
|
||||||
|
});
|
||||||
|
|
||||||
|
ws.on('error', function(err) {
|
||||||
|
utils.error(err.stack + '');
|
||||||
|
});
|
||||||
|
|
||||||
|
ws.on('tcp connect', function(port, host, nonce) {
|
||||||
|
if (socket)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (options.pow) {
|
||||||
|
if (!utils.isNumber(port)
|
||||||
|
|| typeof host !== 'string'
|
||||||
|
|| !utils.isNumber(nonce)) {
|
||||||
|
utils.error('Client did not solve proof of work.');
|
||||||
|
ws.emit('tcp close');
|
||||||
|
ws.disconnect();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
pow = new BufferWriter();
|
||||||
|
pow.writeU32(nonce);
|
||||||
|
pow.writeBytes(snonce);
|
||||||
|
pow.writeU32(port);
|
||||||
|
pow.writeString(host, 'ascii');
|
||||||
|
pow = pow.render();
|
||||||
|
|
||||||
|
if (utils.cmp(utils.dsha256(pow), target) >= 0) {
|
||||||
|
utils.error('Client did not solve proof of work.');
|
||||||
|
ws.emit('tcp close');
|
||||||
|
ws.disconnect();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IP.isPrivate(host)) {
|
||||||
|
utils.error('Client is trying to connect to a private ip.');
|
||||||
|
ws.emit('tcp close');
|
||||||
|
ws.disconnect();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ports.indexOf(port) === -1) {
|
||||||
|
utils.error('Client is trying to connect to a non-bitcoin port.');
|
||||||
|
ws.emit('tcp close');
|
||||||
|
ws.disconnect();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
socket = net.connect(port, host);
|
||||||
|
utils.error('Connecting to %s:%d.', host, port);
|
||||||
|
} catch (e) {
|
||||||
|
utils.error('Closing %s:%d.', host, port);
|
||||||
|
ws.emit('tcp close');
|
||||||
|
ws.disconnect();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
socket.on('connect', function() {
|
||||||
|
ws.emit('tcp connect');
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.on('data', function(data) {
|
||||||
|
ws.emit('tcp data', data.toString('hex'));
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.on('error', function(err) {
|
||||||
|
ws.emit('tcp error', err.message);
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.on('close', function() {
|
||||||
|
utils.error('Closing %s:%d.', host, port);
|
||||||
|
ws.emit('tcp close');
|
||||||
|
ws.disconnect();
|
||||||
|
});
|
||||||
|
|
||||||
|
ws.on('tcp data', function(data) {
|
||||||
|
socket.write(new Buffer(data, 'hex'));
|
||||||
|
});
|
||||||
|
|
||||||
|
ws.on('disconnect', function() {
|
||||||
|
socket.destroy();
|
||||||
|
});
|
||||||
|
|
||||||
|
ws.on('close', function() {
|
||||||
|
socket.destroy();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return io;
|
||||||
|
};
|
||||||
Loading…
Reference in New Issue
Block a user