summaryrefslogtreecommitdiff
path: root/src/SMAPI.Web/Framework
diff options
context:
space:
mode:
Diffstat (limited to 'src/SMAPI.Web/Framework')
-rw-r--r--src/SMAPI.Web/Framework/Clients/Pastebin/PasteInfo.cs2
-rw-r--r--src/SMAPI.Web/Framework/Clients/Pastebin/SavePasteResult.cs15
-rw-r--r--src/SMAPI.Web/Framework/ConfigModels/MongoDbConfig.cs6
-rw-r--r--src/SMAPI.Web/Framework/Storage/IStorageProvider.cs3
-rw-r--r--src/SMAPI.Web/Framework/Storage/StorageProvider.cs116
5 files changed, 92 insertions, 50 deletions
diff --git a/src/SMAPI.Web/Framework/Clients/Pastebin/PasteInfo.cs b/src/SMAPI.Web/Framework/Clients/Pastebin/PasteInfo.cs
index 1ef3ef12..813ea115 100644
--- a/src/SMAPI.Web/Framework/Clients/Pastebin/PasteInfo.cs
+++ b/src/SMAPI.Web/Framework/Clients/Pastebin/PasteInfo.cs
@@ -1,5 +1,3 @@
-using System;
-
namespace StardewModdingAPI.Web.Framework.Clients.Pastebin
{
/// <summary>The response for a get-paste request.</summary>
diff --git a/src/SMAPI.Web/Framework/Clients/Pastebin/SavePasteResult.cs b/src/SMAPI.Web/Framework/Clients/Pastebin/SavePasteResult.cs
deleted file mode 100644
index 89dab697..00000000
--- a/src/SMAPI.Web/Framework/Clients/Pastebin/SavePasteResult.cs
+++ /dev/null
@@ -1,15 +0,0 @@
-namespace StardewModdingAPI.Web.Framework.Clients.Pastebin
-{
- /// <summary>The response for a save-log request.</summary>
- internal class SavePasteResult
- {
- /// <summary>Whether the log was successfully saved.</summary>
- public bool Success { get; set; }
-
- /// <summary>The saved paste ID (if <see cref="Success"/> is <c>true</c>).</summary>
- public string ID { get; set; }
-
- /// <summary>The error message (if saving failed).</summary>
- public string Error { get; set; }
- }
-}
diff --git a/src/SMAPI.Web/Framework/ConfigModels/MongoDbConfig.cs b/src/SMAPI.Web/Framework/ConfigModels/MongoDbConfig.cs
index 3c508300..e2e18477 100644
--- a/src/SMAPI.Web/Framework/ConfigModels/MongoDbConfig.cs
+++ b/src/SMAPI.Web/Framework/ConfigModels/MongoDbConfig.cs
@@ -24,6 +24,12 @@ namespace StardewModdingAPI.Web.Framework.ConfigModels
/*********
** Public method
*********/
+ /// <summary>Get whether a MongoDB instance is configured.</summary>
+ public bool IsConfigured()
+ {
+ return !string.IsNullOrWhiteSpace(this.Host);
+ }
+
/// <summary>Get the MongoDB connection string.</summary>
public string GetConnectionString()
{
diff --git a/src/SMAPI.Web/Framework/Storage/IStorageProvider.cs b/src/SMAPI.Web/Framework/Storage/IStorageProvider.cs
index 12a5e421..96a34fbb 100644
--- a/src/SMAPI.Web/Framework/Storage/IStorageProvider.cs
+++ b/src/SMAPI.Web/Framework/Storage/IStorageProvider.cs
@@ -6,11 +6,10 @@ namespace StardewModdingAPI.Web.Framework.Storage
internal interface IStorageProvider
{
/// <summary>Save a text file to storage.</summary>
- /// <param name="title">The display title, if applicable.</param>
/// <param name="content">The content to upload.</param>
/// <param name="compress">Whether to gzip the text.</param>
/// <returns>Returns metadata about the save attempt.</returns>
- Task<UploadResult> SaveAsync(string title, string content, bool compress = true);
+ Task<UploadResult> SaveAsync(string content, bool compress = true);
/// <summary>Fetch raw text from storage.</summary>
/// <param name="id">The storage ID returned by <see cref="SaveAsync"/>.</param>
diff --git a/src/SMAPI.Web/Framework/Storage/StorageProvider.cs b/src/SMAPI.Web/Framework/Storage/StorageProvider.cs
index 12a35f18..35538443 100644
--- a/src/SMAPI.Web/Framework/Storage/StorageProvider.cs
+++ b/src/SMAPI.Web/Framework/Storage/StorageProvider.cs
@@ -27,6 +27,12 @@ namespace StardewModdingAPI.Web.Framework.Storage
/// <summary>The underlying text compression helper.</summary>
private readonly IGzipHelper GzipHelper;
+ /// <summary>Whether Azure blob storage is configured.</summary>
+ private bool HasAzure => !string.IsNullOrWhiteSpace(this.ClientsConfig.AzureBlobConnectionString);
+
+ /// <summary>The number of days since the blob's last-modified date when it will be deleted.</summary>
+ private int ExpiryDays => this.ClientsConfig.AzureBlobTempExpiryDays;
+
/*********
** Public methods
@@ -43,25 +49,38 @@ namespace StardewModdingAPI.Web.Framework.Storage
}
/// <summary>Save a text file to storage.</summary>
- /// <param name="title">The display title, if applicable.</param>
/// <param name="content">The content to upload.</param>
/// <param name="compress">Whether to gzip the text.</param>
/// <returns>Returns metadata about the save attempt.</returns>
- public async Task<UploadResult> SaveAsync(string title, string content, bool compress = true)
+ public async Task<UploadResult> SaveAsync(string content, bool compress = true)
{
- try
- {
- using Stream stream = new MemoryStream(Encoding.UTF8.GetBytes(content));
- string id = Guid.NewGuid().ToString("N");
+ string id = Guid.NewGuid().ToString("N");
- BlobClient blob = this.GetAzureBlobClient(id);
- await blob.UploadAsync(stream);
+ // save to Azure
+ if (this.HasAzure)
+ {
+ try
+ {
+ using Stream stream = new MemoryStream(Encoding.UTF8.GetBytes(content));
+ BlobClient blob = this.GetAzureBlobClient(id);
+ await blob.UploadAsync(stream);
- return new UploadResult(true, id, null);
+ return new UploadResult(true, id, null);
+ }
+ catch (Exception ex)
+ {
+ return new UploadResult(false, null, ex.Message);
+ }
}
- catch (Exception ex)
+
+ // save to local filesystem for testing
+ else
{
- return new UploadResult(false, null, ex.Message);
+ string path = this.GetDevFilePath(id);
+ Directory.CreateDirectory(Path.GetDirectoryName(path));
+
+ File.WriteAllText(path, content);
+ return new UploadResult(true, id, null);
}
}
@@ -69,39 +88,67 @@ namespace StardewModdingAPI.Web.Framework.Storage
/// <param name="id">The storage ID returned by <see cref="SaveAsync"/>.</param>
public async Task<StoredFileInfo> GetAsync(string id)
{
- // fetch from Azure/Amazon
+ // fetch from blob storage
if (Guid.TryParseExact(id, "N", out Guid _))
{
- // try Azure
- try
+ // Azure Blob storage
+ if (this.HasAzure)
{
- BlobClient blob = this.GetAzureBlobClient(id);
- Response<BlobDownloadInfo> response = await blob.DownloadAsync();
- using BlobDownloadInfo result = response.Value;
+ try
+ {
+ BlobClient blob = this.GetAzureBlobClient(id);
+ Response<BlobDownloadInfo> response = await blob.DownloadAsync();
+ using BlobDownloadInfo result = response.Value;
- using StreamReader reader = new StreamReader(result.Content);
- DateTimeOffset expiry = result.Details.LastModified + TimeSpan.FromDays(this.ClientsConfig.AzureBlobTempExpiryDays);
- string content = this.GzipHelper.DecompressString(reader.ReadToEnd());
+ using StreamReader reader = new StreamReader(result.Content);
+ DateTimeOffset expiry = result.Details.LastModified + TimeSpan.FromDays(this.ExpiryDays);
+ string content = this.GzipHelper.DecompressString(reader.ReadToEnd());
- return new StoredFileInfo
+ return new StoredFileInfo
+ {
+ Success = true,
+ Content = content,
+ Expiry = expiry.UtcDateTime
+ };
+ }
+ catch (RequestFailedException ex)
{
- Success = true,
- Content = content,
- Expiry = expiry.UtcDateTime
- };
+ return new StoredFileInfo
+ {
+ Error = ex.ErrorCode == "BlobNotFound"
+ ? "There's no file with that ID."
+ : $"Could not fetch that file from storage ({ex.ErrorCode}: {ex.Message})."
+ };
+ }
}
- catch (RequestFailedException ex)
+
+ // local filesystem for testing
+ else
{
+ FileInfo file = new FileInfo(this.GetDevFilePath(id));
+ if (file.Exists)
+ {
+ if (file.LastWriteTimeUtc.AddDays(this.ExpiryDays) < DateTime.UtcNow)
+ file.Delete();
+ else
+ {
+ return new StoredFileInfo
+ {
+ Success = true,
+ Content = File.ReadAllText(file.FullName),
+ Expiry = DateTime.UtcNow.AddDays(this.ExpiryDays),
+ Warning = "This file was saved temporarily to the local computer. This should only happen in a local development environment."
+ };
+ }
+ }
return new StoredFileInfo
{
- Error = ex.ErrorCode == "BlobNotFound"
- ? "There's no file with that ID."
- : $"Could not fetch that file from storage ({ex.ErrorCode}: {ex.Message})."
+ Error = "There's no file with that ID."
};
}
}
- // get from PasteBin
+ // get from Pastebin
else
{
PasteInfo response = await this.Pastebin.GetAsync(id);
@@ -116,12 +163,19 @@ namespace StardewModdingAPI.Web.Framework.Storage
}
/// <summary>Get a client for reading and writing to Azure Blob storage.</summary>
- /// <param name="id">The file ID to fetch.</param>
+ /// <param name="id">The file ID.</param>
private BlobClient GetAzureBlobClient(string id)
{
var azure = new BlobServiceClient(this.ClientsConfig.AzureBlobConnectionString);
var container = azure.GetBlobContainerClient(this.ClientsConfig.AzureBlobTempContainer);
return container.GetBlobClient($"uploads/{id}");
}
+
+ /// <summary>Get the absolute file path for an upload when running in a local test environment with no Azure account configured.</summary>
+ /// <param name="id">The file ID.</param>
+ private string GetDevFilePath(string id)
+ {
+ return Path.Combine(Path.GetTempPath(), "smapi-web-temp", $"{id}.txt");
+ }
}
}