2017-03-25 02:41:36 +00:00
|
|
|
package webcmd
|
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/json"
|
|
|
|
"fmt"
|
|
|
|
"io/ioutil"
|
|
|
|
"log"
|
|
|
|
"net/http"
|
|
|
|
"regexp"
|
|
|
|
"sync"
|
|
|
|
)
|
|
|
|
|
2017-03-25 03:28:25 +00:00
|
|
|
var APP_VERSION string = "x.x.x" // Overridden by makefile
|
|
|
|
|
2017-03-25 02:41:36 +00:00
|
|
|
type App struct {
|
|
|
|
cfg AppConfig
|
|
|
|
|
|
|
|
rxTaskInfo *regexp.Regexp
|
|
|
|
|
|
|
|
tasksMtx sync.RWMutex
|
|
|
|
tasks map[string]Task
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewApp(configPath string) (*App, error) {
|
|
|
|
|
|
|
|
confBytes, err := ioutil.ReadFile(configPath)
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("Couldn't open configuration file '%s': %s", configPath, err.Error())
|
|
|
|
}
|
|
|
|
|
|
|
|
cfg := AppConfig{}
|
|
|
|
err = json.Unmarshal(confBytes, &cfg)
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("Invalid configuration file: %s", err.Error())
|
|
|
|
}
|
|
|
|
|
|
|
|
return NewAppFromConfig(cfg), nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewAppFromConfig(cfg AppConfig) *App {
|
|
|
|
return &App{
|
|
|
|
cfg: cfg,
|
|
|
|
rxTaskInfo: regexp.MustCompile(`^/task/([A-Z0-9]+)$`),
|
|
|
|
tasks: make(map[string]Task),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (this *App) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
2017-03-25 03:28:25 +00:00
|
|
|
w.Header().Set("Server", "webcmd/"+APP_VERSION)
|
2017-03-25 02:41:36 +00:00
|
|
|
|
|
|
|
if r.Method == "GET" {
|
|
|
|
if r.URL.Path == "/" {
|
|
|
|
this.Serve_Homepage(w)
|
|
|
|
|
|
|
|
} else if r.URL.Path == "/style.css" {
|
|
|
|
this.Serve_StyleCSS(w)
|
|
|
|
|
|
|
|
} else if r.URL.Path == "/tasks" {
|
|
|
|
this.Serve_Tasks(w)
|
|
|
|
|
|
|
|
} else if matches := this.rxTaskInfo.FindStringSubmatch(r.URL.Path); len(matches) == 2 {
|
|
|
|
this.Serve_TaskInfo(w, matches[1])
|
|
|
|
|
|
|
|
} else {
|
|
|
|
http.Error(w, "No matching route for request", 404)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
} else if r.Method == "POST" {
|
|
|
|
if r.URL.Path == "/x-new-task" {
|
|
|
|
this.Action_NewTask(w, r)
|
|
|
|
|
|
|
|
} else if r.URL.Path == "/x-abandon-task" {
|
|
|
|
this.Action_AbandonTask(w, r)
|
|
|
|
|
|
|
|
} else if r.URL.Path == "/x-clear-completed-tasks" {
|
|
|
|
this.Action_ClearCompleted(w, r)
|
|
|
|
|
|
|
|
} else {
|
|
|
|
http.Error(w, "No matching route for request", 404)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
http.Error(w, "Invalid method", 400)
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (this *App) Run() {
|
|
|
|
mux := http.NewServeMux()
|
|
|
|
mux.Handle("/", this)
|
|
|
|
|
|
|
|
log.Printf("Listening on '%s'...", this.cfg.ListenAddress)
|
|
|
|
err := http.ListenAndServe(this.cfg.ListenAddress, mux)
|
|
|
|
if err != nil {
|
|
|
|
log.Fatalf("Network error: %s", err.Error())
|
|
|
|
}
|
|
|
|
}
|