Initial implementation (#1)

This commit is contained in:
Pavel 2022-02-24 20:10:01 +03:00 committed by GitHub
parent 3a0e71f892
commit f31ce64c9c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 25281 additions and 0 deletions

26
.gitignore vendored Normal file
View File

@ -0,0 +1,26 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
bundle/
/dist/
/worker/dist/
# Dependency directories
node_modules/
jspm_packages/
.idea
# fluence
public/*.wasm
public/runnerScript.web.js
src/_aqua

8
.prettierrc.js Normal file
View File

@ -0,0 +1,8 @@
module.exports = {
semi: true,
trailingComma: 'all',
singleQuote: true,
printWidth: 120,
tabWidth: 4,
useTabs: false,
};

3
aqua/export.aqua Normal file
View File

@ -0,0 +1,3 @@
module Export
import createMyRoute, DiscoveryService, discoverAndNotify from "hello-registry.aqua"
export createMyRoute, DiscoveryService, discoverAndNotify

32
aqua/hello-registry.aqua Normal file
View File

@ -0,0 +1,32 @@
module HelloRegistry declares createMyRoute, DiscoveryService, discoverAndNotify
import "@fluencelabs/registry/routing.aqua"
import "@fluencelabs/aqua-lib/builtin.aqua"
alias PeerId: string
alias RouteId: string
data DiscoveredUser:
route: RouteId
userName: string
service DiscoveryService("discoveryService"):
notify_discovered(route_id: string, userName: string) -> []DiscoveredUser
func createMyRoute(label: string, userName: string) -> string:
relay: ?string
relay <<- HOST_PEER_ID
res <- createRouteAndRegister(label, userName, relay, nil)
DiscoveryService.notify_discovered(res, userName)
<- res
func discoverAndNotify(join_route_id: string, label: string, userName: string) -> string, []DiscoveredUser:
relay: ?string
relay <<- HOST_PEER_ID
our_route_id <- createRouteAndRegister(label, userName, relay, nil)
recs <- resolveRoute(join_route_id, 4)
try:
on recs[0].peer_id via recs[0].relay_id:
peers <- DiscoveryService.notify_discovered(our_route_id, userName)
<- our_route_id, peers

39
docs/_aqua/export.d.ts vendored Normal file
View File

@ -0,0 +1,39 @@
/**
*
* This file is auto-generated. Do not edit manually: changes may be erased.
* Generated by Aqua compiler: https://github.com/fluencelabs/aqua/.
* If you find any bugs, please write an issue on GitHub: https://github.com/fluencelabs/aqua/issues
* Aqua version: 0.6.1-279
*
*/
import { FluencePeer } from '@fluencelabs/fluence';
import { CallParams } from '@fluencelabs/fluence/dist/internal/compilerSupport/v2';
export interface DiscoveryServiceDef {
notify_discovered: (route_id: string, userName: string, callParams: CallParams<'route_id' | 'userName'>) => {
route: string;
userName: string;
}[] | Promise<{
route: string;
userName: string;
}[]>;
}
export declare function registerDiscoveryService(service: DiscoveryServiceDef): void;
export declare function registerDiscoveryService(serviceId: string, service: DiscoveryServiceDef): void;
export declare function registerDiscoveryService(peer: FluencePeer, service: DiscoveryServiceDef): void;
export declare function registerDiscoveryService(peer: FluencePeer, serviceId: string, service: DiscoveryServiceDef): void;
export declare function createMyRoute(label: string, userName: string, config?: {
ttl?: number;
}): Promise<string>;
export declare function createMyRoute(peer: FluencePeer, label: string, userName: string, config?: {
ttl?: number;
}): Promise<string>;
export declare type DiscoverAndNotifyResult = [string, {
route: string;
userName: string;
}[]];
export declare function discoverAndNotify(join_route_id: string, label: string, userName: string, config?: {
ttl?: number;
}): Promise<DiscoverAndNotifyResult>;
export declare function discoverAndNotify(peer: FluencePeer, join_route_id: string, label: string, userName: string, config?: {
ttl?: number;
}): Promise<DiscoverAndNotifyResult>;

BIN
docs/avm.wasm Executable file

Binary file not shown.

3
docs/avmRunner.d.ts vendored Normal file
View File

@ -0,0 +1,3 @@
import { AvmRunnerBackground } from '@fluencelabs/avm-runner-background';
declare const _default: AvmRunnerBackground;
export default _default;

1
docs/index.d.ts vendored Normal file
View File

@ -0,0 +1 @@
import './index.css';

1
docs/index.html Normal file
View File

@ -0,0 +1 @@
<!doctype html><html><head><meta charset="utf-8"/><title>Registry demo</title><script defer="defer" src="main.js"></script></head><body><div id="app" class="hidden"><h1></h1><div>your peer id: <span id="peerid"></span></div><div><label>your name</label> <input id="name" value="my name"/></div><div id="ref-route-id-wrapper" class="hidden">reference route id: <span id="ref-route-id">route id here</span></div><div><button id="go">go!</button></div><div id="join-link-wrapper" class="hidden"><div>Join link: <span id="join-link"></span></div><canvas id="qrcode"/></div><div id="user-list-wrapper" class="hidden"><h1>users in room</h1><ul id="user-list"></ul></div></div><div id="loading">loading</div></body></html>

68
docs/index.js Normal file
View File

@ -0,0 +1,68 @@
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __generator = (this && this.__generator) || function (thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (_) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
};
Object.defineProperty(exports, "__esModule", { value: true });
var avm_runner_background_1 = require("@fluencelabs/avm-runner-background");
var js_base64_1 = require("js-base64");
var vmPeerId = '12D3KooWNzutuy8WHXDKFqFsATvCR6j9cj2FijYbnd47geRKaQZS';
var b = function (s) {
return (0, js_base64_1.toUint8Array)(s);
};
var main = function () { return __awaiter(void 0, void 0, void 0, function () {
var runner, s, params, res;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
runner = new avm_runner_background_1.AvmRunnerBackground();
return [4 /*yield*/, runner.init('off')];
case 1:
_a.sent();
s = "(seq\n (par \n (call \"".concat(vmPeerId, "\" (\"local_service_id\" \"local_fn_name\") [] result_1)\n (call \"remote_peer_id\" (\"service_id\" \"fn_name\") [] g)\n )\n (call \"").concat(vmPeerId, "\" (\"local_service_id\" \"local_fn_name\") [] result_2)\n )");
params = { initPeerId: vmPeerId, currentPeerId: vmPeerId };
return [4 /*yield*/, runner.run(s, b(''), b(''), params, [])];
case 2:
res = _a.sent();
return [4 /*yield*/, runner.terminate()];
case 3:
_a.sent();
return [2 /*return*/, res];
}
});
}); };
// @ts-ignore
window.MAIN = main;
//# sourceMappingURL=index.js.map

1
docs/index.js.map Normal file
View File

@ -0,0 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,4EAAyE;AACzE,uCAAyC;AAEzC,IAAM,QAAQ,GAAG,sDAAsD,CAAC;AAExE,IAAM,CAAC,GAAG,UAAC,CAAS;IAChB,OAAO,IAAA,wBAAY,EAAC,CAAC,CAAC,CAAC;AAC3B,CAAC,CAAC;AAEF,IAAM,IAAI,GAAG;;;;;gBACH,MAAM,GAAG,IAAI,2CAAmB,EAAE,CAAC;gBACzC,qBAAM,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,EAAA;;gBAAxB,SAAwB,CAAC;gBAEnB,CAAC,GAAG,2DAEW,QAAQ,uLAGZ,QAAQ,wEACnB,CAAC;gBAGD,MAAM,GAAG,EAAE,UAAU,EAAE,QAAQ,EAAE,aAAa,EAAE,QAAQ,EAAE,CAAC;gBACrD,qBAAM,MAAM,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,MAAM,EAAE,EAAE,CAAC,EAAA;;gBAAnD,GAAG,GAAG,SAA6C;gBACzD,qBAAM,MAAM,CAAC,SAAS,EAAE,EAAA;;gBAAxB,SAAwB,CAAC;gBAEzB,sBAAO,GAAG,EAAC;;;KACd,CAAC;AAEF,aAAa;AACb,MAAM,CAAC,IAAI,GAAG,IAAI,CAAC"}

