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" >
< title > Login in Room "{{.roomid}}"< / title >
<!-- 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 -->
< link href = "/static/prismjs.min.css" rel = "stylesheet" / >
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 >
< li > < a href = "https://github.com/gin-gonic/gin/tree/develop/examples/realtime-advanced" > Github< / a > < / li >
< / 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 >
< p > < a href = "http://www.html5rocks.com/en/tutorials/eventsource/basics/" > Server-sent events (SSE)< / a > is a technology where a browser receives automatic updates from a server via HTTP connection.< / p >
< p > The chat and the charts data is provided in realtime using the SSE implemention of < a href = "https://github.com/gin-gonic/gin/blob/15b0c49da556d58a3d934b86e3aa552ff224026d/examples/realtime-chat/main.go#L23-L32" > Gin Framework< / a > .< / p >
< div class = "row" >
< div class = "col-md-8" >
2015-05-13 17:44:44 +03:00
< div id = "chat-scroll" style = "overflow-y:scroll; overflow-x:scroll; height:270px" >
2015-05-13 03:35:16 +03:00
< table id = "table-style" class = "table" >
< thead >
< tr >
< th data-field = "id" class = "col-md-2" > Nick< / th >
< th data-field = "name" class = "col-md-8" > Message< / th >
< / tr >
< / thead >
< tbody id = "chat" > < / tbody >
< / table >
< / div >
{{if .nick}}
2015-05-13 18:34:42 +03:00
< form 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 >
< input name = "message" id = "chat-message" placeholder = "a message" type = "text" class = "form-control" / >
< / div >
2015-05-13 03:35:16 +03:00
< / div >
2015-05-13 17:44:44 +03:00
< input type = "submit" class = "btn btn-primary" value = "Send" / >
2015-05-13 03:35:16 +03:00
< / form >
{{end}}
< / div >
< div class = "col-md-4" >
2015-05-13 17:44:44 +03:00
{{if .nick}}
< h3 > Inbound/Outbound< / h3 >
< div id = "messagesChart" class = "epoch category20c" > < / div >
{{else}}
2015-05-13 03:35:16 +03:00
< form action = "" method = "get" >
< legend > Join the SSE real-time chat< / legend >
< div class = "form-group" >
< label for = "nick" > Your Name< / label >
< input value = '' name = "nick" id = "nick" placeholder = "Your name" type = "text" class = "form-control" / >
< / div >
< div class = "form-group text-center" >
< input type = "submit" class = "btn btn-success btn-login-submit" value = "Join" / >
< / div >
< / form >
2015-05-13 17:44:44 +03:00
{{end}}
2015-05-13 03:35:16 +03:00
< / div >
< / 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-13 03:35:16 +03:00
< div class = "col-md-4" >
< h3 > Number of Goroutines< / h3 >
< p >
< div id = "goroutinesChart" class = "epoch category20c" > < / div >
< / p >
< / div >
< div class = "col-md-4" >
< h3 > HEAP/Stack bytes< / h3 >
< p >
< div id = "heapChart" class = "epoch category20b" > < / div >
< / p >
< / div >
< div class = "col-md-4" >
< h3 > Mallocs/Frees< / h3 >
< p >
< div id = "mallocsChart" class = "epoch category10" > < / div >
< / p >
< / div >
< / div >
2015-05-13 17:44:44 +03:00
< div class = "row" >
< h2 > Source code< / h2 >
< 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 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 >