Commit 35424b70 authored by Kevin Lyda's avatar Kevin Lyda 💬

Embed the pages.

parent bcf22ac5
Pipeline #1332 passed with stage
in 2 minutes and 8 seconds
......@@ -21,13 +21,11 @@ Usage of gqgmcd:
--listen-address string Address for HTTP requests (default ":8080")
--model string Model of Geiger Counter (default "gqgmc")
--sleep-cycle int Seconds to sleep per cycle. (default 5)
--static-dir string Static files directory (default "static")
--template-dir string Template directory (default "templates")
```
The config file uses the same variables (not `config` obviously)
but with any dashes replaced with underscores. So
`static_dir = /var/lib/gqgmcd/static` for instance.
but with dashes replaced with underscores. So `sleep-cycle = 10`
for instance.
## Prometheus variables
......
......@@ -19,13 +19,11 @@ import (
)
var (
addr = flag.String("listen-address", ":8080", "Address for HTTP requests")
device = flag.String("device", "/dev/gqgmc", "Device for Geiger Counter")
model = flag.String("model", "gqgmc", "Model of Geiger Counter")
templateDir = flag.String("template-dir", "templates", "Template directory")
staticDir = flag.String("static-dir", "static", "Static files directory")
sleepCycle = flag.Int64("sleep-cycle", 5, "Seconds to sleep per cycle.")
cfg = flag.String("config", "gqgmc.conf", "Config file")
addr = flag.String("listen-address", ":8080", "Address for HTTP requests")
device = flag.String("device", "/dev/gqgmc", "Device for Geiger Counter")
model = flag.String("model", "gqgmc", "Model of Geiger Counter")
sleepCycle = flag.Int64("sleep-cycle", 5, "Seconds to sleep per cycle.")
cfg = flag.String("config", "", "Config file")
)
func main() {
......@@ -36,12 +34,17 @@ func main() {
return
}
gc, _ := geiger.New(geiger.Config{Model: c.Model, Device: c.Device})
gc, gcErr := geiger.New(geiger.Config{Model: c.Model, Device: c.Device})
if gcErr != nil {
log.Printf("Error: %s\n", gcErr)
}
p := pages.New(gc, c.StaticDir, c.TemplateDir)
p := pages.New(gc, gcErr)
p.Register()
m := metrics.Register(gc)
go m.Gather(c.SleepCycle)
if gcErr == nil {
m := metrics.Register(gc)
go m.Gather(c.SleepCycle)
}
log.Fatal(http.ListenAndServe(c.ListenAddress, nil))
}
......@@ -17,8 +17,6 @@ type Config struct {
ListenAddress string `mapstructure:"listen_address"`
Device string `mapstructure:"device"`
Model string `mapstructure:"model"`
TemplateDir string `mapstructure:"template_dir"`
StaticDir string `mapstructure:"static_dir"`
SleepCycle int64 `mapstructure:"sleep_cycle"`
}
......@@ -26,18 +24,18 @@ func setDefaults() {
viper.BindPFlag("listen_address", pflag.Lookup("listen-address"))
viper.BindPFlag("device", pflag.Lookup("device"))
viper.BindPFlag("model", pflag.Lookup("model"))
viper.BindPFlag("template_dir", pflag.Lookup("template-dir"))
viper.BindPFlag("static_dir", pflag.Lookup("static-dir"))
viper.BindPFlag("sleep_cycle", pflag.Lookup("sleep-cycle"))
}
// ReadConfig reads the client configuration from a file into a Config struct.
func ReadConfig(cfg string) (*Config, error) {
setDefaults()
viper.SetConfigFile(cfg)
viper.SetConfigType("hcl")
if err := viper.ReadInConfig(); err != nil {
return nil, err
if cfg != "" {
viper.SetConfigFile(cfg)
viper.SetConfigType("hcl")
if err := viper.ReadInConfig(); err != nil {
return nil, err
}
}
c := &Config{}
if err := viper.Unmarshal(c); err != nil {
......
......@@ -6,6 +6,7 @@
set -xue
go generate ./...
go install -v ./cmd/*
go list ./... |grep -v vendor/ |xargs go test
gofmt -d $(find * -type f -name '*.go' -not -path 'vendor/*')
......
......@@ -5,22 +5,23 @@
// Distributed under terms of the MIT license.
//
//go:generate go get -u github.com/mjibson/esc
//go:generate esc -o static.go -pkg pages static templates
package pages
import (
"html/template"
"log"
"net/http"
"path"
"gitlab.com/lyda/gqgmc/devices/geiger"
)
// Pages where data for pages goes
type Pages struct {
gc geiger.Counter
staticDir,
templateDir string
gc geiger.Counter
gcErr error
}
type indexPage struct {
......@@ -32,36 +33,40 @@ type indexPage struct {
}
// New create new Pages.
func New(gc geiger.Counter, staticDir, templateDir string) Pages {
return Pages{gc: gc, staticDir: staticDir, templateDir: templateDir}
func New(gc geiger.Counter, gcErr error) Pages {
return Pages{gc: gc, gcErr: gcErr}
}
// Register pages.
func (p Pages) Register() {
http.HandleFunc("/", p.indexHandler)
http.HandleFunc("/favicon.ico", p.staticHandler)
http.HandleFunc("/robots.txt", p.staticHandler)
http.HandleFunc("/humans.txt", p.staticHandler)
http.Handle("/static", http.StripPrefix("/static/", http.FileServer(http.Dir(p.staticDir))))
http.Handle("/favicon.ico", http.FileServer(Dir(false, "/static/")))
http.Handle("/robots.txt", http.FileServer(Dir(false, "/static/")))
http.Handle("/humans.txt", http.FileServer(Dir(false, "/static/")))
}
func (p Pages) indexHandler(w http.ResponseWriter, r *http.Request) {
var indexPg indexPage
indexPg.CPM, _ = p.gc.GetCPM()
indexPg.Volts, _ = p.gc.Volts()
indexPg.Model = p.gc.Model()
indexPg.Version = p.gc.Version()
indexPg.Serial = p.gc.Serial()
if p.gcErr == nil {
indexPg.CPM, _ = p.gc.GetCPM()
indexPg.Volts, _ = p.gc.Volts()
indexPg.Model = p.gc.Model()
indexPg.Version = p.gc.Version()
indexPg.Serial = p.gc.Serial()
} else {
indexPg.CPM = 0
indexPg.Volts = 0
indexPg.Model = "ERROR"
indexPg.Version = "ERROR"
indexPg.Serial = "ERROR"
}
t, err := template.ParseFiles(path.Join(p.templateDir, "index.html"))
index, _ := FSString(false, "index.html")
t, err := template.New("index.html").Parse(index)
if err != nil {
log.Printf("Template error: %s\n", err)
return // TODO: 404
}
t.Execute(w, &indexPg)
}
func (p Pages) staticHandler(w http.ResponseWriter, r *http.Request) {
staticFile := path.Join(p.staticDir, path.Base(r.URL.Path))
http.ServeFile(w, r, staticFile)
}
package pages
import (
"bytes"
"compress/gzip"
"encoding/base64"
"io/ioutil"
"net/http"
"os"
"path"
"sync"
"time"
)
type _escLocalFS struct{}
var _escLocal _escLocalFS
type _escStaticFS struct{}
var _escStatic _escStaticFS
type _escDirectory struct {
fs http.FileSystem
name string
}
type _escFile struct {
compressed string
size int64
modtime int64
local string
isDir bool
once sync.Once
data []byte
name string
}
func (_escLocalFS) Open(name string) (http.File, error) {
f, present := _escData[path.Clean(name)]
if !present {
return nil, os.ErrNotExist
}
return os.Open(f.local)
}
func (_escStaticFS) prepare(name string) (*_escFile, error) {
f, present := _escData[path.Clean(name)]
if !present {
return nil, os.ErrNotExist
}
var err error
f.once.Do(func() {
f.name = path.Base(name)
if f.size == 0 {
return
}
var gr *gzip.Reader
b64 := base64.NewDecoder(base64.StdEncoding, bytes.NewBufferString(f.compressed))
gr, err = gzip.NewReader(b64)
if err != nil {
return
}
f.data, err = ioutil.ReadAll(gr)
})
if err != nil {
return nil, err
}
return f, nil
}
func (fs _escStaticFS) Open(name string) (http.File, error) {
f, err := fs.prepare(name)
if err != nil {
return nil, err
}
return f.File()
}
func (dir _escDirectory) Open(name string) (http.File, error) {
return dir.fs.Open(dir.name + name)
}
func (f *_escFile) File() (http.File, error) {
type httpFile struct {
*bytes.Reader
*_escFile
}
return &httpFile{
Reader: bytes.NewReader(f.data),
_escFile: f,
}, nil
}
func (f *_escFile) Close() error {
return nil
}
func (f *_escFile) Readdir(count int) ([]os.FileInfo, error) {
return nil, nil
}
func (f *_escFile) Stat() (os.FileInfo, error) {
return f, nil
}
func (f *_escFile) Name() string {
return f.name
}
func (f *_escFile) Size() int64 {
return f.size
}
func (f *_escFile) Mode() os.FileMode {
return 0
}
func (f *_escFile) ModTime() time.Time {
return time.Unix(f.modtime, 0)
}
func (f *_escFile) IsDir() bool {
return f.isDir
}
func (f *_escFile) Sys() interface{} {
return f
}
// FS returns a http.Filesystem for the embedded assets. If useLocal is true,
// the filesystem's contents are instead used.
func FS(useLocal bool) http.FileSystem {
if useLocal {
return _escLocal
}
return _escStatic
}
// Dir returns a http.Filesystem for the embedded assets on a given prefix dir.
// If useLocal is true, the filesystem's contents are instead used.
func Dir(useLocal bool, name string) http.FileSystem {
if useLocal {
return _escDirectory{fs: _escLocal, name: name}
}
return _escDirectory{fs: _escStatic, name: name}
}
// FSByte returns the named file from the embedded assets. If useLocal is
// true, the filesystem's contents are instead used.
func FSByte(useLocal bool, name string) ([]byte, error) {
if useLocal {
f, err := _escLocal.Open(name)
if err != nil {
return nil, err
}
b, err := ioutil.ReadAll(f)
f.Close()
return b, err
}
f, err := _escStatic.prepare(name)
if err != nil {
return nil, err
}
return f.data, nil
}
// FSMustByte is the same as FSByte, but panics if name is not present.
func FSMustByte(useLocal bool, name string) []byte {
b, err := FSByte(useLocal, name)
if err != nil {
panic(err)
}
return b
}
// FSString is the string version of FSByte.
func FSString(useLocal bool, name string) (string, error) {
b, err := FSByte(useLocal, name)
return string(b), err
}
// FSMustString is the string version of FSMustByte.
func FSMustString(useLocal bool, name string) string {
return string(FSMustByte(useLocal, name))
}
var _escData = map[string]*_escFile{
"/static/favicon.ico": {
local: "static/favicon.ico",
size: 1150,
modtime: 1485950788,
compressed: `
H4sIAAAJbogA/6RSTevpYRCdf/13d6O7uGvL+yl8BFufgG5SspaFl0hJFt7Jy0okC6F8BLHAjqxkIcqS
EHM7o3lC1+qemp7zm3PmaZ6ZH9EXfZHFgtNKf76JfhHRbyKyEJGVHnnBN9HPH49Q8BPu97vht9vtn/zZ
847z+cyj0Yi3262p01rkoMHzDvU0m02u1+ucTqe51+sZHRw5aPB86imfz/PxeBReqVS43+9LgAPQ4Pn0
1mKxyPv93mher1dC/dAKhcJLDc7r9Sq80+nwdDoVPpvNpGcEOAANHgA1esflcuHVasWpVIrdbjc3Gg22
2+2cyWQkwJGDBg+8qNE7k8kkt1otns/nopdKJR4Oh+Z94OVyWTR44EUNakOh0MueMGuXyyXcZrNJAE6n
0+xE/eFwmKPRKK/XazMzzFtn5vF4JHSW3W7XzBI1qN1sNtIvZj8YDDgSici+sGsFOHLBYFA88KIGtdo3
dlur1TgQCMh7HQ6H3I8AR87v93O1WuXT6WTegV50lu12m5fLpfDdbmf2Bw4sFguZne5M36wnZnw4HMy3
z+eTUA809P7+/ynP5XLSG+5OJBI8Ho8lwJGDls1mP/6/2E8sFuN4PM6TycTo4MhBe94hQP+JvwEAAP//
uq6JNX4EAAA=
`,
},
"/static/humans.txt": {
local: "static/humans.txt",
size: 303,
modtime: 1485951109,
compressed: `
H4sIAAAJbogA/0SOsWrzQBCE+3uK6X4wQuqvM7L5nUSOA6cm5SGt7cW6XXPas+O3D3IC6WY+mOFrVui3
6z1WjXP9YXNwn1oyjG0ij2eWmKh2gY08KEWeKkwsF5giYlCxOBiOmlMFsqF2/Z3NKHs8lvVvQ5kp/zx1
OkRjFY+W7VGh1SKWH7Vzi8tu/f4W/mwWFl767ZMEizLGPM4eHRkS4SJ6Bx9hZ5bTjJhJ/hluceIRu37f
NW0IzWtwraarConNHv+1wkfWRHamMrugR7vHTB4butGkVxpRZpYTOpbyVeHGCVFGnNhq9x0AAP//oOY3
by8BAAA=
`,
},
"/static/robots.txt": {
local: "static/robots.txt",
size: 44,
modtime: 1485950875,
compressed: `
H4sIAAAJbogA/wotTi3SdUxPzSuxUtDicsksTszJyS+3UkBi6uemlhRlJhdzAQIAAP//2UBAzSwAAAA=
`,
},
"/templates/index.html": {
local: "templates/index.html",
size: 358,
modtime: 1485942389,
compressed: `
H4sIAAAJbogA/3SQwUrEMBBAz8lXjL1rriJjLlE8FQuK4DHa0QbSBtLJYSn992UzhV0ozSUv4fFgBu9e
3t3nd/cKA4/RapRL4UC+txq2gyOxh9/B55n4uSn8d//YgLFaKeTAkewbhX/K4FKZmDIa+dUKjZQU/qT+
dC0CYIm3TwCMwbapp/gEy/JQaV3RxLDXvijPIU1V3PhI/aAcvCQFD5sp8izFCx1prmur5Lp2r6ApdXtG
hkUj6zwHAAD//4sAPXxmAQAA
`,
},
"/": {
isDir: true,
local: "",
},
"/static": {
isDir: true,
local: "static",
},
"/templates": {
isDir: true,
local: "templates",
},
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment