Skip to content

Commit 5a160d7

Browse files
committed
ftp
1 parent ef48295 commit 5a160d7

38 files changed

+3916
-348
lines changed

ManagedCode.Storage.Core/BaseStorage.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ public Task<Result<BlobMetadata>> UploadAsync(string content, UploadOptions opti
123123
if (string.IsNullOrWhiteSpace(options.MimeType))
124124
options.MimeType = MimeHelper.TEXT;
125125

126-
return UploadInternalAsync(new StringStream(content), SetUploadOptions(options), cancellationToken);
126+
return UploadInternalAsync(new Utf8StringStream(content), SetUploadOptions(options), cancellationToken);
127127
}
128128

129129
public Task<Result<BlobMetadata>> UploadAsync(FileInfo fileInfo, UploadOptions options, CancellationToken cancellationToken = default)
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
namespace ManagedCode.Storage.Core.Constants;
2+
3+
/// <summary>
4+
/// Standard metadata keys for storage providers
5+
/// </summary>
6+
public static class MetadataKeys
7+
{
8+
// File system metadata
9+
public const string Permissions = "permissions";
10+
public const string FileType = "file_type";
11+
public const string Owner = "owner";
12+
public const string Group = "group";
13+
public const string LastAccessed = "last_accessed";
14+
public const string Created = "created";
15+
public const string Modified = "modified";
16+
17+
// FTP specific
18+
public const string FtpRawPermissions = "ftp_raw_permissions";
19+
public const string FtpFileType = "ftp_file_type";
20+
public const string FtpSize = "ftp_size";
21+
public const string FtpModifyTime = "ftp_modify_time";
22+
23+
// Cloud storage metadata
24+
public const string ContentEncoding = "content_encoding";
25+
public const string ContentLanguage = "content_language";
26+
public const string CacheControl = "cache_control";
27+
public const string ETag = "etag";
28+
public const string ContentHash = "content_hash";
29+
public const string StorageClass = "storage_class";
30+
31+
// Azure specific
32+
public const string AzureBlobType = "azure_blob_type";
33+
public const string AzureAccessTier = "azure_access_tier";
34+
public const string AzureServerEncrypted = "azure_server_encrypted";
35+
36+
// AWS specific
37+
public const string AwsStorageClass = "aws_storage_class";
38+
public const string AwsServerSideEncryption = "aws_server_side_encryption";
39+
public const string AwsVersionId = "aws_version_id";
40+
41+
// Google Cloud specific
42+
public const string GcsStorageClass = "gcs_storage_class";
43+
public const string GcsGeneration = "gcs_generation";
44+
public const string GcsMetageneration = "gcs_metageneration";
45+
46+
// Media metadata
47+
public const string ImageWidth = "image_width";
48+
public const string ImageHeight = "image_height";
49+
public const string VideoDuration = "video_duration";
50+
public const string AudioBitrate = "audio_bitrate";
51+
52+
// Custom application metadata
53+
public const string ApplicationName = "app_name";
54+
public const string ApplicationVersion = "app_version";
55+
public const string UserId = "user_id";
56+
public const string SessionId = "session_id";
57+
58+
// Processing metadata
59+
public const string ProcessingStatus = "processing_status";
60+
public const string ThumbnailGenerated = "thumbnail_generated";
61+
public const string VirusScanned = "virus_scanned";
62+
public const string Compressed = "compressed";
63+
public const string Encrypted = "encrypted";
64+
}
65+
66+
/// <summary>
67+
/// Standard metadata values for common scenarios
68+
/// </summary>
69+
public static class MetadataValues
70+
{
71+
// File types
72+
public static class FileTypes
73+
{
74+
public const string File = "file";
75+
public const string Directory = "directory";
76+
public const string SymbolicLink = "symbolic_link";
77+
public const string Unknown = "unknown";
78+
}
79+
80+
// Processing statuses
81+
public static class ProcessingStatus
82+
{
83+
public const string Pending = "pending";
84+
public const string Processing = "processing";
85+
public const string Completed = "completed";
86+
public const string Failed = "failed";
87+
}
88+
89+
// Boolean values
90+
public static class Boolean
91+
{
92+
public const string True = "true";
93+
public const string False = "false";
94+
}
95+
96+
// Storage classes
97+
public static class StorageClasses
98+
{
99+
public const string Standard = "standard";
100+
public const string InfrequentAccess = "infrequent_access";
101+
public const string Archive = "archive";
102+
public const string ColdStorage = "cold_storage";
103+
}
104+
}
Lines changed: 208 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,208 @@
1+
using System;
2+
using System.IO;
3+
4+
namespace ManagedCode.Storage.Core.Helpers;
5+
6+
/// <summary>
7+
/// Helper methods for cross-platform path operations
8+
/// </summary>
9+
public static class PathHelper
10+
{
11+
/// <summary>
12+
/// Normalizes path separators for the target system
13+
/// </summary>
14+
/// <param name="path">Path to normalize</param>
15+
/// <param name="targetSeparator">Target path separator character</param>
16+
/// <returns>Normalized path</returns>
17+
public static string NormalizePath(string? path, char targetSeparator = '/')
18+
{
19+
if (string.IsNullOrEmpty(path))
20+
return string.Empty;
21+
22+
// Replace all possible path separators with target separator
23+
return path.Replace('\\', targetSeparator).Replace('/', targetSeparator);
24+
}
25+
26+
/// <summary>
27+
/// Normalizes path for Unix-like systems (FTP, Linux, etc.)
28+
/// Always uses forward slash (/) as separator
29+
/// </summary>
30+
/// <param name="path">Path to normalize</param>
31+
/// <returns>Unix-style path</returns>
32+
public static string ToUnixPath(string? path)
33+
{
34+
return NormalizePath(path, '/');
35+
}
36+
37+
/// <summary>
38+
/// Normalizes path for Windows systems
39+
/// Always uses backslash (\) as separator
40+
/// </summary>
41+
/// <param name="path">Path to normalize</param>
42+
/// <returns>Windows-style path</returns>
43+
public static string ToWindowsPath(string? path)
44+
{
45+
return NormalizePath(path, '\\');
46+
}
47+
48+
/// <summary>
49+
/// Gets directory path from file path and normalizes separators
50+
/// </summary>
51+
/// <param name="filePath">Full file path</param>
52+
/// <param name="targetSeparator">Target path separator</param>
53+
/// <returns>Normalized directory path or empty string</returns>
54+
public static string GetDirectoryPath(string? filePath, char targetSeparator = '/')
55+
{
56+
if (string.IsNullOrEmpty(filePath))
57+
return string.Empty;
58+
59+
var directoryPath = Path.GetDirectoryName(filePath);
60+
return NormalizePath(directoryPath, targetSeparator);
61+
}
62+
63+
/// <summary>
64+
/// Gets Unix-style directory path from file path
65+
/// </summary>
66+
/// <param name="filePath">Full file path</param>
67+
/// <returns>Unix-style directory path</returns>
68+
public static string GetUnixDirectoryPath(string? filePath)
69+
{
70+
return GetDirectoryPath(filePath, '/');
71+
}
72+
73+
/// <summary>
74+
/// Combines path segments using the specified separator
75+
/// </summary>
76+
/// <param name="separator">Path separator to use</param>
77+
/// <param name="paths">Path segments to combine</param>
78+
/// <returns>Combined path</returns>
79+
public static string CombinePaths(char separator, params string[] paths)
80+
{
81+
if (paths == null || paths.Length == 0)
82+
return string.Empty;
83+
84+
var result = paths[0] ?? string.Empty;
85+
86+
for (int i = 1; i < paths.Length; i++)
87+
{
88+
var path = paths[i];
89+
if (string.IsNullOrEmpty(path))
90+
continue;
91+
92+
// Remove leading separators from current path
93+
path = path.TrimStart('/', '\\');
94+
95+
// Ensure result doesn't end with separator (unless it's root)
96+
if (result.Length > 0 && result[^1] != separator)
97+
result += separator;
98+
99+
result += path;
100+
}
101+
102+
return NormalizePath(result, separator);
103+
}
104+
105+
/// <summary>
106+
/// Combines path segments using Unix-style separators (/)
107+
/// </summary>
108+
/// <param name="paths">Path segments to combine</param>
109+
/// <returns>Combined Unix-style path</returns>
110+
public static string CombineUnixPaths(params string[] paths)
111+
{
112+
return CombinePaths('/', paths);
113+
}
114+
115+
/// <summary>
116+
/// Combines path segments using Windows-style separators (\)
117+
/// </summary>
118+
/// <param name="paths">Path segments to combine</param>
119+
/// <returns>Combined Windows-style path</returns>
120+
public static string CombineWindowsPaths(params string[] paths)
121+
{
122+
return CombinePaths('\\', paths);
123+
}
124+
125+
/// <summary>
126+
/// Ensures path is relative (doesn't start with separator)
127+
/// </summary>
128+
/// <param name="path">Path to make relative</param>
129+
/// <returns>Relative path</returns>
130+
public static string EnsureRelativePath(string? path)
131+
{
132+
if (string.IsNullOrEmpty(path))
133+
return string.Empty;
134+
135+
return path.TrimStart('/', '\\');
136+
}
137+
138+
/// <summary>
139+
/// Ensures path is absolute (starts with separator)
140+
/// </summary>
141+
/// <param name="path">Path to make absolute</param>
142+
/// <param name="separator">Path separator to use</param>
143+
/// <returns>Absolute path</returns>
144+
public static string EnsureAbsolutePath(string? path, char separator = '/')
145+
{
146+
if (string.IsNullOrEmpty(path))
147+
return separator.ToString();
148+
149+
var normalizedPath = NormalizePath(path, separator);
150+
151+
if (normalizedPath[0] != separator)
152+
normalizedPath = separator + normalizedPath;
153+
154+
return normalizedPath;
155+
}
156+
157+
/// <summary>
158+
/// Checks if path is absolute (starts with separator or drive letter on Windows)
159+
/// </summary>
160+
/// <param name="path">Path to check</param>
161+
/// <returns>True if path is absolute</returns>
162+
public static bool IsAbsolutePath(string? path)
163+
{
164+
if (string.IsNullOrEmpty(path))
165+
return false;
166+
167+
// Unix-style absolute path
168+
if (path[0] == '/' || path[0] == '\\')
169+
return true;
170+
171+
// Windows-style absolute path (C:\, D:\, etc.)
172+
if (path.Length >= 2 && char.IsLetter(path[0]) && path[1] == ':')
173+
return true;
174+
175+
return false;
176+
}
177+
178+
/// <summary>
179+
/// Removes trailing path separators from path (except for root paths)
180+
/// </summary>
181+
/// <param name="path">Path to trim</param>
182+
/// <returns>Path without trailing separators</returns>
183+
public static string TrimTrailingSeparators(string? path)
184+
{
185+
if (string.IsNullOrEmpty(path) || path.Length <= 1)
186+
return path ?? string.Empty;
187+
188+
return path.TrimEnd('/', '\\');
189+
}
190+
191+
/// <summary>
192+
/// Gets the file name from path without directory
193+
/// </summary>
194+
/// <param name="path">Full path</param>
195+
/// <returns>File name only</returns>
196+
public static string GetFileName(string? path)
197+
{
198+
if (string.IsNullOrEmpty(path))
199+
return string.Empty;
200+
201+
var normalizedPath = NormalizePath(path);
202+
var lastSeparatorIndex = normalizedPath.LastIndexOfAny(new[] { '/', '\\' });
203+
204+
return lastSeparatorIndex >= 0
205+
? normalizedPath[(lastSeparatorIndex + 1)..]
206+
: normalizedPath;
207+
}
208+
}

ManagedCode.Storage.Core/ManagedCode.Storage.Core.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
</PropertyGroup>
1414

1515
<ItemGroup>
16-
<PackageReference Include="ManagedCode.Communication" Version="9.6.0" />
16+
<PackageReference Include="ManagedCode.Communication" Version="9.6.1" />
1717
<PackageReference Include="ManagedCode.MimeTypes" Version="1.0.3" />
1818
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="9.0.8" />
1919
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="9.0.8" />

0 commit comments

Comments
 (0)