add Waku and Form abstractions as well as scheme

This commit is contained in:
Sasha 2023-10-10 00:46:12 +02:00
parent c6e560af0b
commit b923d852a4
No known key found for this signature in database
10 changed files with 10297 additions and 0 deletions

View File

@ -0,0 +1,15 @@
App root content topic
/free-form/0.0.1/{content-topic-for-particular-use}/proto
1. User logs in with his wallet
1.1 User's preferences are fetched from following content topic
id = waller-or-uuid-or-pubkey
/fee-form/{version}/user:{id}/proto
2. User creates new form
2.1 Form topic is set up
id = uuid
/free-form/0/form:{id}/proto
2.2 User sets form scheme, version, signature
2.3 Scheme is sent
3.

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

View File

@ -0,0 +1,149 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta content="width=device-width, initial-scale=1.0" name="viewport" />
<title>Free Forms</title>
<link rel="apple-touch-icon" href="./favicon.png" />
<link rel="manifest" href="./manifest.json" />
<link rel="icon" href="./favicon.ico" />
<style>
* {
margin: 0;
padding: 0;
word-wrap: break-word;
box-sizing: border-box;
}
html,
body {
width: 100%;
height: 100%;
max-width: 100%;
max-height: 100%;
}
html {
font-size: 16px;
overflow: hidden;
}
body {
display: flex;
align-items: center;
padding: 10px;
flex-direction: column;
justify-content: center;
}
.container {
width: 100%;
min-width: 300px;
max-width: 800px;
height: 100%;
display: flex;
flex-direction: column;
align-content: space-between;
}
h2 {
text-align: center;
margin-bottom: 5px;
}
h3 {
margin-bottom: 10px;
}
h3:last-of-type {
margin-bottom: 20px;
}
h2 span,
h3 span {
font-weight: normal;
}
.progress {
color: #9ea13b;
}
.success {
color: #3ba183;
}
.error {
color: #c84740;
}
button.progress {
color: white;
background-color: #9ea13b;
}
button.success {
color: white;
background-color: #3ba183;
}
button.error {
color: white;
background-color: #c84740;
}
.pairingInfo {
display: flex;
flex-direction: column;
align-items: center;
}
.pairingInfo input {
display: block;
min-width: 250px;
width: 100%;
max-width: 600px;
font-size: 1.1rem;
line-height: 1.5rem;
padding: 5px;
margin-bottom: 10px;
}
.pairingInfo button {
flex-grow: 1;
cursor: pointer;
padding: 10px;
}
.pairingInfo button + button {
margin-left: 5px;
}
.chatArea {
}
.chatArea ul {
margin-bottom: 30px;
list-style: none;
}
.chatArea ul li + li {
margin-top: 5px;
}
.chatArea div {
display: flex;
flex-direction: column;
}
.chatArea div > * {
font-size: 1.1rem;
line-height: 1.5rem;
padding: 5px;
margin-bottom: 10px;
}
</style>
</head>
<body>
<script src="./index.js"></script>
</body>
</html>

View File

@ -0,0 +1,25 @@
import { createDecoder, createEncoder } from "@waku/sdk";
import * as utils from "@waku/utils/bytes";
import protobuf from "protobufjs";
import { Waku } from "./waku";
run()
.then(() => {
console.log("App is running...");
})
.catch((e) => {
console.error("Failed to run app: ", e);
});
async function run() {
const waku = await Waku.create();
window.waku = waku;
window.createForm = (id) => {
return waku.createForm({ id, scheme: "" });
};
window.fetchForm = (id) => {
return waku.fetchForm(id);
};
}

View File

@ -0,0 +1,19 @@
{
"name": "Waku Noise",
"description": "Example showing Waku noise capabilities.",
"icons": [
{
"src": "favicon.ico",
"sizes": "64x64 32x32 24x24 16x16",
"type": "image/x-icon"
},
{
"src": "favicon.png",
"type": "image/png",
"sizes": "192x192"
}
],
"display": "standalone",
"theme_color": "#ffffff",
"background_color": "#ffffff"
}

