Skip to content

Instantly share code, notes, and snippets.

@peerreynders
Created October 22, 2018 14:21
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save peerreynders/474145762df0708fe78bf39b548fab00 to your computer and use it in GitHub Desktop.
Save peerreynders/474145762df0708fe78bf39b548fab00 to your computer and use it in GitHub Desktop.
gen-browser Pinger/Ponger refactor - no async await
// file: src/AddressInput.js
import {getPropPathValue} from './Misc';
// --- DOM hook
const _addressInput = document.querySelector('main input[type="text"]');
function selectAddress(event) {
const name = getPropPathValue(event, ['target','constructor','name'], null);
if(name == 'HTMLInputElement') {
event.target.select();
}
event.preventDefault();
}
export function addSelectListener() {
_addressInput.addEventListener('click', selectAddress, true);
}
export function addPingListener(listener) {
const button = document.querySelector('form > button');
button.addEventListener('click', listener, true);
}
export function setAddress(text) {
_addressInput.value = text;
}
export function getAddress(defaultValue) {
const value = _addressInput.value;
return !value ? defaultValue : value;
}
// file: gen_browser/build.js replaces gen_browser/rollup.config.js
// to run: $ node build.js
const rollup = require('rollup');
const resolve = require('rollup-plugin-node-resolve');
const build = ({input, output}) => {
const write = bundle => {
bundle.write(output);
};
rollup.rollup(input).then(write);
};
const defaultPlugins = [
resolve(),
];
const pinger = {
input: {
input: 'src/Pinger.js',
plugins: defaultPlugins,
},
output: {
format: 'umd',
file: 'Pinger.js',
dir: 'dist',
name: 'Pinger',
}
};
const ponger = {
input: {
input: 'src/Ponger.js',
plugins: defaultPlugins,
},
output: {
format: 'umd',
file: 'Ponger.js',
dir: 'dist',
name: 'Ponger',
}
};
build(pinger);
build(ponger);
// file: src/Misc.js
export function now() {
return new Date().toLocaleTimeString();
}
export function toTextFrom(from) {
const [_, signature] = from.split('--');
return signature.substring(0, 20) + '...';
};
export function getPropPathValue(obj, path, defaultValue) {
let val = obj;
for(let name of path) {
if (!val) {
val = defaultValue;
break;
}
val = val[name];
}
return val;
}
// file: src/MsgTable.js
// --- DOM hooks
const _msgRowTemplate = document.querySelector('#template-msg-row');
const _msgBodyElem = document.querySelector('main tbody:nth-of-type(1)');
function makeMsgRow(msg, time, from){
let fragment = document.importNode(_msgRowTemplate.content, true);
let row = fragment.querySelector('tr');
let detail = row.children;
detail[0].textContent = msg;
detail[1].textContent = time;
detail[2].textContent = from;
return row;
};
export function prependMsgRow(msg, time, from) {
_msgBodyElem.insertBefore(makeMsgRow(msg, time, from), _msgBodyElem.firstChild);
};
{
"name": "gen-browser",
"scripts": {
"build": "node build.js",
"test": "jest",
"pretest": "npm run build"
},
"devDependencies": {
"eventsourcemock": "^2.0.0",
"jest": "^23.6.0",
"rollup": "^0.66.6",
"rollup-plugin-node-resolve": "^3.4.0"
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Pinger</title>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,300italic,700,700italic">
<link rel="stylesheet" href="https://cdn.rawgit.com/necolas/normalize.css/master/normalize.css">
<link rel="stylesheet" href="https://cdn.rawgit.com/milligram/milligram/master/dist/milligram.min.css">
</head>
<body>
<main style="max-width:420px;margin-left:auto;margin-right:auto;">
<h1>Pinger</h1>
<h2>GenBrowser</h2>
<p>Loading ...</p>
<form action="">
<label>Enter address<br>
<input type="text">
</label>
<button type="button">Send Ping</button>
</form>
<hr>
<table>
<thead>
<tr>
<th>Message</th>
<th>Received at</th>
<th>From address</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</main>
<template id="template-msg-row">
<tr>
<td></td>
<td></td>
<td></td>
</tr>
</template>
<script type="text/javascript" src="../dist/Pinger.js"></script>
</body>
</html>
// src/Pinger.js
import {start} from './GenBrowser'; // formerly client.js, now GenBrowser.js
import {setStatus} from './StatusDisplay';
import {addPingListener, addSelectListener, getAddress, setAddress} from './AddressInput';
import {now, toTextFrom} from './Misc';
import {prependMsgRow} from './MsgTable';
addSelectListener();
setStatus('Connecting ...');
start('http://localhost:8080').then(setupClient).catch(onError);
// ===
// --- Core logic (sendPing) - send ping and update table when receiving pong message
function makeSendPing({address, config, send, mailbox}) {
const sendPing = event => {
let pongerAddress = getAddress(config.logger);
send(pongerAddress, {type: 'ping', from: address});
mailbox.receive({timeout: 5000}).then(onReply).catch(onError);
event.preventDefault();
};
return sendPing;
}
function onReply({type, from}) {
console.log("Pong received");
if (type == 'pong') {
prependMsgRow(type, now(), toTextFrom(from));
}
}
function setupClient(client) {
const pingListener = makeSendPing(client);
addPingListener(pingListener);
console.log(client);
setStatus('Ready');
}
function onError(error) {
setStatus(error.toString());
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Ponger</title>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,300italic,700,700italic">
<link rel="stylesheet" href="https://cdn.rawgit.com/necolas/normalize.css/master/normalize.css">
<link rel="stylesheet" href="https://cdn.rawgit.com/milligram/milligram/master/dist/milligram.min.css">
</head>
<body>
<main style="max-width:420px;margin-left:auto;margin-right:auto;">
<h1>Ponger</h1>
<h2>GenBrowser</h2>
<p>Loading ...</p>
<form action="">
<label>This address<br>
<input type="text"></label>
</form>
<hr>
<table>
<thead>
<tr>
<th>Message</th>
<th>Received at</th>
<th>From address</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</main>
<template id="template-msg-row">
<tr>
<td></td>
<td></td>
<td></td>
</tr>
</template>
<script type="text/javascript" src="../dist/Ponger.js"></script>
</body>
</html>
// file: src/Ponger.js
import {start} from './GenBrowser'; // formerly client.js, now GenBrowser.js
import {setStatus} from './StatusDisplay';
import {addSelectListener, setAddress} from './AddressInput';
import {now, toTextFrom} from './Misc';
import {prependMsgRow} from './MsgTable';
addSelectListener();
setStatus('Connecting ...');
start('http://localhost:8080').then(setupClient).catch(onError);
// ===
// --- Core logic (messageHandler) - update table when receiving ping message
function makeMessageHandler(client) {
const handler = message => {
console.log('received message:', message);
const {type, from} = message;
if (type == 'ping') {
prependMsgRow(type, now(), toTextFrom(from));
client.send(from, {type: 'pong', from: client.address});
}
};
return handler;
}
// -- client setup
function setupClient(client) {
console.log(client.address);
setStatus('Ready');
setAddress(client.address);
client.mailbox.setHandler(makeMessageHandler(client));
}
function onError(error) {
setStatus(error.toString());
};
// file: src/StatusDisplay.js
// --- DOM hook
const _statusElem = document.querySelector('main > p:nth-of-type(1)');
export function setStatus(text) {
_statusElem.textContent = text;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment