yznts / kyoto

Asynchronous frontends with Go
https://pkg.go.dev/github.com/yznts/kyoto/v3
MIT License
651 stars 28 forks source link

Better Actions protocol implementation #99

Closed yznts closed 2 years ago

yznts commented 2 years ago

Current approach is far from ideal. State and arguments are passed in SSE query, response must to be base64 encoded to avoid newlines issue (which increases the size of the response).

Websockets cannot be considered:

yznts commented 2 years ago

It's possible to use "chunked" transfer encoding to deliver multiple UI updates.

Example go server:

package main

import (
    "compress/gzip"
    "net/http"
    "time"
)

func main() {
    http.HandleFunc("/", func(rw http.ResponseWriter, r *http.Request) {
        rw.Header().Set("Content-Type", "application/octet-stream")
        rw.Header().Set("Content-Encoding", "gzip")
        rw.Header().Set("Transfer-Encoding", "chunked")
        rw.Header().Set("Access-Control-Allow-Origin", "*")

        writer := gzip.NewWriter(rw)

        writer.Write([]byte("Hello, World 1"))
        writer.Flush()
        rw.(http.Flusher).Flush()
        time.Sleep(time.Second)
        writer.Write([]byte("Hello, World 2"))
        writer.Flush()
        rw.(http.Flusher).Flush()
        time.Sleep(time.Second)
        writer.Write([]byte("Hello, World 3"))
        writer.Flush()
        rw.(http.Flusher).Flush()
        time.Sleep(time.Second)
        writer.Write([]byte("Hello, World 4"))
        writer.Flush()
        rw.(http.Flusher).Flush()
    })

    http.ListenAndServe("localhost:8080", nil)
}

Example JS client:

const response = await fetch('http://localhost:8080');
const reader = response.body.pipeThrough(new TextDecoderStream()).getReader();

while (true) {
    const { value, done } = await reader.read();
    if (done) {
        break
    }
    console.log(value)
}

console.log('end')
yznts commented 2 years ago

Marking as a good first issue. if someone is ready to take, just contact me directly for more information on that.

yznts commented 2 years ago

Better to do that without gzip encoding on handler side, leave it to middlewares.