Skip to content

Commit

Permalink
samples: Add wasm buyer example
Browse files Browse the repository at this point in the history
This adds an example implementation of a split ticket buyer using the
wasm-compiled module.

This example is implemented using electron as runtime environment,
compatible with a decrediton-like architecture.
  • Loading branch information
matheusd committed Jan 9, 2019
1 parent ec0a275 commit 958bbc1
Show file tree
Hide file tree
Showing 13 changed files with 45,589 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
vendor/
data/
dist/
samples/buyer-wasm/node_modules/
samples/buyer-wasm/config.json
*.wasm
27 changes: 27 additions & 0 deletions samples/buyer-wasm/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Split Ticket Wasm Buyer Sample

This is a demo/example for how to run the split ticket buyer wasm module in an electron app.

It requires a recent version of node installed. It currently (as of 2019-01-09) requires a development version of go installed and on your $PATH.

## Compiling

```
cd samples/buyer-wasm
yarn
yarn rebuild-electron-modules
yarn rebuild-module
cp config.sample.json config.json
```

Edit `config.json` as appropriate, so that you can connect to your running wallet and a matcher service.

## Running

```
yarn start
```

After the wasm module is compiled (it takes about 30 seconds), you can click the "run" button and perform a split ticket session.

If everything goes according to plan, you'll join the given split session.
16 changes: 16 additions & 0 deletions samples/buyer-wasm/config.sample.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"walletHost": "127.0.0.1",
"walletPort": 19121,
"walletCertFile": "/home/user/.config/decrediton/wallets/testnet/default-wallet/rpc.cert",
"voteAddress": "Tc...",
"poolAddress": "Ts...",
"maxAmount": 40,
"passphrase": "123",
"matcherHost": "127.0.0.1:8475",
"matcherCertFile": "/home/user/.dcrstmd/rpc.cert",
"testnet": true,
"poolFeeRate": 7.5,
"maxTime": 30,
"maxWaitTime": 0,
"sourceAccount": 0
}
56 changes: 56 additions & 0 deletions samples/buyer-wasm/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<html>

<head>
<meta charset="utf-8">
<title>Split Ticket Buyer Wasm Demo</title>
</head>

<body>
<script src="wasm_exec.js"></script>
<script src="splitticketbuyer.js"></script>
<script>
var splitTicketBuyerModule, inst;

if (!WebAssembly.compileStreaming) { // polyfill
WebAssembly.compileStreaming = async (resp, importObject) => {
const source = await (await resp).arrayBuffer();
return await WebAssembly.compile(source, importObject);
};
}

fetch("splitticketbuyer.wasm")
.then(response => response.arrayBuffer())
.then(bytes => {
console.log("Starting wasm compilation");
return WebAssembly.compile(bytes);
})
.then(mod => {
console.log("Compiled splitticketbuyer.wasm")
splitTicketBuyerModule = mod;
document.getElementById("runButton").disabled = false;
});

async function run() {
document.getElementById("runButton").disabled = true;
go = new Go();
inst = await WebAssembly.instantiate(splitTicketBuyerModule, go.importObject); // reset instance
setTimeout(() => buyerLoop(), 100);
await go.run(inst);
console.log("Go finalized and returned from run(). Resolving promise.");
document.getElementById("runButton").disabled = false;
}

async function buyerLoop() {

const electron = require("electron");
const config = electron.ipcRenderer.sendSync("get-config");
const buyer = new SplitTicketBuyer();
await buyer.setup(config);
buyer.run();
}
</script>

<button onClick="run();" id="runButton" disabled>Run</button><br><br>
</body>

</html>
27 changes: 27 additions & 0 deletions samples/buyer-wasm/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
const { app, BrowserWindow, ipcMain } = require('electron');
const fs = require("fs");
const dns = require("dns");

function createWindow () {
win = new BrowserWindow({width: 800, height: 600});
win.webContents.openDevTools();
win.loadFile('index.html');
}

console.log(`Chrome v${process.versions.chrome}`);
app.on('ready', createWindow);

