Skip to content

Commit 96a8840

Browse files
committed
chore: working on chapter 13
1 parent 20ae795 commit 96a8840

File tree

23 files changed

+1667
-3
lines changed

23 files changed

+1667
-3
lines changed

09-behavioral-design-patterns/17-command-s3-put-object/index.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import { PutObjectCommand, S3Client } from '@aws-sdk/client-s3' // v3.750.0
55
const [bucketName, filePath] = process.argv.slice(2)
66

77
if (!(bucketName && filePath)) {
8-
// biome-ignore lint/nursery/noSecrets: not a secret
98
console.error('Usage: node index.js <bucketName> <filePath>')
109
process.exit(1)
1110
}

10-testing/16-integration-test-http/booking.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ export async function reserveSeat(db, eventId, userId) {
77
}
88

99
const existing = await db.query(
10-
// biome-ignore lint/nursery/noSecrets: <explanation>
1110
'SELECT COUNT(*) AS count FROM reservations WHERE eventId = ?',
1211
[eventId]
1312
)
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
msgHistory/
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
# 04-pubsub-amqp
2+
3+
This sample demonstrates how to integrate a chat application and a microservice
4+
using AMQP
5+
6+
## Dependencies
7+
8+
As pre-requisite to this sample, you first need to
9+
[install RabbitMQ](http://www.rabbitmq.com/download.html)
10+
11+
If you have docker installed, you can run an ephemeral instance of RabbitMQ with
12+
the following command:
13+
14+
```bash
15+
docker run -it -p 5672:5672 --hostname my-rabbit rabbitmq:3
16+
```
17+
18+
This example requires you to install some third-party dependencies from npm.
19+
20+
If you have `pnpm` installed, you can do that with:
21+
22+
```bash
23+
pnpm install
24+
```
25+
26+
Alternatively, if you prefer to use another package manager, make sure to delete
27+
the `pnpm-lock.yaml` file before using it.
28+
29+
If you want to use `npm`, you can run:
30+
31+
```bash
32+
npm install
33+
```
34+
35+
If you want to use `yarn`, you can run:
36+
37+
```bash
38+
yarn install
39+
```
40+
41+
## Run
42+
43+
To run the various components, run in different terminals the following
44+
commands:
45+
46+
```bash
47+
node index.js 8080 # runs a version of the chat application on port 8080
48+
node index.js 8081 # runs a version of the chat application on port 8081
49+
node historySvc.js # runs the history service
50+
```
51+
52+
Then you can access the chat application by opening your browser and navigating
53+
to:
54+
55+
```
56+
http://localhost:8080
57+
```
58+
59+
or
60+
61+
```
62+
http://localhost:8081
63+
```
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import { createServer } from 'node:http'
2+
import amqp from 'amqplib' // v0.10.8
3+
import { Level } from 'level' // v10.0.0
4+
import { monotonicFactory } from 'ulid' // v3.0.1
5+
6+
const ulid = monotonicFactory()
7+
const db = new Level('msgHistory', { valueEncoding: 'json' })
8+
9+
const connection = await amqp.connect('amqp://localhost')
10+
const channel = await connection.createChannel()
11+
await channel.assertExchange('chat', 'fanout')
12+
const { queue } = channel.assertQueue('chat_history')
13+
await channel.bindQueue(queue, 'chat')
14+
15+
channel.consume(queue, async msg => {
16+
const data = JSON.parse(msg.content.toString())
17+
console.log(`Saving message: ${msg.content.toString()}`)
18+
await db.put(ulid(), data)
19+
channel.ack(msg)
20+
})
21+
22+
createServer(async (req, res) => {
23+
const url = new URL(req.url, 'http://localhost')
24+
const lt = url.searchParams.get('lt')
25+
res.writeHead(200, { 'Content-Type': 'application/json' })
26+
const messages = []
27+
for await (const [key, value] of db.iterator({
28+
reverse: true,
29+
limit: 10,
30+
lt,
31+
})) {
32+
messages.unshift({ id: key, ...value })
33+
}
34+
res.end(JSON.stringify(messages, null, 2))
35+
}).listen(8090)
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import { createServer } from 'node:http'
2+
import amqp from 'amqplib' // v0.10.8
3+
import staticHandler from 'serve-handler' // v6.1.6
4+
import { WebSocketServer } from 'ws' // v8.18.2
5+
6+
const httpPort = process.argv[2] || 8080
7+
8+
// register the server with RabbitMQ and create a queue
9+
const connection = await amqp.connect('amqp://localhost')
10+
const channel = await connection.createChannel()
11+
await channel.assertExchange('chat', 'fanout')
12+
const { queue } = await channel.assertQueue(`chat_srv_${httpPort}`, {
13+
exclusive: true,
14+
})
15+
await channel.bindQueue(queue, 'chat')
16+
channel.consume(
17+
queue,
18+
msg => {
19+
msg = msg.content.toString()
20+
console.log(`From queue: ${msg}`)
21+
broadcast(Buffer.from(msg))
22+
},
23+
{ noAck: true }
24+
)
25+
26+
// serve static files
27+
const server = createServer((req, res) => {
28+
return staticHandler(req, res, { public: 'web' })
29+
})
30+
31+
const wss = new WebSocketServer({ server })
32+
wss.on('connection', async client => {
33+
console.log('Client connected')
34+
client.on('message', msg => {
35+
console.log(`Sending message: ${msg}`)
36+
channel.publish(
37+
'chat',
38+
'',
39+
Buffer.from(
40+
JSON.stringify({
41+
text: msg.toString(),
42+
timestamp: Date.now(),
43+
})
44+
)
45+
)
46+
})
47+
48+
// load previous messages from the history service
49+
const res = await fetch('http://localhost:8090')
50+
const messages = await res.json()
51+
for (const message of messages) {
52+
client.send(Buffer.from(JSON.stringify(message)))
53+
}
54+
})
55+
56+
function broadcast(msg) {
57+
for (const client of wss.clients) {
58+
if (client.readyState === WebSocket.OPEN) {
59+
client.send(msg)
60+
}
61+
}
62+
}
63+
64+
server.listen(httpPort)
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
{
2+
"name": "04-pubsub-amqp",
3+
"version": "1.0.0",
4+
"description": "This sample demonstrates how to integrate a chat application and a microservice using AMQP",
5+
"type": "module",
6+
"scripts": {},
7+
"engines": {
8+
"node": ">=24"
9+
},
10+
"engineStrict": true,
11+
"keywords": [],
12+
"author": "Luciano Mammino and Mario Casciaro",
13+
"license": "MIT",
14+
"dependencies": {
15+
"amqplib": "^0.10.8",
16+
"level": "^10.0.0",
17+
"serve-handler": "^6.1.6",
18+
"ulid": "^3.0.1",
19+
"ws": "^8.18.2"
20+
}
21+
}

0 commit comments

Comments
 (0)