Skip to content

Commit 99bb88b

Browse files
authored
examples: add a WebSocket example (#218)
There is nothing really to do in order to support events over websockets. Since a `CloudEvent` can easily be represented in full with JSON, it can be sent over a websocket as `event.toString()`. This example illustrates sending a `CloudEvent` over websocket from a browser or CLI. Fixes: #156 Signed-off-by: Lance Ball <lball@redhat.com>
1 parent 8b2725b commit 99bb88b

File tree

5 files changed

+217
-0
lines changed

5 files changed

+217
-0
lines changed

examples/websocket/README.md

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
# WebSocket Example
2+
3+
This example shows how simple it is to use CloudEvents over a websocket
4+
connection. The code here shows backend communication from two server
5+
side processes, and also between a browser and a server process.
6+
7+
## Running the Example
8+
9+
This simple project consists of a server and a client. The server receives
10+
`CloudEvents` from the client over a local websocket connection.
11+
12+
13+
To get started, first install dependencies.
14+
15+
```sh
16+
npm install
17+
```
18+
19+
### Server
20+
The server opens a websocket and waits for incoming connections. It expects that any
21+
messages it receives will be a CloudEvent. When received, it reads the data field,
22+
expecting a zip code. It then fetches the current weather for that zip code and
23+
responds with a CloudEvent containing the body of the Weather API response as the
24+
event data.
25+
26+
You will need to change one line in the `server.js` file and provide your Open
27+
Weather API key.
28+
29+
To start the server, run `node server.js`.
30+
31+
### Client
32+
Upon start, the client prompts a user for a zip code, then sends a CloudEvent over
33+
a websocket to the server with the provided zip code as the event data. The server
34+
fetches the current weather for that zip code and returns it as a CloudEvent. The
35+
client extracts the data and prints the current weather to the console.
36+
37+
To start the client, run `node client.js`
38+
39+
### Browser
40+
Open the [`index.html`]('./index.html') file in your browser and provide a zip
41+
code in the provided form field. The browser will send the zip code in the data
42+
field of a CloudEvent over a websocket. When it receives a response from the server
43+
it prints the weather, or an error message, to the screen.
44+
45+
To terminate the client or server, type CTL-C.

examples/websocket/client.js

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/* eslint-disable no-console */
2+
const readline = require("readline");
3+
const WebSocket = require("ws");
4+
const ws = new WebSocket("ws://localhost:8080");
5+
6+
const { CloudEvent } = require("cloudevents-sdk");
7+
8+
const rl = readline.createInterface({
9+
input: process.stdin,
10+
output: process.stdout
11+
});
12+
13+
rl.on("close", (_) => console.log("\n\nConnection closed! Press CTL-C to exit."));
14+
15+
ws.on("message", function incoming(message) {
16+
const event = new CloudEvent(JSON.parse(message));
17+
if (event.type === "weather.error") {
18+
console.error(`Error: ${event.data}`);
19+
} else {
20+
print(event.data);
21+
}
22+
ask();
23+
});
24+
25+
function ask() {
26+
rl.question("Would you like to see the current weather? Provide a zip code: ", function (zip) {
27+
console.log("Fetching weather data from server...");
28+
ws.send(new CloudEvent({
29+
type: "weather.query",
30+
source: "/weather.client",
31+
data: zip
32+
}).toString());
33+
});
34+
}
35+
36+
function print(data) {
37+
data = JSON.parse(data);
38+
console.log(`
39+
Current weather for ${data.name}: ${data.weather[0].main}
40+
------------------------------------------
41+
With ${data.weather[0].description}, the temperature is ${Math.round(data.main.temp)}F
42+
and the wind is blowing at ${Math.round(data.wind.speed)}mph.
43+
`);
44+
}
45+
46+
ask();

examples/websocket/index.html

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<title>CloudEvent Example</title>
5+
<script src="../../bundles/cloudevents-sdk.js"></script>
6+
<script>
7+
const CloudEvent = window['cloudevents-sdk'].CloudEvent;
8+
const socket = new WebSocket("ws://localhost:8080");
9+
10+
function print(weather) {
11+
const data = JSON.parse(weather);
12+
const summary = `
13+
<h2>Current weather for ${data.name}: ${data.weather[0].main}</h2>
14+
<hr/>
15+
<p>
16+
With ${data.weather[0].description}, the temperature is ${Math.round(data.main.temp)}F
17+
and the wind is blowing at ${Math.round(data.wind.speed)}mph.
18+
</p>`;
19+
console.log(summary);
20+
const node = document.getElementById("summary");
21+
node.innerHTML = summary;
22+
}
23+
24+
function initialize() {
25+
socket.onmessage = function(message) {
26+
console.log(message.data)
27+
const event = new CloudEvent(JSON.parse(message.data));
28+
if (event.type === "weather.error") {
29+
console.error(`Error: ${event.data}`);
30+
alert(`Error: ${event.data}`);
31+
} else {
32+
print(event.data);
33+
}
34+
}
35+
36+
const input = document.getElementById("zip");
37+
input.addEventListener("keyup", function(event) {
38+
if (event.keyCode === 13) {
39+
event.preventDefault();
40+
socket.send(new CloudEvent({
41+
type: "weather.query",
42+
source: "/weather.client",
43+
data: input.value
44+
}).toString());
45+
}
46+
});
47+
48+
}
49+
</script>
50+
</head>
51+
<body style="font-size: larger; margin: 1em;" onload="initialize()">
52+
<h1>Weather By Zip Code</h1>
53+
<p>Please provide a zip code
54+
<input type="text" id="zip"/>
55+
</p>
56+
<p style="font-family: Arial, Helvetica, sans-serif;" id="summary">
57+
</p>
58+
</body>
59+
</html>

examples/websocket/package.json

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
{
2+
"name": "websocket-cloudevents",
3+
"version": "0.0.1",
4+
"description": "An example application that sends and receives CloudEvents over a websocket",
5+
"main": "server.js",
6+
"scripts": {
7+
"test": "echo \"Error: no test specified\" && exit 1",
8+
"start": "node server.js"
9+
},
10+
"keywords": [
11+
"cloudevents",
12+
"example",
13+
"websocket"
14+
],
15+
"author": "",
16+
"license": "ISC",
17+
"dependencies": {
18+
"cloudevents-sdk": "^2.0.2",
19+
"got": "^11.3.0",
20+
"ws": "^7.3.0"
21+
}
22+
}

examples/websocket/server.js

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/* eslint-disable no-console */
2+
const got = require("got");
3+
4+
const { CloudEvent } = require("cloudevents-sdk");
5+
const WebSocket = require("ws");
6+
const wss = new WebSocket.Server({ port: 8080 });
7+
8+
const api = "https://api.openweathermap.org/data/2.5/weather";
9+
const key = "REPLACE WITH API KEY";
10+
11+
console.log("WebSocket server started. Waiting for events.");
12+
13+
wss.on("connection", function connection(ws) {
14+
console.log("Connection received");
15+
ws.on("message", function incoming(message) {
16+
const event = new CloudEvent(JSON.parse(message));
17+
console.log(`Message received: ${event.toString()}`);
18+
fetch(event.data)
19+
.then((weather) => {
20+
ws.send(new CloudEvent({
21+
dataContentType: "application/json",
22+
type: "current.weather",
23+
source: "/weather.server",
24+
data: weather
25+
}).toString());
26+
})
27+
.catch((err) => {
28+
console.error(err);
29+
ws.send(new CloudEvent({
30+
type: "weather.error",
31+
source: "/weather.server",
32+
data: err.toString()
33+
}).toString());
34+
});
35+
});
36+
});
37+
38+
function fetch(zip) {
39+
const query = `${api}?zip=${zip}&appid=${key}&units=imperial`;
40+
return new Promise((resolve, reject) => {
41+
got(query)
42+
.then((response) => resolve(response.body))
43+
.catch((err) => reject(err.message));
44+
});
45+
}

0 commit comments

Comments
 (0)