-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit d715075
Showing
24 changed files
with
9,715 additions
and
0 deletions.
There are no files selected for viewing
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
test-results/ | ||
tmp/ | ||
routes/ |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
# Gourd | ||
|
||
Analytics dashboard framework written in golang and AngularJS | ||
|
||
# Features | ||
|
||
- pluggable, concurrent data loggers | ||
- custom data processors | ||
|
||
- admin panel for visualizations | ||
|
||
# Stack | ||
|
||
- Nginx reverse proxy to static and go server | ||
- Revel framework | ||
- AngularJS | ||
- some kinda realtime charts |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
package controllers | ||
|
||
import ( | ||
"github.com/revel/revel" | ||
) | ||
|
||
type App struct { | ||
*revel.Controller | ||
} | ||
|
||
func (c App) Index() revel.Result { | ||
return c.Render() | ||
} |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
package controllers | ||
|
||
import ( | ||
"code.google.com/p/go.net/websocket" | ||
"github.com/revel/revel" | ||
"gourd/app/stream" | ||
"strconv" | ||
) | ||
|
||
type WebSocket struct { | ||
*revel.Controller | ||
} | ||
|
||
func (c WebSocket) StreamSocket(ws *websocket.Conn) revel.Result { | ||
// activate new Stream, with NewPoints channel | ||
watcher := stream.Watch() | ||
defer watcher.Unwatch() | ||
|
||
// In order to select between websocket messages and newPoint data, we | ||
// need to stuff websocket events into a channel. | ||
newMessages := make(chan string) | ||
go func() { | ||
// listener on socket | ||
var msg string | ||
for { | ||
err := websocket.Message.Receive(ws, &msg) | ||
if err != nil { | ||
close(newMessages) | ||
return | ||
} | ||
newMessages <- msg | ||
} | ||
}() | ||
|
||
// Now listen for new data | ||
// on the websocket (data) and newMessages (msg, ok). | ||
for { | ||
select { | ||
case point := <-watcher.NewPoints: | ||
// broadcast NewPoint to socket as JSON, e.g. | ||
// {"XVal":1,"YVal":2,"Timestamp":1407452575,"Label":"C"} | ||
if websocket.JSON.Send(ws, &point) != nil { | ||
// They disconnected. | ||
return nil | ||
} | ||
case rate, ok := <-newMessages: | ||
// process received message on the socket | ||
// If the channel is closed, they disconnected. | ||
if !ok { | ||
return nil | ||
} | ||
// Otherwise, say something. | ||
i, _ := strconv.Atoi(rate) | ||
stream.Throttle(i) | ||
} | ||
} | ||
return nil | ||
} |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
package app | ||
|
||
import "github.com/revel/revel" | ||
|
||
func init() { | ||
// Filters is the default set of global filters. | ||
revel.Filters = []revel.Filter{ | ||
revel.PanicFilter, // Recover from panics and display an error page instead. | ||
revel.RouterFilter, // Use the routing table to select the right Action | ||
revel.FilterConfiguringFilter, // A hook for adding or removing per-Action filters. | ||
revel.ParamsFilter, // Parse parameters into Controller.Params. | ||
revel.SessionFilter, // Restore and write the session cookie. | ||
revel.FlashFilter, // Restore and write the flash cookie. | ||
revel.ValidationFilter, // Restore kept validation errors and save new ones from cookie. | ||
revel.I18nFilter, // Resolve the requested language | ||
HeaderFilter, // Add some security based headers | ||
revel.InterceptorFilter, // Run interceptors around the action. | ||
revel.CompressFilter, // Compress the result. | ||
revel.ActionInvoker, // Invoke the action. | ||
} | ||
|
||
// register startup functions with OnAppStart | ||
// ( order dependent ) | ||
// revel.OnAppStart(InitDB()) | ||
// revel.OnAppStart(FillCache()) | ||
} | ||
|
||
// TODO turn this into revel.HeaderFilter | ||
// should probably also have a filter for CSRF | ||
// not sure if it can go in the same filter or not | ||
var HeaderFilter = func(c *revel.Controller, fc []revel.Filter) { | ||
// Add some common security headers | ||
c.Response.Out.Header().Add("X-Frame-Options", "SAMEORIGIN") | ||
c.Response.Out.Header().Add("X-XSS-Protection", "1; mode=block") | ||
c.Response.Out.Header().Add("X-Content-Type-Options", "nosniff") | ||
|
||
fc[0](c, fc[1:]) // Execute the next filter stage. | ||
} |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
package stream | ||
|
||
import ( | ||
"container/list" | ||
"math/rand" | ||
"time" | ||
) | ||
|
||
type Point struct { | ||
XVal int | ||
YVal int | ||
Label string | ||
} | ||
|
||
type Stream struct { | ||
NewPoints chan Point // New points coming in | ||
} | ||
|
||
func (s Stream) Unwatch() { | ||
// Owner of a Stream must Unwatch it when they stop listening to events. | ||
// This gets called automatically with .defer after Watch() | ||
unwatch <- s // unwatch the channel - send the channel to the unwatch channel | ||
drain(s.NewPoints) // Drain it, just in case there was a pending publish. | ||
} | ||
|
||
func Watch() Stream { | ||
// resp := make(chan Stream) // make new channel of Streams | ||
// watch <- resp // put the new Stream into the watch channel | ||
// return <-resp // return the sending-only channel | ||
stream := Stream{make(chan Point)} | ||
watch <- stream | ||
return stream | ||
} | ||
|
||
func Publish(point *Point) { | ||
publish <- *point | ||
} | ||
|
||
func Throttle(rate int) { | ||
throttle <- rate | ||
} | ||
|
||
var ( | ||
// Send a stream here to connect to data feed. | ||
watch = make(chan Stream) // receiving channel | ||
|
||
// Send a stream here to to disconnect from data feed. | ||
unwatch = make(chan Stream) | ||
|
||
// Send points here to publish them to all streams. | ||
publish = make(chan Point) | ||
|
||
// send rate integers here to throttle rate of new points | ||
throttle = make(chan int) | ||
rate = 1 | ||
) | ||
|
||
// This function loops forever, handling the data stream pubsub | ||
func stream() { | ||
// private list of Streams, one per websocket | ||
watchers := list.New() | ||
|
||
for { | ||
select { | ||
// listen to all 'global' channels | ||
case stream := <-watch: | ||
// put stream into list of watcher streams | ||
watchers.PushBack(stream) | ||
|
||
case stream := <-unwatch: | ||
// watcher disconnected - find the channel and remove it | ||
for watcher := watchers.Front(); watcher != nil; watcher = watcher.Next() { | ||
// watcher.Value.(Stream) gets the underlying element, with type Stream | ||
if watcher.Value.(Stream) == stream { | ||
watchers.Remove(watcher) | ||
break | ||
} | ||
} | ||
|
||
case point := <-publish: | ||
// new point, send it to the NewPoints channel of all watcher streams | ||
for watcher := watchers.Front(); watcher != nil; watcher = watcher.Next() { | ||
watcher.Value.(Stream).NewPoints <- point | ||
} | ||
|
||
case newRate := <-throttle: | ||
rate = newRate | ||
} | ||
} | ||
} | ||
|
||
// go routine for generating random points | ||
func generate() { | ||
rand.Seed(42) | ||
labels := []string{"A", "B", "C"} // all possible Point Labels | ||
for { | ||
idx := rand.Intn(len(labels)) | ||
Publish(&Point{rand.Intn(10), rand.Intn(10), labels[idx]}) | ||
time.Sleep(time.Second * time.Duration(rate)) | ||
} | ||
} | ||
|
||
func init() { | ||
go stream() | ||
go generate() | ||
} | ||
|
||
// Helpers | ||
|
||
// Drains a given channel of any points. | ||
func drain(ch <-chan Point) { // <-chan can only release data | ||
for { | ||
select { | ||
case _, ok := <-ch: | ||
if !ok { | ||
return | ||
} | ||
default: | ||
return | ||
} | ||
} | ||
} |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
<html ng-app="app"> | ||
<head> | ||
<title>[[.title]]</title> | ||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"> | ||
<link rel="stylesheet" type="text/css" href="/public/css/bootstrap.css"> | ||
<link rel="shortcut icon" type="image/png" href="/public/img/favicon.png"> | ||
<script src="/public/js/jquery-1.9.1.min.js" type="text/javascript" charset="utf-8"></script> | ||
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.21/angular.min.js"></script> | ||
<script src="/public/js/lib/Chart.js"></script> | ||
<script src="/public/js/controllers.js"></script> | ||
</head> | ||
<body> | ||
<header class="hero-unit"> | ||
<div class="container"> | ||
<div class="row"> | ||
<div class="hero-text"> | ||
<div id="newMessage"> | ||
<input type="button" value="1" class="send"> | ||
<input type="button" value="2" class="send"> | ||
<input type="button" value="3" class="send"> | ||
</div> | ||
<div ng-controller="displays"> | ||
<!-- ng-repeat or use go template generation? (performance might degrade quickly for ng-repeat) --> | ||
<p ng-repeat="(label, loc) in displays"><strong>{{ label }}</strong> {{ loc.x }} {{ loc.y }} </p> | ||
</div> | ||
</div> | ||
</div> | ||
</div> | ||
</header> | ||
|
||
<div class="container"> | ||
<div class="row"> | ||
<div class="span6"> | ||
[[template "flash.html" .]] | ||
</div> | ||
</div> | ||
</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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
<style type="text/css"> | ||
#sidebar { | ||
position: absolute; | ||
right: 0px; | ||
top:69px; | ||
max-width: 75%; | ||
z-index: 1000; | ||
background-color: #fee; | ||
border: thin solid grey; | ||
padding: 10px; | ||
} | ||
#toggleSidebar { | ||
position: absolute; | ||
right: 0px; | ||
top: 50px; | ||
background-color: #fee; | ||
} | ||
|
||
</style> | ||
<div id="sidebar" style="display:none;"> | ||
<h4>Available pipelines</h4> | ||
<dl> | ||
{{ range $index, $value := .}} | ||
<dt>{{$index}}</dt> | ||
<dd>{{$value}}</dd> | ||
{{end}} | ||
</dl> | ||
<h4>Flash</h4> | ||
<dl> | ||
{{ range $index, $value := .flash}} | ||
<dt>{{$index}}</dt> | ||
<dd>{{$value}}</dd> | ||
{{end}} | ||
</dl> | ||
|
||
<h4>Errors</h4> | ||
<dl> | ||
{{ range $index, $value := .errors}} | ||
<dt>{{$index}}</dt> | ||
<dd>{{$value}}</dd> | ||
{{end}} | ||
</dl> | ||
</div> | ||
<a id="toggleSidebar" href="#" class="toggles"><i class="icon-chevron-left"></i></a> | ||
|
||
<script> | ||
$sidebar = 0; | ||
$('#toggleSidebar').click(function() { | ||
if ($sidebar === 1) { | ||
$('#sidebar').hide(); | ||
$('#toggleSidebar i').addClass('icon-chevron-left'); | ||
$('#toggleSidebar i').removeClass('icon-chevron-right'); | ||
$sidebar = 0; | ||
} | ||
else { | ||
$('#sidebar').show(); | ||
$('#toggleSidebar i').addClass('icon-chevron-right'); | ||
$('#toggleSidebar i').removeClass('icon-chevron-left'); | ||
$sidebar = 1; | ||
} | ||
|
||
return false; | ||
}); | ||
</script> |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
<!DOCTYPE html> | ||
<html lang="en"> | ||
<head> | ||
<title>Not found</title> | ||
</head> | ||
<body> | ||
{{if eq .RunMode "dev"}} | ||
{{template "errors/404-dev.html" .}} | ||
{{else}} | ||
{{with .Error}} | ||
<h1> | ||
{{.Title}} | ||
</h1> | ||
<p> | ||
{{.Description}} | ||
</p> | ||
{{end}} | ||
{{end}} | ||
</body> | ||
</html> |
Oops, something went wrong.