💾 Archived View for tilde.team › ~gryffyn › posts › golang-pubsubhubbub captured on 2021-12-03 at 14:04:38. Gemini links have been rewritten to link to archived content
-=-=-=-=-=-=-
The only way, as far as I can tell, to get push notifications from the youtube API is to use google's Pubsubhubbub hub. We're not even a sentence in and I'm already so done with calling it that, so I'm just going to call it PH from now on.
A basic client needs to do two things - implement a GET handler, and a POST handler. The GET handler is used for subscribing and unsubscribing, and the POST handler is for PH to push updates to.
The GET handler needs to return the PH challenge --
func parseGET(w http.ResponseWriter, r *http.Request) { queries, _ := url.ParseQuery(r.URL.RawQuery) _, err := w.Write([]byte(queries.Get("hub.challenge"))) err = r.Body.Close() if err != nil { log.Fatal(err) } }
The POST handler will accept XML containing the PH event data.
func parsePOST(w http.ResponseWriter, r *http.Request) { //... parse XML in r.Body w.WriteHeader(204) // PH uses 204 to indicate successful pushes. err = r.Body.Close() if err != nil { log.Fatal(err) } }
Then we just need a router to handle the handlers --
func makeMuxRouter(loc string) http.Handler { r := mux.NewRouter().StrictSlash(true) r.HandleFunc(loc, parseGET).Methods("GET") r.HandleFunc(loc, parsePOST).Methods("POST") return r }
All that's left is to create an HTTP server, assign the router, and run it.
handlr := makeMuxRouter("/location") server := &http.Server{ Handler: handlr, //... rest of the Server{} } server.ListenAndServe()
will let you subscribe to topics. Set your `https://your-domain.tld/location` as the callback URL.
---
as a little bonus: here's a struct that maps the XML from youtube's `videos.xml` feed.
type Feed struct { XMLName xml.Name `xml:"feed"` Text string `xml:",chardata"` Yt string `xml:"yt,attr"` Xmlns string `xml:"xmlns,attr"` Link []struct { Text string `xml:",chardata"` Rel string `xml:"rel,attr"` Href string `xml:"href,attr"` } `xml:"link"` Title string `xml:"title"` Updated string `xml:"updated"` Entry struct { Text string `xml:",chardata"` ID string `xml:"id"` VideoId string `xml:"videoId"` ChannelId string `xml:"channelId"` Title string `xml:"title"` Link struct { Text string `xml:",chardata"` Rel string `xml:"rel,attr"` Href string `xml:"href,attr"` } `xml:"link"` Author struct { Text string `xml:",chardata"` Name string `xml:"name"` URI string `xml:"uri"` } `xml:"author"` Published string `xml:"published"` Updated string `xml:"updated"` } `xml:"entry"` }