167 lines
3.4 KiB
Go
167 lines
3.4 KiB
Go
package jsondb
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"net/url"
|
|
"os"
|
|
"strings"
|
|
"time"
|
|
|
|
again "git.rootprojects.org/root/go-again"
|
|
)
|
|
|
|
type JSONDB struct {
|
|
dburl string
|
|
path string
|
|
json *dbjson
|
|
}
|
|
|
|
type dbjson struct {
|
|
Schedules []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":[]}`))
|
|
f.Close()
|
|
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)
|
|
f.Close()
|
|
if nil != err {
|
|
return nil, fmt.Errorf("Couldn't parse %q as JSON: %s", path, err)
|
|
}
|
|
|
|
return &JSONDB{
|
|
dburl: dburl,
|
|
path: path,
|
|
json: db,
|
|
}, nil
|
|
}
|
|
|
|
// A copy of again.Schedule, but with access_id json-able
|
|
type Schedule struct {
|
|
ID string `json:"id" db:"id"`
|
|
AccessID string `json:"access_id" db:"access_id"`
|
|
Date string `json:"date" db:"date"`
|
|
Time string `json:"time" db:"time"`
|
|
TZ string `json:"tz" db:"tz"`
|
|
NextRunAt time.Time `json:"next_run_at" db:"next_run_at"`
|
|
Disabled bool `json:"disabled" db:"disabled"`
|
|
Webhooks []again.Webhook `json:"webhooks" db"webhooks"`
|
|
}
|
|
|
|
func (db *JSONDB) List(accessID string) ([]*again.Schedule, error) {
|
|
schedules := []*again.Schedule{}
|
|
for i := range db.json.Schedules {
|
|
s := db.json.Schedules[i]
|
|
if !s.Disabled && accessID == s.AccessID {
|
|
schedules = append(schedules, &again.Schedule{
|
|
ID: s.ID,
|
|
AccessID: s.AccessID,
|
|
Date: s.Date,
|
|
Time: s.Time,
|
|
TZ: s.TZ,
|
|
NextRunAt: s.NextRunAt,
|
|
Webhooks: s.Webhooks,
|
|
})
|
|
}
|
|
}
|
|
return schedules, nil
|
|
}
|
|
|
|
func (db *JSONDB) get(id string) *Schedule {
|
|
for i := range db.json.Schedules {
|
|
schedule := db.json.Schedules[i]
|
|
if id == schedule.AccessID {
|
|
return &schedule
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (db *JSONDB) Set(s again.Schedule) (*again.Schedule, error) {
|
|
newSchedules := []Schedule{}
|
|
|
|
for i := range db.json.Schedules {
|
|
old := db.json.Schedules[i]
|
|
if s.ID == old.AccessID {
|
|
continue
|
|
}
|
|
newSchedules = append(newSchedules, old)
|
|
}
|
|
|
|
schedule := Schedule{
|
|
ID: s.ID,
|
|
AccessID: s.AccessID,
|
|
Date: s.Date,
|
|
Time: s.Time,
|
|
TZ: s.TZ,
|
|
NextRunAt: s.NextRunAt,
|
|
Webhooks: s.Webhooks,
|
|
}
|
|
newSchedules = append(newSchedules, schedule)
|
|
|
|
err := db.save(s.AccessID)
|
|
if nil != err {
|
|
return nil, err
|
|
}
|
|
|
|
return &s, nil
|
|
}
|
|
|
|
func (db *JSONDB) save(accessID string) error {
|
|
// TODO per-user files (w/ mutex lock or channel on open and write)
|
|
f, err := os.OpenFile(db.path, os.O_RDWR|os.O_CREATE, 0700)
|
|
if nil != err {
|
|
return err
|
|
}
|
|
|
|
encoder := json.NewEncoder(f)
|
|
err = encoder.Encode(db.json.Schedules)
|
|
f.Close()
|
|
if nil != err {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|