diff --git a/.idea/.idea.TransitUI/.idea/.gitignore b/.idea/.idea.TransitUI/.idea/.gitignore new file mode 100644 index 0000000..37d22b8 --- /dev/null +++ b/.idea/.idea.TransitUI/.idea/.gitignore @@ -0,0 +1,13 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Rider ignored files +/modules.xml +/contentModel.xml +/projectSettingsUpdater.xml +/.idea.TransitUI.iml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/.idea.TransitUI/.idea/indexLayout.xml b/.idea/.idea.TransitUI/.idea/indexLayout.xml new file mode 100644 index 0000000..7b08163 --- /dev/null +++ b/.idea/.idea.TransitUI/.idea/indexLayout.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/.idea.TransitUI/.idea/vcs.xml b/.idea/.idea.TransitUI/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/.idea.TransitUI/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/Animator/GifCreator.cs b/Animator/GifCreator.cs index f2abe6a..37e5c60 100644 --- a/Animator/GifCreator.cs +++ b/Animator/GifCreator.cs @@ -5,37 +5,38 @@ namespace Animator; public static class GifCreator { - private static Random random = new Random(); - public static string RandomString(int length) + private static Random Random { get; } = new(); + + private static string RandomString(int length) { const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; return new string(Enumerable.Repeat(chars, length) - .Select(s => s[random.Next(s.Length)]).ToArray()); + .Select(s => s[Random.Next(s.Length)]).ToArray()); } - public static Stream ConvertImageStreamsToGifStream(IEnumerable streams) + public static async Task ConvertImageStreamsToGifStream(IEnumerable> streams) { - string randomPathPart = RandomString(64); - string rootPath = $"/tmp/pngs/{randomPathPart}"; + var randomPathPart = RandomString(64); + var rootPath = $"/tmp/pngs/{randomPathPart}"; Directory.CreateDirectory(rootPath); - for (int i = 0; i < streams.Count(); i++) + var streamList = streams.ToList(); + for (var i = 0; i < streamList.Count; i++) { - using FileStream fs = File.Create($"{rootPath}/{i.ToString().PadLeft(8, '0')}.png"); - streams.ElementAt(i).CopyTo(fs); + await using var fs = File.Create($"{rootPath}/{i.ToString().PadLeft(8, '0')}.png"); + await (await streamList.ElementAt(i)).CopyToAsync(fs); } ProcessStartInfo psi = new() { FileName = "convert", Arguments = $"-delay 500 -loop 0 {rootPath}/*.png {rootPath}/out.gif" }; - Process? process = Process.Start(psi); + var process = Process.Start(psi); if (process is null) { throw new Exception($"Process not started"); } - process.WaitForExit(); - // return $"{rootPath}/out.gif"; - FileStream gifFS = File.OpenRead($"{rootPath}/out.gif"); - return gifFS; + await process.WaitForExitAsync(); + var gifFs = File.OpenRead($"{rootPath}/out.gif"); + return gifFs; } } diff --git a/RealTimeDataCrawler/Vip/Crawler.cs b/RealTimeDataCrawler/Vip/Crawler.cs index 2d23b31..00bf11f 100644 --- a/RealTimeDataCrawler/Vip/Crawler.cs +++ b/RealTimeDataCrawler/Vip/Crawler.cs @@ -6,16 +6,16 @@ namespace RealTimeDataCrawler.Vip; public static class Crawler { private static string RequestUri { get; } = @"https://www.swp-potsdam.de/internetservice/services/passageInfo/stopPassages/stop?stop=%STOP_ID%&mode=departure&language=de"; - - public static Station GetFromWeb(int stopId = 61) + + public static async Task GetFromWeb(int stopId = 61) { - string jsonString = GetJsonSource(stopId); + var jsonString = await GetJsonSource(stopId); return Station.GetFromJsonString(jsonString); } - public static string GetJsonSource(int stopId = 61) + public static async Task GetJsonSource(int stopId = 61) { - using WebClient wc = new WebClient(); - return wc.DownloadString(RequestUri.Replace("%STOP_ID%", stopId.ToString())); + using HttpClient httpClient = new(); + return await httpClient.GetStringAsync(RequestUri.Replace("%STOP_ID%", stopId.ToString())); } } diff --git a/RealTimeModels/RealTimeModels.csproj b/RealTimeModels/RealTimeModels.csproj index eb2460e..ddc5e70 100644 --- a/RealTimeModels/RealTimeModels.csproj +++ b/RealTimeModels/RealTimeModels.csproj @@ -6,4 +6,9 @@ enable + + + + + diff --git a/RealTimeModels/Vip/Station.cs b/RealTimeModels/Vip/Station.cs index 34b4b24..4a09694 100644 --- a/RealTimeModels/Vip/Station.cs +++ b/RealTimeModels/Vip/Station.cs @@ -33,13 +33,18 @@ internal Station(PredictionJsonObject json) Actual = json.actual.Select((actual) => new RealTimeEntry(new TimeSpan(0, 0, actual.actualRelativeTime), actual.actualTime is null ? (DateTime?)null : DateTime.Parse(actual.actualTime), actual.alerts?.Select((alert) => new Alert(alert)).ToList(), actual.direction, actual.mixedTime, Convert.ToInt64(actual.passageid), actual.patternText, DateTime.Parse(actual.plannedTime), Routes.Where((route) => route.Id == Convert.ToInt64(actual.routeId)).First(), actual.status, Convert.ToInt64(actual.tripId), null, actual.vias)).ToList(); } // Methods - public static Station GetFromJsonString(string jsonString) + public static Station GetFromJsonString(string jsonString, bool catalogue = true) { var json = JsonSerializer.Deserialize(jsonString); if (json is null) throw new ArgumentNullException(nameof(json), $"JsonSerializer returned null."); - return new Station(json); + Station station = new(json); + if (catalogue) + { + } + + return station; } public override string ToString() { diff --git a/RealTimeModels/Vip/VipContext.cs b/RealTimeModels/Vip/VipContext.cs new file mode 100644 index 0000000..2f28b62 --- /dev/null +++ b/RealTimeModels/Vip/VipContext.cs @@ -0,0 +1,35 @@ +using Microsoft.EntityFrameworkCore; + +namespace RealTimeModels.Vip; + +public class VipContext : DbContext +{ + public DbSet Stations => Set(); + public DbSet RealTimeEntries => Set(); + public DbSet Alerts => Set(); + public DbSet Routes => Set(); + public DbSet Vehicles => Set(); + + private string? ConnectionString { get; set; } + + public VipContext(string? connectionString = null) + { + ConnectionString = connectionString; + } + + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + var stationEntity = modelBuilder.Entity(); + stationEntity + .HasMany(station => station.Actual) + .WithOne(); + stationEntity + } + + protected override void OnConfiguring(DbContextOptionsBuilder options) + { + options.UseNpgsql(ConnectionString ?? "Host=127.0.0.1;Database=transit_vip;Username=postgres;Password=mysecretpassword"); + options.EnableDetailedErrors(); + options.EnableSensitiveDataLogging(); + } +} diff --git a/RealTimeToDotMatrix/DotMatrixPicture.cs b/RealTimeToDotMatrix/DotMatrixPicture.cs index daa82ff..7f7d95f 100644 --- a/RealTimeToDotMatrix/DotMatrixPicture.cs +++ b/RealTimeToDotMatrix/DotMatrixPicture.cs @@ -44,13 +44,16 @@ public string BuildUri() //requestUri = HttpUtility.UrlEncode(requestUri); return requestUri; } - public Stream GetPicture(string? requestUri = null) + public async Task GetPicture(string? requestUri = null) { requestUri ??= BuildUri(); string referer = @"http://avtanski.net/projects/lcd/"; - HttpWebRequest request = WebRequest.CreateHttp(requestUri); - request.Referer = referer; - HttpWebResponse response = (HttpWebResponse)request.GetResponse(); - return response.GetResponseStream(); + // HttpWebRequest request = WebRequest.CreateHttp(requestUri); + using HttpClient httpClient = new(); + httpClient.DefaultRequestHeaders.Referrer = new Uri(referer); + return await httpClient.GetStreamAsync(requestUri); + // request.Referer = referer; + // HttpWebResponse response = (HttpWebResponse)request.GetResponse(); + // return response.GetResponseStream(); } } diff --git a/RealTimeToDotMatrix/Vip/RealTimeToDotMatrix.cs b/RealTimeToDotMatrix/Vip/RealTimeToDotMatrix.cs index b8016fa..76e24cd 100644 --- a/RealTimeToDotMatrix/Vip/RealTimeToDotMatrix.cs +++ b/RealTimeToDotMatrix/Vip/RealTimeToDotMatrix.cs @@ -43,7 +43,7 @@ private static void AddAlertToList(string message, List lines, int cols) message = message.Trim(); lines.Add($"{message}"); } - + private static void AddHeaderToPage(Station station, List emptyPage, int cols, int gap) { emptyPage.Add(station.StationName); @@ -163,14 +163,14 @@ private static (string[] messages, (uint cols, uint rows) dimensions) GenerateTa return (pages.Select(page => string.Join(Environment.NewLine, page)).ToArray(), ((uint)targetCols, MaximalRows)); } - public static Stream Convert(Station station) + public static async Task Convert(Station station) { var (messages, dimensions) = GenerateTarget(station); var pictures = messages.Select(message => new DotMatrixPicture(message, RgbColor.Border, RgbColor.Background, RgbColor.InactivePixels, RgbColor.ActivePixels, dimensions)); // DotMatrixPicture picture = new DotMatrixPicture(message, RgbColor.Border, RgbColor.Background, RgbColor.InactivePixels, RgbColor.ActivePixels, dimensions); - Stream gif = Animator.GifCreator.ConvertImageStreamsToGifStream(pictures.Select(picture => picture.GetPicture())); + Stream gif = await Animator.GifCreator.ConvertImageStreamsToGifStream(pictures.Select(picture => picture.GetPicture())); return gif; - + // return pictures.ElementAt(0).GetPicture(); //return string.Join($"{Environment.NewLine}NEW_LINE{Environment.NewLine}", messages); } diff --git a/TransitUI.sln b/TransitUI.sln index 6a07dd3..cf10197 100644 --- a/TransitUI.sln +++ b/TransitUI.sln @@ -1,6 +1,6 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# +# Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TransitWeb", "TransitWeb\TransitWeb.csproj", "{DA1B73A1-9B61-4C62-9EB4-B4A3FF6980C7}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RealTimeDataCrawler", "RealTimeDataCrawler\RealTimeDataCrawler.csproj", "{4BC68B1E-F133-4C78-81FA-B07B1EE4E614}" diff --git a/TransitWeb/Controllers/WebApi/TransitController.cs b/TransitWeb/Controllers/WebApi/TransitController.cs index adf050a..197a7d2 100644 --- a/TransitWeb/Controllers/WebApi/TransitController.cs +++ b/TransitWeb/Controllers/WebApi/TransitController.cs @@ -12,11 +12,11 @@ namespace TransitWeb.Controllers.WebApi; public class TransitController : Controller { [HttpGet("vip/{id}")] - public IActionResult CheckIfStationExists(int id) + public async Task CheckIfStationExists(int id) { try { - Crawler.GetFromWeb(id); + await Crawler.GetFromWeb(id); return Ok(); } catch @@ -25,12 +25,12 @@ public IActionResult CheckIfStationExists(int id) } } [HttpGet("vip/{id}/dotmatrix")] - public IActionResult GetDotMatrixById(int id) + public async Task GetDotMatrixById(int id) { try { - Station station = Crawler.GetFromWeb(id); - Stream stream = RealTimeToDotMatrix.Vip.RealTimeToDotMatrix.Convert(station); + var station = await Crawler.GetFromWeb(id); + var stream = await RealTimeToDotMatrix.Vip.RealTimeToDotMatrix.Convert(station); // FileStream gif = System.IO.File.OpenRead(gifPath); return File(stream, "image/gif"); // return Content(stream); @@ -39,37 +39,37 @@ public IActionResult GetDotMatrixById(int id) catch (System.Net.WebException ex) { ApiErrorViewModel error = new(ex); - string json = JsonSerializer.Serialize(error); + var json = JsonSerializer.Serialize(error); return NotFound(json); } } [HttpGet("vip/{id}/info")] - public IActionResult GetInfoById(int id) + public async Task GetInfoById(int id) { try { - Station station = Crawler.GetFromWeb(id); + Station station = await Crawler.GetFromWeb(id); return Content(station.ToString()); } catch (System.Net.WebException ex) { - ApiErrorViewModel error = new ApiErrorViewModel(ex); - string json = JsonSerializer.Serialize(error); + ApiErrorViewModel error = new(ex); + var json = JsonSerializer.Serialize(error); return NotFound(json); } } [HttpGet("vip/{id}/json")] - public IActionResult GetJsonSourceById(int id) + public async Task GetJsonSourceById(int id) { try { - string jsonSource = Crawler.GetJsonSource(id); + var jsonSource = await Crawler.GetJsonSource(id); return Content(jsonSource, "application/json"); } catch (System.Net.WebException ex) { - ApiErrorViewModel error = new ApiErrorViewModel(ex); - string json = JsonSerializer.Serialize(error); + ApiErrorViewModel error = new(ex); + var json = JsonSerializer.Serialize(error); return NotFound(json); } } diff --git a/TransitWeb/Dockerfile b/TransitWeb/Dockerfile index c8a4484..d113536 100644 --- a/TransitWeb/Dockerfile +++ b/TransitWeb/Dockerfile @@ -2,6 +2,7 @@ WORKDIR /app EXPOSE 80 EXPOSE 443 +EXPOSE 3654 # Install ImageMagick (see https://askubuntu.com/a/648245) RUN apt update diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..999e1a8 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,27 @@ +version: '3' +services: + db: + image: postgres:13 + container_name: transit_postgres + volumes: + - transit_db:/var/lib/postgresql/data + ports: + - "127.0.0.1:5432:5432" + environment: + - POSTGRES_USER=postgres + - POSTGRES_PASSWORD=mysecretpassword + - POSTGRES_DB=transit_vip + app: + build: + context: . + dockerfile: TransitWeb/Dockerfile + depends_on: + - db + container_name: transit-web + ports: + - "127.0.0.1:3654:80" + expose: + - 3654 + +volumes: + transit_db: