philippseith / signalr

SignalR server and client in go
MIT License
131 stars 39 forks source link

Code Complete Server/Client Example #163

Closed mattBrzezinski closed 1 year ago

mattBrzezinski commented 1 year ago

šŸ‘‹ Hi, I'm pretty new to Go and came across this package.

I was working through the README trying to setup a local server and client, but kept running into issues. I was wondering if you could amend the example to have a code complete solution for both parts to showcase the project. As someone who is new to Go it's a bit confusing as what is actually required to create these components. Right now I have...

Server

package main

import (
    "context"
    "fmt"
    "log"
    "net/http"
    "os"
    "time"

    kitlog "github.com/go-kit/log"
    "github.com/philippseith/signalr"
)

type replayserver struct {
    signalr.Hub
}

func Serve(ctx context.Context) (string, error) {
    address := "localhost:8080"
    hub := receiver{}

    server, _ := signalr.NewServer(
        context.TODO(),
        signalr.SimpleHubFactory(&hub),
        signalr.KeepAliveInterval(2*time.Second),
        signalr.Logger(kitlog.NewLogfmtLogger(os.Stdout), true),
    )

    router := http.NewServeMux()
    server.MapHTTP(signalr.WithHTTPServeMux(router), "/negotiate")  // README was problematic here, where attempting to connect would immediate result in a failed to connect to /negotiate in the Client

    fmt.Printf("Listening for websocket connections on http://%s\n", address)

    if err := http.ListenAndServe(address, router); err != nil {
        log.Fatal("ListenAndServe:", err)
    }

    time.Sleep(5 * time.Second)
    hub.Clients().Caller().Send("update", "Hello from server")

    return "", nil
}

func main() {
    ctx := context.Background()
    Serve(ctx)
}

Client

package main

import (
    "context"
    "fmt"
    "time"
    "github.com/philippseith/signalr"
)

type client struct {
    signalr.Hub
}

func Listen(ctx context.Context) (string, error) {
    address := "http://localhost:8080"
    creationCtx, _ := context.WithTimeout(ctx, 2*time.Second)
    conn, err := signalr.NewHTTPConnection(creationCtx, address)

    if err != nil {
        fmt.Println(err)
        return "Errored connecting to addr", err
    }

    client, err := signalr.NewClient(
        ctx,
        signalr.WithConnection(conn),
        signalr.WithReceiver(&client{}),
    )

    if err != nil {
        return "Errored creating client", err
    }

    client.Start()
    ch := <-client.Invoke("update", "/data")
    fmt.Println(ch)
    return "done.", nil
}

func main() {
    ctx := context.Background()
    Listen(ctx)
}

When I run the server in a terminal session we sit around Listening for websocket connections on http://localhost:8080, when I try to launch the client, I'm getting an error,

POST http://localhost:8080/negotiate -> 400 Bad Request

I'll note that in the server if I change the .MapHTTP to serve on something like /data as the README shows I'll get back the following from the Client,

POST http://localhost:8080/negotiate -> 404 Not Found

philippseith commented 1 year ago
server.MapHTTP(signalr.WithHTTPServeMux(router), "/negotiate")  // README was problematic here, where attempting to connect would immediate result in a failed to connect to /negotiate in the Client

The server in the readme servers the "/chat" address and the client also addresses "/chat", not "/negotitate". negotiate is a internal sub-path used by signalr over http to negotiate which transport to use. I aligned the the paths for the http server and client in doc.go, because there is already a sample for a server/client pair, both written in go. In the readme I like to have a javascript/browser client, because that seems to me the most probable use case.

The doc at https://pkg.go.dev/github.com/philippseith/signalr#section-documentation will not be updated directly but after some time when google scrapes over this repo the next time.