2015-05-13 03:35:16 +03:00
<!DOCTYPE html>
< html lang = "en" >
< head >
< meta charset = "utf-8" >
< meta http-equiv = "X-UA-Compatible" content = "IE=edge" >
< meta name = "viewport" content = "width=device-width, initial-scale=1" >
2015-05-13 21:54:54 +03:00
< title > Server-Sent Events. Room "{{.roomid}}"< / title >
2015-05-13 03:35:16 +03:00
<!-- jQuery -->
< script src = "https://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js" > < / script >
< script src = "http://malsup.github.com/jquery.form.js" > < / script >
<!-- EPOCH -->
< script src = "http://d3js.org/d3.v3.min.js" > < / script >
< script src = "/static/epoch.min.js" > < / script >
< link rel = "stylesheet" href = "/static/epoch.min.css" >
< script src = "/static/realtime.js" > < / script >
<!-- Latest compiled and minified CSS -->
< link rel = "stylesheet" href = "https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css" >
<!-- Optional theme -->
< link rel = "stylesheet" href = "https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap-theme.min.css" >
<!-- Latest compiled and minified JavaScript -->
< script src = "https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/js/bootstrap.min.js" > < / script >
2015-05-13 17:44:44 +03:00
<!-- Primjs -->
2018-11-01 16:48:26 +03:00
< link href = "/static/prismjs.min.css" rel = "stylesheet" >
2015-05-13 17:44:44 +03:00
2015-05-13 03:35:16 +03:00
< script type = "text/javascript" >
$(document).ready(function() {
StartRealtime({{.roomid}}, {{.timestamp}});
});
< / script >
2015-05-13 17:44:44 +03:00
< style >
body { padding-top: 50px; }
< / style >
2015-05-13 03:35:16 +03:00
< / head >
< body >
2015-05-13 17:44:44 +03:00
< nav class = "navbar navbar-fixed-top navbar-inverse" >
< div class = "container" >
< div class = "navbar-header" >
< button type = "button" class = "navbar-toggle collapsed" data-toggle = "collapse" data-target = "#navbar" aria-expanded = "false" aria-controls = "navbar" >
< span class = "sr-only" > Toggle navigation< / span >
< span class = "icon-bar" > < / span >
< span class = "icon-bar" > < / span >
< span class = "icon-bar" > < / span >
< / button >
< a class = "navbar-brand" href = "#" > Server-Sent Events< / a >
< / div >
< div id = "navbar" class = "collapse navbar-collapse" >
< ul class = "nav navbar-nav" >
< li class = "active" > < a href = "#" > Demo< / a > < / li >
< li > < a href = "http://www.w3.org/TR/2009/WD-eventsource-20091029/" > W3 Standard< / a > < / li >
< li > < a href = "http://caniuse.com/#feat=eventsource" > Browser Support< / a > < / li >
< li > < a href = "http://gin-gonic.github.io/gin/" > Gin Framework< / a > < / li >
2018-11-05 04:13:17 +03:00
< li > < a href = "https://github.com/gin-gonic/gin/tree/develop/examples/realtime-advanced" > GitHub< / a > < / li >
2015-05-13 17:44:44 +03:00
< / ul >
< / div > <!-- /.nav - collapse -->
< / div > <!-- /.container -->
< / nav > <!-- /.navbar -->
2015-05-13 03:35:16 +03:00
<!-- Main jumbotron for a primary marketing message or call to action -->
< div class = "jumbotron" >
< div class = "container" >
< h1 > Server-Sent Events in Go< / h1 >
2015-05-13 21:54:54 +03:00
< p > Server-sent events (SSE) is a technology where a browser receives automatic updates from a server via HTTP connection. It is not websockets. < a href = "http://www.html5rocks.com/en/tutorials/eventsource/basics/" > Learn more.< / a > < / p >
2018-11-05 04:13:17 +03:00
< p > The chat and the charts data is provided in realtime using the SSE implementation of < a href = "https://github.com/gin-gonic/gin/blob/15b0c49da556d58a3d934b86e3aa552ff224026d/examples/realtime-chat/main.go#L23-L32" > Gin Framework< / a > .< / p >
2015-05-13 03:35:16 +03:00
< div class = "row" >
< div class = "col-md-8" >
2015-05-14 19:16:00 +03:00
< div id = "chat-scroll" style = "overflow-y:scroll; overflow-x:scroll; height:290px" >
2015-05-14 05:39:17 +03:00
< table id = "table-style" class = "table" data-show-header = "false" >
2015-05-13 03:35:16 +03:00
< thead >
< tr >
2015-05-14 05:39:17 +03:00
< th data-field = "nick" class = "col-md-2" > Nick< / th >
< th data-field = "message" class = "col-md-8" > Message< / th >
2015-05-13 03:35:16 +03:00
< / tr >
< / thead >
< tbody id = "chat" > < / tbody >
< / table >
< / div >
{{if .nick}}
2015-05-14 05:39:17 +03:00
< form autocomplete = "off" class = "form-inline" id = "chat-form" action = "/room-post/{{.roomid}}?nick={{.nick}}" method = "post" >
2015-05-13 17:44:44 +03:00
< div class = "form-group" >
< label class = "sr-only" for = "chat-message" > Message< / label >
< div class = "input-group" >
< div class = "input-group-addon" > {{.nick}}< / div >
2018-11-01 11:05:40 +03:00
< input type = "text" name = "message" id = "chat-message" class = "form-control" placeholder = "a message" value = "" >
2015-05-13 17:44:44 +03:00
< / div >
2015-05-13 03:35:16 +03:00
< / div >
2018-11-01 11:05:40 +03:00
< input type = "submit" class = "btn btn-primary" value = "Send" >
2015-05-13 03:35:16 +03:00
< / form >
2015-05-13 17:44:44 +03:00
{{else}}
2015-05-14 18:01:02 +03:00
< form action = "" method = "get" class = "form-inline" >
2015-05-13 03:35:16 +03:00
< legend > Join the SSE real-time chat< / legend >
< div class = "form-group" >
2018-11-01 11:05:40 +03:00
< input value = '' name = "nick" id = "nick" placeholder = "Your Name" type = "text" class = "form-control" >
2015-05-13 03:35:16 +03:00
< / div >
< div class = "form-group text-center" >
2018-11-01 11:05:40 +03:00
< input type = "submit" class = "btn btn-success btn-login-submit" value = "Join" >
2015-05-13 03:35:16 +03:00
< / div >
< / form >
2015-05-13 17:44:44 +03:00
{{end}}
2015-05-13 03:35:16 +03:00
< / div >
2015-05-14 18:01:02 +03:00
< div class = "col-md-4" >
2015-05-14 19:16:00 +03:00
< div id = "messagesChart" class = "epoch category10" > < / div >
< p >
< span style = "font-size:20px; color:#1f77b4" > ◼︎< / span > Users< br >
< span style = "font-size:20px; color:#ff7f0e" > ◼︎< / span > Inbound messages / sec< br >
< span style = "font-size:20px; color:#2ca02c" > ◼︎< / span > Outbound messages / sec< br >
< / p >
2015-05-14 18:01:02 +03:00
< / div >
2015-05-13 03:35:16 +03:00
< / div >
< / div >
< / div >
< div class = "container" >
< div class = "row" >
2015-05-13 17:44:44 +03:00
< h2 > Realtime server Go stats< / h2 >
2015-05-14 19:16:00 +03:00
< div class = "col-md-6" >
< h3 > Memory usage< / h3 >
2015-05-13 03:35:16 +03:00
< p >
2015-05-14 19:16:00 +03:00
< div id = "heapChart" class = "epoch category20c" > < / div >
2015-05-13 03:35:16 +03:00
< / p >
< p >
2015-05-14 19:16:00 +03:00
< span style = "font-size:20px; color:#1f77b4" > ◼︎< / span > Heap bytes< br >
< span style = "font-size:20px; color:#aec7e8" > ◼︎< / span > Stack bytes< br >
2015-05-13 03:35:16 +03:00
< / p >
< / div >
2015-05-14 19:16:00 +03:00
< div class = "col-md-6" >
< h3 > Allocations per second< / h3 >
< p >
< div id = "mallocsChart" class = "epoch category20b" > < / div >
< / p >
2015-05-13 03:35:16 +03:00
< p >
2015-05-14 19:16:00 +03:00
< span style = "font-size:20px; color:#393b79" > ◼︎< / span > Mallocs / sec< br >
< span style = "font-size:20px; color:#5254a3" > ◼︎< / span > Frees / sec< br >
2015-05-13 03:35:16 +03:00
< / p >
< / div >
< / div >
2015-05-13 17:44:44 +03:00
< div class = "row" >
2015-05-13 21:54:54 +03:00
< h2 > MIT Open Sourced< / h2 >
< ul >
< li > < a href = "https://github.com/gin-gonic/gin/tree/develop/examples/realtime-advanced" > This demo website (JS and Go)< / a > < / li >
< li > < a href = "https://github.com/manucorporat/sse" > The SSE implementation in Go< / a > < / li >
< li > < a href = "https://github.com/gin-gonic/gin" > The Web Framework (Gin)< / a > < / li >
< / ul >
2015-05-13 17:44:44 +03:00
< div class = "col-md-6" >
< script src = "/static/prismjs.min.js" > < / script >
< h3 > Server-side (Go)< / h3 >
< pre > < code class = "language-go" > func streamRoom(c *gin.Context) {
roomid := c.ParamValue(" roomid" )
listener := openListener(roomid)
statsTicker := time.NewTicker(1 * time.Second)
defer closeListener(roomid, listener)
defer statsTicker.Stop()
c.Stream(func(w io.Writer) bool {
select {
case msg := < -listener:
c.SSEvent(" message" , msg)
case < -statsTicker.C:
c.SSEvent(" stats" , Stats())
}
return true
})
}< / code > < / pre >
< / div >
< div class = "col-md-6" >
< h3 > Client-side (JS)< / h3 >
< pre > < code class = "language-javascript" > function StartSSE(roomid) {
var source = new EventSource('/stream/'+roomid);
source.addEventListener('message', newChatMessage, false);
source.addEventListener('stats', stats, false);
}< / code > < / pre >
< / div >
< / div >
2015-05-13 21:54:54 +03:00
< div class = "row" >
< div class = "col-md-12" >
< h3 > SSE package< / h3 >
< pre > < code class = "language-go" > import " github.com/manucorporat/sse"
func httpHandler(w http.ResponseWriter, req *http.Request) {
// data can be a primitive like a string, an integer or a float
sse.Encode(w, sse.Event{
Event: " message" ,
Data: " some data\nmore data" ,
})
// also a complex type, like a map, a struct or a slice
sse.Encode(w, sse.Event{
Id: " 124" ,
Event: " message" ,
Data: map[string]interface{}{
" user" : " manu" ,
" date" : time.Now().Unix(),
" content" : " hi!" ,
},
})
}< / code > < / pre >
< pre > event: message
data: some data\\nmore data
id: 124
event: message
data: {" content" :" hi!" ," date" :1431540810," user" :" manu" }< / pre >
< / div >
< / div >
2015-05-13 03:35:16 +03:00
< hr >
< footer >
2015-05-13 17:44:44 +03:00
< p > Created with < span class = "glyphicon glyphicon-heart" > < / span > by < a href = "https://github.com/manucorporat" > Manu Martinez-Almeida< / a > < / p >
2015-05-13 03:35:16 +03:00
< / footer >
< / div >
< / body >
< / html >