104 lines
2.1 KiB
Go
104 lines
2.1 KiB
Go
package main
|
|
|
|
import (
|
|
"database/sql"
|
|
"encoding/json"
|
|
"fmt"
|
|
"log"
|
|
"net/http"
|
|
"path/filepath"
|
|
"time"
|
|
|
|
"github.com/NYTimes/gziphandler"
|
|
"golang.org/x/crypto/acme/autocert"
|
|
)
|
|
|
|
const AppName = `webscaffold`
|
|
|
|
type WebSession struct {
|
|
LastRefreshTime time.Time
|
|
}
|
|
|
|
type Application struct {
|
|
c Config
|
|
webfile http.Handler
|
|
db *sql.DB
|
|
|
|
sessions map[string]WebSession
|
|
}
|
|
|
|
func (this *Application) Start() error {
|
|
log.Printf("Starting %s application...", AppName)
|
|
|
|
// Connect to DB
|
|
err := this.connectToDB()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Resources
|
|
this.webfile = http.FileServer(http.Dir(this.c.WebrootDir))
|
|
|
|
// Set up HTTP server
|
|
if this.c.Autocert == "" {
|
|
log.Printf("Starting web server (HTTP on %s)...", this.c.ListenAddress)
|
|
return http.ListenAndServe(this.c.ListenAddress, this) // Plain HTTP
|
|
|
|
} else {
|
|
log.Printf("Starting web server (HTTPS as '%s' on :80 + :443)...", this.c.Autocert)
|
|
return http.Serve(autocert.NewListener(this.c.Autocert), this) // HTTPS
|
|
|
|
}
|
|
}
|
|
|
|
func (this *Application) respondWith(object interface{}, nerr netError) http.HandlerFunc {
|
|
return func(w http.ResponseWriter, r *http.Request) { // curry over extra arity
|
|
if nerr != nil {
|
|
nerr.Respond(w)
|
|
return
|
|
}
|
|
|
|
// Plaintext response
|
|
// Buffer the resulting json data, so that we can determine the final size
|
|
|
|
jb, err := json.Marshal(object)
|
|
if err != nil {
|
|
systemError{err}.Respond(w)
|
|
return
|
|
}
|
|
|
|
w.Header().Set(`Content-Type`, `application/json`)
|
|
w.Header().Set(`Content-Length`, fmt.Sprintf("%d", len(jb)))
|
|
w.WriteHeader(200)
|
|
w.Write(jb)
|
|
}
|
|
}
|
|
|
|
func (this *Application) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|
r.Header.Set(`Server`, AppName+`/1.0`)
|
|
|
|
switch r.Method {
|
|
case "GET":
|
|
r.Header.Set(`X-Frame-Options`, `Deny`)
|
|
|
|
if r.URL.Path == `/` {
|
|
http.ServeFile(w, r, filepath.Join(this.c.WebrootDir, "index.html")) // n.b. no gzip
|
|
|
|
} else {
|
|
gziphandler.GzipHandler(this.webfile).ServeHTTP(w, r)
|
|
|
|
}
|
|
|
|
case "POST":
|
|
if r.URL.Path == `/api/v1/login` {
|
|
resp, err := this.apiLogin(r)
|
|
gziphandler.GzipHandler(this.respondWith(resp, err)).ServeHTTP(w, r)
|
|
|
|
} else {
|
|
http.Error(w, "not found", 404)
|
|
|
|
}
|
|
|
|
}
|
|
}
|