Reorganise repo
This commit is contained in:
55
vstp/actions.go
Normal file
55
vstp/actions.go
Normal file
@@ -0,0 +1,55 @@
|
||||
package vstp
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"git.fjla.uk/owlboard/go-types/pkg/database"
|
||||
"git.fjla.uk/owlboard/timetable-mgr/dbAccess"
|
||||
"git.fjla.uk/owlboard/timetable-mgr/log"
|
||||
)
|
||||
|
||||
// Decide, based on the DB Formatted message type, what action needs taking
|
||||
// then either insert, or delete from the database as required
|
||||
func processEntryType(entry database.Service) {
|
||||
|
||||
switch entry.TransactionType {
|
||||
case "Create":
|
||||
createEntry(entry)
|
||||
case "Update":
|
||||
updateEntry(entry)
|
||||
case "Delete":
|
||||
deleteEntry(entry)
|
||||
default:
|
||||
log.Msg.Error("Unknown transaction type: " + entry.TransactionType)
|
||||
}
|
||||
}
|
||||
|
||||
func createEntry(entry database.Service) {
|
||||
log.Msg.Info("Entry Creation requested for: " + entry.TrainUid + " - " + entry.Headcode + " - " + entry.Operator)
|
||||
status := dbAccess.PutOneService(entry)
|
||||
if status {
|
||||
log.Msg.Info("Database entry created")
|
||||
} else {
|
||||
log.Msg.Error("Database entry failed, skipped service")
|
||||
}
|
||||
}
|
||||
|
||||
func updateEntry(entry database.Service) {
|
||||
log.Msg.Info("Entry UPDATE requested for: " + entry.TrainUid + " - " + entry.Headcode + " - " + entry.Operator)
|
||||
}
|
||||
|
||||
func deleteEntry(entry database.Service) {
|
||||
log.Msg.Info("Entry DELETE requested for: " + entry.TrainUid + " - " + entry.Headcode)
|
||||
var deletionQuery = database.DeleteQuery{
|
||||
TrainUid: entry.TrainUid,
|
||||
ScheduleStartDate: entry.ScheduleStartDate,
|
||||
StpIndicator: entry.StpIndicator,
|
||||
}
|
||||
status := dbAccess.DeleteOneService(deletionQuery)
|
||||
if status {
|
||||
log.Msg.Info("Database entry deleted")
|
||||
} else {
|
||||
log.Msg.Error("Database deletion failed, skipped deletion")
|
||||
fmt.Printf("%+v\n", deletionQuery)
|
||||
}
|
||||
}
|
||||
17
vstp/handler.go
Normal file
17
vstp/handler.go
Normal file
@@ -0,0 +1,17 @@
|
||||
package vstp
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"git.fjla.uk/owlboard/timetable-mgr/log"
|
||||
"github.com/go-stomp/stomp/v3"
|
||||
)
|
||||
|
||||
var count uint64 = 0
|
||||
|
||||
func handle(msg *stomp.Message) {
|
||||
count++
|
||||
log.Msg.Info("Messages since started: " + fmt.Sprint(count))
|
||||
schedule := unmarshalData(string(msg.Body))
|
||||
processEntryType(schedule)
|
||||
}
|
||||
158
vstp/parser.go
Normal file
158
vstp/parser.go
Normal file
@@ -0,0 +1,158 @@
|
||||
package vstp
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"git.fjla.uk/owlboard/go-types/pkg/database"
|
||||
"git.fjla.uk/owlboard/go-types/pkg/upstreamApi"
|
||||
"git.fjla.uk/owlboard/timetable-mgr/helpers"
|
||||
"git.fjla.uk/owlboard/timetable-mgr/log"
|
||||
)
|
||||
|
||||
// Unmarshals the JSON data and runs it through the formatData() function and returns the data in a DB ready Struct
|
||||
func unmarshalData(jsonData string) database.Service {
|
||||
var schedule upstreamApi.MsgData
|
||||
err := json.Unmarshal([]byte(jsonData), &schedule)
|
||||
if err != nil {
|
||||
log.Msg.Error("Unable to unmarshal message body: " + err.Error())
|
||||
//return err
|
||||
}
|
||||
log.Msg.Debug("Unmarshalling Complete")
|
||||
|
||||
if schedule.Data.CIFMsg.ScheduleSegment == nil {
|
||||
log.Msg.Warn("ScheduleSegment is nil")
|
||||
} else if len(schedule.Data.CIFMsg.ScheduleSegment) == 0 {
|
||||
log.Msg.Warn("ScheduleSegment is empty")
|
||||
}
|
||||
return formatData(&schedule.Data.CIFMsg)
|
||||
}
|
||||
|
||||
// Transforms the upstreamApi.Schedule type into a database.Service type
|
||||
func formatData(dataInput *upstreamApi.Schedule) database.Service {
|
||||
log.Msg.Debug("ScheduleSegment length: " + fmt.Sprint(len(dataInput.ScheduleSegment)))
|
||||
log.Msg.Debug("Printing dataInput to console:")
|
||||
|
||||
var operator, headcode, powerType string
|
||||
var planSpeed int32
|
||||
var stops []database.Stop
|
||||
|
||||
// Check that the ScheduleSegment contains data, 'Delete' messages have no ScheduleSegment
|
||||
if len(dataInput.ScheduleSegment) > 0 {
|
||||
operator = dataInput.ScheduleSegment[0].ATOCCode
|
||||
headcode = dataInput.ScheduleSegment[0].SignallingID
|
||||
powerType = dataInput.ScheduleSegment[0].CIFPowerType
|
||||
planSpeed = parseSpeed(dataInput.ScheduleSegment[0].CIFSpeed)
|
||||
stops = parseStops(dataInput.ScheduleSegment[0].ScheduleLocation)
|
||||
}
|
||||
if operator == "" {
|
||||
operator = "UK"
|
||||
}
|
||||
service := database.Service{
|
||||
TransactionType: dataInput.TransactionType,
|
||||
StpIndicator: dataInput.CIFSTPIndicator,
|
||||
Vstp: true,
|
||||
Operator: operator,
|
||||
TrainUid: dataInput.CIFTrainUID,
|
||||
Headcode: headcode,
|
||||
PowerType: powerType,
|
||||
PlanSpeed: planSpeed,
|
||||
ScheduleStartDate: parseDate(dataInput.ScheduleStartDate, false),
|
||||
ScheduleEndDate: parseDate(dataInput.ScheduleEndDate, true),
|
||||
DaysRun: parseDaysRun(dataInput.ScheduleDaysRun),
|
||||
Stops: stops,
|
||||
}
|
||||
return service
|
||||
}
|
||||
|
||||
// Uses the map provided in 'helpers' to translate incorrect CIF speeds to their correct equivalent
|
||||
func parseSpeed(CIFSpeed string) int32 {
|
||||
log.Msg.Debug("CIFSpeed Input: '" + CIFSpeed + "'")
|
||||
if CIFSpeed == "" {
|
||||
log.Msg.Debug("Speed data not provided")
|
||||
return int32(0)
|
||||
}
|
||||
actualSpeed, exists := helpers.SpeedMap[CIFSpeed]
|
||||
if !exists {
|
||||
actualSpeed = CIFSpeed
|
||||
}
|
||||
log.Msg.Debug("Corrected Speed: " + actualSpeed)
|
||||
|
||||
speed, err := strconv.ParseInt(actualSpeed, 10, 32)
|
||||
if err != nil {
|
||||
log.Msg.Warn("Unable to parse speed: " + CIFSpeed + ", returning 0")
|
||||
return int32(0)
|
||||
}
|
||||
return int32(speed)
|
||||
}
|
||||
|
||||
// Converts the date string provided from the upstream API into a proper Date type and adds a time
|
||||
func parseDate(dateString string, end bool) time.Time {
|
||||
log.Msg.Debug("Date Input: " + dateString)
|
||||
date, err := time.Parse("2006-01-02", dateString)
|
||||
if err != nil {
|
||||
log.Msg.Error("Unable to parse date: " + dateString)
|
||||
return time.Time{}
|
||||
}
|
||||
|
||||
var hour, minute, second, nanosecond int
|
||||
location := time.UTC
|
||||
if end {
|
||||
hour, minute, second, nanosecond = 23, 59, 59, 0
|
||||
} else {
|
||||
hour, minute, second, nanosecond = 0, 0, 0, 0
|
||||
}
|
||||
|
||||
dateWithTime := time.Date(date.Year(), date.Month(), date.Day(), hour, minute, second, nanosecond, location)
|
||||
log.Msg.Debug("Parsed date: " + dateWithTime.String())
|
||||
return dateWithTime
|
||||
}
|
||||
|
||||
// Converts the binary stype 'daysRun' field into an array of short days
|
||||
func parseDaysRun(daysBinary string) []string {
|
||||
log.Msg.Debug("daysRun Input: " + daysBinary)
|
||||
shortDays := []string{"m", "t", "w", "th", "f", "s", "su"}
|
||||
var result []string
|
||||
for i, digit := range daysBinary {
|
||||
if digit == '1' {
|
||||
result = append(result, shortDays[i])
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// Converts an array if upstreamApi.ScheduleLocation types to an array of database.Stop types
|
||||
func parseStops(inputStops []upstreamApi.ScheduleLocation) []database.Stop {
|
||||
var stops []database.Stop
|
||||
|
||||
for _, loc := range inputStops {
|
||||
stop := database.Stop{
|
||||
PublicDeparture: parseTimeStrings(loc.PublicDepartureTime),
|
||||
WttDeparture: parseTimeStrings(loc.ScheduledDepartureTime),
|
||||
PublicArrival: parseTimeStrings(loc.PublicArrivalTime),
|
||||
WttArrival: parseTimeStrings(loc.ScheduledArrivalTime),
|
||||
IsPublic: strings.TrimSpace(loc.PublicDepartureTime) != "" || strings.TrimSpace(loc.PublicArrivalTime) != "",
|
||||
Tiploc: loc.Tiploc.Tiploc.TiplocId,
|
||||
}
|
||||
|
||||
stops = append(stops, stop)
|
||||
}
|
||||
|
||||
return stops
|
||||
}
|
||||
|
||||
func parseTimeStrings(t string) string {
|
||||
if t == "" {
|
||||
return t
|
||||
}
|
||||
|
||||
strippedT := strings.TrimSpace(t)
|
||||
if strippedT == "" {
|
||||
return ""
|
||||
} else {
|
||||
return strippedT[:4]
|
||||
}
|
||||
}
|
||||
39
vstp/subscribe.go
Normal file
39
vstp/subscribe.go
Normal file
@@ -0,0 +1,39 @@
|
||||
package vstp
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"git.fjla.uk/owlboard/timetable-mgr/log"
|
||||
"git.fjla.uk/owlboard/timetable-mgr/messaging"
|
||||
"github.com/go-stomp/stomp/v3"
|
||||
)
|
||||
|
||||
func Subscribe() {
|
||||
sub, err := messaging.Client.Subscribe("/topic/VSTP_ALL", stomp.AckAuto)
|
||||
if err != nil {
|
||||
log.Msg.Fatal("Unable to start subscription: " + err.Error())
|
||||
}
|
||||
log.Msg.Info("Subscription to VSTP topic successful, listening")
|
||||
|
||||
go func() {
|
||||
log.Msg.Debug("GOROUTINE: VSTP Message Handler Started")
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
log.Msg.Warn("GOROUTINE: VSTP Message Handler Stopped")
|
||||
time.Sleep(time.Second * 10)
|
||||
log.Msg.Fatal("GOROUTINE: VSTP Message Handler Failed")
|
||||
}
|
||||
}()
|
||||
for {
|
||||
msg := <-sub.C
|
||||
if msg.Err != nil {
|
||||
log.Msg.Error("STOMP Message Error: " + msg.Err.Error())
|
||||
} else {
|
||||
log.Msg.Info("STOMP Message Received")
|
||||
handle(msg)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
select {}
|
||||
}
|
||||
Reference in New Issue
Block a user