go-pb-traintimes/main.go

485 lines
10 KiB
Go
Raw Permalink Normal View History

2024-07-28 13:57:08 +00:00
package main
import (
"encoding/json"
"fmt"
"github.com/pocketbase/dbx"
"github.com/pocketbase/pocketbase/models"
"github.com/pocketbase/pocketbase/tools/cron"
"io"
"log"
"net/http"
"os"
"strconv"
"time"
"traintimes/trains"
"github.com/labstack/echo/v5"
"github.com/pocketbase/pocketbase"
"github.com/pocketbase/pocketbase/apis"
"github.com/pocketbase/pocketbase/core"
)
type DummyRecord struct {
Ts string `json:"ts"`
}
type GetTrainsRec struct {
From string `db:"from" json:"from"`
To string `db:"to" json:"to"`
Body string `db:"body" json:"body"`
Ts int64 `db:"ts" json:"ts"`
Hash string `db:"hash" json:"hash"`
}
2024-10-28 17:26:42 +00:00
type GetTrainTimesRec struct {
Hash string `db:"hash" json:"hash"`
Body string `db:"body" json:"body"`
Ts int64 `db:"ts" json:"ts"`
}
2024-07-28 13:57:08 +00:00
const host = "https://huxley2.azurewebsites.net"
var (
Version string
Build string
2024-10-28 17:26:42 +00:00
tr = &http.Transport{
MaxIdleConns: 10,
IdleConnTimeout: 30 * time.Second,
DisableCompression: true,
}
client = &http.Client{Transport: tr}
gmtTimeLoc = time.FixedZone("GMT", 0)
timeFormat = "Mon, 2 Jan 2006 15:04:05 GMT"
2024-07-28 13:57:08 +00:00
)
func main() {
log.Printf("GO-TRAINTIMES v%+v build %+v\n\n", Version, Build)
app := pocketbase.New()
// serves static files from the provided public dir (if exists)
app.OnBeforeServe().Add(func(e *core.ServeEvent) error {
scheduler := cron.New()
e.Router.GET("/*", apis.StaticDirectoryHandler(os.DirFS("./pb_public"), false))
e.Router.GET("/gettrains", func(c echo.Context) error {
apis.ActivityLogger(app)
return getTrains(c, app)
})
e.Router.GET("/getnexttraintimes", func(c echo.Context) error {
apis.ActivityLogger(app)
2024-10-28 17:26:42 +00:00
return GetNextTrainTimes(c, app)
2024-07-28 13:57:08 +00:00
})
scheduler.MustAdd("cleanup", "*/10 * * * *", func() {
go CleanupDB(app)
})
scheduler.Start()
return nil
})
if err := app.Start(); err != nil {
log.Fatal(err)
}
}
func NotImplemented(c echo.Context, from string) error {
params := c.QueryParams()
fmt.Printf("NotImplemented from: %s\n", from)
fmt.Printf("-- %+v\n", params)
return nil
}
func getTrains(c echo.Context, app *pocketbase.PocketBase) error {
params := c.QueryParams()
fmt.Printf("$$:getTrains")
fmt.Printf("-- %+v\n", params)
From := c.QueryParamDefault("from", "")
To := c.QueryParamDefault("to", "")
ts := time.Now().Unix()
log.Printf("-- %+v\n", ts)
log.Printf("-- From: %s\n", From)
log.Printf("-- To: %s\n", To)
dummy := DummyRecord{Ts: strconv.FormatInt(ts, 10)}
if From != "" && To != "" {
log.Println("-- Got something to search for")
// check db first..
recentTrain := GetTrainsRec{}
hash := fmt.Sprintf("%s%s", From, To)
dberr := app.Dao().DB().NewQuery("SELECT * FROM trains WHERE hash = {:hash} and ts >= {:ts}").Bind(dbx.Params{
"ts": ts - 120,
"hash": hash,
}).One(&recentTrain)
if dberr == nil {
// handle error
2024-10-28 17:26:42 +00:00
log.Printf("-- Cache hit train %+v\n", recentTrain.Hash)
2024-07-28 13:57:08 +00:00
return c.String(200, recentTrain.Body)
}
// `/all/${ req.query.from }/to/${ req.query.to }/10?accessToken=215b99fe-b237-4a01-aadc-cf315d6756d8`;
url := "/all/" + From + "/to/" + To + "/10?accessToken=215b99fe-b237-4a01-aadc-cf315d6756d8"
log.Printf("-- url: %+v\n", url)
2024-10-28 17:26:42 +00:00
/*tr := &http.Transport{
2024-07-28 13:57:08 +00:00
MaxIdleConns: 10,
IdleConnTimeout: 30 * time.Second,
DisableCompression: true,
2024-10-28 17:26:42 +00:00
}*/
// client := &http.Client{Transport: tr}
2024-07-28 13:57:08 +00:00
log.Printf("-- full url: %+v\n", host+url)
resp, err := client.Get(host + url)
if err != nil {
// handle error
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
log.Fatal(err)
}
var nTrainRec GetTrainsRec
nTrainRec.To = To
nTrainRec.From = From
nTrainRec.Ts = ts
nTrainRec.Body = string(body)
nTrainRec.Hash = hash
go func() {
err := saveTrainRec(app, nTrainRec)
if err != nil {
log.Println(err)
}
}()
// log.Printf("-- body: %+v\n", string(body))
// return c.SendString(string(body))
return c.String(200, string(body))
}
return c.JSON(http.StatusAccepted, dummy)
}
2024-10-28 17:26:42 +00:00
func GetNextTrainTimes(c echo.Context, app *pocketbase.PocketBase) error {
2024-07-28 13:57:08 +00:00
params := c.QueryParams()
log.Println("$$:GetNextTrainTimes")
log.Printf("-- %+v\n", params)
From := c.QueryParamDefault("from", "")
To := c.QueryParamDefault("to", "")
ts := time.Now().String()
2024-10-28 17:26:42 +00:00
tsUnix := time.Now().Unix()
now := time.Now()
then := now.Add(-2 * time.Minute)
2024-07-28 13:57:08 +00:00
log.Printf("-- %+v\n", ts)
log.Printf("-- From: %+v\n", From)
log.Printf("-- To: %+v\n", To)
dummy := DummyRecord{Ts: ts}
2024-10-28 17:26:42 +00:00
recentTraintimes := GetTrainTimesRec{}
hash := fmt.Sprintf("%s%s", From, To)
dberr := app.Dao().DB().NewQuery("SELECT * FROM traintimes WHERE hash = {:hash} and ts >= {:ts}").Bind(dbx.Params{
"ts": tsUnix - 120,
"hash": hash,
}).One(&recentTraintimes)
if dberr == nil {
// handle error
log.Printf("-- Cache hit traintimes %+v\n", recentTraintimes.Hash)
return c.String(200, recentTraintimes.Body)
}
2024-07-28 13:57:08 +00:00
if From != "" && To != "" {
log.Println("-- Got something to search for")
// `/all/${ req.query.from }/to/${ req.query.to }/10?accessToken=215b99fe-b237-4a01-aadc-cf315d6756d8`;
url := "/next/" + From + "/to/" + To + "?accessToken=215b99fe-b237-4a01-aadc-cf315d6756d8"
log.Printf("-- url: %+v\n", url)
log.Printf("-- full url: %+v\n", host+url)
2024-10-28 17:26:42 +00:00
req, err := http.NewRequest("GET", host+url, nil)
2024-07-28 13:57:08 +00:00
if err != nil {
// handle error
}
2024-10-28 17:26:42 +00:00
req.Header.Add("If-Modified-Since", then.In(gmtTimeLoc).Format(timeFormat))
resp, err := client.Do(req)
2024-07-28 13:57:08 +00:00
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
log.Fatal(err)
}
var services trains.AllDepartures
unerr := json.Unmarshal(body, &services)
if unerr != nil {
log.Println("Failed to Unmarshal json")
panic(unerr)
}
departure := reduceNextTrainTimes(services)
departJson, derr := json.Marshal(departure)
if derr != nil {
log.Println("Failed to marshal json")
panic(derr)
}
2024-10-28 17:26:42 +00:00
var nTrainTimesRec GetTrainTimesRec
nTrainTimesRec.Hash = hash
nTrainTimesRec.Ts = tsUnix
nTrainTimesRec.Body = string(departJson)
go func() {
err := saveTraintimesRec(app, nTrainTimesRec)
if err != nil {
log.Println(err)
}
}()
2024-07-28 13:57:08 +00:00
// log.Println("-- body: %+v\n", string(body))
// c.Set(fiber.HeaderContentType, fiber.MIMEApplicationJSON)
// return c.SendString(string(departJson))
// return c.Send(body)
return c.String(200, string(departJson))
}
return c.JSON(http.StatusAccepted, dummy)
}
func reduceNextTrainTimes(departData trains.AllDepartures) trains.NextTrain {
// log.Printf("-- obj?: %+v\n", departData)
depart := departData.Departures[0].Service
// log.Printf("-- depart: %+v\n", depart)
var output trains.NextTrain
if depart.Origin != nil {
if depart.Sta != "" {
output.Sta = depart.Sta
} else {
output.Sta = depart.Std
}
if depart.Eta != "" {
output.Eta = depart.Eta
} else {
output.Eta = depart.Etd
}
} else {
output.Eta = "No Service"
output.Sta = "No Service"
}
// log.Printf("-- output: %+v\n", depart)
return output
}
func saveTrainRec(app *pocketbase.PocketBase, trainRecord GetTrainsRec) error {
log.Println("$$:saveTrainRec")
// foundTrain := GetTrainsRec{}
collection, err := app.Dao().FindCollectionByNameOrId("trains")
if err != nil {
log.Println(err)
return err
}
record, recErr := app.Dao().FindRecordsByExpr("trains", dbx.NewExp("hash = {:hash}", dbx.Params{
"hash": trainRecord.Hash,
}))
if recErr != nil {
log.Println(recErr)
return recErr
}
if len(record) == 0 {
2024-10-28 17:26:42 +00:00
log.Printf("-- Insert new train\n")
2024-07-28 13:57:08 +00:00
record := models.NewRecord(collection)
record.Set("from", trainRecord.From)
record.Set("to", trainRecord.To)
record.Set("body", trainRecord.Body)
record.Set("ts", trainRecord.Ts)
record.Set("hash", trainRecord.Hash)
if err := app.Dao().SaveRecord(record); err != nil {
log.Println(err)
return err
}
} else {
2024-10-28 17:26:42 +00:00
log.Printf("-- Update train\n")
2024-07-28 13:57:08 +00:00
rec := record[0]
rec.Set("body", trainRecord.Body)
rec.Set("ts", trainRecord.Ts)
if err := app.Dao().SaveRecord(rec); err != nil {
log.Println(err)
return err
}
}
/*dberr := app.Dao().DB().NewQuery("SELECT * FROM trains WHERE hash = {:hash}").Bind(dbx.Params{
"hash": trainRecord.Hash,
}).One(&foundTrain)
if dberr != nil {
// handle error
log.Printf("-- Insert New Record %+v,%+v\n", trainRecord.Hash)
record := models.NewRecord(collection)
record.Set("from", trainRecord.From)
record.Set("to", trainRecord.To)
record.Set("body", trainRecord.Body)
record.Set("ts", trainRecord.Ts)
record.Set("hash", trainRecord.Hash)
if err := app.Dao().SaveRecord(record); err != nil {
log.Println(err)
return err
}
} else {
foundTrain.Ts = trainRecord.Ts
foundTrain.Body = trainRecord.Body
record := models.NewRecord(foundTrain)
if err := app.Dao().SaveRecord(record); err != nil {
log.Println(err)
return err
}
}*/
return nil
}
2024-10-28 17:26:42 +00:00
func saveTraintimesRec(app *pocketbase.PocketBase, traintimesRecord GetTrainTimesRec) error {
log.Println("$$:saveTraintimesRec")
// foundTrain := GetTrainsRec{}
collection, err := app.Dao().FindCollectionByNameOrId("traintimes")
if err != nil {
log.Println(err)
return err
}
record, recErr := app.Dao().FindRecordsByExpr("traintimes", dbx.NewExp("hash = {:hash}", dbx.Params{
"hash": traintimesRecord.Hash,
}))
if recErr != nil {
log.Println(recErr)
return recErr
}
if len(record) == 0 {
log.Printf("-- Insert new traintimes\n")
record := models.NewRecord(collection)
record.Set("body", traintimesRecord.Body)
record.Set("ts", traintimesRecord.Ts)
record.Set("hash", traintimesRecord.Hash)
if err := app.Dao().SaveRecord(record); err != nil {
log.Println(err)
return err
}
} else {
log.Printf("-- Update traintimes\n")
rec := record[0]
rec.Set("body", traintimesRecord.Body)
rec.Set("ts", traintimesRecord.Ts)
if err := app.Dao().SaveRecord(rec); err != nil {
log.Println(err)
return err
}
}
return nil
}
2024-07-28 13:57:08 +00:00
func CleanupDB(app *pocketbase.PocketBase) {
ts := time.Now().Unix() - 600
log.Println("$$:CleanupDB", ts)
/*raw := "Delete from trains where ts <=" + strconv.FormatInt(ts, 10)
if _, err := app.Dao().DB().NewQuery(raw).Execute(); err != nil {
log.Fatalln(err)
}*/
}