Initial commit
This commit is contained in:
commit
0a854f708a
17 changed files with 796 additions and 0 deletions
30
api/api.go
Normal file
30
api/api.go
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
package api
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type apiMetadata struct {
|
||||
Call string `json:"call"`
|
||||
Date time.Time `json:"date"`
|
||||
Version int `json:"version"`
|
||||
}
|
||||
|
||||
type apiResult struct {
|
||||
Result interface{} `json:"result"`
|
||||
Metadata apiMetadata `json:"_metadata"`
|
||||
}
|
||||
|
||||
func APIResult(c *gin.Context, res interface{}) apiResult {
|
||||
return apiResult{
|
||||
Result: res,
|
||||
Metadata: apiMetadata{
|
||||
Call: fmt.Sprintf("%s %s", c.Request.Method, c.Request.URL.Path),
|
||||
Date: time.Now(),
|
||||
Version: 4,
|
||||
},
|
||||
}
|
||||
}
|
||||
9
api/destinations.go
Normal file
9
api/destinations.go
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
package api
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func declareDestinationsRoutes(route *gin.RouterGroup) {
|
||||
|
||||
}
|
||||
138
api/lines.go
Normal file
138
api/lines.go
Normal file
|
|
@ -0,0 +1,138 @@
|
|||
package api
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type IDFMLine struct {
|
||||
DatasetID string `json:"datasetid"`
|
||||
RecordIDs string `json:"recordid"`
|
||||
Fields struct {
|
||||
IdLine string `json:"id_line"`
|
||||
Name string `json:"name_line"`
|
||||
ShortName string `json:"shortname_line"`
|
||||
TransportMode string `json:"transportmode"`
|
||||
TransportSubmode string `json:"transportsubmode"`
|
||||
Type string `json:"type"`
|
||||
OperatorRef string `json:"operatorref"`
|
||||
AdditionalOperators string `json:"additionaloperators,omitempty"`
|
||||
OperatorName string `json:"operatorname"`
|
||||
NetworkName string `json:"networkname,omitempty"`
|
||||
WebColor string `json:"colourweb_hexa"`
|
||||
PrintColor string `json:"colourprint_cmjn"`
|
||||
WebTextColor string `json:"textcolourweb_hexa"`
|
||||
TextPrintColor string `json:"textcolourprint_hexa"`
|
||||
Accessibility string `json:"accessibility"`
|
||||
AudibleSignAvailable string `json:"audiblesigns_available"`
|
||||
VisualSignAvailable string `json:"visualsigns_available"`
|
||||
NoticeTitle string `json:"notice_title"`
|
||||
NoticeText string `json:"notice_text"`
|
||||
Status string `json:"status"`
|
||||
ShortNameGroup string `json:"shortname_groupoflines"`
|
||||
IdGroup string `json:"id_groupoflines"`
|
||||
ExternalCode string `json:"externalcode_line"`
|
||||
} `json:"fields"`
|
||||
RecordTimestamp time.Time `json:"record_timestamp"`
|
||||
}
|
||||
|
||||
type PGLine struct {
|
||||
Code string `json:"code"`
|
||||
Name string `json:"name"`
|
||||
Directions string `json:"directions"`
|
||||
Id string `json:"id"`
|
||||
}
|
||||
|
||||
var IDFMLines []IDFMLine
|
||||
|
||||
func init() {
|
||||
fd, err := os.Open("referentiel-des-lignes.json")
|
||||
if err != nil {
|
||||
log.Fatal("Unable to open `referentiel-des-lignes.json`:", err.Error())
|
||||
}
|
||||
defer fd.Close()
|
||||
|
||||
dec := json.NewDecoder(fd)
|
||||
if err = dec.Decode(&IDFMLines); err != nil {
|
||||
log.Fatal("Unable to decode `referentiel-des-lignes.json`:", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func convertLineType(old string) string {
|
||||
switch old {
|
||||
case "buses":
|
||||
return "bus"
|
||||
case "metros":
|
||||
return "metro"
|
||||
case "noctiliens":
|
||||
return "noctilien"
|
||||
case "rers":
|
||||
return "rail"
|
||||
case "tramways":
|
||||
return "tram"
|
||||
default:
|
||||
return old
|
||||
}
|
||||
}
|
||||
|
||||
func declareLinesRoutes(router *gin.RouterGroup) {
|
||||
router.GET("/lines", func(c *gin.Context) {
|
||||
var modes []string
|
||||
for _, line := range IDFMLines {
|
||||
mode := line.Fields.TransportMode
|
||||
|
||||
found := false
|
||||
for _, m := range modes {
|
||||
if mode == m {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !found {
|
||||
modes = append(modes, mode)
|
||||
}
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, APIResult(c, modes))
|
||||
})
|
||||
|
||||
router.GET("/lines/:type", func(c *gin.Context) {
|
||||
t := convertLineType(string(c.Param("type")))
|
||||
|
||||
var lines []PGLine
|
||||
for _, line := range IDFMLines {
|
||||
if line.Fields.TransportMode == t || strings.ToLower(line.Fields.NetworkName) == t {
|
||||
name := line.Fields.Name
|
||||
|
||||
if line.Fields.ShortNameGroup != "" {
|
||||
if strings.Contains(line.Fields.ShortNameGroup, name) {
|
||||
name = line.Fields.ShortNameGroup
|
||||
} else if name == line.Fields.ShortName {
|
||||
name = fmt.Sprintf("%s - %s", line.Fields.Name, line.Fields.ShortNameGroup)
|
||||
}
|
||||
}
|
||||
|
||||
pgline := PGLine{
|
||||
Code: fmt.Sprintf("IDFM:%s", line.Fields.IdLine),
|
||||
Name: name,
|
||||
Directions: "",
|
||||
Id: line.Fields.IdLine,
|
||||
}
|
||||
|
||||
lines = append(lines, pgline)
|
||||
}
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, APIResult(c, map[string][]PGLine{
|
||||
t: lines,
|
||||
}))
|
||||
})
|
||||
}
|
||||
9
api/missions.go
Normal file
9
api/missions.go
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
package api
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func declareMissionsRoutes(route *gin.RouterGroup) {
|
||||
|
||||
}
|
||||
18
api/routes.go
Normal file
18
api/routes.go
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
package api
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"git.nemunai.re/nemunaire/idfm-api/config"
|
||||
)
|
||||
|
||||
func DeclareRoutes(router *gin.Engine, cfg *config.Config) {
|
||||
apiRoutes := router.Group("/api")
|
||||
|
||||
declareDestinationsRoutes(apiRoutes)
|
||||
declareLinesRoutes(apiRoutes)
|
||||
declareMissionsRoutes(apiRoutes)
|
||||
declareSchedulesRoutes(apiRoutes)
|
||||
declareStationsRoutes(apiRoutes)
|
||||
declareTrafficRoutes(apiRoutes)
|
||||
}
|
||||
153
api/schedules.go
Normal file
153
api/schedules.go
Normal file
|
|
@ -0,0 +1,153 @@
|
|||
package api
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"fmt"
|
||||
"math"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
const IDFM_BASEURL = "https://prim.iledefrance-mobilites.fr/marketplace"
|
||||
|
||||
var IDFM_TOKEN = ""
|
||||
|
||||
func init() {
|
||||
flag.StringVar(&IDFM_TOKEN, "token-IDFM", IDFM_TOKEN, "Token to access IDFM API")
|
||||
}
|
||||
|
||||
type IDFMSchedule struct {
|
||||
Siri struct {
|
||||
ServiceDelivery struct {
|
||||
ResponseTimestamp time.Time `json:"ResponseTimestamp"`
|
||||
ProducerRef string `json:"ProducerRef"`
|
||||
ResponseMessageIdentifier string `json:"ResponseMessageIdentifier"`
|
||||
StopMonitoringDelivery []struct {
|
||||
ResponseTimestamp time.Time `json:"ResponseTimestamp"`
|
||||
Version string `json:"Version"`
|
||||
Status string `json:"Status"`
|
||||
MonitoredStopVisit []struct {
|
||||
RecordedAtTime time.Time `json:"RecordedAtTime"`
|
||||
ItemIdentifier string `json:"ItemIdentifier"`
|
||||
MonitoringRef struct {
|
||||
Value string `json:"value"`
|
||||
} `json:"MonitoringRef"`
|
||||
MonitoredVehicleJourney struct {
|
||||
LineRef struct {
|
||||
Value string `json:"value"`
|
||||
} `json:"LineRef"`
|
||||
OperatorRef struct {
|
||||
Value string `json:"value"`
|
||||
} `json:"OperatorRef"`
|
||||
FramedVehicleJourneyRef struct {
|
||||
DataFrameRef struct {
|
||||
Value string `json:"value"`
|
||||
} `json:"DataFrameRef"`
|
||||
DatedVehicleJourneyRef string `json:"DatedVehicleJourneyRef"`
|
||||
} `json:"FramedVehicleJourneyRef"`
|
||||
DirectionName []struct {
|
||||
Value string `json:"value"`
|
||||
} `json:"DirectionName"`
|
||||
DestinationRef struct {
|
||||
Value string `json:"value"`
|
||||
} `json:"DestinationRef"`
|
||||
DestinationName []struct {
|
||||
Value string `json:"value"`
|
||||
} `json:"DestinationName"`
|
||||
JourneyNote []struct {
|
||||
Value string `json:"value"`
|
||||
} `json:"JourneyNote"`
|
||||
MonitoredCall struct {
|
||||
StopPointName []struct {
|
||||
Value string `json:"value"`
|
||||
} `json:"StopPointName"`
|
||||
VehicleAtStop bool `json:"VehicleAtStop"`
|
||||
DestinationDisplay []struct {
|
||||
Value string `json:"value"`
|
||||
} `json:"DestinationDisplay"`
|
||||
ExpectedArrivalTime time.Time `json:"ExpectedArrivalTime"`
|
||||
ExpectedDepartureTime time.Time `json:"ExpectedDepartureTime"`
|
||||
DepartureStatus string `json:"DepartureStatus"`
|
||||
} `json:"MonitoredCall"`
|
||||
} `json:"MonitoredVehicleJourney"`
|
||||
} `json:"MonitoredStopVisit"`
|
||||
} `json:"StopMonitoringDelivery"`
|
||||
} `json:"ServiceDelivery"`
|
||||
} `json:"siri"`
|
||||
}
|
||||
|
||||
type PGSchedule struct {
|
||||
Destination string `json:"destionation"`
|
||||
Message string `json:"message"`
|
||||
}
|
||||
|
||||
func declareSchedulesRoutes(router *gin.RouterGroup) {
|
||||
router.GET("/schedules/:type/:code/:station/:way", func(c *gin.Context) {
|
||||
t := string(c.Param("type"))
|
||||
station := convertLineType(string(c.Param("station")))
|
||||
|
||||
rurl, err := url.JoinPath(IDFM_BASEURL, "stop-monitoring")
|
||||
if err != nil {
|
||||
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": err.Error()})
|
||||
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()
|
||||
|
||||
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{}
|
||||
for _, vehicule := range schedules.Siri.ServiceDelivery.StopMonitoringDelivery[0].MonitoredStopVisit {
|
||||
msg := vehicule.MonitoredVehicleJourney.MonitoredCall.ExpectedDepartureTime.String()
|
||||
|
||||
if t == "metros" || t == "buses" || t == "tramways" {
|
||||
if vehicule.MonitoredVehicleJourney.MonitoredCall.VehicleAtStop {
|
||||
msg = "À quai"
|
||||
} else {
|
||||
msg = fmt.Sprintf("%d mn", int(math.Floor(time.Until(vehicule.MonitoredVehicleJourney.MonitoredCall.ExpectedDepartureTime).Minutes())))
|
||||
}
|
||||
}
|
||||
|
||||
pgs = append(pgs, PGSchedule{
|
||||
Destination: vehicule.MonitoredVehicleJourney.MonitoredCall.DestinationDisplay[0].Value,
|
||||
Message: msg,
|
||||
})
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, pgs)
|
||||
})
|
||||
}
|
||||
73
api/stations.go
Normal file
73
api/stations.go
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
package api
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type IDFMStation struct {
|
||||
DatasetID string `json:"datasetid"`
|
||||
RecordIDs string `json:"recordid"`
|
||||
Fields struct {
|
||||
Id string `json:"id"`
|
||||
PointGeo []float64 `json:"pointgeo"`
|
||||
StopId string `json:"stop_id"`
|
||||
StopName string `json:"stop_name"`
|
||||
OperatorName string `json:"operatorname"`
|
||||
NomCommune string `json:"nom_commune"`
|
||||
RouteLongName string `json:"route_long_name"`
|
||||
StopLat string `json:"stop_lat"`
|
||||
StopLon string `json:"stop_lon"`
|
||||
CodeINSEE string `json:"code_insee"`
|
||||
} `json:"fields"`
|
||||
Geometry struct {
|
||||
Type string `json:"type"`
|
||||
Coordinates []float64 `json:"coordinates"`
|
||||
} `json:"geometry"`
|
||||
}
|
||||
|
||||
type PGStation struct {
|
||||
Id string `json:"slug"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
var IDFMStations []IDFMStation
|
||||
|
||||
func init() {
|
||||
fd, err := os.Open("arrets-lignes.json")
|
||||
if err != nil {
|
||||
log.Fatal("Unable to open `arrets-lignes.json`:", err.Error())
|
||||
}
|
||||
defer fd.Close()
|
||||
|
||||
dec := json.NewDecoder(fd)
|
||||
if err = dec.Decode(&IDFMStations); err != nil {
|
||||
log.Fatal("Unable to decode `arrets-lignes.json`:", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func declareStationsRoutes(router *gin.RouterGroup) {
|
||||
router.GET("/stations/:type/:code", func(c *gin.Context) {
|
||||
code := convertLineType(string(c.Param("code")))
|
||||
|
||||
var stations []PGStation
|
||||
for _, station := range IDFMStations {
|
||||
if station.Fields.Id == code {
|
||||
pgstation := PGStation{
|
||||
Id: station.Fields.StopId,
|
||||
Name: station.Fields.StopName,
|
||||
}
|
||||
|
||||
stations = append(stations, pgstation)
|
||||
}
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, APIResult(c, map[string][]PGStation{
|
||||
"stations": stations,
|
||||
}))
|
||||
})
|
||||
}
|
||||
9
api/traffic.go
Normal file
9
api/traffic.go
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
package api
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func declareTrafficRoutes(route *gin.RouterGroup) {
|
||||
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue