Update `config.go` Add `feed.go` Add `messageTypes.go` Add `process.go` Update `main.go` Update `structures.go` Update `go.mod` Update `go.sum`
213 lines
5.4 KiB
Go
213 lines
5.4 KiB
Go
package schedule
|
|
|
|
import (
|
|
"bufio"
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"github.com/pkg/errors"
|
|
"github.com/redis/go-redis/v9"
|
|
"github.com/rs/zerolog/log"
|
|
"io"
|
|
"os"
|
|
)
|
|
|
|
func LoadFile(client *redis.Client, filename string) error {
|
|
f, err := os.Open(filename)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer f.Close()
|
|
|
|
scheduleIDCount := make(map[string]int)
|
|
|
|
n := 0
|
|
_, _ = fmt.Fprintf(os.Stderr, "%d\r", 0)
|
|
|
|
rd := bufio.NewReader(f)
|
|
for {
|
|
line, err := rd.ReadBytes('\n')
|
|
if err != nil {
|
|
if errors.Is(err, io.EOF) {
|
|
break
|
|
}
|
|
return err
|
|
}
|
|
|
|
record := new(Record)
|
|
if err := json.Unmarshal(line, record); err != nil {
|
|
log.Debug().Msg(err.Error())
|
|
log.Debug().Bytes("record", line).Send()
|
|
return err
|
|
}
|
|
|
|
if record.TIPLOC != nil {
|
|
r := client.HMSet(context.Background(), fmt.Sprintf("tiploc:%s", record.TIPLOC.Code), record.TIPLOC.ToMap())
|
|
if err := r.Err(); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
if record.Schedule != nil {
|
|
|
|
n := scheduleIDCount[record.Schedule.CIFTrainUid]
|
|
scheduleIDCount[record.Schedule.CIFTrainUid] = n + 1
|
|
|
|
sched := fmt.Sprintf("schedule:%s:%d", record.Schedule.CIFTrainUid, n)
|
|
|
|
r := client.HMSet(context.Background(), sched, record.Schedule.ToMap())
|
|
if err := r.Err(); err != nil {
|
|
return err
|
|
}
|
|
|
|
rr := client.Set(context.Background(), sched+":locations", len(record.Schedule.ScheduleSegment.ScheduleLocation), 0)
|
|
if err := rr.Err(); err != nil {
|
|
return err
|
|
}
|
|
|
|
for i, loc := range record.Schedule.ScheduleSegment.ScheduleLocation {
|
|
r = client.HMSet(context.Background(), fmt.Sprintf("%s:locations:%d", sched, i), loc.ToMap())
|
|
if err := r.Err(); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
n += 1
|
|
if n%1000 == 0 {
|
|
_, _ = fmt.Fprintf(os.Stderr, "%d\r", n)
|
|
}
|
|
}
|
|
|
|
_, _ = fmt.Fprintf(os.Stderr, "%d records processed\n", n)
|
|
|
|
for key, val := range scheduleIDCount {
|
|
client.Set(context.Background(), "schedule:"+key, val, 0)
|
|
}
|
|
|
|
_, _ = fmt.Fprintln(os.Stderr, "Inserted schedule counts")
|
|
|
|
return nil
|
|
}
|
|
|
|
type Record struct {
|
|
//TimetableDecl any `json:"JsonTimetableV1"`
|
|
TIPLOC *TIPLOC `json:"TiplocV1"`
|
|
// TODO: Associations?
|
|
Schedule *Schedule `json:"JsonScheduleV1"`
|
|
}
|
|
|
|
type TIPLOC struct {
|
|
Code string `json:"tiploc_code"`
|
|
Stanox string `json:"stanox"`
|
|
Description string `json:"tps_description"`
|
|
HumanDescription string `json:"description"`
|
|
}
|
|
|
|
func (t *TIPLOC) ToMap() map[string]interface{} {
|
|
mp := map[string]interface{}{
|
|
"description": t.Description,
|
|
}
|
|
|
|
if t.HumanDescription != "" {
|
|
mp["humanDescription"] = t.HumanDescription
|
|
}
|
|
|
|
return mp
|
|
}
|
|
|
|
type Schedule struct {
|
|
CIFStpIndicator string `json:"CIF_stp_indicator"`
|
|
CIFTrainUid string `json:"CIF_train_uid"`
|
|
ScheduleDaysRuns string `json:"schedule_days_runs"`
|
|
ScheduleEndDate string `json:"schedule_end_date"`
|
|
ScheduleSegment *ScheduleSegment `json:"schedule_segment"`
|
|
ScheduleStartDate string `json:"schedule_start_date"`
|
|
TrainStatus string `json:"train_status"`
|
|
}
|
|
|
|
func (s *Schedule) ToMap() map[string]interface{} {
|
|
return map[string]interface{}{
|
|
"signallingID": s.ScheduleSegment.SignallingId,
|
|
"stpIndicator": s.CIFStpIndicator,
|
|
"trainUID": s.CIFTrainUid,
|
|
"scheduleDaysRuns": s.ScheduleDaysRuns,
|
|
"trainStatus": s.TrainStatus,
|
|
}
|
|
}
|
|
|
|
type ScheduleSegment struct {
|
|
SignallingId string `json:"signalling_id"`
|
|
CIFTrainCategory string `json:"CIF_train_category"`
|
|
CIFHeadcode string `json:"CIF_headcode"`
|
|
CIFSpeed string `json:"CIF_speed"`
|
|
CIFTrainClass string `json:"CIF_train_class"`
|
|
ScheduleLocation []*ScheduleLocation `json:"schedule_location"`
|
|
}
|
|
|
|
type ScheduleLocation struct {
|
|
LocationType string `json:"location_type"`
|
|
RecordIdentity string `json:"record_identity"`
|
|
TiplocCode string `json:"tiploc_code"`
|
|
TiplocInstance *string `json:"tiploc_instance"`
|
|
Departure *string `json:"departure,omitempty"`
|
|
PublicDeparture *string `json:"public_departure,omitempty"`
|
|
Platform *string `json:"platform"`
|
|
EngineeringAllowance *string `json:"engineering_allowance,omitempty"`
|
|
PathingAllowance *string `json:"pathing_allowance"`
|
|
PerformanceAllowance *string `json:"performance_allowance"`
|
|
Arrival *string `json:"arrival,omitempty"`
|
|
Pass *string `json:"pass,omitempty"`
|
|
PublicArrival *string `json:"public_arrival,omitempty"`
|
|
}
|
|
|
|
func (s *ScheduleLocation) ToMap() map[string]interface{} {
|
|
m := map[string]interface{}{
|
|
"locationType": s.LocationType,
|
|
"recordIdentity": s.RecordIdentity,
|
|
"tiplocCode": s.TiplocCode,
|
|
}
|
|
|
|
if s.TiplocInstance != nil {
|
|
m["tiplocInstance"] = *s.TiplocInstance
|
|
}
|
|
|
|
if s.Departure != nil {
|
|
m["departure"] = *s.Departure
|
|
}
|
|
|
|
if s.PublicDeparture != nil {
|
|
m["publicDeparture"] = *s.PublicDeparture
|
|
}
|
|
|
|
if s.Platform != nil {
|
|
m["platform"] = *s.Platform
|
|
}
|
|
|
|
if s.EngineeringAllowance != nil {
|
|
m["engineeringAllowance"] = *s.EngineeringAllowance
|
|
}
|
|
|
|
if s.PathingAllowance != nil {
|
|
m["pathingAllowance"] = *s.PathingAllowance
|
|
}
|
|
|
|
if s.PerformanceAllowance != nil {
|
|
m["performanceAllowance"] = *s.PerformanceAllowance
|
|
}
|
|
|
|
if s.Arrival != nil {
|
|
m["arrival"] = *s.Arrival
|
|
}
|
|
|
|
if s.Pass != nil {
|
|
m["pass"] = *s.Pass
|
|
}
|
|
|
|
if s.PublicArrival != nil {
|
|
m["publicArrival"] = *s.PublicArrival
|
|
}
|
|
|
|
return m
|
|
}
|