Oktatóanyag: Adatok közzététele Socket.IO ügyfelek számára kiszolgáló nélküli módban az Azure-függvényben Pythonnal (előzetes verzió)

Ez az oktatóanyag végigvezet azon, hogyan tehet közzé adatokat Socket.IO ügyfelek számára kiszolgáló nélküli módban Pythonban, egy valós idejű NASDAQ indexalkalmazást hozva létre, amely az Azure Functionnel van integrálva.

Az oktatóanyagban használt teljes kódminták keresése:

Fontos

Az alapértelmezett módhoz állandó kiszolgáló szükséges, ezért nem tudja integrálni a Web PubSubot a Socket.IO-hoz alapértelmezett módban az Azure Function-nel.

Előfeltételek

Web PubSub létrehozása Socket.IO erőforráshoz kiszolgáló nélküli módban

Web PubSub Socket.IO létrehozásához az alábbi Azure CLI-parancsot használhatja:

az webpubsub create -g <resource-group> -n <resource-name>---kind socketio --service-mode serverless --sku Premium_P1

Azure-függvényprojekt helyi létrehozása

A helyi Azure-függvényprojekt elindításához kövesse az alábbi lépéseket.

  1. Kövesse a lépést a legújabb Azure Function Core-eszköz telepítéséhez

  2. A terminálablakban vagy egy parancssorból futtassa a következő parancsot egy projekt létrehozásához a SocketIOProject mappában:

    func init SocketIOProject --worker-runtime python
    

    Ez a parancs létrehoz egy Python-alapú függvényprojektet. Lépjen be a mappába SocketIOProject, hogy futtassa a következő parancsokat.

  3. A függvénycsomag jelenleg nem tartalmazza Socket.IO függvénykötést, ezért manuálisan kell hozzáadnia a csomagot.

    1. A függvénycsomag hivatkozásának megszüntetéséhez szerkessze a host.json fájlt, és távolítsa el a következő sorokat.

      "extensionBundle": {
          "id": "Microsoft.Azure.Functions.ExtensionBundle",
          "version": "[4.*, 5.0.0)"
      }
      
    2. Futtassa a következő parancsot:

      func extensions install -p Microsoft.Azure.WebJobs.Extensions.WebPubSubForSocketIO -v 1.0.0-beta.4
      
  4. A function_app.py tartalmát cserélje le a következő kódokra:

    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')
    

    A következő függvények magyarázata:

    • publish_data: Ez a függvény másodpercenként frissíti a NASDAQ-indexet véletlenszerű módosítással, és Socket.IO kimeneti kötéssel rendelkező csatlakoztatott ügyfelekre irányítja.

    • negotiate: Ez a függvény egy tárgyalási eredményt ad vissza az ügyfélnek.

    • index: Ez a függvény egy statikus HTML-lapot ad vissza.

    Ezután adjon hozzá egy index.html fájlt

    Hozza létre a index.html fájlt a következő tartalommal:

    <!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 kulcselem a index.html következőben:

    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);
        });
    }
    

    Először egyeztet a függvényalkalmazással, hogy lekérje az URI-t és a szolgáltatás elérési útját. Regisztráljon visszahívást az index frissítésére.

Az alkalmazás helyi futtatása

A kód elkészítése után kövesse a minta futtatására vonatkozó utasításokat.

Az Azure Storage beállítása az Azure Functions-hoz

Az Azure Functions használatához egy tárfiókra van szükség, amely helyi környezetben is fut. Válasszon a következő két lehetőség közül:

  • Futtassa az ingyenes Azurite emulátort.
  • Használja az Azure Storage szolgáltatást. Ez költségekkel járhat, ha továbbra is használja.
  1. Az Azurite telepítése

    npm install -g azurite
    
  2. Indítsa el az Azurite Storage emulátort:

    azurite -l azurite -d azurite\debug.log
    
  3. Győződjön meg arról, hogy a AzureWebJobsStorage a local.settings.json-ben arra van állítva, hogy UseDevelopmentStorage=true.

Web PubSub konfiguráció beállítása a Socket.IO-hoz

Kapcsolati szöveg hozzáadása a funkcióalkalmazáshoz:

func settings add WebPubSubForSocketIOConnectionString "<connection string>"

Futtassa a mintaalkalmazást

Az alagúteszköz futtatása után helyileg futtathatja a függvényalkalmazást:

func start

És látogasson el a weblapra a következő címen http://localhost:7071/api/index: .

Az alkalmazás képernyőképe.

Következő lépések

Ezután megpróbálhatja a Bicep használatával online üzembe helyezni az alkalmazást identitásalapú hitelesítéssel: