Skip to content

Commit

Permalink
Further work on new tube api
Browse files Browse the repository at this point in the history
  • Loading branch information
benfl3713 committed Oct 24, 2023
1 parent 170d738 commit d671fa1
Show file tree
Hide file tree
Showing 7 changed files with 217 additions and 43 deletions.
6 changes: 5 additions & 1 deletion BusDataAPI/BusDeparture.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,11 @@ public class BusDeparture
public string OperatorCode { get; set; }
public DateTime? AimedDeparture { get; set; }
public DateTime? ExpectedDeparture { get; set; }
public int TimeToStation { get; set; }
public string Platform { get; set; }
public bool IsCancelled { get; set; } = false;

public BusDeparture(string line, string destination, string stopName, string operatorCode, string operatorName, DateTime? aimedDeparture, DateTime? expectedDeparture)
public BusDeparture(string line, string destination, string stopName, string operatorCode, string operatorName, DateTime? aimedDeparture, DateTime? expectedDeparture, string platform = null, int? timeToStation = null)
{
LastUpdated = DateTime.Now;
Line = line;
Expand All @@ -24,6 +26,8 @@ public BusDeparture(string line, string destination, string stopName, string ope
OperatorName = operatorName;
AimedDeparture = aimedDeparture;
ExpectedDeparture = expectedDeparture;
Platform = platform;
TimeToStation = timeToStation ?? TimeSpan.FromTicks((expectedDeparture ?? DateTime.Now).Ticks - DateTime.Now.Ticks).Minutes;
}
}
}
55 changes: 33 additions & 22 deletions BusDataAPI/DataSource/TflApi.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,33 +25,41 @@ private List<BusDeparture> GetDepartures(string code)
var arrivals = JsonConvert.DeserializeObject<List<TflArrival>>(response.Content);

return arrivals
.Select(a => new BusDeparture(a.LineName, a.DestinationName, a.StationName, "TFL", "Transport for London", a.ExpectedArrival, a.ExpectedArrival))
.Select(a => new BusDeparture(
a.LineName,
a.DestinationName,
a.StationName,
"TFL",
"Transport for London",
a.ExpectedArrival,
a.ExpectedArrival,
a.PlatformName,
GetConvertedTimeToStation(a.TimeToStation)
)
)
.Where(a => !string.IsNullOrEmpty(a.Destination))
.OrderBy(a => a.AimedDeparture)
.ToList();
}

// public List<StationLookup.Station> GetAllStations()
// {
// var request = new RestRequest($"StopPoint/mode/tube", Method.Get);
// RestResponse response = SendRequest(request);
//
// var stations = JsonConvert.DeserializeObject<TflStopPointResponse>(response.Content);
//
// return stations.StopPoints.
// Select(s => new StationLookup.Station(s.StationNaptan ?? s.NaptanId, s.CommonName, "GB", DataSourceId))
// .Distinct(new StationDeduplicator())
// .ToList();
// }
private int? GetConvertedTimeToStation(int? timeInSeconds)
{
if (!timeInSeconds.HasValue)
return null;

return Convert.ToInt32(Math.Ceiling(timeInSeconds.Value / 60m));
}

// private class StationDeduplicator : IEqualityComparer<StationLookup.Station>
// {
// public bool Equals(StationLookup.Station x, StationLookup.Station y)
// {
// return x?.Code == y?.Code;
// }
//
// public int GetHashCode(StationLookup.Station obj) => obj.Code.GetHashCode();
// }
public List<StopPoint> GetAllStations()
{
var request = new RestRequest($"StopPoint/mode/tube", Method.Get);
RestResponse response = SendRequest(request);

var stations = JsonConvert.DeserializeObject<TflStopPointResponse>(response.Content);

return stations.StopPoints
.ToList();
}

private RestResponse SendRequest(RestRequest request)
{
Expand All @@ -69,6 +77,8 @@ public class StopPoint
public string NaptanId { get; set; }
public string StationNaptan { get; set; }
public string CommonName { get; set; }
public string PlatformName { get; set; }
public List<dynamic> Lines { get; set; }
}

public class TflArrival
Expand All @@ -78,6 +88,7 @@ public class TflArrival
public string DestinationName { get; set; }
public DateTime ExpectedArrival { get; set; }
public string PlatformName { get; set; }
public int? TimeToStation { get; set; }
}
}
}
Original file line number Diff line number Diff line change
@@ -1,17 +1,36 @@
<h1 class="led centre-text" *ngIf="noBoardsDisplay">
No Departures Found for *****blah*****
<h1 class="led centre-text" *ngIf="departures?.length === 0">
No Departures Found for {{stopName}}
</h1>
<div class="singleboard">
<h1 id="title" class="led centre-text" *ngIf="showStopName">
{{ stopName }}
</h1>
<div class="row" *ngFor="let departure of departures; index as i">
<span class="led col-lg-1 col-1">{{ i + 1 }}</span>

<div class="row" *ngIf="firstDeparture">
<span class="led col-lg-1 col-1">1</span>
<span class="led col">
{{ firstDeparture.destination }}
</span>
<span class="led col-lg-2 col-md-3 col-4 status">
{{firstDeparture.timeToStation}} mins
</span>
</div>

<!-- <div class="row">-->
<!-- <div-->
<!-- id="singleboard-information"-->
<!-- class="led info col-12"-->
<!-- style="height: 48px"-->
<!-- ></div>-->
<!-- </div>-->

<div class="row" *ngFor="let departure of otherDepartures; index as i">
<span class="led col-lg-1 col-1">{{i + 2}}</span>
<span class="led col">
{{ departure.destination }}
</span>
<span class="led col-lg-2 col-md-3 col-4 status">
{{departure.status}}
{{departure.timeToStation}} mins
</span>
</div>

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import {Component, OnDestroy, OnInit} from '@angular/core';
import {Marquee} from "dynamic-marquee";
import {LondonTubeService} from "../../../Services/london-tube.service";

@Component({
selector: 'app-london-tube-singleboard',
Expand All @@ -8,33 +10,71 @@ import {Component, OnDestroy, OnInit} from '@angular/core';
export class LondonTubeSingleboardComponent implements OnInit, OnDestroy {
showStopName: boolean = true;
showClock: boolean = true;
stopName: string = "Test Station";
departures = [
{
destination: "Ealing Broadway",
status: ''
},
{
destination: "Northfields",
status: '2 mins'
},
{
destination: "Leicester Square",
status: '5 mins'
}
];
stopName: string = "Baker Street";
scrollSpeed = 200;
departures;

noBoardsDisplay: boolean;
time = new Date();
timeInterval: NodeJS.Timer;
fetchInterval: NodeJS.Timer;
marquee: Marquee;

constructor(private tubeService: LondonTubeService) {
}

ngOnInit(): void {
this.timeInterval = setInterval(() => {
this.time = new Date();
}, 1000);

// this.marquee = new Marquee(
// document.getElementById("singleboard-information"),
// {
// rate: -this.scrollSpeed,
// }
// );
//
// const span = document.createElement('span');
// span.textContent = "Calling at Bob";
//
// this.marquee.onAllItemsRemoved(() => {
// this.marquee.appendItem("Calling at Bob " + new Date().toLocaleTimeString());
// });
//
// this.marquee.appendItem("Calling at Bob");
//
this.getDepartures();
this.fetchInterval = setInterval(() => this.getDepartures(), 35000);
}

ngOnDestroy(): void {
clearInterval(this.timeInterval);
clearInterval(this.fetchInterval);
}

getDepartures() {
this.tubeService.getDepartures("940GZZLUBST").subscribe({
next: (dep) => {
console.log(dep);
this.departures = (dep as any[])
}
})
}

get firstDeparture() {
if (!this.departures || this.departures.length === 0) {
return null;
}

return this.departures[0];
}

get otherDepartures() {
if (!this.departures || this.departures.length < 2) {
return [];
}

return this.departures.slice(1);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { TestBed } from '@angular/core/testing';

import { LondonTubeService } from './london-tube.service';

describe('LondonTubeService', () => {
let service: LondonTubeService;

beforeEach(() => {
TestBed.configureTestingModule({});
service = TestBed.inject(LondonTubeService);
});

it('should be created', () => {
expect(service).toBeTruthy();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { Injectable } from '@angular/core';
import {HttpClient, HttpParams} from "@angular/common/http";
import {Observable} from "rxjs";
import {environment} from "../../environments/environment";

@Injectable({
providedIn: 'root'
})
export class LondonTubeService {

constructor(private http: HttpClient) {}

getDepartures(stopCode: string, count: number = 4): Observable<object[]> {
const url = "/api/TubeDepartures";

let params = new HttpParams().append("code", stopCode);
params = params.append("count", count.toString());

return this.http.get<object[]>(environment.apiBaseUrl + url, {
params: params,
});
}
}
61 changes: 61 additions & 0 deletions DepartureBoardWeb/Controllers/TubeDeparturesController.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
using System;
using System.Collections.Generic;
using System.Linq;
using BusDataAPI;
using BusDataAPI.DataSource;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Caching.Memory;

namespace DepartureBoardWeb.Controllers;

[Route("api/[controller]")]
[ApiController]
public class TubeDeparturesController : Controller
{
private readonly IMemoryCache _cache;

public TubeDeparturesController(IMemoryCache cache)
{
_cache = cache;
}

[HttpGet]
public List<BusDeparture> GetTubeLiveDepartures(string code, int? count)
{
var cacheEntry = _cache.GetOrCreate($"{code}_{count}", entry =>
{
entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(30);
return GetTubeDepartures(code, count);
});
return cacheEntry;
}

private List<BusDeparture> GetTubeDepartures(string code, int? count)
{
TflApi api = new TflApi();
var departures = api.GetLiveDepartures(code);
if (count.HasValue)
departures = departures.Take(count.Value).ToList();

foreach (BusDeparture busDeparture in departures)
{
if (busDeparture.Destination.Contains(" Underground Station"))
busDeparture.Destination = busDeparture.Destination.Replace(" Underground Station", "");
}

return departures;
}

[HttpGet("search")]
public List<TflApi.StopPoint> Search(string query)
{
var stations = _cache.GetOrCreate("tube_stations", entry =>
{
entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromHours(3);
TflApi api = new TflApi();
return api.GetAllStations();
});

return stations;
}
}

0 comments on commit d671fa1

Please sign in to comment.