2
docs/main.js Normal file

File diff suppressed because one or more lines are too long

36
docs/main.js.LICENSE.txt Normal file
View File

@ -0,0 +1,36 @@
/*!
* Determine if an object is a Buffer
*
* @author Feross Aboukhadijeh <https://feross.org>
* @license MIT
*/
/*!
* The buffer module from node.js, for the browser.
*
* @author Feross Aboukhadijeh <https://feross.org>
* @license MIT
*/
/*! *****************************************************************************
Copyright (c) Microsoft Corporation.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
***************************************************************************** */
/*! ieee754. BSD-3-Clause License. Feross Aboukhadijeh <https://feross.org/opensource> */
/*! noble-ed25519 - MIT License (c) Paul Miller (paulmillr.com) */
/*! noble-secp256k1 - MIT License (c) Paul Miller (paulmillr.com) */
/*! safe-buffer. MIT License. Feross Aboukhadijeh <https://feross.org/opensource> */

BIN
docs/marine-js.wasm Normal file

Binary file not shown.

871
docs/runnerScript.web.js Normal file

File diff suppressed because one or more lines are too long

18
docs/util.d.ts vendored Normal file
View File

@ -0,0 +1,18 @@
import QRCode from 'qrcode';
export declare function addClass(id: string, className: string): void;
export declare function removeClass(id: string, className: string): void;
export declare function hide(id: string): void;
export declare function show(id: string): void;
export declare function onClick(id: string, handler: (el: MouseEvent) => void): void;
export declare function setText(id: string, text: string): void;
export declare function getValue(id: string): any;
export declare function createQrCode(targetId: string, link: string, opts: QRCode.QRCodeRenderersOptions): Promise<void>;
export declare function disable(id: string): void;
export declare function enable(id: string): void;
export declare function link(id: string): string;
interface DiscoveredUser {
route: string;
userName: string;
}
export declare function updateUserList(users: DiscoveredUser[]): Promise<void>;
export {};

33
index.html Normal file
View File

@ -0,0 +1,33 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Registry demo</title>
</head>
<body>
<div id="app" class="hidden">
<h1></h1>
<div>your peer id: <span id="peerid"></span></div>
<div>
<label>your name</label>
<input type="text" id="name" value="my name" />
</div>
<div id="ref-route-id-wrapper" class="hidden">
reference route id: <span id="ref-route-id">route id here</span>
</div>
<div>
<button id="go">go!</button>
</div>
<div id="join-link-wrapper" class="hidden">
<div>Join link: <span id="join-link"></span></div>
<canvas id="qrcode" />
</div>
<div id="user-list-wrapper" class="hidden">
<h1>users in room</h1>
<ul id="user-list"></ul>
</div>
</div>
<div id="loading">loading</div>
</body>
</html>

23808
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

47
package.json Normal file
View File

