mirror of
https://github.com/autistic-symposium/backend-and-orchestration-toolkit.git
synced 2025-06-08 15:02:55 -04:00
🍛 Commit progress before lunch break
This commit is contained in:
parent
4cf49ba50b
commit
9aa9e827c0
19 changed files with 378 additions and 19 deletions
17
README.md
17
README.md
|
@ -54,23 +54,6 @@
|
||||||
* HTTP/3
|
* HTTP/3
|
||||||
* gRPC
|
* gRPC
|
||||||
* WebRTC
|
* WebRTC
|
||||||
|
|
||||||
|
|
||||||
<br>
|
|
||||||
|
|
||||||
|
|
||||||
* **[HTTP](https/)**
|
|
||||||
* https communication
|
|
||||||
* https over TCP with TLS 1.2
|
|
||||||
* https over TCP with TLS 1.3
|
|
||||||
* https over QUIC (HTTP/3)
|
|
||||||
* https over TFO with TLS 1.3
|
|
||||||
* https over TCP with TLS 1.3 and ORTT
|
|
||||||
* https over QUICK with ORTT
|
|
||||||
|
|
||||||
<br>
|
|
||||||
|
|
||||||
* **[proxy and load balance](proxy_and_lb)**
|
|
||||||
* proxy vs. reverse proxy
|
* proxy vs. reverse proxy
|
||||||
* Layer 4 vs. Layer 7 load balancers
|
* Layer 4 vs. Layer 7 load balancers
|
||||||
|
|
||||||
|
|
1
code/protocol_demos/grpc-demo/.gitignore
vendored
Normal file
1
code/protocol_demos/grpc-demo/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
/node_modules
|
35
code/protocol_demos/grpc-demo/client.js
Normal file
35
code/protocol_demos/grpc-demo/client.js
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
const grpc = require("grpc");
|
||||||
|
const protoLoader = require("@grpc/proto-loader")
|
||||||
|
const packageDef = protoLoader.loadSync("todo.proto", {});
|
||||||
|
const grpcObject = grpc.loadPackageDefinition(packageDef);
|
||||||
|
const todoPackage = grpcObject.todoPackage;
|
||||||
|
|
||||||
|
const text = process.argv[2];
|
||||||
|
|
||||||
|
const client = new todoPackage.Todo("localhost:40000",
|
||||||
|
grpc.credentials.createInsecure())
|
||||||
|
console.log(text)
|
||||||
|
|
||||||
|
client.createTodo({
|
||||||
|
"id": -1,
|
||||||
|
"text": text
|
||||||
|
}, (err, response) => {
|
||||||
|
|
||||||
|
console.log("Recieved from server " + JSON.stringify(response))
|
||||||
|
|
||||||
|
})
|
||||||
|
/*
|
||||||
|
client.readTodos(null, (err, response) => {
|
||||||
|
|
||||||
|
console.log("read the todos from server " + JSON.stringify(response))
|
||||||
|
if (!response.items)
|
||||||
|
response.items.forEach(a=>console.log(a.text));
|
||||||
|
})
|
||||||
|
*/
|
||||||
|
|
||||||
|
const call = client.readTodosStream();
|
||||||
|
call.on("data", item => {
|
||||||
|
console.log("received item from server " + JSON.stringify(item))
|
||||||
|
})
|
||||||
|
|
||||||
|
call.on("end", e => console.log("server done!"))
|
16
code/protocol_demos/grpc-demo/package.json
Normal file
16
code/protocol_demos/grpc-demo/package.json
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
{
|
||||||
|
"name": "grpc-demo",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"keywords": [],
|
||||||
|
"author": "",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"@grpc/proto-loader": "^0.5.3",
|
||||||
|
"grpc": "^1.24.9"
|
||||||
|
}
|
||||||
|
}
|
38
code/protocol_demos/grpc-demo/server.js
Normal file
38
code/protocol_demos/grpc-demo/server.js
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
const grpc = require("grpc");
|
||||||
|
const protoLoader = require("@grpc/proto-loader")
|
||||||
|
const packageDef = protoLoader.loadSync("todo.proto", {});
|
||||||
|
const grpcObject = grpc.loadPackageDefinition(packageDef);
|
||||||
|
const todoPackage = grpcObject.todoPackage;
|
||||||
|
|
||||||
|
const server = new grpc.Server();
|
||||||
|
server.bind("0.0.0.0:40000",
|
||||||
|
grpc.ServerCredentials.createInsecure());
|
||||||
|
|
||||||
|
server.addService(todoPackage.Todo.service,
|
||||||
|
{
|
||||||
|
"createTodo": createTodo,
|
||||||
|
"readTodos" : readTodos,
|
||||||
|
"readTodosStream": readTodosStream
|
||||||
|
});
|
||||||
|
server.start();
|
||||||
|
|
||||||
|
const todos = []
|
||||||
|
function createTodo (call, callback) {
|
||||||
|
const todoItem = {
|
||||||
|
"id": todos.length + 1,
|
||||||
|
"text": call.request.text
|
||||||
|
}
|
||||||
|
todos.push(todoItem)
|
||||||
|
callback(null, todoItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
function readTodosStream(call, callback) {
|
||||||
|
|
||||||
|
todos.forEach(t => call.write(t));
|
||||||
|
call.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function readTodos(call, callback) {
|
||||||
|
callback(null, {"items": todos})
|
||||||
|
}
|
21
code/protocol_demos/grpc-demo/todo.proto
Normal file
21
code/protocol_demos/grpc-demo/todo.proto
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
package todoPackage;
|
||||||
|
|
||||||
|
service Todo {
|
||||||
|
rpc createTodo(TodoItem) returns (TodoItem);
|
||||||
|
rpc readTodos(voidNoParam) returns (TodoItems);
|
||||||
|
rpc readTodosStream(voidNoParam) returns (stream TodoItem);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
message voidNoParam {}
|
||||||
|
|
||||||
|
message TodoItem {
|
||||||
|
int32 id = 1;
|
||||||
|
string text = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message TodoItems {
|
||||||
|
repeated TodoItem items = 1;
|
||||||
|
}
|
36
code/protocol_demos/long-polling/index.js
Normal file
36
code/protocol_demos/long-polling/index.js
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
const app = require("express")();
|
||||||
|
const jobs = {}
|
||||||
|
|
||||||
|
app.post("/submit", (req, res) => {
|
||||||
|
const jobId = `job:${Date.now()}`
|
||||||
|
jobs[jobId] = 0;
|
||||||
|
updateJob(jobId,0);
|
||||||
|
res.end("\n\n" + jobId + "\n\n");
|
||||||
|
})
|
||||||
|
|
||||||
|
app.get("/checkstatus", async (req, res) => {
|
||||||
|
console.log(jobs[req.query.jobId])
|
||||||
|
//long polling, don't respond until done
|
||||||
|
while(await checkJobComplete(req.query.jobId) == false);
|
||||||
|
res.end("\n\nJobStatus: Complete " + jobs[req.query.jobId] + "%\n\n")
|
||||||
|
|
||||||
|
} )
|
||||||
|
|
||||||
|
app.listen(8080, () => console.log("listening on 8080"));
|
||||||
|
|
||||||
|
async function checkJobComplete(jobId) {
|
||||||
|
return new Promise( (resolve, reject) => {
|
||||||
|
if (jobs[jobId] < 100)
|
||||||
|
this.setTimeout(()=> resolve(false), 1000);
|
||||||
|
else
|
||||||
|
resolve(true);
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateJob(jobId, prg) {
|
||||||
|
jobs[jobId] = prg;
|
||||||
|
console.log(`updated ${jobId} to ${prg}`)
|
||||||
|
if (prg == 100) return;
|
||||||
|
this.setTimeout(()=> updateJob(jobId, prg + 10), 10000)
|
||||||
|
}
|
15
code/protocol_demos/long-polling/package.json
Normal file
15
code/protocol_demos/long-polling/package.json
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
{
|
||||||
|
"name": "short-polling",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"keywords": [],
|
||||||
|
"author": "",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"express": "^4.18.2"
|
||||||
|
}
|
||||||
|
}
|
29
code/protocol_demos/rabbitmq/consumer.js
Normal file
29
code/protocol_demos/rabbitmq/consumer.js
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
const amqp = require("amqplib");
|
||||||
|
|
||||||
|
connect();
|
||||||
|
async function connect() {
|
||||||
|
|
||||||
|
try {
|
||||||
|
const amqpServer = "amqp://localhost:5672"
|
||||||
|
const connection = await amqp.connect(amqpServer)
|
||||||
|
const channel = await connection.createChannel();
|
||||||
|
await channel.assertQueue("jobs");
|
||||||
|
|
||||||
|
channel.consume("jobs", message => {
|
||||||
|
const input = JSON.parse(message.content.toString());
|
||||||
|
console.log(`Recieved job with input ${input.number}`)
|
||||||
|
//"7" == 7 true
|
||||||
|
//"7" === 7 false
|
||||||
|
|
||||||
|
if (input.number == 7 )
|
||||||
|
channel.ack(message);
|
||||||
|
})
|
||||||
|
|
||||||
|
console.log("Waiting for messages...")
|
||||||
|
|
||||||
|
}
|
||||||
|
catch (ex){
|
||||||
|
console.error(ex)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
16
code/protocol_demos/rabbitmq/package.json
Normal file
16
code/protocol_demos/rabbitmq/package.json
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
{
|
||||||
|
"name": "rabbitmq",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "",
|
||||||
|
"main": "publisher.js",
|
||||||
|
"scripts": {
|
||||||
|
"publish": "node publisher.js",
|
||||||
|
"consume": "node consumer.js"
|
||||||
|
},
|
||||||
|
"keywords": [],
|
||||||
|
"author": "",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"amqplib": "^0.5.5"
|
||||||
|
}
|
||||||
|
}
|
22
code/protocol_demos/rabbitmq/publisher.js
Normal file
22
code/protocol_demos/rabbitmq/publisher.js
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
/* RabbitMQ */
|
||||||
|
const amqp = require("amqplib");
|
||||||
|
|
||||||
|
const msg = {number: process.argv[2]}
|
||||||
|
connect();
|
||||||
|
async function connect() {
|
||||||
|
|
||||||
|
try {
|
||||||
|
const amqpServer = "amqp://localhost:5672"
|
||||||
|
const connection = await amqp.connect(amqpServer)
|
||||||
|
const channel = await connection.createChannel();
|
||||||
|
await channel.assertQueue("jobs");
|
||||||
|
await channel.sendToQueue("jobs", Buffer.from(JSON.stringify(msg)))
|
||||||
|
console.log(`Job sent successfully ${msg.number}`);
|
||||||
|
await channel.close();
|
||||||
|
await connection.close();
|
||||||
|
}
|
||||||
|
catch (ex){
|
||||||
|
console.error(ex)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
20
code/protocol_demos/rabbitmq/scripts.md
Normal file
20
code/protocol_demos/rabbitmq/scripts.md
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
## docker commands
|
||||||
|
|
||||||
|
### Spin rabbitmq server docker
|
||||||
|
docker run --name rabbitmq -p 5672:5672 -d rabbitmq
|
||||||
|
|
||||||
|
### Spin rabbitmq server HTTP server docker
|
||||||
|
|
||||||
|
docker run --name rabbitmq -p 5672:5672 -p 15672:15672 -d rabbitmq:3-management
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
HTTP
|
||||||
|
fetch("http://localhost:15672/api/vhosts”, {headers: {"Authorization" : `Basic ${btoa('guest:guest')}`}}).then(a=>a.json()).then(console.log)
|
||||||
|
|
||||||
|
|
||||||
|
fetch("http://localhost:15672/api/channels", {headers: {"Authorization" : `Basic ${btoa('guest:guest')}`}}).then(a=>a.json()).then(console.log)
|
||||||
|
|
||||||
|
|
||||||
|
fetch("http://localhost:15672/api/queues", {headers: {"Authorization" : `Basic ${btoa('guest:guest')}`}}).then(a=>a.json()).then(console.log)
|
||||||
|
|
30
code/protocol_demos/server-sent-events/index.js
Normal file
30
code/protocol_demos/server-sent-events/index.js
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
/* Client Code
|
||||||
|
|
||||||
|
let sse = new EventSource("http://localhost:8080/stream");
|
||||||
|
sse.onmessage = console.log
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
const app = require("express")();
|
||||||
|
|
||||||
|
app.get("/", (req, res) => res.send("hello!"));
|
||||||
|
|
||||||
|
app.get("/stream", (req,res) => {
|
||||||
|
|
||||||
|
res.setHeader("Content-Type", "text/event-stream");
|
||||||
|
send(res);
|
||||||
|
|
||||||
|
})
|
||||||
|
const port = process.env.PORT || 8888;
|
||||||
|
|
||||||
|
let i = 0;
|
||||||
|
function send (res) {
|
||||||
|
|
||||||
|
res.write("data: " + `hello from server ---- [${i++}]\n\n`);
|
||||||
|
|
||||||
|
|
||||||
|
setTimeout(() => send(res), 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
app.listen(port)
|
||||||
|
console.log(`Listening on ${port}`)
|
15
code/protocol_demos/server-sent-events/package.json
Normal file
15
code/protocol_demos/server-sent-events/package.json
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
{
|
||||||
|
"name": "server-sent-events",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"keywords": [],
|
||||||
|
"author": "",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"express": "^4.18.2"
|
||||||
|
}
|
||||||
|
}
|
24
code/protocol_demos/short-polling/index.js
Normal file
24
code/protocol_demos/short-polling/index.js
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
const app = require("express")();
|
||||||
|
const jobs = {}
|
||||||
|
|
||||||
|
app.post("/submit", (req, res) => {
|
||||||
|
const jobId = `job:${Date.now()}`
|
||||||
|
jobs[jobId] = 0;
|
||||||
|
updateJob(jobId,0);
|
||||||
|
res.end("\n\n" + jobId + "\n\n");
|
||||||
|
})
|
||||||
|
|
||||||
|
app.get("/checkstatus", (req, res) => {
|
||||||
|
console.log(jobs[req.query.jobId])
|
||||||
|
res.end("\n\nJobStatus: " + jobs[req.query.jobId] + "%\n\n")
|
||||||
|
|
||||||
|
} )
|
||||||
|
|
||||||
|
app.listen(8080, () => console.log("listening on 8080"));
|
||||||
|
|
||||||
|
function updateJob(jobId, prg) {
|
||||||
|
jobs[jobId] = prg;
|
||||||
|
console.log(`updated ${jobId} to ${prg}`)
|
||||||
|
if (prg == 100) return;
|
||||||
|
this.setTimeout(()=> updateJob(jobId, prg + 10), 3000)
|
||||||
|
}
|
15
code/protocol_demos/short-polling/package.json
Normal file
15
code/protocol_demos/short-polling/package.json
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
{
|
||||||
|
"name": "short-polling",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"keywords": [],
|
||||||
|
"author": "",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"express": "^4.18.2"
|
||||||
|
}
|
||||||
|
}
|
|
@ -162,9 +162,18 @@ curl -v --trace marinasouza.xyz
|
||||||
|
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
|
* used when a request takes long time to process (e.g., upload a video) and very simple to build.
|
||||||
|
* however, it can be too chatting, use too much network bandwidth and backend resources.
|
||||||
|
|
||||||
|
<br>
|
||||||
#### basic idea
|
#### basic idea
|
||||||
- when a request takes long time to process (e.g., upload a video)
|
|
||||||
- the backend want to sends notification
|
1. client sends a request
|
||||||
|
2. server responds immediately with a handle
|
||||||
|
3. server continues to process the request
|
||||||
|
4. client uses that handle to check for status
|
||||||
|
5. multiple short request response as polls
|
||||||
|
|
||||||
|
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
|
@ -173,6 +182,24 @@ curl -v --trace marinasouza.xyz
|
||||||
### Long Polling
|
### Long Polling
|
||||||
|
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
* a poll requests where the server only responds when the job is ready (used when a request takes long time to process and it's not real time)
|
||||||
|
* used by Kafka
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
#### basic idea
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
1. clients sends a request
|
||||||
|
2. server responds immediately with a handle
|
||||||
|
3. server continues to process the request
|
||||||
|
4. client uses that handle to check for status
|
||||||
|
5. server does not reply until has the response (and there are some timeouts)
|
||||||
|
|
||||||
|
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
---
|
---
|
||||||
|
@ -180,6 +207,22 @@ curl -v --trace marinasouza.xyz
|
||||||
### Server Sent Events
|
### Server Sent Events
|
||||||
|
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
* one request with a long response, but the client must be online and be able to handle the response.
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
#### basic idea
|
||||||
|
|
||||||
|
1. a response has start and end
|
||||||
|
2. client sends a request
|
||||||
|
3. server sends logical events as part of response
|
||||||
|
4. server never writes the end of the response
|
||||||
|
5. it's still a request but an unending response
|
||||||
|
6. client parses the streams data
|
||||||
|
7. works with HTTP
|
||||||
|
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
----
|
----
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue