Automatic seq graph rendering, with debounce

This commit is contained in:
Ladd Hoffman 2022-11-14 10:17:43 -06:00
parent 41506fdcd5
commit a481710cde
12 changed files with 115 additions and 37 deletions

View File

@ -47,7 +47,7 @@ export class Box {
}
setId(id) {
this.el.id = id || this.name;
this.el.id = (id || this.name).replace(/ /g, "");
return this;
}

View File

@ -37,7 +37,10 @@ class Reputation {
const tokensLocked = Array.from(this.locks.values())
.filter(({dateCreated, duration}) => now - dateCreated < duration)
.reduce((acc, cur) => acc += cur.tokens, 0);
return Math.max(this.tokens - tokensLocked, 0);
if (tokensLocked > this.tokens) {
throw new Error("Assertion failure. tokensLocked > tokens");
}
return this.tokens - tokensLocked;
}
}

View File

@ -1,6 +1,7 @@
import { Actor } from './actor.js';
import { Action } from './action.js';
// import mermaid from 'https://unpkg.com/mermaid@9.2.2/dist/mermaid.esm.mjs';
import { debounce } from '../util.js';
import mermaid from 'https://unpkg.com/mermaid@9.2.2/dist/mermaid.esm.mjs';
export class Scene {
constructor(name, rootBox) {
@ -10,11 +11,14 @@ export class Scene {
this.box.addBox('Spacer').setInnerHTML('&nbsp;');
this.displayValuesBox = this.box.addBox(`${this.name}-values`);
this.box.addBox('Spacer').setInnerHTML('&nbsp;');
this.logBox = this.box.addBox(`${this.name}-log`);
this.actors = new Set();
// this.seqDiagramContainer = this.box.addBox(`${this.name}-seq-diagram-container`);
// this.seqDiagramBox = this.box.addBox(`${this.name}-seq-diagram`);
// mermaid.mermaidAPI.initialize({ startOnLoad: false });
this.seqDiagramContainer = this.box.addBox(`${this.name}-seq-diagram-container`);
this.seqDiagramElement = this.box.addBox(`${this.name}-seq-diagram-element`).setId();
this.seqDiagramBox = this.box.addBox(`${this.name}-seq-diagram`);
this.box.addBox('Spacer').setInnerHTML('&nbsp;');
this.logBox = this.box.addBox(`${this.name}-log`);
mermaid.mermaidAPI.initialize({ startOnLoad: false });
this.dateLastRender = null;
}
addActor(name) {
@ -38,6 +42,7 @@ export class Scene {
log(msg) {
this.logBox.addBox().setInnerHTML(msg).monospace();
this.renderSequenceDiagram();
return this;
}
@ -50,16 +55,24 @@ export class Scene {
}
}
// async renderSequenceDiagram() {
// await mermaid.mermaidAPI.render(
// `${this.name}-seq-diagram-element`,
// this.logBox.getInnerText(),
// this.insertSvg,
// this.seqDiagramContainer.el
// );
// }
async renderSequenceDiagram() {
const render = async () => {
const dateStart = new Date();
const graph = await mermaid.mermaidAPI.render(
this.seqDiagramElement.getId(),
this.logBox.getInnerText(),
);
this.seqDiagramBox.setInnerHTML(graph);
if (!this.dateLastRender) {
this.dateLastRender = new Date();
}
console.log(`renderSequenceDiagram time: ${new Date() - dateStart} ms, time since last render: ${dateStart - this.dateLastRender}`);
this.dateLastRender = dateStart;
};
debounce(render, 100);
}
// insertSvg (svgCode) {
// this.seqDiagramBox.setInnerHTML(svgCode);
// };
insertSvg (svgCode) {
this.seqDiagramElement.setInnerHTML(svgCode);
};
}

View File

@ -35,6 +35,7 @@ export class ValidationPool extends Actor {
against: fee * params.mintingRatio * (1 - params.stakeForWin),
author: fee * params.mintingRatio * params.stakeForAuthor,
}
// TODO: Consider availability stakes
}
castVote(signingPublicKey, position, stake, lockingTime) {
@ -126,7 +127,7 @@ export class ValidationPool extends Actor {
distributeTokens(result) {
// Reward the author
// TODO: Penalty to the author if the vote does not pass?
// TODO: If the vote fails, distribute tokens.author among winning voters
this.bench.reputations.addTokens(this.authorId, this.tokens.author);
// Reward the vote winners, in proportion to their stakes
const tokensForWinners = result ? this.tokens.for : this.tokens.against;

View File

@ -0,0 +1,9 @@
<!DOCTYPE html>
<head>
<title>Forum Graph</title>
<script type="module" src="./debounce-test.js" defer></script>
<link type="text/css" rel="stylesheet" href="./index.css" />
</head>
<body>
<div id="debounce-test"></div>
</body>

View File

@ -0,0 +1,15 @@
import { Box } from './classes/box.js';
import { Scene } from './classes/scene.js';
import { debounce, delay } from "./util.js";
const rootElement = document.getElementById('debounce-test');
const rootBox = new Box('rootBox', rootElement).flex();
const scene = window.scene = new Scene('Debounce test', rootBox);
const log = () => scene.log("event");
debounce(log, 500);
debounce(log, 500);
await delay(500);
debounce(log, 500);
debounce(log, 500);

View File

@ -4,10 +4,7 @@ import { Post } from './classes/post.js';
import { Member } from './classes/member.js';
import { ForumNode } from './classes/forum-node.js';
import { ForumNetwork } from './classes/forum-network.js';
const delay = async (ms) => {
await new Promise((resolve) => setTimeout(resolve, ms));
};
import { delay } from './util.js';
const rootElement = document.getElementById('forum-network');
const rootBox = new Box('rootBox', rootElement).flex();
@ -23,10 +20,12 @@ window.forumNode1 = await new ForumNode('node1', window.scene).initialize(window
window.forumNode2 = await new ForumNode('node2', window.scene).initialize(window.forumNetwork);
window.forumNode3 = await new ForumNode('node3', window.scene).initialize(window.forumNetwork);
setInterval(async () => {
const processInterval = setInterval(async () => {
await window.forumNode1.processNextMessage();
await window.forumNode2.processNextMessage();
await window.forumNode3.processNextMessage();
await window.scene.renderSequenceDiagram();
}, 100);
// const blockchain = new Blockchain();
@ -38,3 +37,6 @@ await delay(1000);
await window.author1.submitPost(window.forumNode1, window.post1, 50);
await delay(1000);
await window.author2.submitPost(window.forumNode2, window.post2, 100);
await delay(1000);
clearInterval(processInterval);

View File

@ -22,3 +22,6 @@
font-family: monospace;
font-size: 11pt;
}
svg {
width: 800px;
}

View File

@ -10,5 +10,6 @@
<li><a href="./graph-test.html">Graph test</a></li>
<li><a href="./validation-pool-test.html">Validation Pool test</a></li>
<li><a href="./mermaid-test.html">Mermaid test</a></li>
<li><a href="./debounce-test.html">Debounce test</a></li>
</ul>
</body>

View File

@ -2,7 +2,25 @@
<head>
<title>Forum Network</title>
<link type="text/css" rel="stylesheet" href="./index.css" />
<script type="module" defer>
// import mermaid from './mermaid.mjs';
import mermaid from 'https://unpkg.com/mermaid@9.2.2/dist/mermaid.esm.mjs';
mermaid.mermaidAPI.initialize({ startOnLoad: false });
// Example of using the API var
const element = document.querySelector('#graphDiv');
const insertSvg = function (svgCode, bindFunctions) {
element.innerHTML = svgCode;
};
const graphDefinition = 'graph TB\na-->b';
const graph = await mermaid.mermaidAPI.render('graphDiv', graphDefinition, insertSvg);
console.log("executed...");
console.log(graph);
const div = document.createElement('div');
div.innerHTML = graph;
document.body.append(div);
</script>
</head>
<body>
<div id="graphDiv"></div>
</body>

View File

@ -0,0 +1,15 @@
const timeouts = new Map();
export const debounce = (fn, delay) => {
const key = fn.toString();
if (!timeouts.get(key)) {
timeouts.set(key, setTimeout(async () => {
timeouts.delete(key);
await fn();
}, delay));
}
};
export const delay = async (ms) => {
await new Promise((resolve) => setTimeout(resolve, ms));
};

View File

@ -2,28 +2,24 @@ import { Box } from './classes/box.js';
import { Scene } from './classes/scene.js';
import { Member } from './classes/member.js';
import { Bench } from './classes/bench.js';
const delay = async (ms) => {
await new Promise((resolve) => setTimeout(resolve, ms));
};
import { delay } from './util.js';
const rootElement = document.getElementById('validation-pool');
const rootBox = new Box('rootBox', rootElement).flex();
const scene = window.scene = new Scene('Validation Pool test', rootBox).log('sequenceDiagram');
const bench = window.bench = new Bench("Bench", scene);
const member1 = window.member1 = await new Member("Member1", scene).initialize();
const member2 = window.member2 = await new Member("Member2", scene).initialize();
const bench = window.bench = new Bench("Bench", scene);
const updateDisplayValues = () => {
const updateDisplayValues = async () => {
member1.setValue('rep', bench.reputations.getTokens(member1.reputationPublicKey));
member2.setValue('rep', bench.reputations.getTokens(member2.reputationPublicKey));
bench.setValue('total rep', bench.getTotalReputation());
bench.setValue('available rep', bench.getTotalAvailableReputation());
bench.setValue('active rep', bench.getTotalActiveReputation());
bench.setValue('active available rep', bench.getTotalActiveAvailableReputation());
await scene.renderSequenceDiagram();
};
updateDisplayValues();
@ -34,7 +30,7 @@ await delay(1000);
const pool = member1.initiateValidationPool(bench, {fee: 1, duration: 1000, tokenLossRatio: 1});
await member1.castVote(pool, true, 0, 0);
await member1.revealIdentity(pool); // Vote passes
updateDisplayValues();
await updateDisplayValues();
await delay(1000);
}
@ -43,7 +39,7 @@ try {
const pool = member2.initiateValidationPool(bench, {fee: 1, duration: 1000, tokenLossRatio: 1});
await member2.castVote(pool, true, 0, 0);
await member2.revealIdentity(pool); // Quorum not met!
updateDisplayValues();
await updateDisplayValues();
await delay(1000);
} catch(e) {
if (e.message.match(/Quorum is not met/)) {
@ -59,10 +55,12 @@ try {
const pool = member2.initiateValidationPool(bench, {fee: 1, duration: 1000, tokenLossRatio: 1});
await member1.castVote(pool, true, 0.5, 1);
await member1.revealIdentity(pool); // Vote passes
updateDisplayValues();
await updateDisplayValues();
await delay(1000);
}
updateDisplayValues();
await updateDisplayValues();
scene.deactivateAll();
await updateDisplayValues();