Skip to content

Commit d5b6457

Browse files
committed
Initial commit
0 parents  commit d5b6457

13 files changed

+864
-0
lines changed

LICENSE

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
The MIT License (MIT)
2+
Copyright (c) 2019, Render Developers
3+
4+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
5+
6+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
7+
8+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
9+

README.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# Go Gin Web Server
2+
3+
This repo can be used as a starting point to deploy [Go](https://golang.org/) web applications on Render.
4+
5+
It is based on the [realtime chat](https://github.com/gin-gonic/examples/tree/master/realtime-advanced) example powered by the [Gin](https://github.com/gin-gonic/gin) web framework.
6+
7+
The sample app is up at https://go-gin.onrender.com.
8+
9+
## Deployment
10+
11+
See the guide at https://render.com/docs/deploy-go-gin-web-server.

build.sh

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
#!/usr/bin/env bash
2+
go get -u github.com/gin-gonic/gin
3+
go get -d -v github.com/dustin/go-broadcast/...
4+
go get -d -v github.com/manucorporat/stats/...
5+
go build -o ./app main.go rooms.go routes.go stats.go

main.go

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
"log"
6+
"os"
7+
"runtime"
8+
9+
"github.com/gin-gonic/gin"
10+
)
11+
12+
func main() {
13+
ConfigRuntime()
14+
StartWorkers()
15+
StartGin()
16+
}
17+
18+
// ConfigRuntime sets the number of operating system threads.
19+
func ConfigRuntime() {
20+
nuCPU := runtime.NumCPU()
21+
runtime.GOMAXPROCS(nuCPU)
22+
fmt.Printf("Running with %d CPUs\n", nuCPU)
23+
}
24+
25+
// StartWorkers start starsWorker by goroutine.
26+
func StartWorkers() {
27+
go statsWorker()
28+
}
29+
30+
// StartGin starts gin web server with setting router.
31+
func StartGin() {
32+
gin.SetMode(gin.ReleaseMode)
33+
34+
router := gin.New()
35+
router.Use(rateLimit, gin.Recovery())
36+
router.LoadHTMLGlob("resources/*.templ.html")
37+
router.Static("/static", "resources/static")
38+
router.GET("/", index)
39+
router.GET("/room/:roomid", roomGET)
40+
router.POST("/room-post/:roomid", roomPOST)
41+
router.GET("/stream/:roomid", streamRoom)
42+
43+
port := os.Getenv("PORT")
44+
if port == "" {
45+
port = "8080"
46+
}
47+
if err := router.Run(":" + port); err != nil {
48+
log.Panicf("error: %s", err)
49+
}
50+
}

resources/room_login.templ.html

Lines changed: 208 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,208 @@
1+
<!doctype html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="utf-8">
5+
<meta http-equiv="X-UA-Compatible" content="IE=edge">
6+
<meta name="viewport" content="width=device-width, initial-scale=1">
7+
<title>Server-Sent Events. Room "{{.roomid}}"</title>
8+
<!-- jQuery -->
9+
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>
10+
<script src="https://malsup.github.io/jquery.form.js"></script>
11+
<!-- EPOCH -->
12+
<script src="https://d3js.org/d3.v3.min.js"></script>
13+
<script src="/static/epoch.min.js"></script>
14+
<link rel="stylesheet" href="/static/epoch.min.css">
15+
<script src="/static/realtime.js"></script>
16+
<!-- Latest compiled and minified CSS -->
17+
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css">
18+
<!-- Optional theme -->
19+
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap-theme.min.css">
20+
<!-- Latest compiled and minified JavaScript -->
21+
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/js/bootstrap.min.js"></script>
22+
<!-- Primjs -->
23+
<link href="/static/prismjs.min.css" rel="stylesheet">
24+
25+
<script>
26+
$(document).ready(function() {
27+
StartRealtime({{.roomid}}, {{.timestamp}});
28+
});
29+
</script>
30+
<style>
31+
body { padding-top: 50px; }
32+
</style>
33+
</head>
34+
<body>
35+
<nav class="navbar navbar-fixed-top navbar-inverse">
36+
<div class="container">
37+
<div class="navbar-header">
38+
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
39+
<span class="sr-only">Toggle navigation</span>
40+
<span class="icon-bar"></span>
41+
<span class="icon-bar"></span>
42+
<span class="icon-bar"></span>
43+
</button>
44+
<a class="navbar-brand" href="#">Server-Sent Events</a>
45+
</div>
46+
<div id="navbar" class="collapse navbar-collapse">
47+
<ul class="nav navbar-nav">
48+
<li class="active"><a href="#">Demo</a></li>
49+
<li><a href="https://www.w3.org/TR/2009/WD-eventsource-20091029/">W3 Standard</a></li>
50+
<li><a href="https://caniuse.com/#feat=eventsource">Browser Support</a></li>
51+
<li><a href="https://gin-gonic.github.io/gin/">Gin Framework</a></li>
52+
<li><a href="https://github.com/gin-gonic/gin/tree/master/examples/realtime-advanced">GitHub</a></li>
53+
</ul>
54+
</div><!-- /.nav-collapse -->
55+
</div><!-- /.container -->
56+
</nav><!-- /.navbar -->
57+
<!-- Main jumbotron for a primary marketing message or call to action -->
58+
<div class="jumbotron">
59+
<div class="container">
60+
<h1>Server-Sent Events in Go</h1>
61+
<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="https://www.html5rocks.com/en/tutorials/eventsource/basics/">Learn more.</a></p>
62+
<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>
63+
<div class="row">
64+
<div class="col-md-8">
65+
<div id="chat-scroll" style="overflow-y:scroll; overflow-x:scroll; height:290px">
66+
<table id="table-style" class="table" data-show-header="false">
67+
<thead>
68+
<tr>
69+
<th data-field="nick" class="col-md-2">Nick</th>
70+
<th data-field="message" class="col-md-8">Message</th>
71+
</tr>
72+
</thead>
73+
<tbody id="chat"></tbody>
74+
</table>
75+
</div>
76+
{{if .nick}}
77+
<form autocomplete="off" class="form-inline" id="chat-form" action="/room-post/{{.roomid}}?nick={{.nick}}" method="post">
78+
<div class="form-group">
79+
<label class="sr-only" for="chat-message">Message</label>
80+
<div class="input-group">
81+
<div class="input-group-addon">{{.nick}}</div>
82+
<input type="text" name="message" id="chat-message" class="form-control" placeholder="a message" value="">
83+
</div>
84+
</div>
85+
<input type="submit" class="btn btn-primary" value="Send">
86+
</form>
87+
{{else}}
88+
<form action="" method="get" class="form-inline">
89+
<legend>Join the SSE real-time chat</legend>
90+
<div class="form-group">
91+
<input value='' name="nick" id="nick" placeholder="Your Name" type="text" class="form-control">
92+
</div>
93+
<div class="form-group text-center">
94+
<input type="submit" class="btn btn-success btn-login-submit" value="Join">
95+
</div>
96+
</form>
97+
{{end}}
98+
</div>
99+
<div class="col-md-4">
100+
<div id="messagesChart" class="epoch category10"></div>
101+
<p>
102+
<span style="font-size:20px; color:#1f77b4">◼︎</span> Users<br>
103+
<span style="font-size:20px; color:#ff7f0e">◼︎</span> Inbound messages / sec<br>
104+
<span style="font-size:20px; color:#2ca02c">◼︎</span> Outbound messages / sec<br>
105+
</p>
106+
</div>
107+
</div>
108+
</div>
109+
</div>
110+
<div class="container">
111+
<div class="row">
112+
<h2>Realtime server Go stats</h2>
113+
<div class="col-md-6">
114+
<h3>Memory usage</h3>
115+
<p>
116+
<div id="heapChart" class="epoch category20c"></div>
117+
</p>
118+
<p>
119+
<span style="font-size:20px; color:#1f77b4">◼︎</span> Heap bytes<br>
120+
<span style="font-size:20px; color:#aec7e8">◼︎</span> Stack bytes<br>
121+
</p>
122+
</div>
123+
<div class="col-md-6">
124+
<h3>Allocations per second</h3>
125+
<p>
126+
<div id="mallocsChart" class="epoch category20b"></div>
127+
</p>
128+
<p>
129+
<span style="font-size:20px; color:#393b79">◼︎</span> Mallocs / sec<br>
130+
<span style="font-size:20px; color:#5254a3">◼︎</span> Frees / sec<br>
131+
</p>
132+
</div>
133+
</div>
134+
<div class="row">
135+
<h2>MIT Open Sourced</h2>
136+
<ul>
137+
<li><a href="https://github.com/render-examples/go-gin-web-server">This demo website (JS and Go)</a></li>
138+
<li><a href="https://github.com/manucorporat/sse">The SSE implementation in Go</a></li>
139+
<li><a href="https://github.com/gin-gonic/gin">The Web Framework (Gin)</a></li>
140+
</ul>
141+
<div class="col-md-6">
142+
<script src="/static/prismjs.min.js"></script>
143+
<h3>Server-side (Go)</h3>
144+
<pre><code class="language-go">func streamRoom(c *gin.Context) {
145+
roomid := c.ParamValue(&quot;roomid&quot;)
146+
listener := openListener(roomid)
147+
statsTicker := time.NewTicker(1 * time.Second)
148+
defer closeListener(roomid, listener)
149+
defer statsTicker.Stop()
150+
151+
c.Stream(func(w io.Writer) bool {
152+
select {
153+
case msg := &lt;-listener:
154+
c.SSEvent(&quot;message&quot;, msg)
155+
case &lt;-statsTicker.C:
156+
c.SSEvent(&quot;stats&quot;, Stats())
157+
}
158+
return true
159+
})
160+
}</code></pre>
161+
</div>
162+
<div class="col-md-6">
163+
<h3>Client-side (JS)</h3>
164+
<pre><code class="language-javascript">function StartSSE(roomid) {
165+
var source = new EventSource('/stream/'+roomid);
166+
source.addEventListener('message', newChatMessage, false);
167+
source.addEventListener('stats', stats, false);
168+
}</code></pre>
169+
</div>
170+
</div>
171+
<div class="row">
172+
<div class="col-md-12">
173+
<h3>SSE package</h3>
174+
<pre><code class="language-go">import &quot;github.com/manucorporat/sse&quot;
175+
176+
func httpHandler(w http.ResponseWriter, req *http.Request) {
177+
// data can be a primitive like a string, an integer or a float
178+
sse.Encode(w, sse.Event{
179+
Event: &quot;message&quot;,
180+
Data: &quot;some data\nmore data&quot;,
181+
})
182+
183+
// also a complex type, like a map, a struct or a slice
184+
sse.Encode(w, sse.Event{
185+
Id: &quot;124&quot;,
186+
Event: &quot;message&quot;,
187+
Data: map[string]interface{}{
188+
&quot;user&quot;: &quot;manu&quot;,
189+
&quot;date&quot;: time.Now().Unix(),
190+
&quot;content&quot;: &quot;hi!&quot;,
191+
},
192+
})
193+
}</code></pre>
194+
<pre>event: message
195+
data: some data\\nmore data
196+
197+
id: 124
198+
event: message
199+
data: {&quot;content&quot;:&quot;hi!&quot;,&quot;date&quot;:1431540810,&quot;user&quot;:&quot;manu&quot;}</pre>
200+
</div>
201+
</div>
202+
<hr>
203+
<footer>
204+
<p>Created with <span class="glyphicon glyphicon-heart"></span> by <a href="https://github.com/manucorporat">Manu Martinez-Almeida</a></p>
205+
</footer>
206+
</div>
207+
</body>
208+
</html>

resources/static/epoch.min.css

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)