ipcMain.on("srv-query", (event, host) => {
dns.resolveSrv(host, (err, addrs) => {
event.sender.send("srv-query-result", err, addrs);
})
});

ipcMain.on("get-config", event => {
const buyerConfig = require("./config.json");
buyerConfig.walletCert = fs.readFileSync(buyerConfig.walletCertFile);
if (fs.existsSync(buyerConfig.matcherCertFile)) {
buyerConfig.matcherCert = fs.readFileSync(buyerConfig.matcherCertFile);
}
event.returnValue = buyerConfig;
});
242 changes: 242 additions & 0 deletions samples/buyer-wasm/matcherrpc/api_grpc_pb.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,242 @@
// GENERATED CODE -- DO NOT EDIT!

'use strict';
var grpc = require('grpc');
var api_pb = require('./api_pb.js');

function serialize_dcrticketmatcher_BuyerErrorRequest(arg) {
if (!(arg instanceof api_pb.BuyerErrorRequest)) {
throw new Error('Expected argument of type dcrticketmatcher.BuyerErrorRequest');
}
return new Buffer(arg.serializeBinary());
}

function deserialize_dcrticketmatcher_BuyerErrorRequest(buffer_arg) {
return api_pb.BuyerErrorRequest.deserializeBinary(new Uint8Array(buffer_arg));
}

function serialize_dcrticketmatcher_BuyerErrorResponse(arg) {
if (!(arg instanceof api_pb.BuyerErrorResponse)) {
throw new Error('Expected argument of type dcrticketmatcher.BuyerErrorResponse');
}
return new Buffer(arg.serializeBinary());
}

function deserialize_dcrticketmatcher_BuyerErrorResponse(buffer_arg) {
return api_pb.BuyerErrorResponse.deserializeBinary(new Uint8Array(buffer_arg));
}

function serialize_dcrticketmatcher_FindMatchesRequest(arg) {
if (!(arg instanceof api_pb.FindMatchesRequest)) {
throw new Error('Expected argument of type dcrticketmatcher.FindMatchesRequest');
}
return new Buffer(arg.serializeBinary());
}

function deserialize_dcrticketmatcher_FindMatchesRequest(buffer_arg) {
return api_pb.FindMatchesRequest.deserializeBinary(new Uint8Array(buffer_arg));
}

function serialize_dcrticketmatcher_FindMatchesResponse(arg) {
if (!(arg instanceof api_pb.FindMatchesResponse)) {
throw new Error('Expected argument of type dcrticketmatcher.FindMatchesResponse');
}
return new Buffer(arg.serializeBinary());
}

function deserialize_dcrticketmatcher_FindMatchesResponse(buffer_arg) {
return api_pb.FindMatchesResponse.deserializeBinary(new Uint8Array(buffer_arg));
}

function serialize_dcrticketmatcher_FundSplitTxRequest(arg) {
if (!(arg instanceof api_pb.FundSplitTxRequest)) {
throw new Error('Expected argument of type dcrticketmatcher.FundSplitTxRequest');
}
return new Buffer(arg.serializeBinary());
}

function deserialize_dcrticketmatcher_FundSplitTxRequest(buffer_arg) {
return api_pb.FundSplitTxRequest.deserializeBinary(new Uint8Array(buffer_arg));
}

function serialize_dcrticketmatcher_FundSplitTxResponse(arg) {
if (!(arg instanceof api_pb.FundSplitTxResponse)) {
throw new Error('Expected argument of type dcrticketmatcher.FundSplitTxResponse');
}
return new Buffer(arg.serializeBinary());
}

function deserialize_dcrticketmatcher_FundSplitTxResponse(buffer_arg) {
return api_pb.FundSplitTxResponse.deserializeBinary(new Uint8Array(buffer_arg));
}

function serialize_dcrticketmatcher_FundTicketRequest(arg) {
if (!(arg instanceof api_pb.FundTicketRequest)) {
throw new Error('Expected argument of type dcrticketmatcher.FundTicketRequest');
}
return new Buffer(arg.serializeBinary());
}

function deserialize_dcrticketmatcher_FundTicketRequest(buffer_arg) {
return api_pb.FundTicketRequest.deserializeBinary(new Uint8Array(buffer_arg));
}

function serialize_dcrticketmatcher_FundTicketResponse(arg) {
if (!(arg instanceof api_pb.FundTicketResponse)) {
throw new Error('Expected argument of type dcrticketmatcher.FundTicketResponse');
}
return new Buffer(arg.serializeBinary());
}

function deserialize_dcrticketmatcher_FundTicketResponse(buffer_arg) {
return api_pb.FundTicketResponse.deserializeBinary(new Uint8Array(buffer_arg));
}

function serialize_dcrticketmatcher_GenerateTicketRequest(arg) {
if (!(arg instanceof api_pb.GenerateTicketRequest)) {
throw new Error('Expected argument of type dcrticketmatcher.GenerateTicketRequest');
}
return new Buffer(arg.serializeBinary());
}

function deserialize_dcrticketmatcher_GenerateTicketRequest(buffer_arg) {
return api_pb.GenerateTicketRequest.deserializeBinary(new Uint8Array(buffer_arg));
}

function serialize_dcrticketmatcher_GenerateTicketResponse(arg) {
if (!(arg instanceof api_pb.GenerateTicketResponse)) {
throw new Error('Expected argument of type dcrticketmatcher.GenerateTicketResponse');
}
return new Buffer(arg.serializeBinary());
}

function deserialize_dcrticketmatcher_GenerateTicketResponse(buffer_arg) {
return api_pb.GenerateTicketResponse.deserializeBinary(new Uint8Array(buffer_arg));
}

function serialize_dcrticketmatcher_StatusRequest(arg) {
if (!(arg instanceof api_pb.StatusRequest)) {
throw new Error('Expected argument of type dcrticketmatcher.StatusRequest');
}
return new Buffer(arg.serializeBinary());
}

function deserialize_dcrticketmatcher_StatusRequest(buffer_arg) {
return api_pb.StatusRequest.deserializeBinary(new Uint8Array(buffer_arg));
}

function serialize_dcrticketmatcher_StatusResponse(arg) {
if (!(arg instanceof api_pb.StatusResponse)) {
throw new Error('Expected argument of type dcrticketmatcher.StatusResponse');
}
return new Buffer(arg.serializeBinary());
}

function deserialize_dcrticketmatcher_StatusResponse(buffer_arg) {
return api_pb.StatusResponse.deserializeBinary(new Uint8Array(buffer_arg));
}

function serialize_dcrticketmatcher_WatchWaitingListRequest(arg) {
if (!(arg instanceof api_pb.WatchWaitingListRequest)) {
throw new Error('Expected argument of type dcrticketmatcher.WatchWaitingListRequest');
}
return new Buffer(arg.serializeBinary());
}

function deserialize_dcrticketmatcher_WatchWaitingListRequest(buffer_arg) {
return api_pb.WatchWaitingListRequest.deserializeBinary(new Uint8Array(buffer_arg));
}

function serialize_dcrticketmatcher_WatchWaitingListResponse(arg) {
if (!(arg instanceof api_pb.WatchWaitingListResponse)) {
throw new Error('Expected argument of type dcrticketmatcher.WatchWaitingListResponse');
}
return new Buffer(arg.serializeBinary());
}

function deserialize_dcrticketmatcher_WatchWaitingListResponse(buffer_arg) {
return api_pb.WatchWaitingListResponse.deserializeBinary(new Uint8Array(buffer_arg));
}


