Skip to content

Commit

Permalink
Implement Backup for Tracks, use new file structure for track backup.…
Browse files Browse the repository at this point in the history
… Not much tested yet.
  • Loading branch information
Didosa committed Aug 31, 2024
1 parent bfa81d5 commit 2d64621
Show file tree
Hide file tree
Showing 19 changed files with 341 additions and 181 deletions.
4 changes: 2 additions & 2 deletions DataMigrator/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,12 @@ private static void MoveData() {
foreach(Track aTrack in trackDataReader.ReadAllTracks()) {
if(aTrack?.StartBoatTime != null) {
try {
day = new Model.Common.Date(DateTimeHelper.FromJSTime(aTrack.StartBoatTime));
day = new Model.Common.Date(DateTimeHelper.FromJSTime(aTrack.StartBoatTime.Value));
logbookDay = logbookDataReader.ReadLogbookDay(day);
aTrack.Boat = logbookDay?.LogbookEntries.FirstOrDefault()?.BoatSetup.BoatConfigName ?? defaultBoat;
readMS = (DateTime.UtcNow - dateTime).TotalMilliseconds;
dateTime = DateTime.UtcNow;
trackDataWriter.InsertTrack(aTrack);
trackDataWriter.SaveTrack(aTrack);
writeMS = (DateTime.UtcNow - dateTime).TotalMilliseconds;
dateTime = DateTime.UtcNow;
analyzer = new TrackAnalyzer(aTrack);
Expand Down
4 changes: 2 additions & 2 deletions PiLotAPICore/Controllers/PublishTargetsController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,8 @@ private async Task<TargetData<List<Track>>> LoadTracksAsync(PublishTarget pTarge
List<Track> localTracks = DataConnectionHelper.TrackDataConnector.ReadTracks(trackStart, trackEnd, true, true);
foreach(Track aTrack in localTracks) {
if (aTrack.HasTrackPoints) {
trackStart = aTrack.StartUTC;
trackEnd = aTrack.EndUTC;
trackStart = aTrack.StartUTC.Value;
trackEnd = aTrack.EndUTC.Value;
isBoatTime = false;
}
}
Expand Down
18 changes: 11 additions & 7 deletions PiLotAPICore/Controllers/TracksController.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;

using PiLot.API.ActionFilters;
Expand Down Expand Up @@ -78,20 +79,23 @@ public Boolean[] Get(Int32 year, Int32 month) {
}

/// <summary>
/// Saves a track. The Track must have ID=null. Any existing track for the same
/// boat that overlaps this track will be deleted
/// Saves a track. If there is any overlapping track, this will throw an error
/// </summary>
/// <param name="Track">The track to save, ID must be null</param>
/// <returns>The id of the track</returns>
[Route(Program.APIROOT + "[controller]")]
[HttpPut]
[ServiceFilter(typeof(WriteAuthorizationFilter))]
public Int32 PutInsert(Track track) {
DataConnectionHelper.TrackDataConnector.InsertTrack(track);
if (track.ID != null) {
TrackStatisticsHelper.UpdateStatistics(track.ID.Value, false);
public ActionResult PutInsert(Track track) {
try {
DataConnectionHelper.TrackDataConnector.SaveTrack(track);
if (track.ID != null) {
TrackStatisticsHelper.UpdateStatistics(track.ID.Value, false);
}
return this.Ok(track.ID.Value);
} catch (Exception ex) {
return this.StatusCode(StatusCodes.Status500InternalServerError, ex.Message);
}
return track.ID.Value;
}

/// <summary>
Expand Down
45 changes: 45 additions & 0 deletions PiLotBackupAPI/Controllers/TracksController.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
using System;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;

using PiLot.Backup.API.ActionFilters;
using PiLot.Backup.API.Helpers;
using PiLot.Model.Nav;
using PiLot.Model.Users;
using PiLot.Utils.DateAndTime;
using PiLot.Utils.Logger;

namespace PiLot.Backup.API.Controllers {

[ApiController]
public class TracksController : ControllerBase {

/// <summary>
/// Accepts puts with a track and saves the data to the backup folder. If the folder does
/// not exist yet, it will be created and be pre-populated with the latest backup data.
/// </summary>
/// <param name="track">A Track</param>
/// <param name="backupTime">The unix timestamp for the backup set to create/use</param>
[Route(Program.APIROOT + "[controller]")]
[HttpPut]
[ServiceFilter(typeof(BackupAuthorizationFilter))]
public ActionResult Put(Track track, Int32 backupTime) {
ActionResult result;
Object userObj = this.HttpContext.Items["user"];
if(userObj != null) {
User user = (User)userObj;
try {
DateTime time = DateTimeHelper.FromUnixTime(backupTime);
BackupHelper.BackupTrack(track, user.Username, time);
result = this.Ok();
} catch (Exception ex) {
result = this.StatusCode(StatusCodes.Status500InternalServerError, ex.Message);
Logger.Log(ex, this.HttpContext.Request.Path.ToString());
}
} else {
result = this.Unauthorized();
}
return result;
}
}
}
14 changes: 13 additions & 1 deletion PiLotBackupAPI/Helpers/BackupHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,18 @@ public static void BackupGpsData(List<TrackPoint> pRecords, System.Date pDay, St
Logger.Log("Recieved {0} GpsRecords to backup", pRecords.Count, LogLevels.DEBUG);
}

/// <summary>
/// Backups a Track
/// </summary>
/// <param name="pTrack"></param>
/// <param name="pClientName"></param>
/// <param name="pBackupTime"></param>
public static void BackupTrack(Track pTrack, String pClientName, DateTime pBackupTime) {
DirectoryInfo backupDirectory = BackupHelper.GetTempDirectory(pClientName, pBackupTime);
TrackDataConnector2.GetInstance(backupDirectory.FullName).SaveTrack(pTrack);
Logger.Log($"Recieved Track with id {pTrack.ID} to backup", LogLevels.DEBUG);
}

/// <summary>
/// Backup Logbook Data for one day
/// </summary>
Expand Down Expand Up @@ -170,7 +182,7 @@ public static List<Int32> GetDataSummary(List<DataSource> pDataSources, String p
Int32 dataCount = 0;
switch (aDataSource.DataType) {
case DataTypes.GPS:
dataCount = new TrackDataConnector(backupDirectory.FullName).ReadDaysWithData();
dataCount = TrackDataConnector2.GetInstance(backupDirectory.FullName).ReadDaysWithData();
break;
case DataTypes.Logbook:
dataCount = new LogbookDataConnector(backupDirectory.FullName).ReadLogbookDaysCount();
Expand Down
49 changes: 0 additions & 49 deletions PiLotBackupClient/Data/GPSDataConnector.cs

This file was deleted.

2 changes: 1 addition & 1 deletion PiLotBackupClient/Data/PoiDataConnector.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ internal PoiDataConnector(): base(){}
/// <returns>The date of the latest change or null</returns>
internal DateTime? ReadLatestChange() {
DateTime? result = null;
Logger.Log($"PoiDataConnector.ReadLatestChange", LogLevels.DEBUG);
Logger.Log("PoiDataConnector.ReadLatestChange", LogLevels.DEBUG);
String query = "SELECT * FROM poi_latest_change;";
List<DateTime?> resultList = this.dbHelper.ReadData<DateTime?>(query, new Func<NpgsqlDataReader, DateTime?>(this.dbHelper.ReadDateTime));
if (resultList.Count == 1) {
Expand Down
54 changes: 54 additions & 0 deletions PiLotBackupClient/Data/TrackDataConnector.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using Npgsql;
using PiLot.Backup.Client.Model;
using PiLot.Model.Nav;
using PiLot.Utils.Logger;

namespace PiLot.Backup.Client.Data {

/// <summary>
/// Helper for reading tracks for backup
/// </summary>
internal class TrackDataConnector : PiLot.Data.Postgres.Nav.TrackDataConnector {

internal TrackDataConnector(): base(){}

/// <summary>
/// Reads the total number of non.empty tracks and the ids of the tracks that have been changed since the last backup
/// </summary>
/// <param name="pChangedAfter">The date of the last backup</param>
/// <returns>The ids of the changed tracks, the number of non-empty tracks</returns>
internal BackupTaskData<List<Int32>> GetChangedTracks(DateTime pChangedAfter) {
Logger.Log("TrackDataconnector.ReadLatestChange", LogLevels.DEBUG);
Int32 tracksCount = 0;
List<Int32?> changedTrackIDs = new List<Int32?>(0);
NpgsqlConnection connection = this.dbHelper.GetConnection();
if (connection != null) {
connection.Open();
NpgsqlTransaction transaction = connection.BeginTransaction(IsolationLevel.RepeatableRead);
try {
String tracksCountQuery = "SELECT count(id) FROM tracks WHERE start_utc IS NOT NULL;";
tracksCount = this.dbHelper.ReadValue<Int32?>(tracksCountQuery, transaction) ?? 0;
String changedTrackIDsQuery = "SELECT id FROM tracks WHERE date_changed >= @p_date_changed";
List<(String, Object)> changedTrackIDsPars = new List<(String, Object)>();
changedTrackIDsPars.Add(("@p_date_changed", pChangedAfter));
changedTrackIDs = this.dbHelper.ReadData<Int32?>(changedTrackIDsQuery, new Func<NpgsqlDataReader, Int32?>(this.dbHelper.ReadNullableField<Int32?>), changedTrackIDsPars);
transaction.Commit();
connection.Close();
} catch (Exception ex) {
Logger.Log(ex, "TrackDataConnector.InsertTrack");
transaction.Rollback();
connection.Close();
throw;
}
}
return new BackupTaskData<List<Int32>>() {
ChangedItems = changedTrackIDs.FindAll(id => id != null).Select(id => id.Value).ToList(),
TotalItems = tracksCount
};
}
}
}
20 changes: 11 additions & 9 deletions PiLotBackupClient/Helper/GpsBackupHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
namespace PiLot.Backup.Client.Helper {

/// <summary>
/// Helper to create backups of GPS Data
/// Helper to create backups of GPS Data, a.k.a. Tracks
/// </summary>
public class GpsBackupHelper : BackupHelper, IBackupHelper {

Expand All @@ -21,25 +21,27 @@ public class GpsBackupHelper : BackupHelper, IBackupHelper {
public GpsBackupHelper(BackupServiceProxy pProxy) : base(pProxy) { }

/// <summary>
/// Reads newly created GPS Data and sends a backup of the GPS records for one day to the backup service
/// Reads newly created or changed tracks and sends them to the backup service
/// </summary>
/// <param name="pTask">The backup task, neede to get the last Backup date</param>
/// <param name="pTask">The backup task, needed to get the last Backup date</param>
/// <param name="pBackupTime">The date of the backup</param>
public async Task<BackupTaskResult> PerformBackupTaskAsync(BackupTask pTask, DateTime pBackupTime) {
Boolean success = true;
DateTime lastBackupDate = pTask.LastSuccess ?? new DateTime(0);
BackupTaskData<Dictionary<Date, Track>> gpsData = new GPSDataConnector().GetChangedDailyData(lastBackupDate);
TrackDataConnector dataConnector = new TrackDataConnector();
BackupTaskData<List<Int32>> trackData = dataConnector.GetChangedTracks(lastBackupDate);
Boolean serviceResult;
foreach (Date aDate in gpsData.ChangedItems.Keys) {
serviceResult = await this.proxy.BackupDailyTrackAsync(gpsData.ChangedItems[aDate], aDate, pBackupTime);
foreach (Int32 aTrackID in trackData.ChangedItems) {
Track track = dataConnector.ReadTrack(aTrackID);
serviceResult = await this.proxy.BackupTrackAsync(track, pBackupTime);
if (serviceResult) {
Out.WriteDebug(String.Format("Track backupped for date {0:d}", aDate));
Out.WriteDebug($"Track backupped for track id {aTrackID}");
} else {
Out.WriteError(String.Format("Backing up track for date {0:d} failed", aDate));
Out.WriteError($"Backing up track for track id {aTrackID} failed");
success = false;
}
}
return new BackupTaskResult(pTask, success, gpsData.TotalItems);
return new BackupTaskResult(pTask, success, trackData.TotalItems);
}
}
}
9 changes: 5 additions & 4 deletions PiLotBackupClient/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ private static async Task StartInteractiveSession() {
Boolean fullBackup = false;
Boolean validEntry = false;
Boolean quit = false;
ConsoleColor defaultColor = Console.ForegroundColor;
Console.ResetColor();
Console.Clear();
Console.WriteLine("******************************************");
Console.WriteLine("| PiLot Backup Client - Interactive Mode |");
Expand Down Expand Up @@ -133,11 +133,12 @@ private static async Task StartInteractiveSession() {
} else {
await Program.BackupTargetAsync(selectedTarget, fullBackup);
}
Console.ForegroundColor = defaultColor;
Console.ResetColor();
}
Console.WriteLine();
}
}
Console.ResetColor();
Console.WriteLine("Bye");
Thread.Sleep(1000);
}
Expand Down Expand Up @@ -232,12 +233,12 @@ private static async Task BackupTargetAsync(BackupTarget pTarget, Boolean pFullB
Out.WriteError("Committing backup failed");
}
} else {
Boolean rollbackSuccess = await proxy.RollbackAsync(backupDate);
/*Boolean rollbackSuccess = await proxy.RollbackAsync(backupDate);
if (rollbackSuccess) {
Out.WriteInfo("Rolled back successfully");
} else {
Out.WriteError("Rollback failed");
}
}*/
}
if (success) {
pTarget.BackupTasks.ForEach(t => t.LastSuccess = backupDate);
Expand Down
10 changes: 5 additions & 5 deletions PiLotBackupClient/Proxy/BackupServiceProxy.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,15 +33,15 @@ public BackupServiceProxy(String pTargetApiUrl, String pUsername, String pPasswo
}

/// <summary>
/// Sends the gps records for one day to the server
/// Sends a track to the server
/// </summary>
/// <param name="pTrack">The track of the day</param>
/// <param name="pTrack">The track to back up</param>
/// <param name="pBackupTime">The timestamp of the current backup set</param>
/// <returns>True, if the call was successful, else false</returns>
public async Task<Boolean> BackupDailyTrackAsync(Track pTrack, System.Date pTrackDay, DateTime pBackupTime) {
public async Task<Boolean> BackupTrackAsync(Track pTrack, DateTime pBackupTime) {
Assert.IsNotNull(pTrack, "pTrack must not be null");
String url = $"{this.apiUrl}/Track?backupTime={DateTimeHelper.ToUnixTime(pBackupTime)}&day={DateTimeHelper.ToUnixTime(pTrackDay)}";
String jsonString = JsonSerializer.Serialize(pTrack.TrackPoints);
String url = $"{this.apiUrl}/Tracks?backupTime={DateTimeHelper.ToUnixTime(pBackupTime)}";
String jsonString = JsonSerializer.Serialize(pTrack);
return await this.httpClient.PutAsync(jsonString, url);
}

Expand Down
2 changes: 1 addition & 1 deletion PiLotBackupClient/config.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"backupTargets": [
{
"targetUrl": "http://localhost/PiLotBackupAPINew",
"targetUrl": "http://localhost/pilotbackupAPINew",
"username": "test",
"password": "8888",
"backupTasks": [
Expand Down
2 changes: 1 addition & 1 deletion PiLotData/Nav/ITrackDataConnector.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ public interface ITrackDataConnector {
/// the id must be null and will be set.
/// </summary>
/// <param name="pTrack">The track to save</param>
void InsertTrack(Track pTrack);
void SaveTrack(Track pTrack);

/// <summary>
/// Deletes a track, if it exists. Will only be implemented if SupportTrackIDs=true
Expand Down
2 changes: 1 addition & 1 deletion PiLotDataFiles/Nav/TrackDataConnector.cs
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ public List<Boolean> ReadTracksMonthInfo(Int32 pYear, Int32 pMonth) {
/// Saves all data for a track, deleting overlapping track points
/// </summary>
/// <param name="pTrack">The track, not null</param>
public void InsertTrack(Track pTrack) {
public void SaveTrack(Track pTrack) {
this.SaveTrackPoints(pTrack.TrackPoints);
}

Expand Down
Loading

0 comments on commit 2d64621

Please sign in to comment.