diff --git a/examples/longpoll/redirect-client.go b/examples/longpoll/redirect-client.go new file mode 100644 index 00000000..d9fb0822 --- /dev/null +++ b/examples/longpoll/redirect-client.go @@ -0,0 +1,52 @@ +// This is an example longpoll client. The connection to the corresponding +// server initiates a request on a "Watch". It then waits until a redirect is +// received from the server which indicates that the watch is ready. To signal +// than an event on this watch has occurred, the server sends a final message. +package main + +import ( + "bytes" + "fmt" + "io/ioutil" + "log" + "math/rand" + "net/http" + "time" +) + +const ( + timeout = 15 +) + +func main() { + log.Printf("Starting...") + + checkRedirectFunc := func(req *http.Request, via []*http.Request) error { + log.Printf("Watch is ready!") + return nil + } + + client := &http.Client{ + Timeout: time.Duration(timeout) * time.Second, + CheckRedirect: checkRedirectFunc, + } + + id := rand.Intn(2 ^ 32 - 1) + body := bytes.NewBufferString("hello") + url := fmt.Sprintf("http://127.0.0.1:12345/watch?id=%d", id) + req, err := http.NewRequest("GET", url, body) + if err != nil { + log.Printf("err: %+v", err) + return + } + result, err := client.Do(req) + if err != nil { + log.Printf("err: %+v", err) + return + } + log.Printf("Event received: %+v", result) + + s, err := ioutil.ReadAll(result.Body) // TODO: apparently we can stream + result.Body.Close() + log.Printf("Response: %+v", string(s)) +} diff --git a/examples/longpoll/redirect-server.go b/examples/longpoll/redirect-server.go new file mode 100644 index 00000000..20939f60 --- /dev/null +++ b/examples/longpoll/redirect-server.go @@ -0,0 +1,56 @@ +// This is an example longpoll server. On client connection it starts a "Watch", +// and notifies the client with a redirect when that watch is ready. This is +// important to avoid a possible race between when the client believes the watch +// is actually ready, and when the server actually is watching. +package main + +import ( + "fmt" + "io" + "log" + "math/rand" + "net/http" + "time" +) + +// you can use `wget http://127.0.0.1:12345/hello -O /dev/null` +// or `go run client.go` +const ( + addr = ":12345" +) + +// WatchStart kicks off the initial watch and then redirects the client to +// notify them that we're ready. The watch operation here is simulated. +func WatchStart(w http.ResponseWriter, req *http.Request) { + log.Printf("Start received...") + time.Sleep(time.Duration(5) * time.Second) // 5 seconds to get ready and start *our* watch ;) + //started := time.Now().UnixNano() // time since watch is "started" + log.Printf("URL: %+v", req.URL) + + token := fmt.Sprintf("%d", rand.Intn(2^32-1)) + http.Redirect(w, req, fmt.Sprintf("/ready?token=%s", token), http.StatusSeeOther) // TODO: which code should we use ? + log.Printf("Redirect sent!") +} + +// WatchReady receives the client connection when it has been notified that the +// watch has started, and it returns to signal that an event on the watch +// occurred. The event operation here is simulated. +func WatchReady(w http.ResponseWriter, req *http.Request) { + log.Printf("Ready received") + log.Printf("URL: %+v", req.URL) + + //time.Sleep(time.Duration(10) * time.Second) + time.Sleep(time.Duration(rand.Intn(10)) * time.Second) // wait until an "event" happens + + io.WriteString(w, "Event happened!\n") + log.Printf("Event sent") +} + +func main() { + log.Printf("Starting...") + //rand.Seed(time.Now().UTC().UnixNano()) + http.HandleFunc("/watch", WatchStart) + http.HandleFunc("/ready", WatchReady) + log.Printf("Listening on %s", addr) + log.Fatal(http.ListenAndServe(addr, nil)) +}