Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
В этом руководстве описано, как публиковать данные для Socket.IO клиентов в бессерверном режиме в Python, создавая приложение индекса NASDAQ в режиме реального времени, интегрированное с функцией Azure.
Найдите полные примеры кода, используемые в этом руководстве:
Это важно
В режиме по умолчанию требуется постоянный сервер, вы не можете интегрировать Web PubSub для Socket.IO в режиме по умолчанию с функцией Azure.
Предпосылки
- Учетная запись Azure с активной подпиской. Если у вас нет учетной записи, вы можете создать бесплатную учетную запись.
- Основное средство функции Azure
- Некоторые знания о библиотеке Socket.IO.
Создание ресурса Web PubSub для Socket.IO в режиме без сервера
Чтобы создать web PubSub для Socket.IO, можно использовать следующую команду Azure CLI :
az webpubsub create -g <resource-group> -n <resource-name>---kind socketio --service-mode serverless --sku Premium_P1
Создание проекта функции Azure локально
Выполните действия, чтобы инициировать локальный проект функции Azure.
Следуйте шагу, чтобы установить последнюю версию основного инструмента Azure Functions
В окне терминала или из командной строки выполните следующую команду, чтобы создать проект в папке
SocketIOProject:func init SocketIOProject --worker-runtime pythonЭта команда создает проект функции на основе Python. Введите папку
SocketIOProject, чтобы выполнить следующие команды.В настоящее время пакет функций не включает привязку функции Socket.IO, поэтому необходимо вручную добавить пакет.
Чтобы исключить ссылку на пакет функций, измените файл host.json и удалите следующие строки.
"extensionBundle": { "id": "Microsoft.Azure.Functions.ExtensionBundle", "version": "[4.*, 5.0.0)" }Выполните команду:
func extensions install -p Microsoft.Azure.WebJobs.Extensions.WebPubSubForSocketIO -v 1.0.0-beta.4
Замените содержимое
function_app.pyкодами:import random import azure.functions as func from azure.functions.decorators.core import DataType from azure.functions import Context import json app = func.FunctionApp() current_index= 14000 @app.timer_trigger(schedule="* * * * * *", arg_name="myTimer", run_on_startup=False, use_monitor=False) @app.generic_output_binding("sio", type="socketio", data_type=DataType.STRING, hub="hub") def publish_data(myTimer: func.TimerRequest, sio: func.Out[str]) -> None: change = round(random.uniform(-10, 10), 2) global current_index current_index = current_index + change sio.set(json.dumps({ 'actionName': 'sendToNamespace', 'namespace': '/', 'eventName': 'update', 'parameters': [ current_index ] })) @app.function_name(name="negotiate") @app.route(auth_level=func.AuthLevel.ANONYMOUS) @app.generic_input_binding("negotiationResult", type="socketionegotiation", hub="hub") def negotiate(req: func.HttpRequest, negotiationResult) -> func.HttpResponse: return func.HttpResponse(negotiationResult) @app.function_name(name="index") @app.route(auth_level=func.AuthLevel.ANONYMOUS) def index(req: func.HttpRequest) -> func.HttpResponse: path = './index.html' with open(path, 'rb') as f: return func.HttpResponse(f.read(), mimetype='text/html')Ниже приведено описание этих функций:
publish_data: эта функция обновляет индекс NASDAQ каждую секунду случайным изменением и передает его подключенным клиентам с Socket.IO выходной привязкой.negotiate: Эта функция передает клиенту результат согласования.index: эта функция возвращает статическую HTML-страницу.
Затем добавьте
index.htmlфайлСоздайте файл index.html с содержимым:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Nasdaq Index</title> <style> /* Reset some default styles */ * { margin: 0; padding: 0; box-sizing: border-box; } body { font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; background: linear-gradient(135deg, #f5f7fa, #c3cfe2); height: 100vh; display: flex; justify-content: center; align-items: center; } .container { background-color: white; padding: 40px; border-radius: 12px; box-shadow: 0 4px 6px rgba(0,0,0,0.1); text-align: center; max-width: 300px; width: 100%; } .nasdaq-title { font-size: 2em; color: #003087; margin-bottom: 20px; } .index-value { font-size: 3em; color: #16a34a; margin-bottom: 30px; transition: color 0.3s ease; } .update-button { padding: 10px 20px; font-size: 1em; color: white; background-color: #003087; border: none; border-radius: 6px; cursor: pointer; transition: background-color 0.3s ease; } .update-button:hover { background-color: #002070; } </style> </head> <body> <div class="container"> <div class="nasdaq-title">STOCK INDEX</div> <div id="nasdaqIndex" class="index-value">14,000.00</div> </div> <script src="https://cdn.socket.io/4.7.5/socket.io.min.js"></script> <script> function updateIndexCore(newIndex) { newIndex = parseFloat(newIndex); currentIndex = parseFloat(document.getElementById('nasdaqIndex').innerText.replace(/,/g, '')) change = newIndex - currentIndex; // Update the index value in the DOM document.getElementById('nasdaqIndex').innerText = newIndex.toLocaleString('en-US', {minimumFractionDigits: 2, maximumFractionDigits: 2}); // Optionally, change the color based on increase or decrease const indexElement = document.getElementById('nasdaqIndex'); if (change > 0) { indexElement.style.color = '#16a34a'; // Green for increase } else if (change < 0) { indexElement.style.color = '#dc2626'; // Red for decrease } else { indexElement.style.color = '#16a34a'; // Neutral color } } async function init() { const negotiateResponse = await fetch(`/api/negotiate`); if (!negotiateResponse.ok) { console.log("Failed to negotiate, status code =", negotiateResponse.status); return; } const negotiateJson = await negotiateResponse.json(); socket = io(negotiateJson.endpoint, { path: negotiateJson.path, query: { access_token: negotiateJson.token} }); socket.on('update', (index) => { updateIndexCore(index); }); } init(); </script> </body> </html>Ключевая часть в
index.html:async function init() { const negotiateResponse = await fetch(`/api/negotiate`); if (!negotiateResponse.ok) { console.log("Failed to negotiate, status code =", negotiateResponse.status); return; } const negotiateJson = await negotiateResponse.json(); socket = io(negotiateJson.endpoint, { path: negotiateJson.path, query: { access_token: negotiateJson.token} }); socket.on('update', (index) => { updateIndexCore(index); }); }Сначала он проводит переговоры с функциональным приложением, чтобы получить универсальный код ресурса (URI) и путь к службе. И зарегистрируйте обратный вызов для обновления индекса.
Как локально запустить приложение
После подготовки кода выполните инструкции по выполнению примера.
Настройка службы хранилища Azure для функции Azure
Функции Azure требуют, чтобы учетная запись хранения работала даже в локальной среде. Выберите один из двух следующих вариантов:
- Запустите бесплатный эмулятор Azurite.
- Используйте службу хранилища Azure. Это может привести к затратам, если вы продолжаете использовать его.
Установка Azurite
npm install -g azuriteЗапустите эмулятор хранилища Azurite:
azurite -l azurite -d azurite\debug.logУбедитесь, что в
AzureWebJobsStorageзначение установлено наUseDevelopmentStorage=true.
Настройка конфигурации Web PubSub для Socket.IO
Добавьте строку подключения в приложение-функцию.
func settings add WebPubSubForSocketIOConnectionString "<connection string>"
Запуск примера приложения
После запуска средства туннеля можно локально запустить функциональное приложение:
func start
И посетите веб-страницу по адресу http://localhost:7071/api/index.
Дальнейшие шаги
Затем можно попытаться использовать Bicep для развертывания приложения в Сети с проверкой подлинности на основе удостоверений: