ui
This commit is contained in:
@@ -0,0 +1,59 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Test</title>
|
||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"
|
||||
crossorigin="anonymous">
|
||||
</head>
|
||||
<body>
|
||||
<script type="module" src="./bench.js"></script>
|
||||
<div class="container">
|
||||
<h1 id="title">WS NATS Browser Performance</h1>
|
||||
<label for="server">NATS Websocket Server</label>
|
||||
<input type="text" class="form-control" id="server" placeholder="server" autocomplete="off"
|
||||
value="localhost:9222"><br/>
|
||||
<label for="ws">Use ws:// (uncheck for wss://)</label>
|
||||
<input type="checkbox" class="form-check-input" id="ws" value="true" checked><br/>
|
||||
<label for="subject">Subject</label>
|
||||
<input type="text" class="form-control" id="subject" placeholder="subject" autocomplete="off" value="foo"><br/>
|
||||
<label for="count">Count</label>
|
||||
<input type="number" class="form-control" id="count" placeholder="messages" autocomplete="off"
|
||||
value="100000"><br/>
|
||||
<label for="payload">Payload size</label>
|
||||
<input type="number" class="form-control" id="payload" placeholder="payload size in bytes" autocomplete="off"
|
||||
value="0"><br/>
|
||||
<label for="callbacks">Use callbacks</label>
|
||||
<input type="checkbox" class="form-check-input" id="callbacks" value="true" checked><br/>
|
||||
|
||||
|
||||
<h3>Test</h3>
|
||||
<div class="radio-inline">
|
||||
<label><input class="form-check-input" type="radio" value="pubsub" checked id="pubsub"
|
||||
name="test">Pub/Sub</label>
|
||||
</div>
|
||||
<div class="radio-inline">
|
||||
<label><input class="form-check-input" type="radio" value="pub" id="pub" name="test">Publish</label>
|
||||
</div>
|
||||
<div class="radio-inline">
|
||||
<label><input class="form-check-input" type="radio" value="sub" id="sub" name="test">Subscribe</label>
|
||||
</div>
|
||||
<div class="radio-inline">
|
||||
<label><input class="form-check-input" type="radio" value="sub" id="reqrep" name="test">ReqReq</label>
|
||||
</div>
|
||||
|
||||
|
||||
<br/><br/>
|
||||
<button id="send" onclick="benchapp.run()" class="btn btn-primary">Start</button>
|
||||
</div>
|
||||
<br/>
|
||||
<div class="container">
|
||||
<pre id="results"></pre>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
* Copyright 2020 The NATS Authors
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { Bench, connect, Metric } from "../esm/nats.js";
|
||||
|
||||
function getString(id) {
|
||||
return document.getElementById(id).value;
|
||||
}
|
||||
|
||||
function isChecked(id) {
|
||||
return document.getElementById(id).checked;
|
||||
}
|
||||
|
||||
function getTestChoice() {
|
||||
if (isChecked("pubsub")) {
|
||||
return "pubsub";
|
||||
} else if (isChecked("pub")) {
|
||||
return "pub";
|
||||
} else if (isChecked("sub")) {
|
||||
return "sub";
|
||||
} else if (isChecked("reqrep")) {
|
||||
return "reqrep";
|
||||
}
|
||||
}
|
||||
|
||||
function getNumber(id) {
|
||||
const v = getString(id);
|
||||
if (!isNaN(v)) {
|
||||
return parseInt(v, 10);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
function updateResults(s) {
|
||||
const p = document.createElement("pre");
|
||||
p.appendChild(document.createTextNode(s));
|
||||
document.getElementById("results").appendChild(p);
|
||||
}
|
||||
|
||||
async function run() {
|
||||
const server = getString("server");
|
||||
const ws = isChecked("ws");
|
||||
const nc = await connect(
|
||||
{
|
||||
servers: `${ws ? "ws://" : "wss://"}${server}`,
|
||||
pendingLimit: 8192,
|
||||
},
|
||||
);
|
||||
nc.closed()
|
||||
.then((err) => {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
}
|
||||
});
|
||||
|
||||
const kind = getTestChoice();
|
||||
const t = {};
|
||||
t.callbacks = isChecked("callbacks");
|
||||
t.msgs = getNumber("count");
|
||||
t.size = getNumber("payload");
|
||||
t.subject = getString("subject");
|
||||
t.pub = kind === "pub" || kind === "pubsub";
|
||||
t.sub = kind === "sub" || kind === "pubsub";
|
||||
t.req = kind === "reqrep";
|
||||
t.rep = kind === "reqrep";
|
||||
|
||||
const bench = new Bench(nc, t);
|
||||
const m = await bench.run();
|
||||
const metrics = [];
|
||||
metrics.push(...m);
|
||||
await nc.close();
|
||||
|
||||
const pubsub = metrics.filter((m) => m.name === "pubsub").reduce(
|
||||
reducer,
|
||||
new Metric("pubsub", 0),
|
||||
);
|
||||
const reqrep = metrics.filter((m) => m.name === "reqrep").reduce(
|
||||
reducer,
|
||||
new Metric("reqrep", 0),
|
||||
);
|
||||
const pub = metrics.filter((m) => m.name === "pub").reduce(
|
||||
reducer,
|
||||
new Metric("pub", 0),
|
||||
);
|
||||
const sub = metrics.filter((m) => m.name === "sub").reduce(
|
||||
reducer,
|
||||
new Metric("sub", 0),
|
||||
);
|
||||
const req = metrics.filter((m) => m.name === "req").reduce(
|
||||
reducer,
|
||||
new Metric("req", 0),
|
||||
);
|
||||
const rep = metrics.filter((m) => m.name === "rep").reduce(
|
||||
reducer,
|
||||
new Metric("rep", 0),
|
||||
);
|
||||
|
||||
const report = [];
|
||||
|
||||
if (pubsub && pubsub.msgs) {
|
||||
report.push(pubsub.toString());
|
||||
}
|
||||
if (reqrep && reqrep.msgs) {
|
||||
report.push(reqrep.toString());
|
||||
}
|
||||
if (pub && pub.msgs) {
|
||||
report.push(pub.toString());
|
||||
}
|
||||
if (sub && sub.msgs) {
|
||||
report.push(sub.toString());
|
||||
}
|
||||
if (req && req.msgs) {
|
||||
report.push(req.toString());
|
||||
}
|
||||
if (rep && rep.msgs) {
|
||||
report.push(rep.toString());
|
||||
}
|
||||
updateResults(report.join("\n"));
|
||||
}
|
||||
|
||||
const reducer = (a, m) => {
|
||||
if (a) {
|
||||
a.name = m.name;
|
||||
a.payload = m.payload;
|
||||
a.bytes += m.bytes;
|
||||
a.duration += m.duration;
|
||||
a.msgs += m.msgs;
|
||||
a.lang = m.lang;
|
||||
a.version = m.version;
|
||||
a.async = m.async;
|
||||
|
||||
a.max = Math.max(a.max === undefined ? 0 : a.max, m.duration);
|
||||
a.min = Math.min(a.min === undefined ? m.duration : a.max, m.duration);
|
||||
}
|
||||
return a;
|
||||
};
|
||||
|
||||
window.benchapp = {
|
||||
run: run,
|
||||
};
|
||||
@@ -0,0 +1,30 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>ws-nats chat</title>
|
||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"
|
||||
crossorigin="anonymous">
|
||||
<script type="module" src="/assets/nats.ws-1.30.3/examples/chat.js"></script>
|
||||
|
||||
</head>
|
||||
<!-- when the browser exits, we publish a message -->
|
||||
|
||||
<body onunload="chat.exiting()">
|
||||
|
||||
<!-- a form for entering messages -->
|
||||
<div class="container">
|
||||
<h1>ws-nats chat</h1>
|
||||
<input type="text" class="form-control" id="data" placeholder="Message" autocomplete="off"><br />
|
||||
<button id="send" onclick="chat.send()" class="btn btn-primary">Send</button>
|
||||
</div>
|
||||
<br />
|
||||
|
||||
<!-- a place to record messages -->
|
||||
<div id="chats" class="container"></div>
|
||||
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
* Copyright 2020 The NATS Authors
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { connect, JSONCodec } from "/assets/nats.ws-1.30.3/esm/nats.js";
|
||||
const me = Date.now();
|
||||
|
||||
window.chat = {
|
||||
send: send,
|
||||
exiting: exiting,
|
||||
};
|
||||
|
||||
// create a decoder, the client is sending JSON
|
||||
const jc = JSONCodec();
|
||||
|
||||
// create a connection, and register listeners
|
||||
const init = async function () {
|
||||
// if the connection doesn't resolve, an exception is thrown
|
||||
// a real app would allow configuring the hostport and whether
|
||||
// to use WSS or not.
|
||||
const conn = await connect(
|
||||
{ servers: "ws://localhost:9222" },
|
||||
);
|
||||
|
||||
// handle connection to the server is closed - should disable the ui
|
||||
conn.closed().then((err) => {
|
||||
let m = "NATS connection closed";
|
||||
addEntry(`${m} ${err ? err.message : ""}`);
|
||||
});
|
||||
(async () => {
|
||||
for await (const s of conn.status()) {
|
||||
addEntry(`Received status update: ${s.type}`);
|
||||
}
|
||||
})().then();
|
||||
|
||||
// the chat application listens for messages sent under the subject 'chat'
|
||||
(async () => {
|
||||
const chat = conn.subscribe("chat");
|
||||
for await (const m of chat) {
|
||||
const jm = jc.decode(m.data);
|
||||
addEntry(
|
||||
jm.id === me ? `(me): ${jm.m}` : `(${jm.id}): ${jm.m}`,
|
||||
);
|
||||
}
|
||||
})().then();
|
||||
|
||||
// when a new browser joins, the joining browser publishes an 'enter' message
|
||||
(async () => {
|
||||
const enter = conn.subscribe("enter");
|
||||
for await (const m of enter) {
|
||||
const jm = jc.decode(m.data);
|
||||
addEntry(`${jm.id} entered.`);
|
||||
}
|
||||
})().then();
|
||||
|
||||
(async () => {
|
||||
const exit = conn.subscribe("exit");
|
||||
for await (const m of exit) {
|
||||
const jm = jc.decode(m.data);
|
||||
if (jm.id !== me) {
|
||||
addEntry(`${jm.id} exited.`);
|
||||
}
|
||||
}
|
||||
})().then();
|
||||
|
||||
// we connected, and we publish our enter message
|
||||
conn.publish("enter", jc.encode({ id: me }));
|
||||
return conn;
|
||||
};
|
||||
|
||||
init().then((conn) => {
|
||||
window.nc = conn;
|
||||
}).catch((ex) => {
|
||||
addEntry(`Error connecting to NATS: ${ex}`);
|
||||
});
|
||||
|
||||
// this is the input field
|
||||
let input = document.getElementById("data");
|
||||
// add a listener to detect edits. If they hit Enter, we publish it
|
||||
input.addEventListener("keyup", (e) => {
|
||||
if (e.key === "Enter") {
|
||||
document.getElementById("send").click();
|
||||
} else {
|
||||
e.preventDefault();
|
||||
}
|
||||
});
|
||||
|
||||
// send a message if user typed one
|
||||
function send() {
|
||||
input = document.getElementById("data");
|
||||
const m = input.value;
|
||||
if (m !== "" && window.nc) {
|
||||
window.nc.publish("chat", jc.encode({ id: me, m: m }));
|
||||
input.value = "";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// send the exit message
|
||||
function exiting() {
|
||||
if (window.nc) {
|
||||
window.nc.publish("exit", jc.encode({ id: me }));
|
||||
}
|
||||
}
|
||||
|
||||
// add an entry to the document
|
||||
function addEntry(s) {
|
||||
const p = document.createElement("pre");
|
||||
p.appendChild(document.createTextNode(s));
|
||||
document.getElementById("chats").appendChild(p);
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Simple</title>
|
||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"
|
||||
crossorigin="anonymous">
|
||||
</head>
|
||||
<body>
|
||||
<!-- a place to record messages -->
|
||||
<div id="messages" class="container"></div>
|
||||
<!-- load a script -->
|
||||
<script type="module">
|
||||
import { connect, StringCodec, credsAuthenticator } from '../esm/nats.js'
|
||||
|
||||
// add an entry to the document
|
||||
function addEntry (s) {
|
||||
const p = document.createElement('pre')
|
||||
p.appendChild(document.createTextNode(s))
|
||||
document.getElementById('messages').appendChild(p)
|
||||
}
|
||||
|
||||
const sc = StringCodec()
|
||||
|
||||
async function testConnection (nc) {
|
||||
addEntry('connected to NATS!')
|
||||
|
||||
// simple publisher
|
||||
nc.publish('hello', sc.encode('nats'))
|
||||
addEntry('published a message to `hello`')
|
||||
|
||||
// simple subscriber, if the message has a reply subject
|
||||
// send a reply
|
||||
const sub = await nc.subscribe('help');
|
||||
(async () => {
|
||||
addEntry('listening for request on `help`')
|
||||
for await (const m of sub) {
|
||||
m.respond(sc.encode(`I can help ${sc.decode(m.data)}`))
|
||||
}
|
||||
})().then()
|
||||
|
||||
// request data - requests only receive one message
|
||||
// to receive multiple messages, create a subscription
|
||||
addEntry('making a request to `help`')
|
||||
const msg = await nc.request('help', sc.encode('nats request'))
|
||||
|
||||
addEntry(`got response '${sc.decode(msg.data)}'`)
|
||||
|
||||
// close the connection
|
||||
nc.close()
|
||||
addEntry('closed the connection')
|
||||
}
|
||||
|
||||
|
||||
async function init () {
|
||||
// To connect to NGS you need a creds or jwt authenticator
|
||||
// you can create one with nsc:
|
||||
// nsc add operator -u synadia
|
||||
// nsc add account myaccount
|
||||
// nsc add user myuser
|
||||
// nsc generate creds -a myaccount -n myuser -o ./myuser.creds
|
||||
// fetch the creds
|
||||
const creds = await fetch('./myuser.creds')
|
||||
if (!creds.ok) {
|
||||
addEntry("unable to find ./myuser.creds - aborting")
|
||||
return;
|
||||
}
|
||||
const token = await creds.text()
|
||||
const auth = credsAuthenticator(sc.encode(token))
|
||||
// connect
|
||||
let nc = await connect({ servers: 'wss://connect.ngs.global', authenticator: auth, debug: true })
|
||||
await testConnection(nc)
|
||||
await nc.closed
|
||||
}
|
||||
|
||||
init()
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,6 @@
|
||||
port: 4222
|
||||
websocket: {
|
||||
port: 9222
|
||||
no_tls: true
|
||||
compression: true
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Simple</title>
|
||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"
|
||||
crossorigin="anonymous">
|
||||
<script type="module" src="/assets/nats.ws-1.30.3/examples/simple.js"></script>
|
||||
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<!-- a place to record messages -->
|
||||
<div id="messages" class="container"></div>
|
||||
<!-- load a script -->
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1,8 @@
|
||||
port: 4222
|
||||
websocket: {
|
||||
port: 443
|
||||
tls: {
|
||||
cert_file: "../certs/cert.pem"
|
||||
key_file: "../certs/key.pem"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Simple</title>
|
||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"
|
||||
crossorigin="anonymous">
|
||||
</head>
|
||||
<body>
|
||||
<!-- a place to record messages -->
|
||||
<div id="messages" class="container"></div>
|
||||
<!-- load a script -->
|
||||
<script type="module">
|
||||
import { connect } from '../nats.js'
|
||||
|
||||
// add an entry to the document
|
||||
function addEntry(s) {
|
||||
const p = document.createElement("pre");
|
||||
p.appendChild(document.createTextNode(s));
|
||||
document.getElementById("messages").appendChild(p);
|
||||
}
|
||||
|
||||
const init = async function () {
|
||||
try {
|
||||
// create a connection to a wss server
|
||||
const nc = await connect({ servers: 'wss://localhost:9222' });
|
||||
addEntry('connected!');
|
||||
await nc.flush();
|
||||
addEntry('did a round-trip to the server');
|
||||
|
||||
// close the connection
|
||||
await nc.close();
|
||||
addEntry('closed the connection');
|
||||
} catch(err) {
|
||||
addEntry(`error connecting - did you setup a wss server? ${err}`);
|
||||
console.error(err)
|
||||
}
|
||||
}
|
||||
init();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user