WIP: more nae nae

This commit is contained in:
AJ ONeal 2019-06-22 01:10:21 -06:00
parent 53190fcfdc
commit 6712864da0
5 changed files with 154 additions and 8 deletions

4
.gitignore vendored
View File

@ -1,3 +1,7 @@
db.json
/cmd/again/again
/again
# ---> Go # ---> Go
# Binaries for programs and plugins # Binaries for programs and plugins
*.exe *.exe

Binary file not shown.

View File

@ -1,6 +1,7 @@
package main package main
import ( import (
"encoding/json"
"flag" "flag"
"fmt" "fmt"
"log" "log"
@ -9,14 +10,17 @@ import (
"strconv" "strconv"
"time" "time"
again "git.rootprojects.org/root/go-again"
"git.rootprojects.org/root/go-again/data/jsondb" "git.rootprojects.org/root/go-again/data/jsondb"
) )
func main() { func main() {
portEnv := os.Getenv("PORT") portEnv := os.Getenv("PORT")
dbEnv := os.Getenv("DATABASE_URL")
portInt := flag.Int("port", 0, "port on which to serve http") portInt := flag.Int("port", 0, "port on which to serve http")
addr := flag.String("addr", "", "address on which to serve http") addr := flag.String("addr", "", "address on which to serve http")
dburl := flag.String("database-url", "", "For example: json://relative-path/db.json or json:///absolute-path/db.json")
flag.Parse() flag.Parse()
if "" != portEnv { if "" != portEnv {
@ -32,24 +36,86 @@ func main() {
*portInt = n *portInt = n
} }
if *portInt < 1024 || *portInt > 65535 { if *portInt < 1024 || *portInt > 65535 {
log.Fatalf("port should be between 1024 and 65535, not %d.", *portInt) log.Fatalf("`port` should be between 1024 and 65535, not %d.", *portInt)
return return
} }
portEnv = strconv.Itoa(*portInt) portEnv = strconv.Itoa(*portInt)
if "" != dbEnv {
if "" != *dburl {
log.Fatal("You may set DATABASE_URL or --database-url, but not both.")
return
}
*dburl = dbEnv
// TODO parse string?
// TODO have each connector try in sequence by registering with build tags like go-migrate does?
}
if "" == *dburl {
log.Fatalf("`database-url` must be specified." +
" Something like --database-url='json:///var/go-again/db.json' should do nicely.")
return
}
db, err := jsondb.Connect(*dburl)
if nil != err {
log.Fatalf("Could not connect to database %q: %s", *dburl, err)
return
}
s := &scheduler{
DB: db,
}
mux := http.NewServeMux()
server := &http.Server{ server := &http.Server{
Addr: fmt.Sprintf("%s:%s", *addr, portEnv), Addr: fmt.Sprintf("%s:%s", *addr, portEnv),
Handler: http.HandlerFunc(handleFunc), Handler: mux,
ReadTimeout: 10 * time.Second, ReadTimeout: 10 * time.Second,
WriteTimeout: 10 * time.Second, WriteTimeout: 10 * time.Second,
MaxHeaderBytes: 1 << 20, MaxHeaderBytes: 1 << 20,
} }
//mux.Handle("/api/", http.HandlerFunc(handleFunc))
mux.HandleFunc("/api/schedules", s.Handle)
// TODO Filebox FS
mux.Handle("/", http.FileServer(http.Dir("./public")))
fmt.Println("Listening on", server.Addr) fmt.Println("Listening on", server.Addr)
log.Fatal(server.ListenAndServe()) log.Fatal(server.ListenAndServe())
} }
func handleFunc(w http.ResponseWriter, r *http.Request) { type ScheduleDB interface {
jsondb.List() List() ([]again.Schedule, error)
w.Write([]byte("Hello, World!")) }
type scheduler struct {
DB ScheduleDB
}
func (s *scheduler) Handle(w http.ResponseWriter, r *http.Request) {
fmt.Println("whatever", r.Method, r.URL)
switch r.Method {
case http.MethodGet:
s.List(w, r)
return
case http.MethodPost:
http.Error(w, "Not Implemented", http.StatusNotImplemented)
return
default:
http.Error(w, "Not Implemented", http.StatusNotImplemented)
return
}
}
func (s *scheduler) List(w http.ResponseWriter, r *http.Request) {
schedules, err := s.DB.List()
if nil != err {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
buf, err := json.Marshal(schedules)
if nil != err {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.Write(buf)
} }

View File

@ -1,11 +1,78 @@
package jsondb package jsondb
import ( import (
"errors" "encoding/json"
"fmt"
"net/url"
"os"
"strings"
again "git.rootprojects.org/root/go-again" again "git.rootprojects.org/root/go-again"
) )
func List() ([]again.Schedule, error) { type JSONDB struct {
return nil, errors.New("Not Implemented") dburl string
file *os.File
json *dbjson
}
type dbjson struct {
Schedules []again.Schedule `json:"schedules"`
}
func Connect(dburl string) (*JSONDB, error) {
u, err := url.Parse(dburl)
if nil != err {
return nil, err
}
// json:/abspath/to/db.json
fmt.Println("url.Opaque:", u.Opaque)
// json:///abspath/to/db.json
fmt.Println("url.Path:", u.Path)
fmt.Println(u)
path := u.Opaque
if "" == path {
path = u.Path
if "" == path {
// json:relpath/to/db.json
// json://relpath/to/db.json
path = strings.TrimSuffix(u.Host+"/"+u.Path, "/")
}
}
f, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE, 0700)
if nil != err {
return nil, fmt.Errorf("Couldn't open %q: %s", path, err)
}
stat, err := f.Stat()
if 0 == stat.Size() {
_, err := f.Write([]byte(`{"schedules":[]}`))
if nil != err {
return nil, err
}
f, err = os.OpenFile(path, os.O_RDWR|os.O_CREATE, 0700)
if nil != err {
return nil, err
}
}
decoder := json.NewDecoder(f)
db := &dbjson{}
err = decoder.Decode(db)
if nil != err {
return nil, fmt.Errorf("Couldn't parse %q as JSON: %s", path, err)
}
return &JSONDB{
dburl: dburl,
file: f,
json: db,
}, nil
}
func (db *JSONDB) List() ([]again.Schedule, error) {
return db.json.Schedules, nil
} }

9
public/index.html Normal file
View File

@ -0,0 +1,9 @@
<!DOCTYPE html>
<html>
<head>
<title>Go Again</title>
</head>
<body>
<h1>Hello, World!</h1>
</body>
</html>