@ -0,0 +1,47 @@
{
"name": "registry-demo",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"postinstall": "copy-avm-public public",
"start": "webpack serve",
"prestart": "npm run compile-aqua",
"prebuild": "npm run compile-aqua",
"copy-public": "copy-avm public && copy-avm-runner public",
"build": "webpack --mode=production --node-env=production",
"build:dev": "webpack --mode=development",
"build:prod": "webpack --mode=production --node-env=production",
"watch": "webpack --watch",
"serve": "webpack serve",
"compile-aqua": "aqua -i ./aqua/ -o ./src/_aqua",
"watch-aqua": "chokidar \"**/*.aqua\" -c \"npm run compile-aqua\"",
"pages": "npm run build && cp -r ./dist/* ./docs && cp -r ./public/* ./docs"
},
"author": "",
"license": "ISC",
"dependencies": {
"@fluencelabs/avm-runner-background": "^0.2.0",
"@fluencelabs/fluence": "^0.20.1",
"@fluencelabs/fluence-network-environment": "^1.0.13",
"process": "^0.11.10",
"qrcode": "^1.5.0"
},
"devDependencies": {
"@fluencelabs/aqua": "^0.6.1-279",
"@fluencelabs/registry": "^0.3.1",
"@fluencelabs/aqua-lib": "^0.4.0",
"@fluencelabs/marine-js": "^0.1.0",
"@types/qrcode": "^1.4.2",
"@webpack-cli/generators": "^2.4.1",
"css-loader": "^6.5.1",
"html-webpack-plugin": "^5.5.0",
"style-loader": "^3.3.1",
"ts-loader": "^8.3.0",
"typescript": "^4.5.4",
"util": "^0.12.4",
"webpack": "^5.65.0",
"webpack-cli": "^4.9.1",
"webpack-dev-server": "^4.6.0"
}
}

10
src/avmRunner.ts Normal file
View File

@ -0,0 +1,10 @@
import { AvmRunnerBackground } from '@fluencelabs/avm-runner-background';
export default new AvmRunnerBackground({
method: 'fetch-from-url',
baseUrl: 'https://fluence.one/registry-demo/',
filePaths: {
avm: 'avm.wasm',
marine: 'marine-js.wasm',
},
});

3
src/index.css Normal file
View File

@ -0,0 +1,3 @@
.hidden {
display: none;
}

97
src/index.ts Normal file
View File

@ -0,0 +1,97 @@
import './index.css';
import { CallParams, Fluence } from '@fluencelabs/fluence';
import { krasnodar } from '@fluencelabs/fluence-network-environment';
import avmRunner from './avmRunner';
import { createQrCode, disable, getValue, hide, link, onClick, setText, show, updateUserList } from './util';
import { createMyRoute, discoverAndNotify, registerDiscoveryService, DiscoveryServiceDef } from './_aqua/export';
const label = 'registry-demo';
let selfDiscoveryRouteId: string;
let joinRouteId: string | null;
interface DiscoveredUser {
route: string;
userName: string;
}
class DiscoveryService implements DiscoveryServiceDef {
private _discoveredUsers: DiscoveredUser[] = [];
notify_discovered(route_id: string, userName: string): DiscoveredUser[] {
if (this._discoveredUsers.every((x) => x.route !== route_id)) {
this._discoveredUsers.push({
userName: userName,
route: route_id,
});
if (this.onUpdated) {
this.onUpdated(this._discoveredUsers);
}
}
return this._discoveredUsers;
}
setInitialList(userList: DiscoveredUser[]) {
this._discoveredUsers = userList;
if (this.onUpdated) {
this.onUpdated(this._discoveredUsers);
}
}
onUpdated: ((users: DiscoveredUser[]) => void) | null = null;
}
const discoveryServiceInstance = new DiscoveryService();
discoveryServiceInstance.onUpdated = updateUserList;
async function main() {
await Fluence.start({
avmRunner: avmRunner,
connectTo: krasnodar[4],
});
registerDiscoveryService(discoveryServiceInstance);
const selfPeerId = Fluence.getStatus().peerId!;
setText('peerid', selfPeerId);
const params = new URLSearchParams(window.location.search);
joinRouteId = params.get('join');
if (joinRouteId) {
setText('ref-route-id', joinRouteId);
show('ref-route-id-wrapper');
}
hide('loading');
show('app');
}
onClick('go', async () => {
disable('go');
const myName = getValue('name');
if (joinRouteId) {
const [routeId, knownUsers] = await discoverAndNotify(joinRouteId, label, myName);
discoveryServiceInstance.setInitialList(knownUsers);
selfDiscoveryRouteId = routeId;
} else {
selfDiscoveryRouteId = await createMyRoute(label, myName);
}
setText('join-link', link(selfDiscoveryRouteId));
await createQrCode('qrcode', link(selfDiscoveryRouteId), { width: 480 });
hide('ref-route-id-wrapper');
show('join-link-wrapper');
show('user-list-wrapper');
});
main();

81
src/util.ts Normal file
View File

@ -0,0 +1,81 @@
import QRCode from 'qrcode';
export function addClass(id: string, className: string) {
const el = document.getElementById(id)!;
el.classList.add(className);
}
export function removeClass(id: string, className: string) {
const el = document.getElementById(id)!;
el.classList.remove(className);
}
export function hide(id: string) {
addClass(id, 'hidden');
}
export function show(id: string) {
removeClass(id, 'hidden');
}
export function onClick(id: string, handler: (el: MouseEvent) => void) {
const el = document.getElementById(id)!;
el.onclick = handler;
}
export function setText(id: string, text: string) {
const el = document.getElementById(id)!;
el.textContent = text;
}
export function getValue(id: string) {
const el: any = document.getElementById(id)!;
return el.value;
}
export async function createQrCode(targetId: string, link: string, opts: QRCode.QRCodeRenderersOptions) {
const el = document.getElementById(targetId)!;
await QRCode.toCanvas(el, link, opts);
}
export function disable(id: string) {
const el = document.getElementById(id)!;
el.setAttribute('disabled', 'true');
}
export function enable(id: string) {
const el = document.getElementById(id)!;
el.removeAttribute('disabled');
}
export function link(id: string): string {
return 'https://fluence.one/registry-demo/?join=' + id;
}
interface DiscoveredUser {
route: string;
userName: string;
}
export async function updateUserList(users: DiscoveredUser[]) {
const promises = users.map(async (x) => {
const html =
// force new line
`<div class="user">
<div class="user__name">${x.userName}</div>
<canvas class="user__canvas" id="${x.route}" />
</div>`;
const li = document.createElement('li');
li.innerHTML = html;
return li;
});
const lis = await Promise.all(promises);
const ul = document.getElementById('user-list')!;
ul?.replaceChildren(...lis);
for (let x of users) {
createQrCode(x.route, link(x.route), {});
}
}

26
tsconfig.json Normal file
View File

@ -0,0 +1,26 @@
{
"compilerOptions": {
"lib": [
"es2015",
"dom"
],
"outDir": "./dist/",
"target": "es5",
"module": "commonjs",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"declaration": true,
"declarationMap": false,
"sourceMap": true,
"noImplicitAny": false
},
"exclude": [
"node_modules",
"dist"
],
"include": [
"src"
]
}

67
webpack.config.js Normal file
View File

@ -0,0 +1,67 @@
// Generated using webpack-cli https://github.com/webpack/webpack-cli
const webpack = require('webpack');
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
// const isProduction = process.env.NODE_ENV == 'production';
const isProduction = false;
const stylesHandler = 'style-loader';
const config = {
entry: './src/index.ts',
output: {
path: path.resolve(__dirname, 'dist'),
},
devServer: {
open: true,
host: 'localhost',
static: {
directory: path.join(__dirname, 'public'),
},
},
plugins: [
new HtmlWebpackPlugin({
template: 'index.html',
}),
new webpack.ProvidePlugin({
process: 'process/browser',
}),
// Add your plugins here
// Learn more about plugins from https://webpack.js.org/configuration/plugins/
],
module: {
rules: [
{
test: /\.(ts|tsx)$/i,
loader: 'ts-loader',
exclude: ['/node_modules/'],
},
{
test: /\.css$/i,
use: [stylesHandler, 'css-loader'],
},
{
test: /\.(eot|svg|ttf|woff|woff2|png|jpg|gif)$/i,
type: 'asset',
},
// Add your rules for custom modules here
// Learn more about loaders from https://webpack.js.org/loaders/
],
},
resolve: {
extensions: ['.ts', '.js', 'css'],
},
};
module.exports = () => {
if (isProduction) {
config.mode = 'production';
} else {
config.mode = 'development';
}
return config;
};