Raw Messages

Raw messages menyediakan saluran komunikasi level rendah antara frontend dan backend Anda, melewati sistem binding standar. Ini menukar kenyamanan demi kecepatan.

Kapan Menggunakan Raw Messages

Raw messages paling cocok untuk kasus edge yang ekstrem:

  • Pembaruan frekuensi ultra-tinggi - Ribuan pesan per detik di mana setiap mikrodetik penting
  • Protokol pesan kustom - Saat Anda memerlukan kontrol penuh atas format wire

Setup Backend

Konfigurasi RawMessageHandler di opsi aplikasi Anda:

package main

import (
    "encoding/json"
    "fmt"

    "github.com/wailsapp/wails/v3/pkg/application"
)

func main() {
    app := application.New(application.Options{
        Name: "Raw Message Demo",
        Assets: application.AssetOptions{
            Handler: application.BundledAssetFileServer(assets),
        },
        RawMessageHandler: func(window application.Window, message string, originInfo *application.OriginInfo) {
            fmt.Printf("Raw message from window '%s': %s (origin: %+v)\n", window.Name(), message, originInfo.Origin)

            // Proses pesan dan respons via event
            response := processMessage(message)
            window.EmitEvent("raw-response", response)
        },
    })

    app.Window.NewWithOptions(application.WebviewWindowOptions{
        Title: "My App",
        Name:  "main",
    })

    app.Run()
}

func processMessage(message string) map[string]any {
    // Logika pemrosesan pesan kustom Anda
    return map[string]any{
        "received": message,
        "status":   "processed",
    }
}

Signature Handler

RawMessageHandler func(window Window, message string, originInfo *application.OriginInfo)
Parameter Tipe Deskripsi
window Window Window yang mengirim pesan
message string Konten pesan mentah
originInfo *application.OriginInfo Informasi origin tentang sumber pesan

Struktur OriginInfo

type OriginInfo struct {
	Origin      string
	TopOrigin   string
	IsMainFrame bool
}
Field Tipe Deskripsi
Origin string URL origin dokumen yang mengirim pesan
TopOrigin string URL origin level atas (mungkin berbeda dari Origin di iframe)
IsMainFrame bool Apakah pesan berasal dari main frame

Ketersediaan Spesifik Platform

  • macOS: Origin dan IsMainFrame disediakan
  • Windows: Origin dan TopOrigin disediakan
  • Linux: Hanya Origin yang disediakan

Validasi Origin

Selalu verifikasi origin pesan masuk sebelum memprosesnya. Parameter originInfo menyediakan informasi keamanan kritis yang harus divalidasi untuk mencegah akses tidak sah. Konten berbahaya, konten yang dikompromikan, atau skrip yang tidak diinginkan dapat mengirim raw message. Tanpa validasi origin, Anda mungkin memproses perintah dari sumber tidak tepercaya. Gunakan originInfo untuk memastikan pesan berasal dari sumber yang diharapkan.

Poin Validasi Utama

  • Selalu periksa Origin - Verifikasi origin cocok dengan sumber tepercaya yang diharapkan (biasanya wails://wails atau http://wails.localhost untuk asset lokal atau origin spesifik aplikasi Anda)
  • Validasi IsMainFrame (macOS) - Waspadai jika pesan berasal dari iframe, karena ini mungkin menunjukkan konten tersemat dengan konteks keamanan berbeda
  • Gunakan TopOrigin (Windows) - Verifikasi origin level atas saat menangani konten ber-frame
  • Tolak origin yang tidak diharapkan - Gagal dengan aman dengan menolak pesan dari origin yang tidak Anda izinkan secara eksplisit

Setup Frontend

Kirim raw message menggunakan System.invoke():

<!DOCTYPE html>
<html>
<head>
    <script type="module">
        import { System, Events } from '@wailsio/runtime'

        // Kirim raw message
        document.getElementById('send').addEventListener('click', () => {
            const message = document.getElementById('input').value
            System.invoke(message)
        })

        // Dengarkan respons
        Events.On('raw-response', (event) => {
            console.log('Response:', event.data)
        })
    </script>
</head>
<body>
    <input type="text" id="input" placeholder="Enter message" />
    <button id="send">Send</button>
</body>
</html>

Menggunakan Bundle Siap Pakai

Jika Anda tidak menggunakan npm, akses invoke melalui objek global wails:

<script type="module" src="/wails/runtime.js"></script>
<script>
    window.onload = function() {
        document.getElementById('send').onclick = function() {
            wails.System.invoke('my-message')
        }
    }
</script>

Pesan Terstruktur

Untuk data kompleks, serialisasi ke JSON:

Frontend

import { System } from '@wailsio/runtime'

const command = {
    action: 'update',
    payload: {
        id: 123,
        value: 'new value'
    }
}

System.invoke(JSON.stringify(command))

Backend

RawMessageHandler: func(window application.Window, message string, originInfo *application.OriginInfo) {
    var cmd struct {
        Action  string `json:"action"`
        Payload struct {
            ID    int    `json:"id"`
            Value string `json:"value"`
        } `json:"payload"`
    }

    if err := json.Unmarshal([]byte(message), &cmd); err != nil {
        window.EmitEvent("error", err.Error())
        return
    }

    switch cmd.Action {
    case "update":
        // Tangani update
        result := handleUpdate(cmd.Payload.ID, cmd.Payload.Value)
        window.EmitEvent("update-complete", result)
    default:
        window.EmitEvent("error", "unknown action")
    }
}

Perbandingan Performa

Pendekatan Overhead Type Safety Kasus Penggunaan
Service Bindings Lebih tinggi Penuh Tujuan umum
Raw Messages Minimal Manual Frekuensi tinggi, kritis performa

Contoh Benchmark

Raw messages dapat memproses jauh lebih banyak pesan per detik dibandingkan service bindings untuk payload sederhana:

// Raw message handler - overhead minimal
RawMessageHandler: func(window application.Window, message string, originInfo *application.OriginInfo) {
    // Pemrosesan string langsung, tanpa reflection atau marshaling
    counter++
}

Contoh Lengkap

Berikut contoh lengkap yang mengimplementasikan protokol perintah sederhana:

main.go

package main

import (
    "embed"
    "encoding/json"
    "fmt"
    "time"

    "github.com/wailsapp/wails/v3/pkg/application"
)

//go:embed assets
var assets embed.FS

type Command struct {
    Type string          `json:"type"`
    Data json.RawMessage `json:"data"`
}

func main() {
    app := application.New(application.Options{
        Name: "Raw Message Demo",
        Assets: application.AssetOptions{
            Handler: application.BundledAssetFileServer(assets),
        },
        Mac: application.MacOptions{
            ApplicationShouldTerminateAfterLastWindowClosed: true,
        },
        RawMessageHandler: func(window application.Window, message string, originInfo *application.OriginInfo) {
            var cmd Command
            if err := json.Unmarshal([]byte(message), &cmd); err != nil {
                window.EmitEvent("error", map[string]string{"error": err.Error()})
                return
            }

            switch cmd.Type {
            case "ping":
                window.EmitEvent("pong", map[string]any{
                    "time":   time.Now().UnixMilli(),
                    "window": window.Name(),
                })
            case "echo":
                var text string
                json.Unmarshal(cmd.Data, &text)
                window.EmitEvent("echo", text)
            default:
                window.EmitEvent("error", map[string]string{
                    "error": fmt.Sprintf("unknown command: %s", cmd.Type),
                })
            }
        },
    })

    app.Window.NewWithOptions(application.WebviewWindowOptions{
        Title: "Raw Message Demo",
        Name:  "main",
        Width: 400,
        Height: 300,
    })

    app.Run()
}

assets/index.html

<!DOCTYPE html>
<html>
<head>
    <title>Raw Message Demo</title>
    <style>
        body { font-family: sans-serif; padding: 20px; }
        button { margin: 5px; padding: 10px 20px; }
        #output { margin-top: 20px; padding: 10px; background: #f0f0f0; }
    </style>
</head>
<body>
    <h1>Raw Message Demo</h1>

    <button id="ping">Ping</button>
    <button id="echo">Echo "Hello"</button>

    <div id="output">Waiting for response...</div>

    <script type="module">
        import { System, Events } from '@wailsio/runtime'

        const output = document.getElementById('output')

        function send(type, data) {
            System.invoke(JSON.stringify({ type, data }))
        }

        document.getElementById('ping').onclick = () => send('ping')
        document.getElementById('echo').onclick = () => send('echo', 'Hello')

        Events.On('pong', (e) => {
            output.textContent = `Pong from ${e.data.window} at ${e.data.time}`
        })

        Events.On('echo', (e) => {
            output.textContent = `Echo: ${e.data}`
        })

        Events.On('error', (e) => {
            output.textContent = `Error: ${e.data.error}`
        })
    </script>
</body>
</html>

Praktik Terbaik

Lakukan

  • Gunakan raw messages untuk jalur yang benar-benar kritis performa
  • Implementasikan penanganan error yang benar di handler Anda
  • Gunakan event untuk mengirim respons kembali ke frontend
  • Pertimbangkan JSON untuk data terstruktur
  • Jaga pemrosesan pesan tetap cepat agar tidak blocking

Jangan

  • Gunakan raw messages saat service bindings sudah cukup
  • Lupa memvalidasi pesan masuk
  • Blocking di handler dengan operasi berjalan lama (gunakan goroutine)
  • Abaikan parameter window saat respons perlu menarget window tertentu

Pertimbangan Multi-Window

Parameter window mengidentifikasi window mana yang mengirim pesan, memungkinkan Anda untuk:

  • Mengirim respons ke window yang benar
  • Mengimplementasikan perilaku spesifik window
  • Melacak sumber pesan untuk debugging
RawMessageHandler: func(window application.Window, message string, originInfo *application.OriginInfo) {
    // Respons hanya ke window pengirim
    window.EmitEvent("response", result)

    // Atau broadcast ke semua window
    app.Event.Emit("broadcast", result)
}

Langkah Selanjutnya

  • Service Bindings - Pendekatan standar untuk sebagian besar aplikasi
  • Events - Sistem event untuk komunikasi backend-ke-frontend
  • Performance - Optimasi performa umum
Edit page

Last updated: