-
Notifications
You must be signed in to change notification settings - Fork 69
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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>
- Loading branch information
Showing
5 changed files
with
217 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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)); | ||
}); | ||
} |