9907
examples/free-forms/tmp/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,23 @@
{
"name": "free-forms",
"private": true,
"version": "0.1.0",
"description": "",
"main": "index.js",
"scripts": {
"build": "webpack --config webpack.config.js",
"start": "webpack-dev-server"
},
"dependencies": {
"@waku/dns-discovery": "^0.0.17",
"@waku/sdk": "0.0.19",
"@waku/utils": "0.0.11",
"protobufjs": "^7.1.2"
},
"devDependencies": {
"copy-webpack-plugin": "^11.0.0",
"webpack": "^5.74.0",
"webpack-cli": "^4.10.0",
"webpack-dev-server": "^4.11.1"
}
}

View File

@ -0,0 +1,140 @@
import {
createDecoder,
createEncoder,
createLightNode,
waitForRemotePeer,
} from "@waku/sdk";
import { enrTree, wakuDnsDiscovery } from "@waku/dns-discovery";
import * as utils from "@waku/utils/bytes";
const VERSION = `0.0.00001`;
export class Waku {
constructor(node) {
this.node = node;
}
static async create() {
const node = await createLightNode({
defaultBootstrap: true,
libp2p: {
peerDiscovery: [
wakuDnsDiscovery([enrTree["PROD"]], {
lightPush: 1,
store: 1,
filter: 1,
}),
],
},
});
await waitForRemotePeer(node);
return new Waku(node);
}
fetchForm(id) {
return Form.fetch(this.node, id);
}
createForm({ id, scheme }) {
return Form.create(this.node, { id, scheme });
}
}
class Form {
constructor(id, waku) {
this.waku = waku;
this.history = [];
this.contentTopic = `/free-form/${VERSION}/definition:${id}/proto`;
this.decoder = createDecoder(this.contentTopic);
this.encoder = createEncoder({ contentTopic: this.contentTopic });
}
// Initiates new form
static async create(waku, { id, scheme }) {
const form = new Form(id, waku);
await form.createNew({ scheme });
return form;
}
// Fetches history of an existing form
static async fetch(waku, id) {
// TODO: throw on attempt to fetch non existing form
const form = new Form(id, waku);
await form.fetchState(id);
return form;
}
async createNew({ scheme }) {
// TODO: throw on attempt to create existing form
const command = {
type: "CREATE",
nonce: 0,
signature: "",
scheme,
};
const payload = this.toPayload(command);
await this.waku.lightPush.send(this.encoder, { payload });
this.history.push(command);
console.log("DEBUG", this.history);
}
async fetchState() {
let historyPromises = [];
for await (const promises of this.waku.store.queryGenerator([
this.decoder,
])) {
historyPromises = [...historyPromises, ...promises];
}
if (!historyPromises.length) {
console.error("DEBUG", "No form info fetched from store");
}
const commandPackets = await Promise.all(historyPromises);
const commands = commandPackets
.map(({ payload }) => {
try {
// validate scheme of command record
// check signature
const command = this.toCommand(payload);
return command;
} catch (e) {
console.error("DEBUG", "failed to parse update command.");
return;
}
})
.filter((c) => !!c);
this.history = [...this.history, ...commands];
console.log("DEBUG", this.history);
}
async patchState({ scheme }) {
if (!this.history.length) {
throw Error("no history");
}
const command = {
type: "PATCH",
nonce: this.history[this.history.length - 1].nonce + 1,
signature: "",
scheme,
};
const payload = this.toPayload(command);
await this.waku.lightPush.send(this.encoder, { payload });
this.history.push(command);
console.log("DEBUG patch", this.history);
}
toPayload(command) {
return utils.utf8ToBytes(JSON.stringify(command));
}
toCommand(payload) {
return JSON.parse(utils.bytesToUtf8(payload));
}
}

View File

@ -0,0 +1,19 @@
const CopyWebpackPlugin = require("copy-webpack-plugin");
const path = require("path");
module.exports = {
entry: "./index.js",
output: {
path: path.resolve(__dirname, "build"),
filename: "index.js",
},
experiments: {
asyncWebAssembly: true,
},
mode: "development",
plugins: [
new CopyWebpackPlugin({
patterns: ["index.html", "favicon.ico", "favicon.png", "manifest.json"],
}),
],
};