Last active
December 18, 2015 09:29
-
-
Save fcarriedo/5762125 to your computer and use it in GitHub Desktop.
HTML5 Server sent events demo implementation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<div class="msg"> | |
<h3>Msg</h3> | |
<p>This is the message: </p> | |
<p><i>{{.}}</i></p> | |
</div> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<html> | |
<head> | |
<style> | |
body {font-family: helvetica;} | |
#msgs .msg {float: left;} | |
.msg {font-size: 8pt; color: #666; background-color: #eee; padding: 2px; border-radius: 5px; width: 200px; margin: 0px 3px 3px 0px;} | |
</style> | |
<script> | |
window.onload = function() { | |
// Create the event source | |
var source = new EventSource("/stream"); | |
// On open/close events of the stream | |
source.onopen = function () { console.log('opened..') }; | |
source.onerror = function () { console.log('error'); /*source.close();*/ }; | |
// On message handling | |
var msgContainer = document.getElementById('msgs'); | |
source.onmessage = function (evt) { | |
msgContainer.insertAdjacentHTML('beforeend', evt.data); | |
} | |
// Capture a specific event | |
source.addEventListener('foo-evt', function(evt) { | |
console.log('Got an event! : ' + evt.data); | |
}); | |
}; | |
</script> | |
</head> | |
<body> | |
<h1 id='title'>Server-sent events > Hello World!</h1> | |
<div id='msgs'> | |
</div> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"bytes" | |
"fmt" | |
"io" | |
"net/http" | |
"os" | |
"strings" | |
"text/template" | |
"time" | |
) | |
type message struct { | |
Id int | |
Event string | |
Data []string | |
} | |
var elems = []int{1, 2, 3} | |
// Event format that conforms to the spec as defined in: | |
// http://www.w3.org/TR/2011/WD-eventsource-20110208/#event-stream-interpretation | |
const evtMsgFormat = "" + | |
"{{if .Id}}id: {{.Id}}\n{{end}}" + // optional | |
"{{if .Event}}event: {{.Event}}\n{{end}}" + // optional | |
"{{range .Data}}data: {{.}}\n{{end}}" + // required | |
"\r\n" // Empty line delimits message (preferably '\r\n') | |
// Creates a new message | |
func newMsg(id int, evt, data string) message { | |
return message{Id: id, Event: evt, Data: strings.Split(data, "\r\n")} | |
} | |
// Templates | |
var evtFormatTmpl = template.Must(template.New("evtTmpl").Parse(evtMsgFormat)) | |
var dataTmpls = template.Must(template.ParseFiles("data-tmpl.html")) | |
func handleStream(w http.ResponseWriter, r *http.Request) { | |
fmt.Println("Request to handle stream") | |
// Write the event stream headers | |
w.Header().Set("Content-Type", "text/event-stream") | |
fmt.Fprintf(w, "retry: %d\r\n", 5000) // Retry policy: 5 sec | |
for _, i := range elems { | |
for _, j := range elems { | |
var buf bytes.Buffer | |
dataTmpls.ExecuteTemplate(&buf, "data-tmpl.html", fmt.Sprintf("some dynamic data: %d", j)) | |
msg := newMsg(j, "", buf.String()) | |
fmt.Printf("Sending: %#v\n", msg) | |
sendMsg(w, msg) | |
// Also send an event under certain conditions | |
if i == 2 && j == 2 { | |
msg = newMsg(i, "foo-evt", fmt.Sprintf("This is an event! %d", j)) | |
sendMsg(w, msg) | |
} | |
} | |
time.Sleep(3 * time.Second) | |
} | |
} | |
func sendMsg(w io.Writer, msg message) { | |
// Apply the server sent message format | |
mw := io.MultiWriter(os.Stdout, w) | |
if err := evtFormatTmpl.Execute(mw, msg); err != nil { | |
panic("Template couldn't be executed") | |
} | |
// Flush so that it gets pushed immediately to the client | |
w.(http.Flusher).Flush() | |
} | |
func main() { | |
http.HandleFunc("/stream", handleStream) | |
http.Handle("/monitor/", http.StripPrefix("/monitor", http.FileServer(http.Dir(".")))) | |
fmt.Println("Server up & running in port: 8089") | |
http.ListenAndServe(":8089", nil) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment