Implement destinations

This commit is contained in:
nemunaire 2022-10-23 00:56:24 +02:00
parent c458a32d7b
commit a0659dd9bd
3 changed files with 211 additions and 44 deletions

View File

@ -1,9 +1,154 @@
package api package api
import ( import (
"encoding/json"
"fmt"
"net/http"
"net/url"
"strings"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
) )
func declareDestinationsRoutes(route *gin.RouterGroup) { type IDFMSchedule struct {
Line struct {
Id string `json:"id"`
Label string `json:"label"`
Name string `json:"name"`
ShortName string `json:"shortName"`
Companies []struct {
Id string `json:"id"`
Label string `json:"label"`
} `json:"companies"`
Network struct {
Id string `json:"id"`
Label string `json:"label"`
} `json:"network"`
Mode string `json:"mode"`
ModeLabel string `json:"modeLabel"`
Realtime bool `json:"realtime"`
UFR bool `json:"ufr"`
Visual bool `json:"visual"`
Sound bool `json:"sound"`
Color string `json:"color"`
TextColor string `json:"textColor"`
} `json:"line"`
Schedules []struct {
RouteId string `json:"routeId"`
From string `json:"from"`
To string `json:"to"`
First string `json:"first"`
Last string `json:"last"`
} `json:"schedules"`
Plans []struct {
Link string `json:"link"`
Label string `json:"label"`
} `json:"plans"`
ScheduleDocs []struct {
Link string `json:"link"`
Label string `json:"label"`
} `json:"scheduleDocs"`
CurrentIT []struct {
Id string `json:"id"`
Title string `json:"title"`
Message string `json:"message"`
ImpactStartTime IDFMTime `json:"impactStartTime"`
ImpactEndTime IDFMTime `json:"impactEndTime"`
Severity int `json:"severity"`
Type int `json:"type"`
} `json:"currentIT"`
}
type PGDestination struct {
Name string `json:"name"`
Way string `json:"way"`
}
func getSchedules(code string) (*IDFMSchedule, error) {
rurl, err := url.JoinPath(IDFM_BASEURL, "lines", code, "schedules")
if err != nil {
return nil, err
}
requrl, err := url.Parse(rurl)
if err != nil {
return nil, err
}
reqquery := url.Values{}
reqquery.Add("complete", "false")
requrl.RawQuery = reqquery.Encode()
req, err := http.NewRequest("GET", requrl.String(), nil)
if err != nil {
return nil, err
}
req.Header.Add("Accept", "application/json")
req.Header.Add("apikey", IDFM_TOKEN)
res, err := http.DefaultClient.Do(req)
if err != nil {
return nil, err
}
defer res.Body.Close()
if res.StatusCode >= 400 {
return nil, fmt.Errorf("Schedule not found")
}
var schedules IDFMSchedule
dec := json.NewDecoder(res.Body)
if err = dec.Decode(&schedules); err != nil {
return nil, err
}
return &schedules, nil
}
func declareDestinationsRoutes(router *gin.RouterGroup) {
router.GET("/destinations/:type/:code", func(c *gin.Context) {
t := convertLineType(string(c.Param("type")))
code := string(c.Param("code"))
if !strings.HasPrefix(code, "line:IDFM:") {
if len(code) != 6 || !strings.HasPrefix(code, "C") {
code = searchLine(t, code)
}
code = "line:IDFM:" + code
}
schedule, err := getSchedules(code)
if err != nil {
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": err.Error()})
return
}
pgd := []PGDestination{}
destination:
for i, s := range schedule.Schedules {
for _, d := range pgd {
if d.Name == s.To {
continue destination
}
}
way := "R"
if i%2 == 0 {
way = "A"
}
pgd = append(pgd, PGDestination{
Name: s.To,
Way: way,
})
}
c.JSON(http.StatusOK, APIResult(c, map[string][]PGDestination{
"destinations": pgd,
}))
})
} }

View File

@ -2,6 +2,7 @@ package api
import ( import (
"encoding/json" "encoding/json"
"fmt"
"net/http" "net/http"
"net/url" "net/url"
"strconv" "strconv"
@ -13,7 +14,7 @@ import (
const IDFM_BASEURL = "https://api-iv.iledefrance-mobilites.fr/" const IDFM_BASEURL = "https://api-iv.iledefrance-mobilites.fr/"
type IDFMSchedule struct { type IDFMRealTime struct {
NextDepartures struct { NextDepartures struct {
StatusCode int `json:"statusCode"` StatusCode int `json:"statusCode"`
Data []struct { Data []struct {
@ -52,10 +53,53 @@ func convertLineCode(code string) string {
return strings.TrimSuffix(strings.Replace(code, "STIF:Line::", "IDFM:", 1), ":") return strings.TrimSuffix(strings.Replace(code, "STIF:Line::", "IDFM:", 1), ":")
} }
func getRealTime(code, station string) (*IDFMRealTime, error) {
rurl, err := url.JoinPath(IDFM_BASEURL, "lines", code, "stops", station, "realTime")
if err != nil {
return nil, err
}
requrl, err := url.Parse(rurl)
if err != nil {
return nil, err
}
reqquery := url.Values{}
reqquery.Add("MonitoringRef", station)
requrl.RawQuery = reqquery.Encode()
req, err := http.NewRequest("GET", requrl.String(), nil)
if err != nil {
return nil, err
}
req.Header.Add("Accept", "application/json")
req.Header.Add("apikey", IDFM_TOKEN)
res, err := http.DefaultClient.Do(req)
if err != nil {
return nil, err
}
defer res.Body.Close()
if res.StatusCode >= 400 {
return nil, fmt.Errorf("Schedule not found")
}
var schedules IDFMRealTime
dec := json.NewDecoder(res.Body)
if err = dec.Decode(&schedules); err != nil {
return nil, err
}
return &schedules, nil
}
func declareSchedulesRoutes(router *gin.RouterGroup) { func declareSchedulesRoutes(router *gin.RouterGroup) {
router.GET("/schedules/:type/:code/:station/:way", func(c *gin.Context) { router.GET("/schedules/:type/:code/:station/:way", func(c *gin.Context) {
t := convertLineType(string(c.Param("type"))) t := convertLineType(string(c.Param("type")))
code := convertLineType(string(c.Param("code"))) code := string(c.Param("code"))
station := string(c.Param("station")) station := string(c.Param("station"))
way := string(c.Param("way")) way := string(c.Param("way"))
@ -79,51 +123,12 @@ func declareSchedulesRoutes(router *gin.RouterGroup) {
} }
} }
rurl, err := url.JoinPath(IDFM_BASEURL, "lines", code, "stops", station, "realTime") schedules, err := getRealTime(code, station)
if err != nil { if err != nil {
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": err.Error()}) c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": err.Error()})
return return
} }
requrl, err := url.Parse(rurl)
if err != nil {
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": err.Error()})
return
}
reqquery := url.Values{}
reqquery.Add("MonitoringRef", station)
requrl.RawQuery = reqquery.Encode()
req, err := http.NewRequest("GET", requrl.String(), nil)
if err != nil {
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": err.Error()})
return
}
req.Header.Add("Accept", "application/json")
req.Header.Add("apikey", IDFM_TOKEN)
res, err := http.DefaultClient.Do(req)
if err != nil {
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": err.Error()})
return
}
defer res.Body.Close()
if res.StatusCode >= 400 {
c.AbortWithStatusJSON(res.StatusCode, APIResult(c, nil))
return
}
var schedules IDFMSchedule
dec := json.NewDecoder(res.Body)
if err = dec.Decode(&schedules); err != nil {
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": err.Error()})
return
}
pgs := []PGSchedule{} pgs := []PGSchedule{}
for _, vehicule := range schedules.NextDepartures.Data { for _, vehicule := range schedules.NextDepartures.Data {
if (way == "A" && vehicule.Sens == "-1") || (way == "R" && vehicule.Sens == "1") { if (way == "A" && vehicule.Sens == "-1") || (way == "R" && vehicule.Sens == "1") {

17
api/time.go Normal file
View File

@ -0,0 +1,17 @@
package api
import (
"time"
)
type IDFMTime time.Time
func (t *IDFMTime) UnmarshalJSON(b []byte) error {
tmp, err := time.Parse("\"2006-01-02T15:04\"", string(b))
*t = IDFMTime(tmp)
return err
}
func (t IDFMTime) MarshalJSON() ([]byte, error) {
return []byte(time.Time(t).Format("\"2006-01-02T15:04\"")), nil
}