Unverified Commit f332c402 authored by Justin Kromlinger's avatar Justin Kromlinger
Browse files

Initial commit

parents
css
bin
server/bindata.go
This diff is collapsed.
BINARY_PRE=*.go server/*.go css/main.css server/bindata.go
BINARY_SOURCE=*.go
BINDATA_DATA=css/main.css static/* templates/* img/*
BINDATA_FLAGS=-pkg server
BINDATA_FLAGS_DEBUG=-pkg server -debug
SASS_PRE=sass/*.scss
SASS_SOURCE=sass/main.scss
SASS_FLAGS=-t compressed
SASS_FLAGS_DEBUG=-t nested -l
build: bin/hashworksNET
run: build
bin/hashworksNET
distribute: build
./distribute.sh
debug: SASS_FLAGS=$(SASS_FLAGS_DEBUG)
debug: BINDATA_FLAGS=$(BINDATA_FLAGS_DEBUG)
debug: run
dependencies:
go get -u github.com/gin-gonic/gin
go get -u github.com/ekyoung/gin-nice-recovery
go get -u github.com/gin-contrib/multitemplate
go get -u github.com/gin-contrib/cache
go get -u github.com/jteeuwen/go-bindata/...
go get -u github.com/elazarl/go-bindata-assetfs/...
go get -u github.com/mattn/go-isatty
go get -u github.com/wcharczuk/go-chart
clean:
rm -Rf ./bin ./css ./server/bindata.go
debug-css: SASS_FLAGS=$(SASS_FLAGS_DEBUG)
debug-css: css
css/main.css: $(SASS_PRE)
mkdir -p css
sassc $(SASS_FLAGS) $(SASS_SOURCE) $@
debug-bindata: BINDATA_FLAGS=$(BINDATA_FLAGS_DEBUG)
debug-bindata: server/bindata.go
server/bindata.go: $(BINDATA_DATA)
go-bindata $(BINDATA_FLAGS) -o $@ $(BINDATA_DATA)
bin/hashworksNET: $(BINARY_PRE)
mkdir -p bin
go build -o bin/hashworksNET $(BINARY_SOURCE)
#!/usr/bin/env bash
name=hashworksNET
export CGO_ENABLED=1
platforms=(
linux-amd64 windows-amd64
linux-386 windows-386
linux-armv5 linux-armv6 linux-armv7
#linux-armv8
)
checkCommand() {
which "$1" >/dev/null 2>&1
if [ "$?" != "0" ]; then
echo Please make sure the following command is available: "$1" >&2
exit "$?"
fi
}
checkCommand go
checkCommand tar
checkCommand zip
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
cd "$DIR"
commit="$(git rev-parse --short HEAD 2>/dev/null)"
date="$(date --iso-8601=seconds)"
if [ "$commit" == "" ]; then
commit="unknown"
fi
if [ "$1" == "" ]; then
version=$(git tag | tail -1)
echo You didn\'t provide a version string as the first parameter, setting version to the current git tag \"${version}\".
else
version="$1"
fi
rm -Rf ./bin/
mkdir ./bin/ 2>/dev/null
for plat in "${platforms[@]}"; do
export GOOS="${plat%-*}"
export GOARCH="${plat#*-}"
if [ "$GOOS" != "windows" ]; then
tmpFile="/tmp/${name}/bin/${name}"
else
tmpFile="/tmp/${name}/bin/${name}.exe"
fi
if [ "$CGO_ENABLED" == 1 ]; then
if [ "$plat" = "windows-amd64" ]; then
export CC=x86_64-w64-mingw32-gcc
elif [ "$plat" = "windows-386" ]; then
export CC=i686-w64-mingw32-gcc
elif [ "${GOARCH%v*}" = "arm" ]; then
export GOARM="${GOARCH#*v}"
if [ "GOARM" = 8 ]; then
unset GOARM=""
export CC=armv8l-linux-gnueabihf-gcc
export GOARCH="arm64"
else
export CC=arm-linux-gnueabihf-gcc
export GOARCH="arm"
fi
else
export CC=gcc
fi
fi
echo Building "$plat" with "$CC" ...
go build -ldflags '-extld='"$CC"' -X main.VERSION='"$version"' -X main.BUILD_COMMIT='"$commit"' -X main.BUILD_DATE='"$date" \
-o "$tmpFile" "$DIR"/*.go
if [ "$?" != 0 ]; then
echo Build failed! >&2
exit "$?"
fi
if [ "$GOOS" != "windows" ]; then
finalPath="$DIR"/bin/${name}-"$plat".tar.gz
echo Build succeeded, creating "$finalPath" ...
tar -czf "$finalPath" -C "${tmpFile%/*}" ${name}
else
finalPath="$DIR"/bin/${name}-"$plat".zip
echo Build succeeded, creating "$finalPath" ...
zip -j "$finalPath" "$tmpFile"
fi
if [ "$?" != 0 ]; then
echo Failed to pack the binary! >&2
exit "$?"
fi
echo "Signing…"
if ! gpg --armor --detach-sign "$finalPath"; then
echo Failed to sign the package! >&2
exit "$?"
fi
echo Done!
rm "$tmpFile"
echo
done
\ No newline at end of file
package main
import (
"flag"
"fmt"
"github.com/hashworks/hashworksNET/server"
"os"
)
var (
// Set the following uppercase three with -ldflags "-X main.VERSION=v1.2.3 [...]"
VERSION string = "unknown"
BUILD_COMMIT string = "unknown"
BUILD_DATE string = "unknown"
versionFlag bool
address string
port int
)
func main() {
flagSet := flag.NewFlagSet(os.Args[0], flag.ExitOnError)
flagSet.BoolVar(&versionFlag, "version", false, "Displays the version and license information.")
flagSet.StringVar(&address, "address", "", "The address to listen on.")
flagSet.IntVar(&port, "port", 65431, "The port to listen on.")
flagSet.Parse(os.Args[1:])
switch {
case versionFlag:
fmt.Println("hashworksNET")
fmt.Println("https://github.com/hashworks/hashworksNET")
fmt.Println("Version: " + VERSION)
fmt.Println("Commit: " + BUILD_COMMIT)
fmt.Println("Build date: " + BUILD_DATE)
fmt.Println()
fmt.Println("Published under the GNU General Public License v3.0.")
default:
s := server.NewServer()
s.Router.Run(fmt.Sprintf("%s:%d", address, port))
}
}
@import 'configuration';
body {
background-color: $bg-color1;
color: $fg-color-normal;
font-family: sans-serif;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
}
a {
cursor: pointer;
text-decoration: none;
}
a,
a:visited,
a:active {
color: $fg-color-normal;
}
::selection {
background: $fg-color-normal;
}
svg {
path {
fill: $fg-color-normal;
stroke: $fg-color-normal;
}
}
.header {
background-color: $bg-color3;
box-shadow: 0 5px 5px 0 $shadow-color;
font-size: 1.3em;
left: 0;
min-height: $header-height;
right: 0;
top: 0;
width: 100%;
z-index: 5;
.title,
.menu .entry {
padding: $header-height/3.5 $header-height/3.5 0;
}
.title {
padding-right: 30px;
}
@media (max-width: $small-screen-max-width) {
.menu {
min-width: 100%;
}
}
.menu {
display: flex;
position: relative;
.entry {
cursor: pointer;
flex-grow: 1;
height: $header-height;
max-width: 300px;
text-align: center;
}
.entry:not(.selected) {
opacity: .6;
}
.entry:hover,
.entry.active {
opacity: 1;
}
.menu-border {
$border-height: 3px;
background-color: $fg-color-normal;
height: $border-height;
left: 0;
position: absolute;
top: $header-height - $border-height;
}
}
.icons {
position: absolute;
right: $header-height/3.5;
top: $header-height/3.5;
.icon {
opacity: .6;
}
.icon:hover {
opacity: 1;
}
}
}
.content {
.page {
height: auto;
padding: $content-spacing;
}
}
.cards {
display: flex;
flex-flow: row wrap;
margin-left: -$content-spacing;
margin-top: -$content-spacing;
.card {
background-color: $bg-color2;
box-shadow: -5px 5px 5px 0 $shadow-color;
flex-grow: 1;
margin-left: $content-spacing;
margin-top: $content-spacing;
min-height: 250px;
padding: $content-spacing;
width: 440px;
.tag {
float: right;
margin-right: 10px;
margin-top: 3px;
}
&.full {
flex-grow: 2;
width: 100%;
}
a {
color: $fg-color-link;
text-decoration: underline;
}
a:visited,
a:active,
a:hover {
color: $fg-color-normal;
}
}
}
\ No newline at end of file
$fg-color-normal: #fff;
$fg-color-link: #999;
$bg-color1: #444448;
$bg-color2: #272727;
//$bg-color2 : #222426;
$bg-color3: #222;
$shadow-color: rgba(#000, .26);
$small-screen-max-width: 720px;
$header-height: 64px;
$content-spacing: 64px / 2;
html,
body {
margin: 0;
width: 100%;
}
* {
box-sizing: border-box;
}
h1,
h2,
h3,
h4,
h5,
h6 {
margin: 0;
}
\ No newline at end of file
.left {
float: left;
}
.right {
float: right;
}
.bold {
font-weight: bold;
}
\ No newline at end of file
.status-svg {
// "Loading graph…" image
background: url('data:image/svg+xml;charset=UTF-8,<svg width="200" height="100" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><text y="20" fill="white" font-size="24" font-family="sans-serif">Loading graph…</text></svg>') no-repeat center;
@media screen and (max-width: 200px) {
background: none;
}
div {
background: url('/status.svg?w=1244&h=700') no-repeat center;
background-size: contain;
height: 700px;
@media screen and (max-width: 1600px) {
background-image: url('/status.svg?w=924&h=520');
height: 520px;
}
@media screen and (max-width: 1366px) {
background-image: url('/status.svg?w=689&h=388');
height: 388px;
}
@media screen and (max-width: 720px) {
background-image: url('/status.svg?w=600&h=337');
height: 337px;
}
@media screen and (max-width: 600px) {
background-image: url('/status.svg?w=400&h=225');
height: 225px;
}
@media screen and (max-width: 400px) {
background-image: url('/status.svg?w=200&h=112');
height: 112px;
}
@media screen and (max-width: 200px) {
background: none;
height: auto;
&::after {
content: 'Please use a wider screen.';
}
}
}
}
\ No newline at end of file
@import 'fixes';
@import 'globalClasses';
@import 'base';
@import 'status';
\ No newline at end of file
package server
import (
"github.com/gin-gonic/gin"
"net/http"
)
func (s Server) index(c *gin.Context) {
c.Header("Cache-Control", "max-age=600")
c.HTML(http.StatusOK, "index", gin.H{
"ContactTab": true,
})
}
package server
import (
"github.com/ekyoung/gin-nice-recovery"
"log"
"strings"
"time"
// gin/logger.go might report undefined: isatty.IsCygwinTerminal
// Fix: go get -u github.com/mattn/go-isatty
"github.com/elazarl/go-bindata-assetfs"
"github.com/gin-contrib/cache"
"github.com/gin-contrib/cache/persistence"
"github.com/gin-contrib/multitemplate"
"github.com/gin-gonic/gin"
"html/template"
"net/http"
)
// I'm using this struct to pass stuff around. Like database connnection
type Server struct {
Router *gin.Engine
Store *persistence.InMemoryStore
}
func NewServer() Server {
var err error
//gin.SetMode(gin.ReleaseMode)
s := Server{
Router: gin.Default(),
Store: persistence.NewInMemoryStore(time.Minute),
}
s.Router.Use(nice.Recovery(recoveryHandler))
// Load template file names from Asset
templateNames, err := AssetDir("templates")
if err != nil {
panic(err)
}
// Create a base template where we add the template functions
tmpl := template.New("")
tmpl.Funcs(s.templateFunctionMap())
// Iterate trough template files, load them into multitemplate
multiT := multitemplate.New()
for _, templateName := range templateNames {
index := strings.Index(templateName, ".")
basename := templateName[:index]
tmpl := tmpl.New(basename)
tmpl, err := tmpl.Parse(string(MustAsset("templates/" + templateName)))
if err != nil {
panic(err)
}
multiT.Add(basename, tmpl)
log.Printf("Loaded templates/%s as %s\n", templateName, basename)
}
// multitemplate is our new HTML renderer
s.Router.HTMLRender = multiT
s.Router.StaticFS("/img", &assetfs.AssetFS{Asset: Asset, AssetDir: AssetDir, AssetInfo: AssetInfo, Prefix: "img"})
s.Router.StaticFS("/static", &assetfs.AssetFS{Asset: Asset, AssetDir: AssetDir, AssetInfo: AssetInfo, Prefix: "static"})
s.Router.GET("/robots.txt", func(c *gin.Context) {
c.String(http.StatusOK, "User-agent: *\nDisallow: /status\nDisallow: /status.svg")
})
s.Router.GET("/favicon.ico", func(c *gin.Context) {
c.Redirect(http.StatusMovedPermanently, "/img/favicon.ico")
})
s.Router.GET("/", cache.CachePage(s.Store, 10*time.Minute, s.index))
s.Router.GET("/status", cache.CachePage(s.Store, 10*time.Minute, s.status))
s.Router.GET("/status.svg", cache.CachePage(s.Store, 10*time.Minute, s.statusSVG))
s.Router.NoRoute(cache.CachePage(s.Store, 10*time.Minute, func(c *gin.Context) {
c.Header("Cache-Control", "max-age=600")
c.HTML(http.StatusNotFound, "error404", gin.H{
"Title": "404",
})
}))
return s
}
func recoveryHandler(c *gin.Context, err interface{}) {
log.Printf("Error: %s", err)
c.String(http.StatusInternalServerError, "There was an internal server error, please report this to mail@hashworks.net.")
}
package server
import (
"encoding/json"
"github.com/gin-gonic/gin"
"github.com/influxdata/influxdb/client/v2"
"github.com/wcharczuk/go-chart"
"github.com/wcharczuk/go-chart/drawing"
"net/http"
"strconv"
"time"
)
func (s Server) statusSVG(c *gin.Context) {
c.Header("Cache-Control", "max-age=600")
height, err := strconv.ParseInt(c.DefaultQuery("h", "450"), 10, 16)
if err != nil || height <= 0 {
c.AbortWithStatus(http.StatusBadRequest)
return
}
width, err := strconv.ParseInt(c.DefaultQuery("w", "800"), 10, 16)
if err != nil || width <= 0 {
c.AbortWithStatus(http.StatusBadRequest)
return
}
httpClient, err := client.NewHTTPClient(client.HTTPConfig{
Addr: "http://127.0.0.1:8086",
})
defer httpClient.Close()
if err != nil {
recoveryHandler(c, err)