WIP: more nae nae
This commit is contained in:
parent
53190fcfdc
commit
6712864da0
|
@ -1,3 +1,7 @@
|
||||||
|
db.json
|
||||||
|
/cmd/again/again
|
||||||
|
/again
|
||||||
|
|
||||||
# ---> Go
|
# ---> Go
|
||||||
# Binaries for programs and plugins
|
# Binaries for programs and plugins
|
||||||
*.exe
|
*.exe
|
||||||
|
|
BIN
cmd/again/again
BIN
cmd/again/again
Binary file not shown.
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Go Again</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>Hello, World!</h1>
|
||||||
|
</body>
|
||||||
|
</html>
|
Loading…
Reference in New Issue