Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use DateTimeOffset and TimeProvider #2246

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/Abstractions/NexusMods.Abstractions.Games/RunGameTool.cs
Original file line number Diff line number Diff line change
Expand Up @@ -207,8 +207,8 @@ private async Task RunThroughHeroic(string type, long appId, CancellationToken c

try
{
var start = DateTime.UtcNow;
while (!cancellationToken.IsCancellationRequested && start + timeout > DateTime.UtcNow)
var start = TimeProvider.System.GetTimestamp();
while (!cancellationToken.IsCancellationRequested && TimeProvider.System.GetElapsedTime(start) > timeout)
{
var processes = Process.GetProcessesByName(processName);
var target = existingProcesses is not null
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ namespace NexusMods.Abstractions.IO.StreamFactories;
public class NativeFileStreamFactory : IStreamFactory
{
private AbsolutePath _file;
private DateTime? _lastModifiedCache;

/// <inheritdoc />
public Size Size => _file.FileInfo.Size;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -340,7 +340,7 @@ await ActionExtractToDisk(groupings, register, tx,
tx.Add(gameMetadataId, GameInstallMetadata.LastSyncedLoadout, loadout.Id);
tx.Add(gameMetadataId, GameInstallMetadata.LastSyncedLoadoutTransaction, EntityId.From(tx.ThisTxId.Value));
tx.Add(gameMetadataId, GameInstallMetadata.LastScannedDiskStateTransaction, EntityId.From(tx.ThisTxId.Value));
tx.Add(loadout.Id, Loadout.LastAppliedDateTime, DateTime.UtcNow);
tx.Add(loadout.Id, Loadout.LastAppliedDateTime, TimeProvider.System.GetLocalNow());
await tx.Commit();

loadout = loadout.Rebase();
Expand Down Expand Up @@ -499,7 +499,7 @@ await _fileStore.ExtractFiles(toExtract.Select(item =>
{
tx.Add(entry.Disk.Value.Id, DiskStateEntry.Hash, entry.LoadoutFileHash.Value);
tx.Add(entry.Disk.Value.Id, DiskStateEntry.Size, entry.LoadoutFileSize.Value);
tx.Add(entry.Disk.Value.Id, DiskStateEntry.LastModified, DateTime.UtcNow);
tx.Add(entry.Disk.Value.Id, DiskStateEntry.LastModified, TimeProvider.System.GetLocalNow());
}
else
{
Expand All @@ -508,7 +508,7 @@ await _fileStore.ExtractFiles(toExtract.Select(item =>
Path = entry.Path.ToGamePathParentTuple(gameMetadataId),
Hash = entry.LoadoutFileHash.Value,
Size = entry.LoadoutFileSize.Value,
LastModified = DateTime.UtcNow,
LastModified = TimeProvider.System.GetLocalNow(),
GameId = gameMetadataId,
};
}
Expand Down Expand Up @@ -591,7 +591,7 @@ private async Task ActionIngestFromDisk(SyncActionGroupings<SyncTreeNode> groupi
tx.Add(prevLoadoutFile.Id, LoadoutFile.Hash, file.Disk.Value.Hash);
tx.Add(prevLoadoutFile.Id, LoadoutFile.Size, file.Disk.Value.Size);

tx.Add(file.Disk.Value.Id, DiskStateEntry.LastModified, DateTime.UtcNow);
tx.Add(file.Disk.Value.Id, DiskStateEntry.LastModified, TimeProvider.System.GetLocalNow());
continue;
}
}
Expand Down Expand Up @@ -624,7 +624,7 @@ private async Task ActionIngestFromDisk(SyncActionGroupings<SyncTreeNode> groupi
LoadoutFileEntry = loadoutFile,
}
);
tx.Add(file.Disk.Value.Id, DiskStateEntry.LastModified, DateTime.UtcNow);
tx.Add(file.Disk.Value.Id, DiskStateEntry.LastModified, TimeProvider.System.GetLocalNow());
}

if (added.Count > 0)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ public partial class DiskStateEntry : IModelDefinition
/// <summary>
/// The last modified time of the file
/// </summary>
public static readonly DateTimeAttribute LastModified = new(Namespace, nameof(LastModified));
public static readonly TimestampAttribute LastModified = new(Namespace, nameof(LastModified));

/// <summary>
/// The owning game installation
Expand Down
9 changes: 2 additions & 7 deletions src/Abstractions/NexusMods.Abstractions.Loadouts/Loadout.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,14 +54,9 @@ public partial class Loadout : IModelDefinition

/// <summary>
/// DateTime when the loadout was last applied.
/// Returns DateTime.MinValue if the loadout has never been applied.
/// </summary>
public static readonly DateTimeAttribute LastAppliedDateTime = new(Namespace, nameof(LastAppliedDateTime))
{
IsOptional = true,
DefaultValue = DateTime.MinValue,
};

public static readonly TimestampAttribute LastAppliedDateTime = new(Namespace, nameof(LastAppliedDateTime)) { IsOptional = true, };

/// <summary>
/// All items in the Loadout.
/// </summary>
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,11 @@ public static TxId MostRecentTxId(this IReadOnlyModel model)
/// <param name="model"></param>
/// <param name="dateTime">A default value to return if the model doesn't exist.</param>
/// <returns></returns>
public static DateTimeOffset GetCreatedAt<T>(this T model, DateTime? dateTime = null)
public static DateTimeOffset GetCreatedAt<T>(this T model, DateTimeOffset? dateTime = null)
where T : IReadOnlyModel
{
if (model.Count == 0)
return dateTime ?? DateTime.MinValue;
return dateTime ?? DateTimeOffset.MinValue;
var tx = new Transaction.ReadOnly(model.Db, EntityId.From(model.Min(m => m.T).Value));
return Transaction.Timestamp.Get(tx);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ public partial class NexusModsFileMetadata : IModelDefinition
/// <summary>
/// The date the file was uploaded at.
/// </summary>
public static readonly DateTimeAttribute UploadedAt = new(Namespace, nameof(UploadedAt));
public static readonly TimestampAttribute UploadedAt = new(Namespace, nameof(UploadedAt));

/// <summary>
/// The size in bytes of the file.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public partial class NexusModsModPageMetadata : IModelDefinition
/// <summary>
/// The last time the mod page was updated (UTC). This is useful for cache invalidation.
/// </summary>
public static readonly DateTimeAttribute UpdatedAt = new(Namespace, nameof(UpdatedAt));
public static readonly TimestampAttribute UpdatedAt = new(Namespace, nameof(UpdatedAt));

/// <summary>
/// Uri for the full sized picture of the mod.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ public class GameInfo : IJsonArraySerializable<GameInfo>
/// <summary>
/// Timestamp of when the game was approved by the site staff, expressed as UTC, Coordinated Universal Time.
/// </summary>
public DateTime ApprovedDateUtc => DateTimeOffset.FromUnixTimeSeconds(ApprovedDate).UtcDateTime;
public DateTimeOffset ApprovedDateUtc => DateTimeOffset.FromUnixTimeSeconds(ApprovedDate);

/// <summary>
/// Number of views on this file.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ public class ModFile : IJsonSerializable<ModFile>
/// Expressed as ISO 8601 compatible date/time notation.
/// </remarks>
[JsonPropertyName("uploaded_time")]
public DateTime UploadedTime { get; set; }
public DateTimeOffset UploadedTime { get; set; }

/// <summary>
/// Version of the mod. See <see cref="Version"/> for more details.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,13 +64,13 @@ public class ModInfo : IJsonSerializable<ModInfo>
public int CreatedTimestamp { get; set; }

[JsonPropertyName("created_time")]
public DateTime CreatedTime { get; set; }
public DateTimeOffset CreatedTime { get; set; }

[JsonPropertyName("updated_timestamp")]
public int UpdatedTimestamp { get; set; }

[JsonPropertyName("updated_time")]
public DateTime UpdatedTime { get; set; }
public DateTimeOffset UpdatedTime { get; set; }

[JsonPropertyName("author")]
public string Author { get; set; } = "";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ public class ModUpdate : IJsonArraySerializable<ModUpdate>
/// <summary>
/// The last time a file on the mod page was updated.
/// </summary>
public DateTime LatestFileUpdatedUtc => DateTimeOffset.FromUnixTimeSeconds(LatestFileUpdated).UtcDateTime;
public DateTimeOffset LatestFileUpdatedUtc => DateTimeOffset.FromUnixTimeSeconds(LatestFileUpdated);

/// <summary>
/// The last time any change was made to the mod page.
Expand All @@ -53,7 +53,7 @@ public class ModUpdate : IJsonArraySerializable<ModUpdate>
/// <summary>
/// The last time any change was made to the mod page.
/// </summary>
public DateTime LatestModActivityUtc => DateTimeOffset.FromUnixTimeSeconds(LatestModActivity).UtcDateTime;
public DateTimeOffset LatestModActivityUtc => DateTimeOffset.FromUnixTimeSeconds(LatestModActivity);

/// <inheritdoc />
public static JsonTypeInfo<ModUpdate[]> GetArrayTypeInfo() => ModUpdateArrayContext.Default.ModUpdateArray;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public class ResponseMetadata
/// <summary>
/// [Rate Limit] Stores the time when the daily limit is next reset.
/// </summary>
public DateTime DailyReset { get; set; }
public DateTimeOffset DailyReset { get; set; }

/// <summary>
/// [Rate Limit] Stores the limit your <see cref="HourlyRemaining"/> will be reset to once
Expand All @@ -37,7 +37,7 @@ public class ResponseMetadata
/// <summary>
/// [Rate Limit] Stores the time when the hourly limit is next reset.
/// </summary>
public DateTime HourlyReset { get; set; }
public DateTimeOffset HourlyReset { get; set; }

/// <summary>
/// Time taken to execute the request server side, in seconds.
Expand All @@ -58,11 +58,11 @@ void ParseInt(string headerName, out int output)
output = limit;
}

void ParseDateTime(string headerName, out DateTime output)
void ParseDateTime(string headerName, out DateTimeOffset output)
{
output = default;
if (result.Headers.TryGetValues(headerName, out var values))
if (DateTime.TryParse(values.First(), out var limit))
if (DateTimeOffset.TryParse(values.First(), out var limit))
output = limit;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,7 @@ public interface INexusApiClient
/// <remarks>
/// Currently available for Premium users only; with some minor exceptions [nxm links].
/// </remarks>
Task<Response<DownloadLink[]>> DownloadLinksAsync(string domain, ModId modId, FileId fileId, NXMKey key, DateTime expireTime, CancellationToken token = default);

Task<Response<DownloadLink[]>> DownloadLinksAsync(string domain, ModId modId, FileId fileId, NXMKey key, DateTimeOffset expireTime, CancellationToken token = default);

/// <summary>
/// Get the download links for a collection.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,12 @@ public class NXMUrl
/// <summary>
/// if applicable, the time the url becomes invalid
/// </summary>
public DateTime? ExpireTime
public DateTimeOffset? ExpireTime
{
get
{
var expires = Query.Get("expires");
return expires != null ? DateTime.UnixEpoch.AddSeconds(ulong.Parse(expires)) : null;
return expires != null ? DateTimeOffset.UnixEpoch.AddSeconds(ulong.Parse(expires)) : null;
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using JetBrains.Annotations;
using NexusMods.Abstractions.MnemonicDB.Attributes;
using NexusMods.MnemonicDB.Abstractions.Attributes;
using NexusMods.MnemonicDB.Abstractions.Models;

namespace NexusMods.Abstractions.Resources.DB;
Expand All @@ -20,7 +21,7 @@ public partial class PersistedDbResource : IModelDefinition
/// <summary>
/// The expiration date.
/// </summary>
public static readonly DateTimeAttribute ExpiresAt = new(Namespace, nameof(ExpiresAt));
public static readonly TimestampAttribute ExpiresAt = new(Namespace, nameof(ExpiresAt));

/// <summary>
/// The resource identifier as a hash.
Expand All @@ -32,6 +33,6 @@ public partial struct ReadOnly
/// <summary>
/// Whether the resource is expired.
/// </summary>
public bool IsExpired => DateTime.UtcNow > ExpiresAt;
public bool IsExpired => TimeProvider.System.GetLocalNow() > ExpiresAt;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,19 +35,18 @@ public async ValueTask<Resource<byte[]>> LoadResourceAsync(Uri resourceIdentifie
};
}

private static DateTime GetExpiresAt(HttpResponseMessage responseMessage)
private static DateTimeOffset GetExpiresAt(HttpResponseMessage responseMessage)
{
var cacheControl = responseMessage.Headers.CacheControl;
if (cacheControl is null) return DateTime.MaxValue;

var maxAge = cacheControl.MaxAge;
if (!maxAge.HasValue) return DateTime.MaxValue;
var maxAge = cacheControl?.MaxAge;
if (!maxAge.HasValue) return DateTimeOffset.MaxValue;

var age = responseMessage.Headers.Age;

var diff = maxAge.Value;
if (age.HasValue) diff -= age.Value;

return DateTime.UtcNow + diff;
return TimeProvider.System.GetUtcNow() + diff;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public record Resource<TData> where TData : notnull
/// <summary>
/// Gets the expiration date.
/// </summary>
public DateTime ExpiresAt { get; init; } = DateTime.MaxValue;
public DateTimeOffset ExpiresAt { get; init; } = DateTimeOffset.MaxValue;

/// <summary>
/// Creates a new resource.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ public interface IModFeedItem

/// <summary>
/// Retrieves the time the item was last updated.
/// This date is in UTC.
/// </summary>
public DateTime GetLastUpdatedDateUtc();
public DateTimeOffset GetLastUpdatedDateUtc();
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ namespace NexusMods.Networking.ModUpdates.Mixins;
/// </summary>
public readonly struct ModFeedItemUpdateMixin : IModFeedItem
{
private readonly DateTime _lastUpdatedDate;
private readonly DateTimeOffset _lastUpdatedDate;
private readonly GameId _gameId;
private readonly ModId _modId;

Expand All @@ -29,7 +29,7 @@ private ModFeedItemUpdateMixin(ModUpdate update, GameId gameId)
public static IEnumerable<ModFeedItemUpdateMixin> FromUpdateResults(IEnumerable<ModUpdate> updates, GameId gameId) => updates.Select(update => new ModFeedItemUpdateMixin(update, gameId));

/// <inheritdoc />
public DateTime GetLastUpdatedDateUtc() => _lastUpdatedDate;
public DateTimeOffset GetLastUpdatedDateUtc() => _lastUpdatedDate;

/// <inheritdoc />
public UidForMod GetModPageId() => new()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ public struct PageMetadataMixin : IModFeedItem
public EntityId GetModPageEntityId() => _metadata.Id;

/// <inheritodc/>
public DateTime GetLastUpdatedDateUtc() => _metadata.UpdatedAt; // <= TODO: Change this with 'last file updated at' when V2 supports this field.
public DateTimeOffset GetLastUpdatedDateUtc() => _metadata.UpdatedAt; // <= TODO: Change this with 'last file updated at' when V2 supports this field.

/// <summary>
/// Returns the database entries containing page metadata(s) as a mixin.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,7 @@ public PerFeedCacheUpdater(TUpdateableItem[] items, TimeSpan expiry)
_itemToIndex[_items[x].GetModPageId().ModId] = x;

// Set the action to refresh cache for any mods which exceed max age.
var utcNow = DateTime.UtcNow;
var minCachedDate = utcNow - expiry;
var minCachedDate = TimeProvider.System.GetLocalNow()- expiry;
for (var x = 0; x < _items.Length; x++)
{
if (_items[x].GetLastUpdatedDateUtc() < minCachedDate)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ public static Optional<EntityId> Create(IDb db, ITransaction tx, JwtTokenReply r

tx.Add(entityId, AccessToken, reply.AccessToken);
tx.Add(entityId, RefreshToken, reply.RefreshToken);
tx.Add(entityId, ExpiresAt, DateTimeOffset.FromUnixTimeSeconds(reply.CreatedAt).DateTime + TimeSpan.FromSeconds(reply.ExpiresIn));
tx.Add(entityId, ExpiresAt, DateTimeOffset.FromUnixTimeSeconds(reply.CreatedAt) + TimeSpan.FromSeconds(reply.ExpiresIn));

return entityId;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ public static EntityId Resolve(this IModFileFragment modFileFragment, IDb db, IT
nexusFileResolver.Add(NexusModsFileMetadata.ModPageId, modPageEid);
nexusFileResolver.Add(NexusModsFileMetadata.Name, modFileFragment.Name);
nexusFileResolver.Add(NexusModsFileMetadata.Version, modFileFragment.Version);
nexusFileResolver.Add(NexusModsFileMetadata.UploadedAt, DateTimeOffset.FromUnixTimeSeconds(modFileFragment.Date).DateTime);
nexusFileResolver.Add(NexusModsFileMetadata.UploadedAt, DateTimeOffset.FromUnixTimeSeconds(modFileFragment.Date));

if (ulong.TryParse(modFileFragment.SizeInBytes, out var size))
{
Expand All @@ -62,7 +62,7 @@ public static EntityId Resolve(this IModFragment modFragment, IDb db, ITransacti
var nexusModResolver = GraphQLResolver.Create(db, tx, NexusModsModPageMetadata.Uid, UidForMod.FromV2Api(modFragment.Uid));
nexusModResolver.Add(NexusModsModPageMetadata.Name, modFragment.Name);
nexusModResolver.Add(NexusModsModPageMetadata.GameDomain, GameDomain.From(modFragment.Game.DomainName));
nexusModResolver.Add(NexusModsModPageMetadata.UpdatedAt, modFragment.UpdatedAt.UtcDateTime);
nexusModResolver.Add(NexusModsModPageMetadata.UpdatedAt, modFragment.UpdatedAt);

if (Uri.TryCreate(modFragment.PictureUrl, UriKind.Absolute, out var fullSizedPictureUri))
nexusModResolver.Add(NexusModsModPageMetadata.FullSizedPictureUri, fullSizedPictureUri);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,10 +105,10 @@ public async Task<Response<DownloadLink[]>> DownloadLinksAsync(string domain, Mo
/// <remarks>
/// Currently available for Premium users only; with some minor exceptions [nxm links].
/// </remarks>
public async Task<Response<DownloadLink[]>> DownloadLinksAsync(string domain, ModId modId, FileId fileId, NXMKey key, DateTime expireTime, CancellationToken token = default)
public async Task<Response<DownloadLink[]>> DownloadLinksAsync(string domain, ModId modId, FileId fileId, NXMKey key, DateTimeOffset expireTime, CancellationToken token = default)
{
var msg = await _factory.Create(HttpMethod.Get, new Uri(
$"https://api.nexusmods.com/v1/games/{domain}/mods/{modId}/files/{fileId}/download_link.json?key={key}&expires={new DateTimeOffset(expireTime).ToUnixTimeSeconds()}"));
$"https://api.nexusmods.com/v1/games/{domain}/mods/{modId}/files/{fileId}/download_link.json?key={key}&expires={expireTime.ToUnixTimeSeconds()}"));
return await SendAsyncArray<DownloadLink>(msg, token);
}

Expand Down
Loading
Loading