sseserver icon indicating copy to clipboard operation
sseserver copied to clipboard

Provide stats per subscription channel

Open steddyman opened this issue 1 year ago • 5 comments

I'd love for a way to create an API endpoint when I can report how many active connections there are per listening subscirption, eg pets/cat and pets/dog separate.

I am running my owner server that in summary operates as per the code below. However, despite what the docs says, queries to /admin/ endpoints all return a 404 error:

func main() {
	fmt.Println("Starting pusher server")
	s := sseserver.NewServer()
	mux := http.NewServeMux()

	// Function called from pusher realtime microservice to update live mints
	mux.HandleFunc("/updatelive", func(w http.ResponseWriter, r *http.Request) {
        ...
        }

	mux.Handle("/subscribe/", s)
	http.ListenAndServe(":8110", mux)
}

steddyman avatar Nov 08 '23 22:11 steddyman

I would love if you could provide some feedback on this issue. Thanks

steddyman avatar Jan 01 '24 16:01 steddyman

Sorry for the delay here, I get a lot of GitHub notifications and I don't have a good way to triage the ones from humans vs bots currently.

I'm not sure why this wouldn't work. I do plan on changing this a bit in #18 and making the admin API an optional load from its own package (I do need to get around to that, but its below some other repos on my spare time priority list currently), but with the current setup, what you're doing should work...

I suspect it may have to do with how you're mounting the server in a mux. If you look at https://github.com/mroth/sseserver/blob/bcf7700eaad347406a6bef9385d2ab110c8f1def/server.go#L46-L58, you can see how in the current release version the http.Handler interface for server is basically just a mux for /subscribe and /admin mapped to respective handlers. So based on your sample code, I believe you may be mounting that mux as /subscribe/subscribe ? When you are running it now, can you access any of the endpoints? It would be helpful to see what endpoints you can hit at which paths, and which don't work.

mroth avatar Jan 02 '24 20:01 mroth

Thanks for the response @mroth I had found that code, but currently I am instantiating a mux in my own module, then using listenAndServce which doesn't include the mux for admin:

	mux.Handle("/subscribe/", s)
	http.ListenAndServe(":8110", mux)

I did try and add the adminHandler on my mux, but I don't think adminHandler is exposed on the module I am importing.

steddyman avatar Jan 02 '24 20:01 steddyman

This seems to have something to do with how the nested muxes work. I tried something very similar to your test code and can reproduce, but if I mount it at mux.Handle("/", s) it works as expected. While the future path is better with the v2 of this module, let me play around and see if I can figure out what's going on with this anyhow.

mroth avatar Jan 02 '24 22:01 mroth

Yeah, this is an issue as to how you're nesting the muxes. For example, I am testing with the following sample code where I mount the Server's http.Handler in a mux subpath:

func main() {
	mux := http.NewServeMux()
	s := sseserver.NewServer()

	mux.HandleFunc("/hello", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("hello world\n"))
	})
	mux.Handle("/sse/", http.StripPrefix("/sse", s))

	go func() {
		for {
			<-time.After(time.Second)
			s.Broadcast <- sseserver.SSEMessage{Data: []byte("moo"), Namespace: "/cow"}
		}
	}()

	if err := http.ListenAndServe("127.0.0.1:8000", mux); err != nil {
		log.Fatal(err)
	}
}

And can hit all the endpoints as nested:

❯ curl http://localhost:8000/hello
hello world
❯ curl http://localhost:8000/sse/subscribe/cow
data:moo

^C
❯ curl --head http://localhost:8000/sse/admin/
HTTP/1.1 200 OK
Accept-Ranges: bytes
Content-Length: 4899
Content-Type: text/html; charset=utf-8
Last-Modified: Tue, 22 Jul 2014 16:40:02 GMT
Date: Tue, 02 Jan 2024 22:45:10 GMT

Does that make sense?

mroth avatar Jan 02 '24 22:01 mroth