Skip to content

Commit

Permalink
examples: add a WebSocket example (#218)
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
lance authored Jun 10, 2020
1 parent 8b2725b commit 99bb88b
Show file tree
Hide file tree
Showing 5 changed files with 217 additions and 0 deletions.
45 changes: 45 additions & 0 deletions examples/websocket/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# WebSocket Example

This example shows how simple it is to use CloudEvents over a websocket
connection. The code here shows backend communication from two server
side processes, and also between a browser and a server process.

## Running the Example

This simple project consists of a server and a client. The server receives
`CloudEvents` from the client over a local websocket connection.


To get started, first install dependencies.

```sh
npm install
```

### Server
The server opens a websocket and waits for incoming connections. It expects that any
messages it receives will be a CloudEvent. When received, it reads the data field,
expecting a zip code. It then fetches the current weather for that zip code and
responds with a CloudEvent containing the body of the Weather API response as the
event data.

You will need to change one line in the `server.js` file and provide your Open
Weather API key.

To start the server, run `node server.js`.

### Client
Upon start, the client prompts a user for a zip code, then sends a CloudEvent over
a websocket to the server with the provided zip code as the event data. The server
fetches the current weather for that zip code and returns it as a CloudEvent. The
client extracts the data and prints the current weather to the console.

To start the client, run `node client.js`

### Browser
Open the [`index.html`]('./index.html') file in your browser and provide a zip
code in the provided form field. The browser will send the zip code in the data
field of a CloudEvent over a websocket. When it receives a response from the server
it prints the weather, or an error message, to the screen.

To terminate the client or server, type CTL-C.
46 changes: 46 additions & 0 deletions examples/websocket/client.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/* eslint-disable no-console */
const readline = require("readline");
const WebSocket = require("ws");
const ws = new WebSocket("ws://localhost:8080");

const { CloudEvent } = require("cloudevents-sdk");

const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});

rl.on("close", (_) => console.log("\n\nConnection closed! Press CTL-C to exit."));

ws.on("message", function incoming(message) {
const event = new CloudEvent(JSON.parse(message));
if (event.type === "weather.error") {
console.error(`Error: ${event.data}`);
} else {
print(event.data);
}
ask();
});

function ask() {
rl.question("Would you like to see the current weather? Provide a zip code: ", function (zip) {
console.log("Fetching weather data from server...");
ws.send(new CloudEvent({
type: "weather.query",
source: "/weather.client",
data: zip
}).toString());
});
}

function print(data) {
data = JSON.parse(data);
console.log(`
Current weather for ${data.name}: ${data.weather[0].main}
------------------------------------------
With ${data.weather[0].description}, the temperature is ${Math.round(data.main.temp)}F
and the wind is blowing at ${Math.round(data.wind.speed)}mph.
`);
}

ask();
59 changes: 59 additions & 0 deletions examples/websocket/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
<!DOCTYPE html>
<html>
<head>
<title>CloudEvent Example</title>
<script src="../../bundles/cloudevents-sdk.js"></script>
<script>
const CloudEvent = window['cloudevents-sdk'].CloudEvent;
const socket = new WebSocket("ws://localhost:8080");

function print(weather) {
const data = JSON.parse(weather);
const summary = `
<h2>Current weather for ${data.name}: ${data.weather[0].main}</h2>
<hr/>
<p>
With ${data.weather[0].description}, the temperature is ${Math.round(data.main.temp)}F
and the wind is blowing at ${Math.round(data.wind.speed)}mph.
</p>`;
console.log(summary);
const node = document.getElementById("summary");
node.innerHTML = summary;
}

function initialize() {
socket.onmessage = function(message) {
console.log(message.data)
const event = new CloudEvent(JSON.parse(message.data));
if (event.type === "weather.error") {
console.error(`Error: ${event.data}`);
alert(`Error: ${event.data}`);
} else {
print(event.data);
}
}

const input = document.getElementById("zip");
input.addEventListener("keyup", function(event) {
if (event.keyCode === 13) {
event.preventDefault();
socket.send(new CloudEvent({
type: "weather.query",
source: "/weather.client",
data: input.value
}).toString());
}
});

}
</script>
</head>
<body style="font-size: larger; margin: 1em;" onload="initialize()">
<h1>Weather By Zip Code</h1>
<p>Please provide a zip code
<input type="text" id="zip"/>
</p>
<p style="font-family: Arial, Helvetica, sans-serif;" id="summary">
</p>
</body>
</html>
22 changes: 22 additions & 0 deletions examples/websocket/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"name": "websocket-cloudevents",
"version": "0.0.1",
"description": "An example application that sends and receives CloudEvents over a websocket",
"main": "server.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "node server.js"
},
"keywords": [
"cloudevents",
"example",
"websocket"
],
"author": "",
"license": "ISC",
"dependencies": {
"cloudevents-sdk": "^2.0.2",
"got": "^11.3.0",
"ws": "^7.3.0"
}
}
45 changes: 45 additions & 0 deletions examples/websocket/server.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/* eslint-disable no-console */
const got = require("got");

const { CloudEvent } = require("cloudevents-sdk");
const WebSocket = require("ws");
const wss = new WebSocket.Server({ port: 8080 });

const api = "https://api.openweathermap.org/data/2.5/weather";
const key = "REPLACE WITH API KEY";

console.log("WebSocket server started. Waiting for events.");

wss.on("connection", function connection(ws) {
console.log("Connection received");
ws.on("message", function incoming(message) {
const event = new CloudEvent(JSON.parse(message));
console.log(`Message received: ${event.toString()}`);
fetch(event.data)
.then((weather) => {
ws.send(new CloudEvent({
dataContentType: "application/json",
type: "current.weather",
source: "/weather.server",
data: weather
}).toString());
})
.catch((err) => {
console.error(err);
ws.send(new CloudEvent({
type: "weather.error",
source: "/weather.server",
data: err.toString()
}).toString());
});
});
});

function fetch(zip) {
const query = `${api}?zip=${zip}&appid=${key}&units=imperial`;
return new Promise((resolve, reject) => {
got(query)
.then((response) => resolve(response.body))
.catch((err) => reject(err.message));
});
}

0 comments on commit 99bb88b

Please # to comment.