Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
Este tutorial orienta você sobre como publicar dados para clientes de Socket.IO no modo sem servidor, usando Python, criando um aplicativo de índice NASDAQ em tempo real integrado ao Azure Functions.
Encontre exemplos de código completo que são usados neste tutorial:
Importante
O Modo Padrão precisa de um servidor persistente, você não pode integrar o Web PubSub para Socket.IO no modo padrão com o Azure Function.
Pré-requisitos
- Uma conta do Azure com uma assinatura ativa. Se você não tiver uma, poderá criar uma conta gratuita.
- Ferramenta principal do Azure Function
- Alguma familiaridade com a biblioteca de Socket.IO.
Criar um recurso Web PubSub para Socket.IO no Modo Sem Servidor
Para criar um Web PubSub para Socket.IO, você pode usar o seguinte comando da CLI do Azure:
az webpubsub create -g <resource-group> -n <resource-name>---kind socketio --service-mode serverless --sku Premium_P1
Criar um projeto do Azure Function localmente
Você deve seguir as etapas para iniciar um projeto local do Azure Function.
Siga a etapa para instalar a ferramenta principal mais recente do Azure Function
Na janela do terminal ou em um prompt de comando, execute o seguinte comando para criar um projeto na pasta
SocketIOProject:func init SocketIOProject --worker-runtime pythonEsse comando cria um projeto de função baseado em Python. E insira a pasta
SocketIOProjectpara executar os comandos a seguir.Atualmente, o Pacote de Function não inclui Socket.IO Vinculação do Function, portanto, você precisa adicionar manualmente o pacote.
Para eliminar a referência do pacote de funções, edite o arquivo host.json e remova as linhas a seguir.
"extensionBundle": { "id": "Microsoft.Azure.Functions.ExtensionBundle", "version": "[4.*, 5.0.0)" }Execute o comando:
func extensions install -p Microsoft.Azure.WebJobs.Extensions.WebPubSubForSocketIO -v 1.0.0-beta.4
Substitua o conteúdo
function_app.pypelos códigos: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')Aqui está a explicação dessas funções:
publish_data: essa função atualiza o índice NASDAQ a cada segundo com uma alteração aleatória e o transmite para clientes conectados com Socket.IO de Saída.negotiate: essa função responde a um resultado de negociação para o cliente.index: essa função retorna uma página HTML estática.
Em seguida, adicione um
index.htmlarquivoCrie o arquivo index.html com o conteúdo:
<!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>A parte chave no
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); }); }Primeiro, ele negocia com o Aplicativo de Funções para obter o URI e o caminho para o serviço. E registre um callback para atualizar o índice.
Para executar o aplicativo localmente
Depois que o código é preparado, siga as instruções para executar o exemplo.
Configurar o Armazenamento do Azure para o Azure Function
O Azure Functions exige uma conta de armazenamento para funcionar, mesmo em execução local. Escolha uma das duas opções a seguir:
- Execute o emulador Azurite gratuito.
- Use o serviço de Armazenamento do Microsoft Azure. Isso poderá incorrer em custos se você continuar a usá-lo.
Instalar o Azurite
npm install -g azuriteInicie o emulador de armazenamento do Azurite:
azurite -l azurite -d azurite\debug.logGaranta que o
AzureWebJobsStorageem local.settings.json está definido comoUseDevelopmentStorage=true.
Definir a configuração do Web PubSub para Socket.IO
Adicionar cadeia de conexão ao APLICATIVO Function:
func settings add WebPubSubForSocketIOConnectionString "<connection string>"
Executar o aplicativo de exemplo
Depois que a ferramenta de túnel estiver em execução, você poderá executar o Aplicativo Function localmente:
func start
E visite a página da Web em http://localhost:7071/api/index.
Próximas etapas
Em seguida, você pode tentar usar o Bicep para implantar o aplicativo online com autenticação baseada em identidade: