Skip to content

Commit b001773

Browse files
authored
Updates
1 parent 001e9c2 commit b001773

File tree

11 files changed

+518
-516
lines changed

11 files changed

+518
-516
lines changed
File renamed without changes.

articles/azure-web-pubsub/socketio-serverless-overview.md renamed to articles/azure-web-pubsub/socket-io-serverless-overview.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
---
2-
title: Overview Socket.IO Serverless Mode
2+
title: Overview of Web PubSub for Socket.IO Serverless Mode
33
description: Get an overview of Azure's support for the open-source Socket.IO library on serverless mode.
44
keywords: Socket.IO, Socket.IO on Azure, serverless, multi-node Socket.IO, scaling Socket.IO, socketio, azure socketio
55
author: zackliu
@@ -29,5 +29,7 @@ This article provides you with an overview of the Serverless Mode of Web PubSub
2929

3030
> [!div class="nextstepaction"]
3131
> [Tutorial: Build chat app with Azure Function in Serverless Mode](./socketio-serverless-tutorial.md)
32+
>
3233
> [Serverless Protocols](./socketio-serverless-protocol.md)
34+
>
3335
> [Serverless Function Binding](./socketio-serverless-function-binding.md)

articles/azure-web-pubsub/socketio-serverless-protocol.md renamed to articles/azure-web-pubsub/socket-io-serverless-protocol.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
---
2-
title: Socket.IO Serverless Mode Specification
2+
title: Web PubSub for Socket.IO Serverless Mode Specification
33
description: Get the specification of Socket.IO Serverless
44
keywords: Socket.IO, Socket.IO on Azure, serverless, multi-node Socket.IO, scaling Socket.IO, socketio, azure socketio
55
author: zackliu
@@ -45,7 +45,7 @@ Explanations of the previous sample:
4545

4646
When a client attempts to connect to the service, the process is divided into two distinct steps: establishing an Engine.IO (physical) connection and connecting to a namespace, which is referred to as a socket in Socket.IO terminology. The authentication process differs between these two steps:
4747

48-
1. **Engine.IO connection**: During this step, the service authenticates the client using an access token to determine whether to accept the connection. If the corresponding hub is configured to allow anonymous mode, the Engine.IO connection can proceed without validating the access token. However, for security reasons, we recommend to disable anonymous mode in production environments.
48+
1. **Engine.IO connection**: During this step, the service authenticates the client using an access token to determine whether to accept the connection. If the corresponding hub is configured to allow anonymous mode, the Engine.IO connection can proceed without validating the access token. However, for security reasons, we recommend disabling anonymous mode in production environments.
4949

5050
- The Engine.IO connection url follows the format. But in most cases, it should be handled by Socket.IO client library.
5151

@@ -155,7 +155,7 @@ The application which is used to request a token must use the resource `https://
155155

156156
#### Token for Engine.IO connection
157157

158-
Different from the RESTful API, Engine.IO connection doesn't use the Entra ID token directly. Instead, you must make a RESTful call to the service to get a token and use the returned token as the access token for client.
158+
Different from the RESTful API, Engine.IO connection doesn't use the Microsoft Entra ID token directly. Instead, you must make a RESTful call to the service to get a token and use the returned token as the access token for client.
159159

160160
```Http
161161
POST {endpoint}/api/hubs/{hub}/:generateToken?api-version=2024-01-01

articles/azure-web-pubsub/socketio-serverless-quickstart.md renamed to articles/azure-web-pubsub/socket-io-serverless-quickstart.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
---
22
title: 'Quickstart: Build chat app with Azure Function in Socket.IO Serverless Mode'
3-
description: In this article, you will familiar with the samples of using Web PubSub for Socket.IO with Azure Function in Serverless Mode.
3+
description: In this article, you can familiar with the samples of using Web PubSub for Socket.IO with Azure Function in Serverless Mode.
44
keywords: Socket.IO, serverless, azure function, Socket.IO on Azure, multi-node Socket.IO, scaling Socket.IO, socketio, azure socketio
55
author: zackliu
66
ms.author: chenyl
@@ -15,7 +15,7 @@ In this article, you'll learn how to build a chat app using Web PubSub for Socke
1515

1616
The project source uses Bicep to deploy the infrastructure on Azure, and Azure Functions Core Tools to deploy the code to the Function App.
1717

18-
## Prerequest
18+
## Prerequisites
1919

2020
+ An Azure account with an active subscription. [Create an account for free](https://azure.microsoft.com/free/?ref=microsoft.com&utm_source=microsoft.com&utm_medium=docs&utm_campaign=visualstudio).
2121

@@ -103,7 +103,7 @@ After the code is deployed, visit the website to try the sample:
103103
https://<function-endpoint>/api/index
104104
```
105105

106-
:::image type="content" source="./media/socketio-serverless-quickstart/chatsample.png" alt-text="Screenshot of the serverless chat app.":::
106+
:::image type="content" source="./media/socket-io-serverless-quickstart/chat-sample.png" alt-text="Screenshot of the serverless chat app.":::
107107

108108
## Next steps
109109
Next, you can follow the tutorial to write the app step by step:
Lines changed: 321 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,321 @@
1+
---
2+
title: 'Tutorial: Publish data to Web PubSub for Socket.IO clients in Serverless Mode in Python'
3+
description: In this tutorial, you learn how to use Web PubSub for Socket.IO with Azure Function in Serverless Mode to publish data to sockets with a real-time NASDAQ index update application
4+
keywords: Socket.IO, serverless, azure function, Socket.IO on Azure, multi-node Socket.IO, scaling Socket.IO, socketio, azure socketio
5+
author: zackliu
6+
ms.author: chenyl
7+
ms.date: 09/01/2024
8+
ms.service: azure-web-pubsub
9+
ms.topic: tutorial
10+
---
11+
12+
# Tutorial: Publish data to Socket.IO clients in Serverless Mode in Azure Function with Python (Preview)
13+
14+
This tutorial guides you through how to publish data to Socket.IO clients in Serverless Mode in Python by creating a real-time NASDAQ index application integrated with Azure Function.
15+
16+
Find full code samples that are used in this tutorial:
17+
18+
- [Socket.IO Serverless Python Sample](https://github.com/Azure/azure-webpubsub/tree/main/sdk/webpubsub-socketio-extension/examples/publish-only-python)
19+
20+
> [!IMPORTANT]
21+
> Default Mode needs a persistent server, you cannot integration Web PubSub for Socket.IO in default mode with Azure Function.
22+
23+
## Prerequisites
24+
25+
> [!div class="checklist"]
26+
> * An Azure account with an active subscription. If you don't have one, you can [create a free account](https://azure.microsoft.com/free/).
27+
> * [Azure Function core tool](../azure-functions/functions-run-local.md)
28+
> * Some familiarity with the Socket.IO library.
29+
30+
## Create a Web PubSub for Socket.IO resource in Serverless Mode
31+
32+
To create a Web PubSub for Socket.IO, you can use the following [Azure CLI](/cli/azure/install-azure-cli) command:
33+
34+
```azcli
35+
az webpubsub create -g <resource-group> -n <resource-name>---kind socketio --service-mode serverless --sku Premium_P1
36+
```
37+
38+
## Create an Azure Function project locally
39+
40+
You should follow the steps to initiate a local Azure Function project.
41+
42+
1. Follow to step to install the latest [Azure Function core tool](../azure-functions/functions-run-local.md#install-the-azure-functions-core-tools)
43+
44+
1. In the terminal window or from a command prompt, run the following command to create a project in the `SocketIOProject` folder:
45+
46+
```bash
47+
func init SocketIOProject --worker-runtime python
48+
```
49+
50+
This command creates a Python-based Function project. And enter the folder `SocketIOProject` to run the following commands.
51+
52+
1. Currently, the Function Bundle doesn't include Socket.IO Function Binding, so you need to manually add the package.
53+
54+
1. To eliminate the function bundle reference, edit the host.json file and remove the following lines.
55+
56+
```json
57+
"extensionBundle": {
58+
"id": "Microsoft.Azure.Functions.ExtensionBundle",
59+
"version": "[4.*, 5.0.0)"
60+
}
61+
```
62+
63+
1. Run the command:
64+
65+
```bash
66+
func extensions install -p Microsoft.Azure.WebJobs.Extensions.WebPubSubForSocketIO -v 1.0.0-beta.4
67+
```
68+
69+
1. Replace the content in `function_app.py` with the codes:
70+
71+
```python
72+
import random
73+
import azure.functions as func
74+
from azure.functions.decorators.core import DataType
75+
from azure.functions import Context
76+
import json
77+
78+
app = func.FunctionApp()
79+
current_index= 14000
80+
81+
@app.timer_trigger(schedule="* * * * * *", arg_name="myTimer", run_on_startup=False,
82+
use_monitor=False)
83+
@app.generic_output_binding("sio", type="socketio", data_type=DataType.STRING, hub="hub")
84+
def publish_data(myTimer: func.TimerRequest,
85+
sio: func.Out[str]) -> None:
86+
change = round(random.uniform(-10, 10), 2)
87+
global current_index
88+
current_index = current_index + change
89+
sio.set(json.dumps({
90+
'actionName': 'sendToNamespace',
91+
'namespace': '/',
92+
'eventName': 'update',
93+
'parameters': [
94+
current_index
95+
]
96+
}))
97+
98+
@app.function_name(name="negotiate")
99+
@app.route(auth_level=func.AuthLevel.ANONYMOUS)
100+
@app.generic_input_binding("negotiationResult", type="socketionegotiation", hub="hub")
101+
def negotiate(req: func.HttpRequest, negotiationResult) -> func.HttpResponse:
102+
return func.HttpResponse(negotiationResult)
103+
104+
@app.function_name(name="index")
105+
@app.route(auth_level=func.AuthLevel.ANONYMOUS)
106+
def index(req: func.HttpRequest) -> func.HttpResponse:
107+
path = './index.html'
108+
with open(path, 'rb') as f:
109+
return func.HttpResponse(f.read(), mimetype='text/html')
110+
```
111+
112+
Here's the explanation of these functions:
113+
114+
- `publish_data`: This function updates the NASDAQ index every second with a random change and broadcasts it to connected clients with Socket.IO Output Binding.
115+
116+
- `negotiate`: This function response a negotiation result to the client.
117+
118+
- `index`: This function returns a static HTML page.
119+
120+
121+
Then add a `index.html` file
122+
123+
Create the index.html file with the content:
124+
125+
```html
126+
<!DOCTYPE html>
127+
<html lang="en">
128+
<head>
129+
<meta charset="UTF-8">
130+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
131+
<title>Nasdaq Index</title>
132+
<style>
133+
/* Reset some default styles */
134+
* {
135+
margin: 0;
136+
padding: 0;
137+
box-sizing: border-box;
138+
}
139+
140+
body {
141+
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
142+
background: linear-gradient(135deg, #f5f7fa, #c3cfe2);
143+
height: 100vh;
144+
display: flex;
145+
justify-content: center;
146+
align-items: center;
147+
}
148+
149+
.container {
150+
background-color: white;
151+
padding: 40px;
152+
border-radius: 12px;
153+
box-shadow: 0 4px 6px rgba(0,0,0,0.1);
154+
text-align: center;
155+
max-width: 300px;
156+
width: 100%;
157+
}
158+
159+
.nasdaq-title {
160+
font-size: 2em;
161+
color: #003087;
162+
margin-bottom: 20px;
163+
}
164+
165+
.index-value {
166+
font-size: 3em;
167+
color: #16a34a;
168+
margin-bottom: 30px;
169+
transition: color 0.3s ease;
170+
}
171+
172+
.update-button {
173+
padding: 10px 20px;
174+
font-size: 1em;
175+
color: white;
176+
background-color: #003087;
177+
border: none;
178+
border-radius: 6px;
179+
cursor: pointer;
180+
transition: background-color 0.3s ease;
181+
}
182+
183+
.update-button:hover {
184+
background-color: #002070;
185+
}
186+
</style>
187+
</head>
188+
<body>
189+
<div class="container">
190+
<div class="nasdaq-title">NASDAQ</div>
191+
<div id="nasdaqIndex" class="index-value">14,000.00</div>
192+
</div>
193+
194+
<script src="https://cdn.socket.io/4.7.5/socket.io.min.js"></script>
195+
<script>
196+
function updateIndexCore(newIndex) {
197+
newIndex = parseFloat(newIndex);
198+
currentIndex = parseFloat(document.getElementById('nasdaqIndex').innerText.replace(/,/g, ''))
199+
change = newIndex - currentIndex;
200+
// Update the index value in the DOM
201+
document.getElementById('nasdaqIndex').innerText = newIndex.toLocaleString('en-US', {minimumFractionDigits: 2, maximumFractionDigits: 2});
202+
203+
// Optionally, change the color based on increase or decrease
204+
const indexElement = document.getElementById('nasdaqIndex');
205+
if (change > 0) {
206+
indexElement.style.color = '#16a34a'; // Green for increase
207+
} else if (change < 0) {
208+
indexElement.style.color = '#dc2626'; // Red for decrease
209+
} else {
210+
indexElement.style.color = '#16a34a'; // Neutral color
211+
}
212+
}
213+
214+
async function init() {
215+
const negotiateResponse = await fetch(`/api/negotiate`);
216+
if (!negotiateResponse.ok) {
217+
console.log("Failed to negotiate, status code =", negotiateResponse.status);
218+
return;
219+
}
220+
const negotiateJson = await negotiateResponse.json();
221+
socket = io(negotiateJson.endpoint, {
222+
path: negotiateJson.path,
223+
query: { access_token: negotiateJson.token}
224+
});
225+
226+
socket.on('update', (index) => {
227+
updateIndexCore(index);
228+
});
229+
}
230+
231+
init();
232+
</script>
233+
</body>
234+
</html>
235+
```
236+
237+
The key part in the `index.html`:
238+
239+
```javascript
240+
async function init() {
241+
const negotiateResponse = await fetch(`/api/negotiate`);
242+
if (!negotiateResponse.ok) {
243+
console.log("Failed to negotiate, status code =", negotiateResponse.status);
244+
return;
245+
}
246+
const negotiateJson = await negotiateResponse.json();
247+
socket = io(negotiateJson.endpoint, {
248+
path: negotiateJson.path,
249+
query: { access_token: negotiateJson.token}
250+
});
251+
252+
socket.on('update', (index) => {
253+
updateIndexCore(index);
254+
});
255+
}
256+
```
257+
258+
It first negotiates with the Function App to get the Uri and the path to the service. And register a callback to update index.
259+
260+
## How to run the App locally
261+
262+
After code is prepared, following the instructions to run the sample.
263+
264+
### Set up Azure Storage for Azure Function
265+
266+
Azure Functions requires a storage account to work even running in local. Choose either of the two following options:
267+
268+
* Run the free [Azurite emulator](../storage/common/storage-use-azurite.md).
269+
* Use the Azure Storage service. This may incur costs if you continue to use it.
270+
271+
#### [Local emulation](#tab/storage-azurite)
272+
273+
1. Install the Azurite
274+
275+
```bash
276+
npm install -g azurite
277+
```
278+
279+
1. Start the Azurite storage emulator:
280+
281+
```bash
282+
azurite -l azurite -d azurite\debug.log
283+
```
284+
285+
1. Make sure the `AzureWebJobsStorage` in *local.settings.json* set to `UseDevelopmentStorage=true`.
286+
287+
#### [Azure Blob Storage](#tab/azure-blob-storage)
288+
289+
Update the project to use the Azure Blob Storage connection string.
290+
291+
```bash
292+
func settings add AzureWebJobsStorage "<storage-connection-string>"
293+
```
294+
295+
---
296+
297+
### Set up configuration of Web PubSub for Socket.IO
298+
299+
Add connection string to the Function APP:
300+
301+
```bash
302+
func settings add WebPubSubForSocketIOConnectionString "<connection string>"
303+
```
304+
305+
### Run Sample App
306+
307+
After tunnel tool is running, you can run the Function App locally:
308+
309+
```bash
310+
func start
311+
```
312+
313+
And visit the webpage at `http://localhost:7071/api/index`.
314+
315+
:::image type="content" source="./media/socket-io-serverless-tutorial-python/python-sample.png" alt-text="Screenshot of the app.":::
316+
317+
## Next steps
318+
Next, you can try to use Bicep to deploy the app online with identity-based authentication:
319+
320+
> [!div class="nextstepaction"]
321+
> [Quickstart: Build chat app with Azure Function in Socket.IO Serverless Mode](./socketio-serverless-quickstart.md)

0 commit comments

Comments
 (0)