var SplitTicketMatcherServiceService = exports.SplitTicketMatcherServiceService = {
watchWaitingList: {
path: '/dcrticketmatcher.SplitTicketMatcherService/WatchWaitingList',
requestStream: false,
responseStream: true,
requestType: api_pb.WatchWaitingListRequest,
responseType: api_pb.WatchWaitingListResponse,
requestSerialize: serialize_dcrticketmatcher_WatchWaitingListRequest,
requestDeserialize: deserialize_dcrticketmatcher_WatchWaitingListRequest,
responseSerialize: serialize_dcrticketmatcher_WatchWaitingListResponse,
responseDeserialize: deserialize_dcrticketmatcher_WatchWaitingListResponse,
},
findMatches: {
path: '/dcrticketmatcher.SplitTicketMatcherService/FindMatches',
requestStream: false,
responseStream: false,
requestType: api_pb.FindMatchesRequest,
responseType: api_pb.FindMatchesResponse,
requestSerialize: serialize_dcrticketmatcher_FindMatchesRequest,
requestDeserialize: deserialize_dcrticketmatcher_FindMatchesRequest,
responseSerialize: serialize_dcrticketmatcher_FindMatchesResponse,
responseDeserialize: deserialize_dcrticketmatcher_FindMatchesResponse,
},
generateTicket: {
path: '/dcrticketmatcher.SplitTicketMatcherService/GenerateTicket',
requestStream: false,
responseStream: false,
requestType: api_pb.GenerateTicketRequest,
responseType: api_pb.GenerateTicketResponse,
requestSerialize: serialize_dcrticketmatcher_GenerateTicketRequest,
requestDeserialize: deserialize_dcrticketmatcher_GenerateTicketRequest,
responseSerialize: serialize_dcrticketmatcher_GenerateTicketResponse,
responseDeserialize: deserialize_dcrticketmatcher_GenerateTicketResponse,
},
fundTicket: {
path: '/dcrticketmatcher.SplitTicketMatcherService/FundTicket',
requestStream: false,
responseStream: false,
requestType: api_pb.FundTicketRequest,
responseType: api_pb.FundTicketResponse,
requestSerialize: serialize_dcrticketmatcher_FundTicketRequest,
requestDeserialize: deserialize_dcrticketmatcher_FundTicketRequest,
responseSerialize: serialize_dcrticketmatcher_FundTicketResponse,
responseDeserialize: deserialize_dcrticketmatcher_FundTicketResponse,
},
fundSplitTx: {
path: '/dcrticketmatcher.SplitTicketMatcherService/FundSplitTx',
requestStream: false,
responseStream: false,
requestType: api_pb.FundSplitTxRequest,
responseType: api_pb.FundSplitTxResponse,
requestSerialize: serialize_dcrticketmatcher_FundSplitTxRequest,
requestDeserialize: deserialize_dcrticketmatcher_FundSplitTxRequest,
responseSerialize: serialize_dcrticketmatcher_FundSplitTxResponse,
responseDeserialize: deserialize_dcrticketmatcher_FundSplitTxResponse,
},
status: {
path: '/dcrticketmatcher.SplitTicketMatcherService/Status',
requestStream: false,
responseStream: false,
requestType: api_pb.StatusRequest,
responseType: api_pb.StatusResponse,
requestSerialize: serialize_dcrticketmatcher_StatusRequest,
requestDeserialize: deserialize_dcrticketmatcher_StatusRequest,
responseSerialize: serialize_dcrticketmatcher_StatusResponse,
responseDeserialize: deserialize_dcrticketmatcher_StatusResponse,
},
buyerError: {
path: '/dcrticketmatcher.SplitTicketMatcherService/BuyerError',
requestStream: false,
responseStream: false,
requestType: api_pb.BuyerErrorRequest,
responseType: api_pb.BuyerErrorResponse,
requestSerialize: serialize_dcrticketmatcher_BuyerErrorRequest,
requestDeserialize: deserialize_dcrticketmatcher_BuyerErrorRequest,
responseSerialize: serialize_dcrticketmatcher_BuyerErrorResponse,
responseDeserialize: deserialize_dcrticketmatcher_BuyerErrorResponse,
},
};

exports.SplitTicketMatcherServiceClient = grpc.makeGenericClientConstructor(SplitTicketMatcherServiceService);
Loading

0 comments on commit 958bbc1

Please sign in to comment.