github.com/angenalZZZ/gofunc@v0.0.0-20210507121333-48ff1be3917b/http/longpoll/examples/basic/basic.go (about)

     1  // This is a basic example of how to use longpoll.
     2  //
     3  // In this example, we'll generate some random events and provide a way for
     4  // browsers to subscribe to those events.
     5  //
     6  // To run this example:
     7  //   go build examples/basic/basic.go
     8  // Then run the binary and visit http://127.0.0.1:8081/basic
     9  //
    10  // A couple of notes:
    11  //   - In this example, event payloads are string data, but they can be anything
    12  //     that is convert-able to JSON (passes encoding/json's Marshal() function)
    13  //
    14  //   - LongpollManager.SubscriptionHandler is directly bound to a http handler.
    15  //     But there's no reason why you can't wrap that handler in your own
    16  //     function to add a layer of validation, access control, or whatever else
    17  //     you can think up.  See the advanced example on how to do this.
    18  //
    19  //   - Our events are simple and randomly generated in a goroutine, but you can
    20  //     create events anywhere and anyhow as long as you pass a reference to the
    21  //     LongpollManager and just call Publish().  Maybe you have a goroutine that
    22  //     checks the weather, a stock price, or something cool.  Or you can even
    23  //     have another http handler that calls Publish().  To do this, you must
    24  //     capture the manager reference in a closure.  See the advanced example.
    25  //
    26  package main
    27  
    28  import (
    29  	"fmt"
    30  	"github.com/angenalZZZ/gofunc/http/longpoll"
    31  	"log"
    32  	"math/rand"
    33  	"net/http"
    34  	"time"
    35  )
    36  
    37  func main() {
    38  	manager, err := longpoll.StartLongpoll(longpoll.Options{
    39  		LoggingEnabled: true,
    40  		// NOTE: if not defined here, other options have reasonable defaults,
    41  		// so no need specifying options you don't care about
    42  	})
    43  	if err != nil {
    44  		log.Fatalf("Failed to create manager: %q", err)
    45  	}
    46  	// pump out random events
    47  	go generateRandomEvents(manager)
    48  	// Serve our basic example driver webpage
    49  	http.HandleFunc("/basic", BasicExampleHomepage)
    50  
    51  	// Serve our event subscription web handler
    52  	http.HandleFunc("/basic/events", manager.SubscriptionHandler)
    53  
    54  	fmt.Println("Serving webpage at http://127.0.0.1:8081/basic")
    55  	http.ListenAndServe("127.0.0.1:8081", nil)
    56  
    57  	// We'll never get here as long as http.ListenAndServe starts successfully
    58  	// because it runs until you kill the program (like pressing Control-C)
    59  	// Buf if you make a stoppable http server, or want to shut down the
    60  	// internal longpoll manager for other reasons, you can do so via
    61  	// Shutdown:
    62  	manager.Shutdown() // Stops the internal goroutine that provides subscription behavior
    63  	// Again, calling shutdown is a bit silly here since the goroutines will
    64  	// exit on main() exit.  But I wanted to show you that it is possible.
    65  }
    66  
    67  func generateRandomEvents(lpManager *longpoll.LongpollManager) {
    68  	farm_events := []string{
    69  		"Cow says 'Moooo!'",
    70  		"Duck went 'Quack!'",
    71  		"Chicken says: 'Cluck!'",
    72  		"Goat chewed grass.",
    73  		"Pig went 'Oink! Oink!'",
    74  		"Horse ate hay.",
    75  		"Tractor went: Vroom Vroom!",
    76  		"Farmer ate bacon.",
    77  	}
    78  	// every 0-5 seconds, something happens at the farm:
    79  	for {
    80  		time.Sleep(time.Duration(rand.Intn(5000)) * time.Millisecond)
    81  		lpManager.Publish("farm", farm_events[rand.Intn(len(farm_events))])
    82  	}
    83  }
    84  
    85  // Here we're providing a webpage that shows events as they happen.
    86  // In this code you'll see a sample of how to implement longpolling on the
    87  // client side in javascript.  I used jquery here...
    88  //
    89  // I was too lazy to serve this file statically.
    90  // This is me setting a bad example :)
    91  func BasicExampleHomepage(w http.ResponseWriter, r *http.Request) {
    92  	fmt.Fprintf(w, `
    93  <html>
    94  <head>
    95      <title>golongpoll basic example</title>
    96  </head>
    97  <body>
    98      <h1>golongpoll basic example</h1>
    99      <h2>Here's whats happening around the farm:</h2>
   100      <ul id="animal-events"></ul>
   101  <script src="http://code.jquery.com/jquery-1.11.3.min.js"></script>
   102  <script>
   103  
   104      // for browsers that don't have console
   105      if(typeof window.console == 'undefined') { window.console = {log: function (msg) {} }; }
   106  
   107      // Start checking for any events that occurred after page load time (right now)
   108      // Notice how we use .getTime() to have num milliseconds since epoch in UTC
   109      // This is the time format the longpoll server uses.
   110      var sinceTime = (new Date(Date.now())).getTime();
   111  
   112      // Let's subscribe to animal related events.
   113      var category = "farm";
   114  
   115      (function poll() {
   116          var timeout = 45;  // in seconds
   117          var optionalSince = "";
   118          if (sinceTime) {
   119              optionalSince = "&since_time=" + sinceTime;
   120          }
   121          var pollUrl = "/basic/events?timeout=" + timeout + "&category=" + category + optionalSince;
   122          // how long to wait before starting next longpoll request in each case:
   123          var successDelay = 10;  // 10 ms
   124          var errorDelay = 3000;  // 3 sec
   125          $.ajax({ url: pollUrl,
   126              success: function(data) {
   127                  if (data && data.events && data.events.length > 0) {
   128                      // got events, process them
   129                      // NOTE: these events are in chronological order (oldest first)
   130                      for (var i = 0; i < data.events.length; i++) {
   131                          // Display event
   132                          var event = data.events[i];
   133                          $("#animal-events").append("<li>" + event.data + " at " + (new Date(event.timestamp).toLocaleTimeString()) +  "</li>")
   134                          // Update sinceTime to only request events that occurred after this one.
   135                          sinceTime = event.timestamp;
   136                      }
   137                      // success!  start next longpoll
   138                      setTimeout(poll, successDelay);
   139                      return;
   140                  }
   141                  if (data && data.timeout) {
   142                      console.log("No events, checking again.");
   143                      // no events within timeout window, start another longpoll:
   144                      setTimeout(poll, successDelay);
   145                      return;
   146                  }
   147                  if (data && data.error) {
   148                      console.log("Error response: " + data.error);
   149                      console.log("Trying again shortly...")
   150                      setTimeout(poll, errorDelay);
   151                      return;
   152                  }
   153                  // We should have gotten one of the above 3 cases:
   154                  // either nonempty event data, a timeout, or an error.
   155                  console.log("Didn't get expected event data, try again shortly...");
   156                  setTimeout(poll, errorDelay);
   157              }, dataType: "json",
   158          error: function (data) {
   159              console.log("Error in ajax request--trying again shortly...");
   160              setTimeout(poll, errorDelay);  // 3s
   161          }
   162          });
   163      })();
   164  </script>
   165  </body>
   166  </html>`)
   167  }