Aracılığıyla paylaş


Öğretici: Python ile Azure İşlevi'nde Sunucusuz Modda Socket.IO istemcilere veri yayımlama (Önizleme)

Bu öğretici, Azure İşlevi ile tümleşik gerçek zamanlı bir NASDAQ dizin uygulaması oluşturarak Python'da Sunucusuz Modda Socket.IO istemcilere veri yayımlama konusunda size yol gösterir.

Bu öğreticide kullanılan tam kod örneklerini bulun:

Önemli

Varsayılan Mod kalıcı bir sunucuya ihtiyaç duyar; Azure İşlevi ile varsayılan modda Socket.IO için Web PubSub tümleştirmesi yapamazsınız.

Önkoşullar

Sunucusuz Modda Socket.IO kaynağı için Web PubSub oluşturma

Socket.IO için bir Web PubSub oluşturmak için aşağıdaki Azure CLI komutunu kullanabilirsiniz:

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

Yerel olarak Azure İşlevi projesi oluşturma

Yerel bir Azure İşlevi projesi başlatmak için adımları izlemeniz gerekir.

  1. En son Azure İşlevi çekirdek aracını yüklemek için adım adım izleyin

  2. Terminal penceresinde veya komut isteminden aşağıdaki komutu çalıştırarak klasörde bir proje SocketIOProject oluşturun:

    func init SocketIOProject --worker-runtime python
    

    Bu komut Python tabanlı bir İşlev projesi oluşturur. Aşağıdaki komutları çalıştırmak için klasörünü SocketIOProject girin.

  3. şu anda İşlev Paketi Socket.IO İşlev Bağlaması içermez, bu nedenle paketi el ile eklemeniz gerekir.

    1. İşlev paketi başvurularını ortadan kaldırmak için host.json dosyasını düzenleyin ve aşağıdaki satırları kaldırın.

      "extensionBundle": {
          "id": "Microsoft.Azure.Functions.ExtensionBundle",
          "version": "[4.*, 5.0.0)"
      }
      
    2. Komutu çalıştırın:

      func extensions install -p Microsoft.Azure.WebJobs.Extensions.WebPubSubForSocketIO -v 1.0.0-beta.4
      
  4. içindeki function_app.py içeriği kodlarla değiştirin:

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

    Bu işlevlerin açıklaması aşağıdadır:

    • publish_data: Bu işlev NASDAQ dizinini her saniye rastgele bir değişiklikle güncelleştirir ve Socket.IO Çıkış Bağlaması ile bağlı istemcilere yayınlar.

    • negotiate: Bu işlev istemciye bir anlaşma sonucu yanıtlar.

    • index: Bu işlev statik bir HTML sayfası döndürür.

    Ardından bir index.html dosya ekleyin

    İçerikle index.html dosyasını oluşturun:

    <!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 içindeki önemli bölüm

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

    İlk olarak İşlev Uygulaması ile iletişim kurarak URI ve hizmete giden yolu almak için müzakere eder. Dizini güncelleştirmek için bir geri çağırma kaydedin.

Uygulamayı yerel olarak çalıştırma

Kod hazırlandıktan sonra, örneği çalıştırma yönergelerini izleyin.

Azure İşlevi için Azure Depolama'yı ayarlama

Azure İşlevleri, yerel ortamda çalışan bir depolama hesabının bile çalışmasını gerektirir. Aşağıdaki iki seçenek arasından birini belirleyin:

  • Ücretsiz Azurite öykünücüsü çalıştırın.
  • Azure Depolama hizmetini kullanın. Kullanmaya devam ederseniz bu maliyete neden olabilir.
  1. Azurite'yi yükleme

    npm install -g azurite
    
  2. Azurite depolama öykünücüsİnİ başlatın:

    azurite -l azurite -d azurite\debug.log
    
  3. local.settings.json değerinin AzureWebJobsStorageolarak ayarlandığından UseDevelopmentStorage=trueemin olun.

Socket.IO için Web PubSub yapılandırmasını ayarlama

İşlev UYGULAMASına bağlantı dizesi ekleyin:

func settings add WebPubSubForSocketIOConnectionString "<connection string>"

Örnek Uygulamayı Çalıştırma

Tünel aracı çalıştırıldıktan sonra İşlev Uygulamasını yerel olarak çalıştırabilirsiniz:

func start

Ve adresinden http://localhost:7071/api/indexweb sayfasını ziyaret edin.

Uygulamanın ekran görüntüsü.

Sonraki Adımlar

Ardından, uygulamayı kimlik tabanlı kimlik doğrulamasıyla çevrimiçi dağıtmak için Bicep'i kullanmayı deneyebilirsiniz: