Compare commits

..

No commits in common. "master" and "master" have entirely different histories.

215 changed files with 3272 additions and 10279 deletions

View file

@ -1,901 +0,0 @@
[*.cs]
# CA1001: Types that own disposable fields should be disposable
dotnet_diagnostic.CA1001.severity = warning
# CA1000: Do not declare static members on generic types
dotnet_diagnostic.CA1000.severity = warning
# CA1002: Do not expose generic lists
dotnet_diagnostic.CA1002.severity = warning
# CA1003: Use generic event handler instances
dotnet_diagnostic.CA1003.severity = warning
# CA1005: Avoid excessive parameters on generic types
dotnet_diagnostic.CA1005.severity = warning
# CA1008: Enums should have zero value
dotnet_diagnostic.CA1008.severity = warning
# CA1010: Generic interface should also be implemented
dotnet_diagnostic.CA1010.severity = warning
# CA1012: Abstract types should not have public constructors
dotnet_diagnostic.CA1012.severity = warning
# CA1014: Mark assemblies with CLSCompliant
dotnet_diagnostic.CA1014.severity = warning
# CA1016: Mark assemblies with assembly version
dotnet_diagnostic.CA1016.severity = warning
# CA1017: Mark assemblies with ComVisible
dotnet_diagnostic.CA1017.severity = warning
# CA1018: Mark attributes with AttributeUsageAttribute
dotnet_diagnostic.CA1018.severity = warning
# CA1019: Define accessors for attribute arguments
dotnet_diagnostic.CA1019.severity = warning
# CA1021: Avoid out parameters
dotnet_diagnostic.CA1021.severity = warning
# CA1024: Use properties where appropriate
dotnet_diagnostic.CA1024.severity = warning
# CA1027: Mark enums with FlagsAttribute
dotnet_diagnostic.CA1027.severity = warning
# CA1028: Enum Storage should be Int32
dotnet_diagnostic.CA1028.severity = warning
# CA1030: Use events where appropriate
dotnet_diagnostic.CA1030.severity = warning
# CA1031: Do not catch general exception types
dotnet_diagnostic.CA1031.severity = warning
# CA1033: Interface methods should be callable by child types
dotnet_diagnostic.CA1033.severity = warning
# CA1034: Nested types should not be visible
dotnet_diagnostic.CA1034.severity = warning
# CA1036: Override methods on comparable types
dotnet_diagnostic.CA1036.severity = warning
# CA1040: Avoid empty interfaces
dotnet_diagnostic.CA1040.severity = warning
# CA1041: Provide ObsoleteAttribute message
dotnet_diagnostic.CA1041.severity = warning
# CA1043: Use Integral Or String Argument For Indexers
dotnet_diagnostic.CA1043.severity = warning
# CA1044: Properties should not be write only
dotnet_diagnostic.CA1044.severity = warning
# CA1045: Do not pass types by reference
dotnet_diagnostic.CA1045.severity = warning
# CA1046: Do not overload equality operator on reference types
dotnet_diagnostic.CA1046.severity = warning
# CA1050: Declare types in namespaces
dotnet_diagnostic.CA1050.severity = warning
# CA1051: Do not declare visible instance fields
dotnet_diagnostic.CA1051.severity = warning
# CA1052: Static holder types should be Static or NotInheritable
dotnet_diagnostic.CA1052.severity = warning
# CA1054: URI-like parameters should not be strings
dotnet_diagnostic.CA1054.severity = warning
# CA1055: URI-like return values should not be strings
dotnet_diagnostic.CA1055.severity = warning
# CA1056: URI-like properties should not be strings
dotnet_diagnostic.CA1056.severity = warning
# CA1058: Types should not extend certain base types
dotnet_diagnostic.CA1058.severity = warning
# CA1060: Move pinvokes to native methods class
dotnet_diagnostic.CA1060.severity = warning
# CA1061: Do not hide base class methods
dotnet_diagnostic.CA1061.severity = warning
# CA1062: Validate arguments of public methods
dotnet_diagnostic.CA1062.severity = warning
# CA1063: Implement IDisposable Correctly
dotnet_diagnostic.CA1063.severity = warning
# CA1064: Exceptions should be public
dotnet_diagnostic.CA1064.severity = warning
# CA1065: Do not raise exceptions in unexpected locations
dotnet_diagnostic.CA1065.severity = warning
# CA1066: Implement IEquatable when overriding Object.Equals
dotnet_diagnostic.CA1066.severity = warning
# CA1067: Override Object.Equals(object) when implementing IEquatable<T>
dotnet_diagnostic.CA1067.severity = warning
# CA1068: CancellationToken parameters must come last
dotnet_diagnostic.CA1068.severity = warning
# CA1069: Enums values should not be duplicated
dotnet_diagnostic.CA1069.severity = warning
# CA1070: Do not declare event fields as virtual
dotnet_diagnostic.CA1070.severity = warning
# CA1303: Do not pass literals as localized parameters
dotnet_diagnostic.CA1303.severity = warning
# CA1304: Specify CultureInfo
dotnet_diagnostic.CA1304.severity = warning
# CA1305: Specify IFormatProvider
dotnet_diagnostic.CA1305.severity = warning
# CA1307: Specify StringComparison for clarity
dotnet_diagnostic.CA1307.severity = warning
# CA1308: Normalize strings to uppercase
dotnet_diagnostic.CA1308.severity = warning
# CA1310: Specify StringComparison for correctness
dotnet_diagnostic.CA1310.severity = warning
# CA1401: P/Invokes should not be visible
dotnet_diagnostic.CA1401.severity = warning
# CA1416: Validate platform compatibility
dotnet_diagnostic.CA1416.severity = warning
# CA1417: Do not use 'OutAttribute' on string parameters for P/Invokes
dotnet_diagnostic.CA1417.severity = warning
# CA1418: Use valid platform string
dotnet_diagnostic.CA1418.severity = warning
# CA1419: Provide a parameterless constructor that is as visible as the containing type for concrete types derived from 'System.Runtime.InteropServices.SafeHandle'
dotnet_diagnostic.CA1419.severity = warning
# CA1420: Property, type, or attribute requires runtime marshalling
dotnet_diagnostic.CA1420.severity = warning
# CA1421: This method uses runtime marshalling even when the 'DisableRuntimeMarshallingAttribute' is applied
dotnet_diagnostic.CA1421.severity = warning
# CA1422: Validate platform compatibility
dotnet_diagnostic.CA1422.severity = warning
# CA1501: Avoid excessive inheritance
dotnet_diagnostic.CA1501.severity = warning
# CA1502: Avoid excessive complexity
dotnet_diagnostic.CA1502.severity = warning
# CA1505: Avoid unmaintainable code
dotnet_diagnostic.CA1505.severity = warning
# CA1506: Avoid excessive class coupling
# dotnet_diagnostic.CA1506.severity = warning
# CA1509: Invalid entry in code metrics rule specification file
dotnet_diagnostic.CA1509.severity = warning
# CA1510: Use ArgumentNullException throw helper
dotnet_diagnostic.CA1510.severity = warning
# CA1511: Use ArgumentException throw helper
dotnet_diagnostic.CA1511.severity = warning
# CA1512: Use ArgumentOutOfRangeException throw helper
dotnet_diagnostic.CA1512.severity = warning
# CA1513: Use ObjectDisposedException throw helper
dotnet_diagnostic.CA1513.severity = warning
# CA1700: Do not name enum values 'Reserved'
dotnet_diagnostic.CA1700.severity = warning
# CA1707: Identifiers should not contain underscores
dotnet_diagnostic.CA1707.severity = warning
# CA1708: Identifiers should differ by more than case
dotnet_diagnostic.CA1708.severity = warning
# CA1710: Identifiers should have correct suffix
dotnet_diagnostic.CA1710.severity = warning
# CA1711: Identifiers should not have incorrect suffix
dotnet_diagnostic.CA1711.severity = warning
# CA1712: Do not prefix enum values with type name
dotnet_diagnostic.CA1712.severity = warning
# CA1713: Events should not have 'Before' or 'After' prefix
dotnet_diagnostic.CA1713.severity = warning
# CA1715: Identifiers should have correct prefix
dotnet_diagnostic.CA1715.severity = warning
# CA1716: Identifiers should not match keywords
dotnet_diagnostic.CA1716.severity = warning
# CA1720: Identifier contains type name
dotnet_diagnostic.CA1720.severity = warning
# CA1721: Property names should not match get methods
dotnet_diagnostic.CA1721.severity = warning
# CA1724: Type names should not match namespaces
dotnet_diagnostic.CA1724.severity = warning
# CA1725: Parameter names should match base declaration
dotnet_diagnostic.CA1725.severity = warning
# CA1727: Use PascalCase for named placeholders
dotnet_diagnostic.CA1727.severity = warning
# CA1806: Do not ignore method results
dotnet_diagnostic.CA1806.severity = warning
# CA1810: Initialize reference type static fields inline
dotnet_diagnostic.CA1810.severity = warning
# CA1813: Avoid unsealed attributes
dotnet_diagnostic.CA1813.severity = warning
# CA1814: Prefer jagged arrays over multidimensional
dotnet_diagnostic.CA1814.severity = warning
# CA1815: Override equals and operator equals on value types
dotnet_diagnostic.CA1815.severity = warning
# CA1816: Dispose methods should call SuppressFinalize
dotnet_diagnostic.CA1816.severity = warning
# CA1819: Properties should not return arrays
# dotnet_diagnostic.CA1819.severity = warning
# CA1820: Test for empty strings using string length
dotnet_diagnostic.CA1820.severity = warning
# CA1821: Remove empty Finalizers
dotnet_diagnostic.CA1821.severity = warning
# CA1822: Mark members as static
dotnet_diagnostic.CA1822.severity = warning
# CA1823: Avoid unused private fields
dotnet_diagnostic.CA1823.severity = warning
# CA1826: Do not use Enumerable methods on indexable collections
dotnet_diagnostic.CA1826.severity = warning
# CA1827: Do not use Count() or LongCount() when Any() can be used
dotnet_diagnostic.CA1827.severity = warning
# CA1828: Do not use CountAsync() or LongCountAsync() when AnyAsync() can be used
dotnet_diagnostic.CA1828.severity = warning
# CA1829: Use Length/Count property instead of Count() when available
dotnet_diagnostic.CA1829.severity = warning
# CA1830: Prefer strongly-typed Append and Insert method overloads on StringBuilder
dotnet_diagnostic.CA1830.severity = warning
# CA1831: Use AsSpan or AsMemory instead of Range-based indexers when appropriate
dotnet_diagnostic.CA1831.severity = warning
# CA1832: Use AsSpan or AsMemory instead of Range-based indexers when appropriate
dotnet_diagnostic.CA1832.severity = warning
# CA1833: Use AsSpan or AsMemory instead of Range-based indexers when appropriate
dotnet_diagnostic.CA1833.severity = warning
# CA1834: Consider using 'StringBuilder.Append(char)' when applicable
dotnet_diagnostic.CA1834.severity = warning
# CA1835: Prefer the 'Memory'-based overloads for 'ReadAsync' and 'WriteAsync'
dotnet_diagnostic.CA1835.severity = warning
# CA1836: Prefer IsEmpty over Count
dotnet_diagnostic.CA1836.severity = warning
# CA1837: Use 'Environment.ProcessId'
dotnet_diagnostic.CA1837.severity = warning
# CA1838: Avoid 'StringBuilder' parameters for P/Invokes
dotnet_diagnostic.CA1838.severity = warning
# CA1839: Use 'Environment.ProcessPath'
dotnet_diagnostic.CA1839.severity = warning
# CA1840: Use 'Environment.CurrentManagedThreadId'
dotnet_diagnostic.CA1840.severity = warning
# CA1842: Do not use 'WhenAll' with a single task
dotnet_diagnostic.CA1842.severity = warning
# CA1843: Do not use 'WaitAll' with a single task
dotnet_diagnostic.CA1843.severity = warning
# CA1844: Provide memory-based overrides of async methods when subclassing 'Stream'
dotnet_diagnostic.CA1844.severity = warning
# CA1846: Prefer 'AsSpan' over 'Substring'
dotnet_diagnostic.CA1846.severity = warning
# CA1847: Use char literal for a single character lookup
dotnet_diagnostic.CA1847.severity = warning
# CA1848: Use the LoggerMessage delegates
dotnet_diagnostic.CA1848.severity = warning
# CA1849: Call async methods when in an async method
dotnet_diagnostic.CA1849.severity = warning
# CA1850: Prefer static 'HashData' method over 'ComputeHash'
dotnet_diagnostic.CA1850.severity = warning
# CA1852: Seal internal types
dotnet_diagnostic.CA1852.severity = warning
# CA1853: Unnecessary call to 'Dictionary.ContainsKey(key)'
dotnet_diagnostic.CA1853.severity = warning
# CA1854: Prefer the 'IDictionary.TryGetValue(TKey, out TValue)' method
dotnet_diagnostic.CA1854.severity = warning
# CA1858: Use 'StartsWith' instead of 'IndexOf'
dotnet_diagnostic.CA1858.severity = warning
# CA1859: Use concrete types when possible for improved performance
dotnet_diagnostic.CA1859.severity = warning
# CA1860: Avoid using 'Enumerable.Any()' extension method
dotnet_diagnostic.CA1860.severity = warning
# CA1861: Avoid constant arrays as arguments
dotnet_diagnostic.CA1861.severity = warning
# CA1862: Use the 'StringComparison' method overloads to perform case-insensitive string comparisons
dotnet_diagnostic.CA1862.severity = warning
# CA1863: Use 'CompositeFormat'
dotnet_diagnostic.CA1863.severity = warning
# CA1864: Prefer the 'IDictionary.TryAdd(TKey, TValue)' method
dotnet_diagnostic.CA1864.severity = warning
# CA1868: Unnecessary call to 'Contains(item)'
dotnet_diagnostic.CA1868.severity = warning
# CA1869: Cache and reuse 'JsonSerializerOptions' instances
dotnet_diagnostic.CA1869.severity = warning
# CA2000: Dispose objects before losing scope
dotnet_diagnostic.CA2000.severity = warning
# CA2002: Do not lock on objects with weak identity
dotnet_diagnostic.CA2002.severity = warning
# CA2007: Consider calling ConfigureAwait on the awaited task
dotnet_diagnostic.CA2007.severity = warning
# CA2008: Do not create tasks without passing a TaskScheduler
dotnet_diagnostic.CA2008.severity = warning
# CA2009: Do not call ToImmutableCollection on an ImmutableCollection value
dotnet_diagnostic.CA2009.severity = warning
# CA2011: Avoid infinite recursion
dotnet_diagnostic.CA2011.severity = warning
# CA2012: Use ValueTasks correctly
dotnet_diagnostic.CA2012.severity = warning
# CA2013: Do not use ReferenceEquals with value types
dotnet_diagnostic.CA2013.severity = warning
# CA2015: Do not define finalizers for types derived from MemoryManager<T>
dotnet_diagnostic.CA2015.severity = warning
# CA2017: Parameter count mismatch
dotnet_diagnostic.CA2017.severity = warning
# CA2018: 'Buffer.BlockCopy' expects the number of bytes to be copied for the 'count' argument
dotnet_diagnostic.CA2018.severity = warning
# CA2019: Improper 'ThreadStatic' field initialization
dotnet_diagnostic.CA2019.severity = warning
# CA2021: Do not call Enumerable.Cast<T> or Enumerable.OfType<T> with incompatible types
dotnet_diagnostic.CA2021.severity = warning
# CA2100: Review SQL queries for security vulnerabilities
dotnet_diagnostic.CA2100.severity = warning
# CA2101: Specify marshaling for P/Invoke string arguments
dotnet_diagnostic.CA2101.severity = warning
# CA2119: Seal methods that satisfy private interfaces
dotnet_diagnostic.CA2119.severity = warning
# CA2153: Do Not Catch Corrupted State Exceptions
dotnet_diagnostic.CA2153.severity = warning
# CA2200: Rethrow to preserve stack details
dotnet_diagnostic.CA2200.severity = warning
# CA2201: Do not raise reserved exception types
dotnet_diagnostic.CA2201.severity = warning
# CA2207: Initialize value type static fields inline
dotnet_diagnostic.CA2207.severity = warning
# CA2208: Instantiate argument exceptions correctly
dotnet_diagnostic.CA2208.severity = warning
# CA2211: Non-constant fields should not be visible
dotnet_diagnostic.CA2211.severity = warning
# CA2213: Disposable fields should be disposed
dotnet_diagnostic.CA2213.severity = warning
# CA2214: Do not call overridable methods in constructors
dotnet_diagnostic.CA2214.severity = warning
# CA2215: Dispose methods should call base class dispose
dotnet_diagnostic.CA2215.severity = warning
# CA2216: Disposable types should declare finalizer
dotnet_diagnostic.CA2216.severity = warning
# CA2217: Do not mark enums with FlagsAttribute
dotnet_diagnostic.CA2217.severity = warning
# CA2219: Do not raise exceptions in finally clauses
dotnet_diagnostic.CA2219.severity = warning
# CA2225: Operator overloads have named alternates
dotnet_diagnostic.CA2225.severity = warning
# CA2226: Operators should have symmetrical overloads
dotnet_diagnostic.CA2226.severity = warning
# CA2227: Collection properties should be read only
dotnet_diagnostic.CA2227.severity = warning
# CA2231: Overload operator equals on overriding value type Equals
dotnet_diagnostic.CA2231.severity = warning
# CA2235: Mark all non-serializable fields
dotnet_diagnostic.CA2235.severity = warning
# CA2237: Mark ISerializable types with serializable
dotnet_diagnostic.CA2237.severity = warning
# CA2241: Provide correct arguments to formatting methods
dotnet_diagnostic.CA2241.severity = warning
# CA2242: Test for NaN correctly
dotnet_diagnostic.CA2242.severity = warning
# CA2243: Attribute string literals should parse correctly
dotnet_diagnostic.CA2243.severity = warning
# CA2244: Do not duplicate indexed element initializations
dotnet_diagnostic.CA2244.severity = warning
# CA2245: Do not assign a property to itself
dotnet_diagnostic.CA2245.severity = warning
# CA2246: Assigning symbol and its member in the same statement
dotnet_diagnostic.CA2246.severity = warning
# CA2247: Argument passed to TaskCompletionSource constructor should be TaskCreationOptions enum instead of TaskContinuationOptions enum
dotnet_diagnostic.CA2247.severity = warning
# CA2248: Provide correct 'enum' argument to 'Enum.HasFlag'
dotnet_diagnostic.CA2248.severity = warning
# CA2249: Consider using 'string.Contains' instead of 'string.IndexOf'
dotnet_diagnostic.CA2249.severity = warning
# CA2250: Use 'ThrowIfCancellationRequested'
dotnet_diagnostic.CA2250.severity = warning
# CA2251: Use 'string.Equals'
dotnet_diagnostic.CA2251.severity = warning
# CA2253: Named placeholders should not be numeric values
dotnet_diagnostic.CA2253.severity = warning
# CA2254: Template should be a static expression
dotnet_diagnostic.CA2254.severity = warning
# CA2255: The 'ModuleInitializer' attribute should not be used in libraries
dotnet_diagnostic.CA2255.severity = warning
# CA2256: All members declared in parent interfaces must have an implementation in a DynamicInterfaceCastableImplementation-attributed interface
dotnet_diagnostic.CA2256.severity = warning
# CA2257: Members defined on an interface with the 'DynamicInterfaceCastableImplementationAttribute' should be 'static'
dotnet_diagnostic.CA2257.severity = warning
# CA2258: Providing a 'DynamicInterfaceCastableImplementation' interface in Visual Basic is unsupported
dotnet_diagnostic.CA2258.severity = warning
# CA2259: 'ThreadStatic' only affects static fields
dotnet_diagnostic.CA2259.severity = warning
# CA2261: Do not use ConfigureAwaitOptions.SuppressThrowing with Task<TResult>
dotnet_diagnostic.CA2261.severity = warning
# CA2300: Do not use insecure deserializer BinaryFormatter
dotnet_diagnostic.CA2300.severity = warning
# CA2301: Do not call BinaryFormatter.Deserialize without first setting BinaryFormatter.Binder
dotnet_diagnostic.CA2301.severity = warning
# CA2302: Ensure BinaryFormatter.Binder is set before calling BinaryFormatter.Deserialize
dotnet_diagnostic.CA2302.severity = warning
# CA2305: Do not use insecure deserializer LosFormatter
dotnet_diagnostic.CA2305.severity = warning
# CA2310: Do not use insecure deserializer NetDataContractSerializer
dotnet_diagnostic.CA2310.severity = warning
# CA2311: Do not deserialize without first setting NetDataContractSerializer.Binder
dotnet_diagnostic.CA2311.severity = warning
# CA2312: Ensure NetDataContractSerializer.Binder is set before deserializing
dotnet_diagnostic.CA2312.severity = warning
# CA2315: Do not use insecure deserializer ObjectStateFormatter
dotnet_diagnostic.CA2315.severity = warning
# CA2321: Do not deserialize with JavaScriptSerializer using a SimpleTypeResolver
dotnet_diagnostic.CA2321.severity = warning
# CA2322: Ensure JavaScriptSerializer is not initialized with SimpleTypeResolver before deserializing
dotnet_diagnostic.CA2322.severity = warning
# CA2326: Do not use TypeNameHandling values other than None
dotnet_diagnostic.CA2326.severity = warning
# CA2327: Do not use insecure JsonSerializerSettings
dotnet_diagnostic.CA2327.severity = warning
# CA2328: Ensure that JsonSerializerSettings are secure
dotnet_diagnostic.CA2328.severity = warning
# CA2329: Do not deserialize with JsonSerializer using an insecure configuration
dotnet_diagnostic.CA2329.severity = warning
# CA2330: Ensure that JsonSerializer has a secure configuration when deserializing
dotnet_diagnostic.CA2330.severity = warning
# CA2350: Do not use DataTable.ReadXml() with untrusted data
dotnet_diagnostic.CA2350.severity = warning
# CA2351: Do not use DataSet.ReadXml() with untrusted data
dotnet_diagnostic.CA2351.severity = warning
# CA2361: Ensure auto-generated class containing DataSet.ReadXml() is not used with untrusted data
dotnet_diagnostic.CA2361.severity = warning
# CA3001: Review code for SQL injection vulnerabilities
dotnet_diagnostic.CA3001.severity = warning
# CA3002: Review code for XSS vulnerabilities
dotnet_diagnostic.CA3002.severity = warning
# CA3003: Review code for file path injection vulnerabilities
dotnet_diagnostic.CA3003.severity = warning
# CA3004: Review code for information disclosure vulnerabilities
dotnet_diagnostic.CA3004.severity = warning
# CA3005: Review code for LDAP injection vulnerabilities
dotnet_diagnostic.CA3005.severity = warning
# CA3006: Review code for process command injection vulnerabilities
dotnet_diagnostic.CA3006.severity = warning
# CA3007: Review code for open redirect vulnerabilities
dotnet_diagnostic.CA3007.severity = warning
# CA3008: Review code for XPath injection vulnerabilities
dotnet_diagnostic.CA3008.severity = warning
# CA3009: Review code for XML injection vulnerabilities
dotnet_diagnostic.CA3009.severity = warning
# CA3010: Review code for XAML injection vulnerabilities
dotnet_diagnostic.CA3010.severity = warning
# CA3011: Review code for DLL injection vulnerabilities
dotnet_diagnostic.CA3011.severity = warning
# CA3012: Review code for regex injection vulnerabilities
dotnet_diagnostic.CA3012.severity = warning
# CA3061: Do Not Add Schema By URL
dotnet_diagnostic.CA3061.severity = warning
# CA3075: Insecure DTD processing in XML
dotnet_diagnostic.CA3075.severity = warning
# CA3076: Insecure XSLT script processing
dotnet_diagnostic.CA3076.severity = warning
# CA3077: Insecure Processing in API Design, XmlDocument and XmlTextReader
dotnet_diagnostic.CA3077.severity = warning
# CA3147: Mark Verb Handlers With Validate Antiforgery Token
dotnet_diagnostic.CA3147.severity = warning
# CA5350: Do Not Use Weak Cryptographic Algorithms
dotnet_diagnostic.CA5350.severity = warning
# CA5351: Do Not Use Broken Cryptographic Algorithms
dotnet_diagnostic.CA5351.severity = warning
# CA5358: Review cipher mode usage with cryptography experts
dotnet_diagnostic.CA5358.severity = warning
# CA5359: Do Not Disable Certificate Validation
dotnet_diagnostic.CA5359.severity = warning
# CA5360: Do Not Call Dangerous Methods In Deserialization
dotnet_diagnostic.CA5360.severity = warning
# CA5361: Do Not Disable SChannel Use of Strong Crypto
dotnet_diagnostic.CA5361.severity = warning
# CA5362: Potential reference cycle in deserialized object graph
dotnet_diagnostic.CA5362.severity = warning
# CA5363: Do Not Disable Request Validation
dotnet_diagnostic.CA5363.severity = warning
# CA5364: Do Not Use Deprecated Security Protocols
dotnet_diagnostic.CA5364.severity = warning
# CA5365: Do Not Disable HTTP Header Checking
dotnet_diagnostic.CA5365.severity = warning
# CA5366: Use XmlReader for 'DataSet.ReadXml()'
dotnet_diagnostic.CA5366.severity = warning
# CA5367: Do Not Serialize Types With Pointer Fields
dotnet_diagnostic.CA5367.severity = warning
# CA5368: Set ViewStateUserKey For Classes Derived From Page
dotnet_diagnostic.CA5368.severity = warning
# CA5369: Use XmlReader for 'XmlSerializer.Deserialize()'
dotnet_diagnostic.CA5369.severity = warning
# CA5370: Use XmlReader for XmlValidatingReader constructor
dotnet_diagnostic.CA5370.severity = warning
# CA5371: Use XmlReader for 'XmlSchema.Read()'
dotnet_diagnostic.CA5371.severity = warning
# CA5372: Use XmlReader for XPathDocument constructor
dotnet_diagnostic.CA5372.severity = warning
# CA5373: Do not use obsolete key derivation function
dotnet_diagnostic.CA5373.severity = warning
# CA5374: Do Not Use XslTransform
dotnet_diagnostic.CA5374.severity = warning
# CA5375: Do Not Use Account Shared Access Signature
dotnet_diagnostic.CA5375.severity = warning
# CA5376: Use SharedAccessProtocol HttpsOnly
dotnet_diagnostic.CA5376.severity = warning
# CA5377: Use Container Level Access Policy
dotnet_diagnostic.CA5377.severity = warning
# CA5378: Do not disable ServicePointManagerSecurityProtocols
dotnet_diagnostic.CA5378.severity = warning
# CA5379: Ensure Key Derivation Function algorithm is sufficiently strong
dotnet_diagnostic.CA5379.severity = warning
# CA5380: Do Not Add Certificates To Root Store
dotnet_diagnostic.CA5380.severity = warning
# CA5381: Ensure Certificates Are Not Added To Root Store
dotnet_diagnostic.CA5381.severity = warning
# CA5382: Use Secure Cookies In ASP.NET Core
dotnet_diagnostic.CA5382.severity = warning
# CA5383: Ensure Use Secure Cookies In ASP.NET Core
dotnet_diagnostic.CA5383.severity = warning
# CA5384: Do Not Use Digital Signature Algorithm (DSA)
dotnet_diagnostic.CA5384.severity = warning
# CA5385: Use Rivest-Shamir-Adleman (RSA) Algorithm With Sufficient Key Size
dotnet_diagnostic.CA5385.severity = warning
# CA5386: Avoid hardcoding SecurityProtocolType value
dotnet_diagnostic.CA5386.severity = warning
# CA5387: Do Not Use Weak Key Derivation Function With Insufficient Iteration Count
dotnet_diagnostic.CA5387.severity = warning
# CA5388: Ensure Sufficient Iteration Count When Using Weak Key Derivation Function
dotnet_diagnostic.CA5388.severity = warning
# CA5389: Do Not Add Archive Item's Path To The Target File System Path
dotnet_diagnostic.CA5389.severity = warning
# CA5390: Do not hard-code encryption key
dotnet_diagnostic.CA5390.severity = warning
# CA5391: Use antiforgery tokens in ASP.NET Core MVC controllers
dotnet_diagnostic.CA5391.severity = warning
# CA5392: Use DefaultDllImportSearchPaths attribute for P/Invokes
dotnet_diagnostic.CA5392.severity = warning
# CA5393: Do not use unsafe DllImportSearchPath value
dotnet_diagnostic.CA5393.severity = warning
# CA5394: Do not use insecure randomness
dotnet_diagnostic.CA5394.severity = warning
# CA5395: Miss HttpVerb attribute for action methods
dotnet_diagnostic.CA5395.severity = warning
# CA5396: Set HttpOnly to true for HttpCookie
dotnet_diagnostic.CA5396.severity = warning
# CA5397: Do not use deprecated SslProtocols values
dotnet_diagnostic.CA5397.severity = warning
# CA5398: Avoid hardcoded SslProtocols values
dotnet_diagnostic.CA5398.severity = warning
# CA5399: HttpClients should enable certificate revocation list checks
dotnet_diagnostic.CA5399.severity = warning
# CA5400: Ensure HttpClient certificate revocation list check is not disabled
dotnet_diagnostic.CA5400.severity = warning
# CA5401: Do not use CreateEncryptor with non-default IV
dotnet_diagnostic.CA5401.severity = warning
# CA5402: Use CreateEncryptor with the default IV
dotnet_diagnostic.CA5402.severity = warning
# CA5403: Do not hard-code certificate
dotnet_diagnostic.CA5403.severity = warning
# CA5404: Do not disable token validation checks
dotnet_diagnostic.CA5404.severity = warning
# CA5405: Do not always skip token validation in delegates
dotnet_diagnostic.CA5405.severity = warning
# CA1032: Implement standard exception constructors
dotnet_diagnostic.CA1032.severity = warning
# CA1200: Avoid using cref tags with a prefix
dotnet_diagnostic.CA1200.severity = warning
# CA1309: Use ordinal string comparison
dotnet_diagnostic.CA1309.severity = warning
# CA1311: Specify a culture or use an invariant version
dotnet_diagnostic.CA1311.severity = warning
# CA1507: Use nameof to express symbol names
dotnet_diagnostic.CA1507.severity = warning
# CA1508: Avoid dead conditional code
dotnet_diagnostic.CA1508.severity = warning
# CA1802: Use literals where appropriate
dotnet_diagnostic.CA1802.severity = warning
# CA1805: Do not initialize unnecessarily
dotnet_diagnostic.CA1805.severity = warning
# CA1812: Avoid uninstantiated internal classes
dotnet_diagnostic.CA1812.severity = warning
# CA1824: Mark assemblies with NeutralResourcesLanguageAttribute
dotnet_diagnostic.CA1824.severity = warning
# CA1825: Avoid zero-length array allocations
dotnet_diagnostic.CA1825.severity = warning
# CA1841: Prefer Dictionary.Contains methods
dotnet_diagnostic.CA1841.severity = warning
# CA1845: Use span-based 'string.Concat'
dotnet_diagnostic.CA1845.severity = warning
# CA1851: Possible multiple enumerations of 'IEnumerable' collection
dotnet_diagnostic.CA1851.severity = warning
# CA1855: Prefer 'Clear' over 'Fill'
dotnet_diagnostic.CA1855.severity = warning
# CA1856: Incorrect usage of ConstantExpected attribute
dotnet_diagnostic.CA1856.severity = warning
# CA1857: A constant is expected for the parameter
dotnet_diagnostic.CA1857.severity = warning
# CA1865: Use char overload
dotnet_diagnostic.CA1865.severity = warning
# CA1866: Use char overload
dotnet_diagnostic.CA1866.severity = warning
# CA1867: Use char overload
dotnet_diagnostic.CA1867.severity = warning
# CA1870: Use a cached 'SearchValues' instance
dotnet_diagnostic.CA1870.severity = warning
# CA2014: Do not use stackalloc in loops
dotnet_diagnostic.CA2014.severity = warning
# CA2016: Forward the 'CancellationToken' parameter to methods
dotnet_diagnostic.CA2016.severity = warning
# CA2020: Prevent behavioral change
dotnet_diagnostic.CA2020.severity = warning
# CA2234: Pass system uri objects instead of strings
dotnet_diagnostic.CA2234.severity = warning
# CA2252: This API requires opting into preview features
dotnet_diagnostic.CA2252.severity = warning
# CA2260: Use correct type parameter
dotnet_diagnostic.CA2260.severity = warning
# CA2352: Unsafe DataSet or DataTable in serializable type can be vulnerable to remote code execution attacks
dotnet_diagnostic.CA2352.severity = warning
# CA2353: Unsafe DataSet or DataTable in serializable type
dotnet_diagnostic.CA2353.severity = warning
# CA2354: Unsafe DataSet or DataTable in deserialized object graph can be vulnerable to remote code execution attacks
dotnet_diagnostic.CA2354.severity = warning
# CA2355: Unsafe DataSet or DataTable type found in deserializable object graph
dotnet_diagnostic.CA2355.severity = warning
# CA2356: Unsafe DataSet or DataTable type in web deserializable object graph
dotnet_diagnostic.CA2356.severity = warning
# CA2362: Unsafe DataSet or DataTable in auto-generated serializable type can be vulnerable to remote code execution attacks
dotnet_diagnostic.CA2362.severity = warning

3
.gitignore vendored
View file

@ -4,7 +4,6 @@
*.dll
*.so
*.dylib
*.pdb
# Test binary, built with `go test -c`
*.test
@ -18,7 +17,6 @@ vendor/
# IDE
.idea
.vscode
.vs
# coverage
coverage.txt
@ -33,4 +31,3 @@ antlr-*.jar
# binary
bin/
release/
obj/

View file

@ -1,20 +1,12 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.5.002.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FrostFS.SDK.ClientV2", "src\FrostFS.SDK.ClientV2\FrostFS.SDK.ClientV2.csproj", "{50D8F61F-C302-4AC9-8D8A-AB0B8C0988C3}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FrostFS.SDK.ProtosV2", "src\FrostFS.SDK.ProtosV2\FrostFS.SDK.ProtosV2.csproj", "{A087047E-2505-4137-97CC-689A5AD58A0C}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FrostFS.SDK.Cryptography", "src\FrostFS.SDK.Cryptography\FrostFS.SDK.Cryptography.csproj", "{3D804F4A-B0B2-47A5-B006-BE447BE64B50}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FrostFS.SDK.ClientV2", "src\FrostFS.SDK.ClientV2\FrostFS.SDK.ClientV2.csproj", "{F9CE6347-111A-4CE6-8BB2-545469838F47}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FrostFS.SDK.ProtosV2", "src\FrostFS.SDK.ProtosV2\FrostFS.SDK.ProtosV2.csproj", "{5012EF96-9C9E-4E77-BC78-B4111EE54107}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FrostFS.SDK.Cryptography", "src\FrostFS.SDK.Cryptography\FrostFS.SDK.Cryptography.csproj", "{599E2FF8-12C0-414D-B295-4C971A0A1A63}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FrostFS.SDK.Tests", "src\FrostFS.SDK.Tests\FrostFS.SDK.Tests.csproj", "{8FDA7E0D-9C75-4874-988E-6592CD28F76C}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{2F030ACD-F87C-4E83-9A68-4CC5DF03AD90}"
ProjectSection(SolutionItems) = preProject
.editorconfig = .editorconfig
EndProjectSection
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FrostFS.SDK.ModelsV2", "src\FrostFS.SDK.ModelsV2\FrostFS.SDK.ModelsV2.csproj", "{3F6E5EE6-2AAC-45BE-A5E2-B83D11F90CC3}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@ -22,24 +14,25 @@ Global
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{50D8F61F-C302-4AC9-8D8A-AB0B8C0988C3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{50D8F61F-C302-4AC9-8D8A-AB0B8C0988C3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{50D8F61F-C302-4AC9-8D8A-AB0B8C0988C3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{50D8F61F-C302-4AC9-8D8A-AB0B8C0988C3}.Release|Any CPU.Build.0 = Release|Any CPU
{3D804F4A-B0B2-47A5-B006-BE447BE64B50}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3D804F4A-B0B2-47A5-B006-BE447BE64B50}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3D804F4A-B0B2-47A5-B006-BE447BE64B50}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3D804F4A-B0B2-47A5-B006-BE447BE64B50}.Release|Any CPU.Build.0 = Release|Any CPU
{5012EF96-9C9E-4E77-BC78-B4111EE54107}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5012EF96-9C9E-4E77-BC78-B4111EE54107}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5012EF96-9C9E-4E77-BC78-B4111EE54107}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5012EF96-9C9E-4E77-BC78-B4111EE54107}.Release|Any CPU.Build.0 = Release|Any CPU
{8FDA7E0D-9C75-4874-988E-6592CD28F76C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8FDA7E0D-9C75-4874-988E-6592CD28F76C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8FDA7E0D-9C75-4874-988E-6592CD28F76C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8FDA7E0D-9C75-4874-988E-6592CD28F76C}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
{A087047E-2505-4137-97CC-689A5AD58A0C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A087047E-2505-4137-97CC-689A5AD58A0C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A087047E-2505-4137-97CC-689A5AD58A0C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A087047E-2505-4137-97CC-689A5AD58A0C}.Release|Any CPU.Build.0 = Release|Any CPU
{F9CE6347-111A-4CE6-8BB2-545469838F47}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F9CE6347-111A-4CE6-8BB2-545469838F47}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F9CE6347-111A-4CE6-8BB2-545469838F47}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F9CE6347-111A-4CE6-8BB2-545469838F47}.Release|Any CPU.Build.0 = Release|Any CPU
{B04EBDF5-A446-49D6-B1D7-7D729D94E8E0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B04EBDF5-A446-49D6-B1D7-7D729D94E8E0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B04EBDF5-A446-49D6-B1D7-7D729D94E8E0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B04EBDF5-A446-49D6-B1D7-7D729D94E8E0}.Release|Any CPU.Build.0 = Release|Any CPU
{599E2FF8-12C0-414D-B295-4C971A0A1A63}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{599E2FF8-12C0-414D-B295-4C971A0A1A63}.Debug|Any CPU.Build.0 = Debug|Any CPU
{599E2FF8-12C0-414D-B295-4C971A0A1A63}.Release|Any CPU.ActiveCfg = Release|Any CPU
{599E2FF8-12C0-414D-B295-4C971A0A1A63}.Release|Any CPU.Build.0 = Release|Any CPU
{3F6E5EE6-2AAC-45BE-A5E2-B83D11F90CC3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3F6E5EE6-2AAC-45BE-A5E2-B83D11F90CC3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3F6E5EE6-2AAC-45BE-A5E2-B83D11F90CC3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3F6E5EE6-2AAC-45BE-A5E2-B83D11F90CC3}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal

102
README.md
View file

@ -21,62 +21,60 @@ neo-go wallet export -w <path_to_your_wallet> -d <address_from_p1>
### Container
```csharp
using FrostFS.SDK;
using FrostFS.SDK.ClientV2;
using FrostFS.SDK.ModelsV2;
using FrostFS.SDK.ModelsV2.Enums;
using FrostFS.SDK.ModelsV2.Netmap;
using Microsoft.Extensions.Options;
var fsClient = new Client(<your_key>, <your_host>);
var Key = "KwHDAJ66o8FoLBjVbjP2sWBmgBMGjt7Vv4boA7xQrBoAYBE397Aq";
var Host = "http://172.22.33.44:8080";
// List containers
var containersIds = await fsClient.ListContainersAsync();
var options = Options.Create(new SingleOwnerClientSettings
{
Key = Key,
Host = Host
});
// Create container
var placementPolicy = new PlacementPolicy(true, new Replica(1));
var containerId = await fsClient.CreateContainerAsync(
new Container(
BasicAcl.PublicRW,
placementPolicy
)
);
using var client = Client.GetSingleOwnerInstance(options);
// Get container
var container = await fsClient.GetContainerAsync(cId);
await foreach (var cid in client.ListContainersAsync())
{
await client.DeleteContainerAsync(new PrmContainerDelete(cid));
}
var placementPolicy = new FrostFsPlacementPolicy(true, new FrostFsReplica(1));
var createContainerParam = new PrmContainerCreate(
new FrostFsContainerInfo(BasicAcl.PublicRW, new FrostFsPlacementPolicy(true, new FrostFsReplica(1))));
var containerId = await client.CreateContainerAsync(createContainerParam);
using var fileStream = File.OpenRead(@"C:\Users\Paul\Pictures\cat.jpeg");
var param = new PrmObjectPut
{
Header = new FrostFsObjectHeader(
containerId: containerId,
type: FrostFsObjectType.Regular,
[new FrostFsAttribute("fileName", "test")]),
Payload = fileStream
};
FrostFsObjectId objectId = await client.PutObjectAsync(param);
var filter = new FilterByAttribute(FrostFsMatchType.Equals, "fileName", "test");
await foreach (var objId in client.SearchObjectsAsync(new PrmObjectSearch(containerId) { Filters = [filter] }))
{
var objHeader = await client.GetObjectHeadAsync(new PrmObjectHeadGet(containerId, objId));
}
var @object = await client.GetObjectAsync(new PrmObjectGet(containerId, objectId));
var downloadedBytes = new byte[@object.Header.PayloadLength];
MemoryStream ms = new(downloadedBytes);
ReadOnlyMemory<byte>? chunk = null;
while ((chunk = await @object.ObjectReader!.ReadChunk()) != null)
{
ms.Write(chunk.Value.Span);
}
// Delete container
await fsClient.DeleteContainerAsync(containerId);
```
### Object
```csharp
using FrostFS.SDK.ClientV2;
using FrostFS.SDK.ModelsV2;
using FrostFS.SDK.ModelsV2.Enums;
using FrostFS.SDK.ModelsV2.Netmap;
var fsClient = new Client(<your_key>, <your_host>);
// Search regular objects
var objectsIds = await fsClient.SearchObjectAsync(
cId,
ObjectFilter.RootFilter()
);
// Put object
var f = File.OpenRead("cat.jpg");
var cat = new ObjectHeader(
containerId: cId,
type: ObjectType.Regular,
new ObjectAttribute("Filename", "cat.jpg")
);
var oId = await fsClient.PutObjectAsync(cat, f);
// Get object header
var objHeader = await fsClient.GetObjectHeadAsync(cId, oId);
// Get object
var obj = await fsClient.GetObjectAsync(cId, oId);
```

View file

@ -1,23 +0,0 @@
using Microsoft.Extensions.Caching.Memory;
namespace FrostFS.SDK.ClientV2
{
internal static class Cache
{
private static readonly IMemoryCache _ownersCache = new MemoryCache(new MemoryCacheOptions
{
// TODO: get from options?
SizeLimit = 256
});
private static readonly IMemoryCache _containersCache = new MemoryCache(new MemoryCacheOptions
{
// TODO: get from options?
SizeLimit = 1024
});
internal static IMemoryCache Owners => _ownersCache;
internal static IMemoryCache Containers => _containersCache;
}
}

View file

@ -0,0 +1,102 @@
using System.Security.Cryptography;
using FrostFS.Container;
using FrostFS.Netmap;
using FrostFS.Object;
using FrostFS.SDK.ClientV2.Interfaces;
using FrostFS.SDK.Cryptography;
using FrostFS.SDK.ModelsV2;
using FrostFS.Session;
using Grpc.Core;
using Grpc.Net.Client;
using Version = FrostFS.SDK.ModelsV2.Version;
namespace FrostFS.SDK.ClientV2;
public partial class Client: IFrostFSClient
{
private GrpcChannel _channel;
private readonly ECDsa _key;
public readonly OwnerId OwnerId;
public readonly Version Version = new (2, 13);
private ContainerService.ContainerServiceClient _containerServiceClient;
private NetmapService.NetmapServiceClient _netmapServiceClient;
private ObjectService.ObjectServiceClient _objectServiceClient;
private SessionService.SessionServiceClient _sessionServiceClient;
public Client(string key, string host)
{
// TODO: Развязать клиент и реализацию GRPC
_key = key.LoadWif();
OwnerId = OwnerId.FromKey(_key);
InitGrpcChannel(host);
InitContainerClient();
InitNetmapClient();
InitObjectClient();
InitSessionClient();
CheckFrostFsVersionSupport();
}
private async void CheckFrostFsVersionSupport()
{
var localNodeInfo = await GetLocalNodeInfoAsync();
if (!localNodeInfo.Version.IsSupported(Version))
{
var msg = $"FrostFS {localNodeInfo.Version} is not supported.";
Console.WriteLine(msg);
throw new ApplicationException(msg);
}
}
private void InitGrpcChannel(string host)
{
Uri uri;
try
{
uri = new Uri(host);
}
catch (UriFormatException e)
{
var msg = $"Host '{host}' has invalid format. Error: {e.Message}";
Console.WriteLine(msg);
throw new ArgumentException(msg);
}
ChannelCredentials grpcCredentials;
switch (uri.Scheme)
{
case "https":
grpcCredentials = ChannelCredentials.SecureSsl;
break;
case "http":
grpcCredentials = ChannelCredentials.Insecure;
break;
default:
var msg = $"Host '{host}' has invalid URI scheme: '{uri.Scheme}'.";
Console.WriteLine(msg);
throw new ArgumentException(msg);
}
_channel = GrpcChannel.ForAddress(uri, new GrpcChannelOptions { Credentials = grpcCredentials });
}
private void InitContainerClient()
{
_containerServiceClient = new ContainerService.ContainerServiceClient(_channel);
}
private void InitNetmapClient()
{
_netmapServiceClient = new NetmapService.NetmapServiceClient(_channel);
}
private void InitObjectClient()
{
_objectServiceClient = new ObjectService.ObjectServiceClient(_channel);
}
private void InitSessionClient()
{
_sessionServiceClient = new SessionService.SessionServiceClient(_channel);
}
}

View file

@ -1,15 +0,0 @@
using System.Security.Cryptography;
using FrostFS.SDK.Cryptography;
using Google.Protobuf;
namespace FrostFS.SDK.ClientV2
{
public class ClientKey(ECDsa key)
{
internal ECDsa ECDsaKey { get; } = key;
internal ByteString PublicKeyProto { get; } = ByteString.CopyFrom(key.PublicKey());
}
}

View file

@ -1,18 +0,0 @@
using System;
namespace FrostFS.SDK.ClientV2;
public class FrostFsException : Exception
{
public FrostFsException()
{
}
public FrostFsException(string message) : base(message)
{
}
public FrostFsException(string message, Exception innerException) : base(message, innerException)
{
}
}

View file

@ -1,18 +0,0 @@
using System;
namespace FrostFS.SDK.ClientV2;
public class InvalidObjectException : Exception
{
public InvalidObjectException()
{
}
public InvalidObjectException(string message) : base(message)
{
}
public InvalidObjectException(string message, Exception innerException) : base(message, innerException)
{
}
}

View file

@ -1,25 +0,0 @@
using System;
namespace FrostFS.SDK.ClientV2;
public class ResponseException : Exception
{
public FrostFsResponseStatus? Status { get; private set; }
public ResponseException()
{
}
public ResponseException(FrostFsResponseStatus status)
{
Status = status;
}
public ResponseException(string message) : base(message)
{
}
public ResponseException(string message, Exception innerException) : base(message, innerException)
{
}
}

View file

@ -1,36 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<LangVersion>12.0</LangVersion>
<Nullable>enable</Nullable>
<AnalysisMode>AllEnabledByDefault</AnalysisMode>
</PropertyGroup>
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<PropertyGroup>
<EnableNETAnalyzers>true</EnableNETAnalyzers>
</PropertyGroup>
<PropertyGroup>
<CodeAnalysisTreatWarningsAsErrors>true</CodeAnalysisTreatWarningsAsErrors>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="8.0.0" />
<PackageReference Include="Microsoft.CodeAnalysis.NetAnalyzers" Version="8.0.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.Extensions.Caching.Abstractions" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Options" Version="8.0.2" />
<PackageReference Include="System.Diagnostics.DiagnosticSource" Version="8.0.1" />
<PackageReference Include="System.Runtime.Caching" Version="8.0.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\FrostFS.SDK.Cryptography\FrostFS.SDK.Cryptography.csproj" />
<ProjectReference Include="..\FrostFS.SDK.ProtosV2\FrostFS.SDK.ProtosV2.csproj" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\FrostFS.SDK.Cryptography\FrostFS.SDK.Cryptography.csproj" />
<ProjectReference Include="..\FrostFS.SDK.ModelsV2\FrostFS.SDK.ModelsV2.csproj" />
<ProjectReference Include="..\FrostFS.SDK.ProtosV2\FrostFS.SDK.ProtosV2.csproj" />
</ItemGroup>
</Project>

View file

@ -1,483 +0,0 @@
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Threading.Tasks;
using Frostfs.V2.Ape;
using Frostfs.V2.Apemanager;
using FrostFS.Container;
using FrostFS.Netmap;
using FrostFS.Object;
using FrostFS.SDK.ClientV2.Interfaces;
using FrostFS.SDK.Cryptography;
using FrostFS.Session;
using Grpc.Core;
using Grpc.Core.Interceptors;
using Grpc.Net.Client;
using Microsoft.Extensions.Options;
namespace FrostFS.SDK.ClientV2;
public class FrostFSClient : IFrostFSClient
{
private bool isDisposed;
internal ContainerService.ContainerServiceClient? ContainerServiceClient { get; set; }
internal NetmapService.NetmapServiceClient? NetmapServiceClient { get; set; }
internal APEManagerService.APEManagerServiceClient? ApeManagerServiceClient { get; set; }
internal SessionService.SessionServiceClient? SessionServiceClient { get; set; }
internal ObjectService.ObjectServiceClient? ObjectServiceClient { get; set; }
internal ClientEnvironment ClientCtx { get; set; }
public static IFrostFSClient GetInstance(IOptions<ClientSettings> clientOptions, GrpcChannelOptions? channelOptions = null)
{
return new FrostFSClient(clientOptions, channelOptions);
}
public static IFrostFSClient GetSingleOwnerInstance(IOptions<SingleOwnerClientSettings> clientOptions, GrpcChannelOptions? channelOptions = null)
{
return new FrostFSClient(clientOptions, channelOptions);
}
/// <summary>
/// For test only. Provide custom implementation or mock object to inject required logic instead of internal gRPC client.
/// </summary>
/// <param name="clientOptions">Global setting for client</param>
/// <param name="channelOptions">Setting for gRPC channel</param>
/// <param name="containerService">ContainerService.ContainerServiceClient implementation</param>
/// <param name="netmapService">Netmap.NetmapService.NetmapServiceClient implementation</param>
/// <param name="sessionService">Session.SessionService.SessionServiceClient implementation</param>
/// <param name="objectService">Object.ObjectService.ObjectServiceClient implementation</param>
/// <returns></returns>
public static IFrostFSClient GetTestInstance(
IOptions<SingleOwnerClientSettings> clientOptions,
GrpcChannelOptions? channelOptions,
NetmapService.NetmapServiceClient netmapService,
SessionService.SessionServiceClient sessionService,
ContainerService.ContainerServiceClient containerService,
ObjectService.ObjectServiceClient objectService)
{
if (clientOptions is null)
{
throw new ArgumentNullException(nameof(clientOptions));
}
return new FrostFSClient(clientOptions, channelOptions, containerService, netmapService, sessionService, objectService);
}
private FrostFSClient(
IOptions<SingleOwnerClientSettings> settings,
GrpcChannelOptions? channelOptions,
ContainerService.ContainerServiceClient containerService,
NetmapService.NetmapServiceClient netmapService,
SessionService.SessionServiceClient sessionService,
ObjectService.ObjectServiceClient objectService)
{
if (settings is null)
{
throw new ArgumentNullException(nameof(settings));
}
var ecdsaKey = settings.Value.Key.LoadWif();
FrostFsOwner.FromKey(ecdsaKey);
ClientCtx = new ClientEnvironment(
client: this,
key: ecdsaKey,
owner: FrostFsOwner.FromKey(ecdsaKey),
channel: InitGrpcChannel(settings.Value.Host, channelOptions),
version: new FrostFsVersion(2, 13));
ContainerServiceClient = containerService ?? throw new ArgumentNullException(nameof(containerService));
NetmapServiceClient = netmapService ?? throw new ArgumentNullException(nameof(netmapService));
SessionServiceClient = sessionService ?? throw new ArgumentNullException(nameof(sessionService));
ObjectServiceClient = objectService ?? throw new ArgumentNullException(nameof(objectService));
}
private FrostFSClient(IOptions<ClientSettings> options, GrpcChannelOptions? channelOptions)
{
var clientSettings = (options?.Value) ?? throw new ArgumentException("Options must be initialized");
clientSettings.Validate();
var channel = InitGrpcChannel(clientSettings.Host, channelOptions);
ClientCtx = new ClientEnvironment(
this,
key: null,
owner: null,
channel: channel,
version: new FrostFsVersion(2, 13));
// TODO: define timeout logic
// CheckFrostFsVersionSupport(new Context { Timeout = TimeSpan.FromSeconds(20) });
}
private FrostFSClient(IOptions<SingleOwnerClientSettings> options, GrpcChannelOptions? channelOptions)
{
var clientSettings = (options?.Value) ?? throw new ArgumentException("Options must be initialized");
clientSettings.Validate();
var ecdsaKey = clientSettings.Key.LoadWif();
var channel = InitGrpcChannel(clientSettings.Host, channelOptions);
ClientCtx = new ClientEnvironment(
this,
key: ecdsaKey,
owner: FrostFsOwner.FromKey(ecdsaKey),
channel: channel,
version: new FrostFsVersion(2, 13));
// TODO: define timeout logic
// CheckFrostFsVersionSupport(new Context { Timeout = TimeSpan.FromSeconds(20) });
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposing && !isDisposed)
{
ClientCtx?.Dispose();
isDisposed = true;
}
}
#region ApeManagerImplementation
public Task<byte[]> AddChainAsync(PrmApeChainAdd args)
{
if (args is null)
{
throw new ArgumentNullException(nameof(args));
}
var service = GetApeManagerService(args);
return service.AddChainAsync(args);
}
public Task RemoveChainAsync(PrmApeChainRemove args)
{
if (args is null)
{
throw new ArgumentNullException(nameof(args));
}
var service = GetApeManagerService(args);
return service.RemoveChainAsync(args);
}
public Task<Chain[]> ListChainAsync(PrmApeChainList args)
{
if (args is null)
throw new ArgumentNullException(nameof(args));
var service = GetApeManagerService(args);
return service.ListChainAsync(args);
}
#endregion
#region ContainerImplementation
public Task<FrostFsContainerInfo> GetContainerAsync(PrmContainerGet args)
{
if (args is null)
throw new ArgumentNullException(nameof(args));
var service = GetContainerService(args);
return service.GetContainerAsync(args);
}
public IAsyncEnumerable<FrostFsContainerId> ListContainersAsync(PrmContainerGetAll? args = null)
{
args ??= new PrmContainerGetAll();
var service = GetContainerService(args);
return service.ListContainersAsync(args);
}
public Task<FrostFsContainerId> CreateContainerAsync(PrmContainerCreate args)
{
if (args is null)
throw new ArgumentNullException(nameof(args));
var service = GetContainerService(args);
return service.CreateContainerAsync(args);
}
public Task DeleteContainerAsync(PrmContainerDelete args)
{
if (args is null)
throw new ArgumentNullException(nameof(args));
var service = GetContainerService(args);
return service.DeleteContainerAsync(args);
}
#endregion
#region NetworkImplementation
public Task<FrostFsNetmapSnapshot> GetNetmapSnapshotAsync(PrmNetmapSnapshot? args)
{
args ??= new PrmNetmapSnapshot();
var service = GetNetmapService(args);
return service.GetNetmapSnapshotAsync(args);
}
public Task<FrostFsNodeInfo> GetNodeInfoAsync(PrmNodeInfo? args)
{
args ??= new PrmNodeInfo();
var service = GetNetmapService(args);
return service.GetLocalNodeInfoAsync(args);
}
public Task<NetworkSettings> GetNetworkSettingsAsync(PrmNetworkSettings? args)
{
args ??= new PrmNetworkSettings();
var service = GetNetmapService(args);
return service.GetNetworkSettingsAsync(args.Context!);
}
#endregion
#region ObjectImplementation
public Task<FrostFsObjectHeader> GetObjectHeadAsync(PrmObjectHeadGet args)
{
if (args is null)
throw new ArgumentNullException(nameof(args));
var service = GetObjectService(args);
return service.GetObjectHeadAsync(args);
}
public Task<FrostFsObject> GetObjectAsync(PrmObjectGet args)
{
if (args is null)
throw new ArgumentNullException(nameof(args));
var service = GetObjectService(args);
return service.GetObjectAsync(args);
}
public Task<FrostFsObjectId> PutObjectAsync(PrmObjectPut args)
{
if (args is null)
throw new ArgumentNullException(nameof(args));
var service = GetObjectService(args);
return service.PutObjectAsync(args);
}
public Task<FrostFsObjectId> PutSingleObjectAsync(PrmSingleObjectPut args)
{
if (args is null)
throw new ArgumentNullException(nameof(args));
var service = GetObjectService(args);
return service.PutSingleObjectAsync(args);
}
public Task DeleteObjectAsync(PrmObjectDelete args)
{
if (args is null)
throw new ArgumentNullException(nameof(args));
var service = GetObjectService(args);
return service.DeleteObjectAsync(args);
}
public IAsyncEnumerable<FrostFsObjectId> SearchObjectsAsync(PrmObjectSearch args)
{
if (args is null)
throw new ArgumentNullException(nameof(args));
var service = GetObjectService(args);
return service.SearchObjectsAsync(args);
}
#endregion
#region SessionImplementation
public async Task<FrostFsSessionToken> CreateSessionAsync(PrmSessionCreate args)
{
if (args is null)
throw new ArgumentNullException(nameof(args));
var session = await CreateSessionInternalAsync(args).ConfigureAwait(false);
var token = session.Serialize();
return new FrostFsSessionToken(token);
}
internal Task<SessionToken> CreateSessionInternalAsync(PrmSessionCreate args)
{
if (args is null)
throw new ArgumentNullException(nameof(args));
var service = GetSessionService(args);
return service.CreateSessionAsync(args);
}
#endregion
#region ToolsImplementation
public FrostFsObjectId CalculateObjectId(FrostFsObjectHeader header, Context ctx)
{
if (header == null)
throw new ArgumentNullException(nameof(header));
return ObjectTools.CalculateObjectId(header, ctx);
}
#endregion
private async void CheckFrostFsVersionSupport(Context? ctx = default)
{
var args = new PrmNodeInfo { Context = ctx };
if (ctx?.Version == null)
throw new InvalidObjectException(nameof(ctx.Version));
var service = GetNetmapService(args);
var localNodeInfo = await service.GetLocalNodeInfoAsync(args).ConfigureAwait(false);
if (!localNodeInfo.Version.IsSupported(ctx.Version))
{
var msg = $"FrostFS {localNodeInfo.Version} is not supported.";
throw new FrostFsException(msg);
}
}
private CallInvoker? SetupEnvironment(IContext ctx)
{
if (isDisposed)
throw new InvalidObjectException("Client is disposed.");
ctx.Context ??= new Context();
if (ctx.Context.Key == null)
{
if (ClientCtx.Key == null)
{
throw new InvalidObjectException("Key is not initialized.");
}
ctx.Context.Key = ClientCtx.Key.ECDsaKey;
}
if (ctx.Context.OwnerId == null)
{
ctx.Context.OwnerId = ClientCtx.Owner ?? FrostFsOwner.FromKey(ctx.Context.Key);
}
if (ctx.Context.Version == null)
{
if (ClientCtx.Version == null)
{
throw new InvalidObjectException("Version is not initialized.");
}
ctx.Context.Version = ClientCtx.Version;
}
CallInvoker? callInvoker = null;
if (ctx.Context.Interceptors != null && ctx.Context.Interceptors.Count > 0)
{
foreach (var interceptor in ctx.Context.Interceptors)
{
callInvoker = AddInvoker(callInvoker, interceptor);
}
}
if (ctx.Context.Callback != null)
callInvoker = AddInvoker(callInvoker, new MetricsInterceptor(ctx.Context.Callback));
return callInvoker;
CallInvoker AddInvoker(CallInvoker? callInvoker, Interceptor interceptor)
{
if (callInvoker == null)
callInvoker = ClientCtx.Channel.Intercept(interceptor);
else
callInvoker.Intercept(interceptor);
return callInvoker;
}
}
private NetmapServiceProvider GetNetmapService(IContext ctx)
{
var callInvoker = SetupEnvironment(ctx);
var client = NetmapServiceClient ?? (callInvoker != null
? new NetmapService.NetmapServiceClient(callInvoker)
: new NetmapService.NetmapServiceClient(ClientCtx.Channel));
return new NetmapServiceProvider(client, ClientCtx);
}
private SessionServiceProvider GetSessionService(IContext ctx)
{
var callInvoker = SetupEnvironment(ctx);
var client = SessionServiceClient ?? (callInvoker != null
? new SessionService.SessionServiceClient(callInvoker)
: new SessionService.SessionServiceClient(ClientCtx.Channel));
return new SessionServiceProvider(client, ClientCtx);
}
private ApeManagerServiceProvider GetApeManagerService(IContext ctx)
{
var callInvoker = SetupEnvironment(ctx);
var client = ApeManagerServiceClient ?? (callInvoker != null
? new APEManagerService.APEManagerServiceClient(callInvoker)
: new APEManagerService.APEManagerServiceClient(ClientCtx.Channel));
return new ApeManagerServiceProvider(client, ClientCtx);
}
private ContainerServiceProvider GetContainerService(IContext ctx)
{
var callInvoker = SetupEnvironment(ctx);
var client = ContainerServiceClient ?? (callInvoker != null
? new ContainerService.ContainerServiceClient(callInvoker)
: new ContainerService.ContainerServiceClient(ClientCtx.Channel));
return new ContainerServiceProvider(client, ClientCtx);
}
private ObjectServiceProvider GetObjectService(IContext ctx)
{
var callInvoker = SetupEnvironment(ctx);
var client = ObjectServiceClient ?? (callInvoker != null
? new ObjectService.ObjectServiceClient(callInvoker)
: new ObjectService.ObjectServiceClient(ClientCtx.Channel));
return new ObjectServiceProvider(client, ClientCtx);
}
private static GrpcChannel InitGrpcChannel(string host, GrpcChannelOptions? channelOptions)
{
try
{
var uri = new Uri(host);
if (channelOptions != null)
return GrpcChannel.ForAddress(uri, channelOptions);
return GrpcChannel.ForAddress(uri, new GrpcChannelOptions
{
HttpHandler = new HttpClientHandler()
});
}
catch (UriFormatException e)
{
throw new ArgumentException($"Host '{host}' has invalid format. Error: {e.Message}");
}
}
}

View file

@ -1,81 +0,0 @@
using System;
using System.Diagnostics;
using System.Threading.Tasks;
using Grpc.Core;
using Grpc.Core.Interceptors;
namespace FrostFS.SDK.ClientV2;
public class MetricsInterceptor(Action<CallStatistics> callback) : Interceptor
{
public override AsyncUnaryCall<TResponse> AsyncUnaryCall<TRequest, TResponse>(
TRequest request,
ClientInterceptorContext<TRequest, TResponse> context,
AsyncUnaryCallContinuation<TRequest, TResponse> continuation)
{
if (continuation is null)
{
throw new ArgumentNullException(nameof(continuation));
}
var call = continuation(request, context);
return new AsyncUnaryCall<TResponse>(
HandleUnaryResponse(call),
call.ResponseHeadersAsync,
call.GetStatus,
call.GetTrailers,
call.Dispose);
}
public override AsyncClientStreamingCall<TRequest, TResponse> AsyncClientStreamingCall<TRequest, TResponse>(
ClientInterceptorContext<TRequest, TResponse> context,
AsyncClientStreamingCallContinuation<TRequest, TResponse> continuation)
{
if (continuation is null)
throw new ArgumentNullException(nameof(continuation));
var call = continuation(context);
return new AsyncClientStreamingCall<TRequest, TResponse>(
call.RequestStream,
HandleStreamResponse(call),
call.ResponseHeadersAsync,
call.GetStatus,
call.GetTrailers,
call.Dispose);
}
private async Task<TResponse> HandleUnaryResponse<TResponse>(AsyncUnaryCall<TResponse> call)
{
var watch = new Stopwatch();
watch.Start();
var response = await call.ResponseAsync.ConfigureAwait(false);
watch.Stop();
var elapsed = watch.ElapsedTicks * 1_000_000 / Stopwatch.Frequency;
callback(new CallStatistics { MethodName = call.ToString(), ElapsedMicroSeconds = elapsed });
return response;
}
private async Task<TResponse> HandleStreamResponse<TRequest, TResponse>(AsyncClientStreamingCall<TRequest, TResponse> call)
{
var watch = new Stopwatch();
watch.Start();
var response = await call.ResponseAsync.ConfigureAwait(false);
watch.Stop();
var elapsed = watch.ElapsedTicks * 1_000_000 / Stopwatch.Frequency;
callback(new CallStatistics { MethodName = call.ToString(), ElapsedMicroSeconds = elapsed });
return response;
}
}

View file

@ -1,57 +1,17 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using FrostFS.SDK.ModelsV2;
using Frostfs.V2.Ape;
namespace FrostFS.SDK.ClientV2.Interfaces;
public interface IFrostFSClient : IDisposable
public interface IFrostFSClient
{
#region Network
Task<FrostFsNetmapSnapshot> GetNetmapSnapshotAsync(PrmNetmapSnapshot? args = null);
Task<FrostFsNodeInfo> GetNodeInfoAsync(PrmNodeInfo? args = null);
Task<NetworkSettings> GetNetworkSettingsAsync(PrmNetworkSettings? args = null);
#endregion
#region Session
Task<FrostFsSessionToken> CreateSessionAsync(PrmSessionCreate args);
#endregion
#region ApeMAnager
Task<byte[]> AddChainAsync(PrmApeChainAdd args);
Task RemoveChainAsync(PrmApeChainRemove args);
Task<Chain[]> ListChainAsync(PrmApeChainList args);
#endregion
#region Container
Task<FrostFsContainerInfo> GetContainerAsync(PrmContainerGet args);
IAsyncEnumerable<FrostFsContainerId> ListContainersAsync(PrmContainerGetAll? args = null);
Task<FrostFsContainerId> CreateContainerAsync(PrmContainerCreate args);
Task DeleteContainerAsync(PrmContainerDelete args);
#endregion
#region Object
Task<FrostFsObjectHeader> GetObjectHeadAsync(PrmObjectHeadGet args);
Task<FrostFsObject> GetObjectAsync(PrmObjectGet args);
Task<FrostFsObjectId> PutObjectAsync(PrmObjectPut args);
Task<FrostFsObjectId> PutSingleObjectAsync(PrmSingleObjectPut args);
Task DeleteObjectAsync(PrmObjectDelete args);
IAsyncEnumerable<FrostFsObjectId> SearchObjectsAsync(PrmObjectSearch args);
#endregion
#region Tools
FrostFsObjectId CalculateObjectId(FrostFsObjectHeader header, Context ctx);
#endregion
Task<ModelsV2.Container> GetContainerAsync(ContainerId containerId);
IAsyncEnumerable<ContainerId> ListContainersAsync();
Task<ContainerId> CreateContainerAsync(ModelsV2.Container container);
Task DeleteContainerAsync(ContainerId containerId);
Task<ObjectHeader> GetObjectHeadAsync(ContainerId containerId, ObjectId objectId);
Task<ModelsV2.Object> GetObjectAsync(ContainerId containerId, ObjectId objectId);
Task<ObjectId> PutObjectAsync(ObjectHeader header, Stream payload);
Task<ObjectId> PutObjectAsync(ObjectHeader header, byte[] payload);
Task DeleteObjectAsync(ContainerId containerId, ObjectId objectId);
IAsyncEnumerable<ObjectId> SearchObjectsAsync(ContainerId cid, params ObjectFilter[] filters);
}

View file

@ -1,22 +0,0 @@
using System;
using System.Linq;
using FrostFS.SDK.Cryptography;
namespace FrostFS.SDK.ClientV2.Mappers.GRPC;
public static class ContainerMapper
{
public static FrostFsContainerInfo ToModel(this Container.Container container)
{
if (container == null)
throw new ArgumentNullException(nameof(container));
return new FrostFsContainerInfo(
container.PlacementPolicy.ToModel(),
container.Attributes?.Select(a => new FrostFsAttributePair(a.Key, a.Value)).ToArray(),
container.Version?.ToModel(),
container.OwnerId?.ToModel(),
container.Nonce?.ToUuid());
}
}

View file

@ -1,39 +0,0 @@
using System;
using FrostFS.Refs;
using FrostFS.SDK.Cryptography;
using Google.Protobuf;
using Microsoft.Extensions.Caching.Memory;
namespace FrostFS.SDK.ClientV2.Mappers.GRPC;
public static class ContainerIdMapper
{
private static readonly MemoryCacheEntryOptions _oneHourExpiration = new MemoryCacheEntryOptions()
.SetSlidingExpiration(TimeSpan.FromHours(1))
.SetSize(1);
public static ContainerID ToMessage(this FrostFsContainerId model)
{
if (model is null)
{
throw new ArgumentNullException(nameof(model));
}
var containerId = model.GetValue() ?? throw new ArgumentNullException(nameof(model));
if (!Cache.Containers.TryGetValue(containerId, out ContainerID? message))
{
message = new ContainerID
{
Value = ByteString.CopyFrom(Base58.Decode(containerId))
};
Cache.Containers.Set(containerId, message, _oneHourExpiration);
}
return message!;
}
}

View file

@ -0,0 +1,37 @@
using FrostFS.SDK.ClientV2.Mappers.GRPC.Netmap;
using FrostFS.SDK.Cryptography;
using FrostFS.SDK.ModelsV2.Enums;
using Google.Protobuf;
namespace FrostFS.SDK.ClientV2.Mappers.GRPC;
public static class ContainerMapper
{
public static Container.Container ToGrpcMessage(this ModelsV2.Container container)
{
return new Container.Container
{
BasicAcl = (uint)container.BasicAcl,
PlacementPolicy = container.PlacementPolicy.ToGrpcMessage(),
Nonce = ByteString.CopyFrom(container.Nonce.ToBytes())
};
}
public static ModelsV2.Container ToModel(this Container.Container container)
{
var basicAclName = Enum.GetName(typeof(BasicAcl), container.BasicAcl);
if (basicAclName is null)
{
throw new ArgumentException($"Unknown BasicACL rule. Value: '{container.BasicAcl}'.");
}
return new ModelsV2.Container(
Enum.Parse<BasicAcl>(basicAclName),
container.PlacementPolicy.ToModel()
)
{
Nonce = container.Nonce.ToUuid(),
Version = container.Version.ToModel()
};
}
}

View file

@ -0,0 +1,16 @@
using FrostFS.Refs;
using FrostFS.SDK.ModelsV2;
using Google.Protobuf;
namespace FrostFS.SDK.ClientV2.Mappers.GRPC;
public static class ContainerIdMapper
{
public static ContainerID ToGrpcMessage(this ContainerId containerId)
{
return new ContainerID
{
Value = ByteString.CopyFrom(containerId.ToHash())
};
}
}

View file

@ -0,0 +1,23 @@
using FrostFS.SDK.ModelsV2;
using FrostFS.Session;
using Version = FrostFS.Refs.Version;
namespace FrostFS.SDK.ClientV2.Mappers.GRPC;
public static class MetaHeaderMapper
{
public static RequestMetaHeader ToGrpcMessage(this MetaHeader metaHeader)
{
return new RequestMetaHeader
{
Version = new Version
{
Major = (uint)metaHeader.Version.Major,
Minor = (uint)metaHeader.Version.Minor,
},
Epoch = (uint)metaHeader.Epoch,
Ttl = (uint)metaHeader.Ttl
};
}
}

View file

@ -0,0 +1,22 @@
using FrostFS.Netmap;
using FrostFS.SDK.ModelsV2.Enums;
using NodeInfo = FrostFS.SDK.ModelsV2.Netmap.NodeInfo;
namespace FrostFS.SDK.ClientV2.Mappers.GRPC.Netmap;
public static class NodeInfoMapper
{
public static NodeInfo ToModel(this LocalNodeInfoResponse.Types.Body nodeInfo)
{
var nodeStateName = Enum.GetName(typeof(NodeState), nodeInfo.NodeInfo.State);
if (nodeStateName is null)
{
throw new ArgumentException($"Unknown NodeState. Value: '{nodeInfo.NodeInfo.State}'.");
}
return new NodeInfo
{
State = Enum.Parse<NodeState>(nodeStateName),
Version = nodeInfo.Version.ToModel()
};
}
}

View file

@ -0,0 +1,31 @@
using FrostFS.Netmap;
namespace FrostFS.SDK.ClientV2.Mappers.GRPC.Netmap;
public static class PlacementPolicyMapper
{
public static PlacementPolicy ToGrpcMessage(this ModelsV2.Netmap.PlacementPolicy placementPolicy)
{
var pp = new PlacementPolicy
{
Filters = { },
Selectors = { },
Replicas = { },
Unique = placementPolicy.Unique
};
foreach (var replica in placementPolicy.Replicas)
{
pp.Replicas.Add(replica.ToGrpcMessage());
}
return pp;
}
public static ModelsV2.Netmap.PlacementPolicy ToModel(this PlacementPolicy placementPolicy)
{
return new ModelsV2.Netmap.PlacementPolicy(
placementPolicy.Unique,
placementPolicy.Replicas.Select(replica => replica.ToModel()).ToArray()
);
}
}

View file

@ -0,0 +1,20 @@
using FrostFS.Netmap;
namespace FrostFS.SDK.ClientV2.Mappers.GRPC.Netmap;
public static class ReplicaMapper
{
public static Replica ToGrpcMessage(this ModelsV2.Netmap.Replica replica)
{
return new Replica
{
Count = (uint)replica.Count,
Selector = replica.Selector
};
}
public static ModelsV2.Netmap.Replica ToModel(this Replica replica)
{
return new ModelsV2.Netmap.Replica((int)replica.Count, replica.Selector);
}
}

View file

@ -0,0 +1,99 @@
using FrostFS.Object;
using FrostFS.SDK.ModelsV2;
using MatchType = FrostFS.Object.MatchType;
using ObjectType = FrostFS.Object.ObjectType;
namespace FrostFS.SDK.ClientV2.Mappers.GRPC;
public static class ObjectAttributeMapper
{
public static Header.Types.Attribute ToGrpcMessage(this ObjectAttribute attribute)
{
return new Header.Types.Attribute
{
Key = attribute.Key,
Value = attribute.Value
};
}
public static ObjectAttribute ToModel(this Header.Types.Attribute attribute)
{
return new ObjectAttribute(attribute.Key, attribute.Value);
}
}
public static class ObjectFilterMapper
{
public static SearchRequest.Types.Body.Types.Filter ToGrpcMessage(this ObjectFilter filter)
{
var objMatchTypeName = Enum.GetName(typeof(MatchType), filter.MatchType);
if (objMatchTypeName is null)
{
throw new ArgumentException($"Unknown MatchType. Value: '{filter.MatchType}'.");
}
return new SearchRequest.Types.Body.Types.Filter
{
MatchType = Enum.Parse<MatchType>(objMatchTypeName),
Key = filter.Key,
Value = filter.Value
};
}
}
public static class ObjectHeaderMapper
{
public static Header ToGrpcMessage(this ObjectHeader header)
{
var objTypeName = Enum.GetName(typeof(ObjectType), header.ObjectType);
if (objTypeName is null)
{
throw new ArgumentException($"Unknown ObjectType. Value: '{header.ObjectType}'.");
}
var head = new Header
{
Attributes = { },
ContainerId = header.ContainerId.ToGrpcMessage(),
ObjectType = Enum.Parse<ObjectType>(objTypeName)
};
foreach (var attribute in header.Attributes)
{
head.Attributes.Add(attribute.ToGrpcMessage());
}
return head;
}
public static ObjectHeader ToModel(this Header header)
{
var objTypeName = Enum.GetName(typeof(ModelsV2.Enums.ObjectType), header.ObjectType);
if (objTypeName is null)
{
throw new ArgumentException($"Unknown ObjectType. Value: '{header.ObjectType}'.");
}
return new ObjectHeader(
ContainerId.FromHash(header.ContainerId.Value.ToByteArray()),
Enum.Parse<ModelsV2.Enums.ObjectType>(objTypeName),
header.Attributes.Select(attribute => attribute.ToModel()).ToArray()
)
{
Size = (long)header.PayloadLength,
Version = header.Version.ToModel()
};
}
}
public static class ObjectMapper
{
public static ModelsV2.Object ToModel(this Object.Object obj)
{
return new ModelsV2.Object
{
Header = obj.Header.ToModel(),
ObjectId = ObjectId.FromHash(obj.ObjectId.Value.ToByteArray()),
Payload = obj.Payload.ToByteArray()
};
}
}

View file

@ -0,0 +1,16 @@
using FrostFS.Refs;
using FrostFS.SDK.ModelsV2;
using Google.Protobuf;
namespace FrostFS.SDK.ClientV2.Mappers.GRPC;
public static class ObjectIdMapper
{
public static ObjectID ToGrpcMessage(this ObjectId objectId)
{
return new ObjectID
{
Value = ByteString.CopyFrom(objectId.ToHash())
};
}
}

View file

@ -0,0 +1,16 @@
using FrostFS.Refs;
using FrostFS.SDK.ModelsV2;
using Google.Protobuf;
namespace FrostFS.SDK.ClientV2.Mappers.GRPC;
public static class OwnerIdMapper
{
public static OwnerID ToGrpcMessage(this OwnerId ownerId)
{
return new OwnerID
{
Value = ByteString.CopyFrom(ownerId.ToHash())
};
}
}

View file

@ -0,0 +1,19 @@
using FrostFS.SDK.ModelsV2.Enums;
namespace FrostFS.SDK.ClientV2.Mappers.GRPC;
public static class StatusMapper
{
public static ModelsV2.Status ToModel(this Status.Status status)
{
if (status is null) return new ModelsV2.Status(StatusCode.Success);
var codeName = Enum.GetName(typeof(StatusCode), status.Code);
if (codeName is null)
{
throw new ArgumentException($"Unknown StatusCode. Value: '{status.Code}'.");
}
return new ModelsV2.Status(Enum.Parse<StatusCode>(codeName), status.Message);
}
}

View file

@ -0,0 +1,20 @@
using Version = FrostFS.Refs.Version;
namespace FrostFS.SDK.ClientV2.Mappers.GRPC;
public static class VersionMapper
{
public static Version ToGrpcMessage(this ModelsV2.Version version)
{
return new Version
{
Major = (uint)version.Major,
Minor = (uint)version.Minor
};
}
public static ModelsV2.Version ToModel(this Version version)
{
return new ModelsV2.Version((int)version.Major, (int)version.Minor);
}
}

View file

@ -1,23 +0,0 @@
using System;
using FrostFS.Session;
namespace FrostFS.SDK.ClientV2.Mappers.GRPC;
public static class MetaHeaderMapper
{
public static RequestMetaHeader ToMessage(this MetaHeader metaHeader)
{
if (metaHeader is null)
{
throw new ArgumentNullException(nameof(metaHeader));
}
return new RequestMetaHeader
{
Version = metaHeader.Version.ToMessage(),
Epoch = (uint)metaHeader.Epoch,
Ttl = (uint)metaHeader.Ttl
};
}
}

View file

@ -1,23 +0,0 @@
using System;
using System.Linq;
using FrostFS.Netmap;
namespace FrostFS.SDK.ClientV2;
public static class NetmapMapper
{
public static FrostFsNetmapSnapshot ToModel(this NetmapSnapshotResponse netmap)
{
if (netmap is null)
{
throw new ArgumentNullException(nameof(netmap));
}
return new FrostFsNetmapSnapshot(
netmap.Body.Netmap.Epoch,
netmap.Body.Netmap.Nodes
.Select(n => n.ToModel(netmap.MetaHeader.Version))
.ToArray());
}
}

View file

@ -1,45 +0,0 @@
using System;
using System.Linq;
using FrostFS.Netmap;
using FrostFS.SDK.ClientV2.Mappers.GRPC;
namespace FrostFS.SDK.ClientV2;
public static class NodeInfoMapper
{
public static FrostFsNodeInfo ToModel(this LocalNodeInfoResponse.Types.Body node)
{
if (node is null)
{
throw new ArgumentNullException(nameof(node));
}
return node.NodeInfo.ToModel(node.Version);
}
public static FrostFsNodeInfo ToModel(this NodeInfo nodeInfo, Refs.Version version)
{
if (nodeInfo is null)
{
throw new ArgumentNullException(nameof(nodeInfo));
}
NodeState state = nodeInfo.State switch
{
NodeInfo.Types.State.Unspecified => NodeState.Unspecified,
NodeInfo.Types.State.Online => NodeState.Online,
NodeInfo.Types.State.Offline => NodeState.Offline,
NodeInfo.Types.State.Maintenance => NodeState.Maintenance,
_ => throw new ArgumentException($"Unknown NodeState. Value: '{nodeInfo.State}'.")
};
return new FrostFsNodeInfo(
version: version.ToModel(),
state: state,
addresses: [.. nodeInfo.Addresses],
attributes: nodeInfo.Attributes.ToDictionary(n => n.Key, n => n.Value),
publicKey: nodeInfo.PublicKey.ToByteArray()
);
}
}

View file

@ -1,22 +0,0 @@
using System;
using System.Linq;
using FrostFS.Netmap;
namespace FrostFS.SDK.ClientV2;
public static class PlacementPolicyMapper
{
public static FrostFsPlacementPolicy ToModel(this PlacementPolicy placementPolicy)
{
if (placementPolicy is null)
{
throw new ArgumentNullException(nameof(placementPolicy));
}
return new FrostFsPlacementPolicy(
placementPolicy.Unique,
placementPolicy.Replicas.Select(replica => replica.ToModel()).ToArray()
);
}
}

View file

@ -1,27 +0,0 @@
using System;
using FrostFS.Netmap;
namespace FrostFS.SDK.ClientV2;
public static class ReplicaMapper
{
public static Replica ToMessage(this FrostFsReplica replica)
{
return new Replica
{
Count = (uint)replica.Count,
Selector = replica.Selector
};
}
public static FrostFsReplica ToModel(this Replica replica)
{
if (replica is null)
{
throw new ArgumentNullException(nameof(replica));
}
return new FrostFsReplica((int)replica.Count, replica.Selector);
}
}

View file

@ -1,12 +0,0 @@
namespace FrostFS.SDK.ClientV2.Mappers.GRPC;
internal static class ObjectMapper
{
internal static FrostFsObject ToModel(this Object.Object obj)
{
return new FrostFsObject(obj.Header.ToModel())
{
ObjectId = FrostFsObjectId.FromHash(obj.ObjectId.Value.ToByteArray())
};
}
}

View file

@ -1,32 +0,0 @@
using System;
using FrostFS.Object;
namespace FrostFS.SDK.ClientV2.Mappers.GRPC;
public static class ObjectAttributeMapper
{
public static Header.Types.Attribute ToMessage(this FrostFsAttributePair attribute)
{
if (attribute is null)
{
throw new ArgumentNullException(nameof(attribute));
}
return new Header.Types.Attribute
{
Key = attribute.Key,
Value = attribute.Value
};
}
public static FrostFsAttributePair ToModel(this Header.Types.Attribute attribute)
{
if (attribute is null)
{
throw new ArgumentNullException(nameof(attribute));
}
return new FrostFsAttributePair(attribute.Key, attribute.Value);
}
}

View file

@ -1,34 +0,0 @@
using System;
using FrostFS.Object;
namespace FrostFS.SDK.ClientV2.Mappers.GRPC;
public static class ObjectFilterMapper
{
public static SearchRequest.Types.Body.Types.Filter ToMessage(this IObjectFilter filter)
{
if (filter is null)
{
throw new ArgumentNullException(nameof(filter));
}
var objMatchTypeName = filter.MatchType switch
{
FrostFsMatchType.Unspecified => MatchType.Unspecified,
FrostFsMatchType.Equals => MatchType.StringEqual,
FrostFsMatchType.NotEquals => MatchType.StringNotEqual,
FrostFsMatchType.KeyAbsent => MatchType.NotPresent,
FrostFsMatchType.StartsWith => MatchType.CommonPrefix,
_ => throw new ArgumentException($"Unknown MatchType. Value: '{filter.MatchType}'.")
};
return new SearchRequest.Types.Body.Types.Filter
{
MatchType = objMatchTypeName,
Key = filter.Key,
Value = filter.GetSerializedValue()
};
}
}

View file

@ -1,55 +0,0 @@
using System;
using System.Collections.ObjectModel;
using System.Linq;
using FrostFS.Object;
using FrostFS.SDK.Cryptography;
namespace FrostFS.SDK.ClientV2.Mappers.GRPC;
public static class ObjectHeaderMapper
{
public static FrostFsObjectHeader ToModel(this Header header)
{
if (header is null)
{
throw new ArgumentNullException(nameof(header));
}
var objTypeName = header.ObjectType switch
{
ObjectType.Regular => FrostFsObjectType.Regular,
ObjectType.Lock => FrostFsObjectType.Lock,
ObjectType.Tombstone => FrostFsObjectType.Tombstone,
_ => throw new ArgumentException($"Unknown ObjectType. Value: '{header.ObjectType}'.")
};
FrostFsSplit? split = null;
if (header.Split != null)
{
var children = header.Split.Children.Count != 0 ? new ReadOnlyCollection<FrostFsObjectId>(
header.Split.Children.Select(x => x.ToModel()).ToList()) : null;
split = new FrostFsSplit(new SplitId(header.Split.SplitId.ToUuid()),
header.Split.Previous?.ToModel(),
header.Split.Parent?.ToModel(),
header.Split.ParentHeader?.ToModel(),
null,
children);
}
var model = new FrostFsObjectHeader(
new FrostFsContainerId(Base58.Encode(header.ContainerId.Value.ToByteArray())),
objTypeName,
header.Attributes.Select(attribute => attribute.ToModel()).ToArray(),
split,
header.OwnerId.ToModel(),
header.Version.ToModel())
{
PayloadLength = header.PayloadLength,
};
return model;
}
}

View file

@ -1,33 +0,0 @@
using System;
using FrostFS.Refs;
using Google.Protobuf;
namespace FrostFS.SDK.ClientV2.Mappers.GRPC;
public static class ObjectIdMapper
{
public static ObjectID ToMessage(this FrostFsObjectId objectId)
{
if (objectId is null)
{
throw new ArgumentNullException(nameof(objectId));
}
return new ObjectID
{
Value = ByteString.CopyFrom(objectId.ToHash())
};
}
public static FrostFsObjectId ToModel(this ObjectID objectId)
{
if (objectId is null)
{
throw new ArgumentNullException(nameof(objectId));
}
return FrostFsObjectId.FromHash(objectId.Value.ToByteArray());
}
}

View file

@ -1,54 +0,0 @@
using System;
using FrostFS.Refs;
using FrostFS.SDK.Cryptography;
using Google.Protobuf;
using Microsoft.Extensions.Caching.Memory;
namespace FrostFS.SDK.ClientV2.Mappers.GRPC;
public static class OwnerIdMapper
{
private static readonly MemoryCacheEntryOptions _oneHourExpiration = new MemoryCacheEntryOptions()
.SetSlidingExpiration(TimeSpan.FromHours(1))
.SetSize(1);
public static OwnerID ToMessage(this FrostFsOwner model)
{
if (model is null)
{
throw new ArgumentNullException(nameof(model));
}
if (!Cache.Owners.TryGetValue(model, out OwnerID? message))
{
message = new OwnerID
{
Value = ByteString.CopyFrom(model.ToHash())
};
Cache.Owners.Set(model, message, _oneHourExpiration);
}
return message!;
}
public static FrostFsOwner ToModel(this OwnerID message)
{
if (message is null)
{
throw new ArgumentNullException(nameof(message));
}
if (!Cache.Owners.TryGetValue(message, out FrostFsOwner? model))
{
model = new FrostFsOwner(Base58.Encode(message.Value.ToByteArray()));
Cache.Owners.Set(message, model, _oneHourExpiration);
}
return model!;
}
}

View file

@ -1,28 +0,0 @@
using System;
using Google.Protobuf;
namespace FrostFS.SDK.ClientV2;
public static class SessionMapper
{
public static byte[] Serialize(this Session.SessionToken token)
{
if (token is null)
{
throw new ArgumentNullException(nameof(token));
}
byte[] bytes = new byte[token.CalculateSize()];
using CodedOutputStream stream = new(bytes);
token.WriteTo(stream);
return bytes;
}
public static Session.SessionToken Deserialize(this Session.SessionToken token, byte[] bytes)
{
token.MergeFrom(bytes);
return token;
}
}

View file

@ -1,31 +0,0 @@
using System;
using Google.Protobuf;
namespace FrostFS.SDK.ClientV2.Mappers.GRPC;
public static class SignatureMapper
{
public static Refs.Signature ToMessage(this FrostFsSignature signature)
{
if (signature is null)
{
throw new ArgumentNullException(nameof(signature));
}
var scheme = signature.Scheme switch
{
SignatureScheme.EcdsaRfc6979Sha256 => Refs.SignatureScheme.EcdsaRfc6979Sha256,
SignatureScheme.EcdsaRfc6979Sha256WalletConnect => Refs.SignatureScheme.EcdsaRfc6979Sha256WalletConnect,
SignatureScheme.EcdsaSha512 => Refs.SignatureScheme.EcdsaSha512,
_ => throw new ArgumentException(nameof(signature.Scheme), $"Unexpected enum value: {signature.Scheme}")
};
return new Refs.Signature
{
Key = ByteString.CopyFrom(signature.Key),
Scheme = scheme,
Sign = ByteString.CopyFrom(signature.Sign)
};
}
}

View file

@ -1,18 +0,0 @@
using System;
namespace FrostFS.SDK.ClientV2.Mappers.GRPC;
public static class StatusMapper
{
public static FrostFsResponseStatus ToModel(this Status.Status status)
{
if (status is null)
return new FrostFsResponseStatus(FrostFsStatusCode.Success);
var codeName = Enum.GetName(typeof(FrostFsStatusCode), status.Code);
return codeName is null
? throw new ArgumentException($"Unknown StatusCode. Value: '{status.Code}'.")
: new FrostFsResponseStatus((FrostFsStatusCode)status.Code, status.Message);
}
}

View file

@ -1,85 +0,0 @@
using System.Collections;
using System.Threading;
using FrostFS.Refs;
namespace FrostFS.SDK.ClientV2.Mappers.GRPC;
public static class VersionMapper
{
private static readonly Hashtable _cacheMessages = [];
private static readonly Hashtable _cacheModels = [];
private static SpinLock _spinlock;
public static Version ToMessage(this FrostFsVersion model)
{
if (model is null)
{
throw new System.ArgumentNullException(nameof(model));
}
var key = model.Major << 16 + model.Minor;
if (!_cacheMessages.ContainsKey(key))
{
bool lockTaken = false;
try
{
_spinlock.Enter(ref lockTaken);
var message = new Version
{
Major = (uint)model.Major,
Minor = (uint)model.Minor
};
_cacheMessages.Add(key, message);
return message;
}
catch (System.ArgumentException)
{
// ignore attempt to add duplicate
}
finally
{
if (lockTaken)
_spinlock.Exit(false);
}
}
return (Version)_cacheMessages[key];
}
public static FrostFsVersion ToModel(this Version message)
{
if (message is null)
{
throw new System.ArgumentNullException(nameof(message));
}
var key = (int)message.Major << 16 + (int)message.Minor;
if (!_cacheModels.ContainsKey(key))
{
bool lockTaken = false;
try
{
_spinlock.Enter(ref lockTaken);
var model = new FrostFsVersion((int)message.Major, (int)message.Minor);
_cacheModels.Add(key, model);
return model;
}
catch (System.ArgumentException)
{
// ignore attempt to add duplicate
}
finally
{
if (lockTaken)
_spinlock.Exit(false);
}
}
return (FrostFsVersion)_cacheModels[key];
}
}

View file

@ -1,63 +0,0 @@
using System;
using Frostfs.V2.Ape;
namespace FrostFS.SDK.ClientV2
{
public struct FrostFsChainTarget(FrostFsTargetType type, string name) : IEquatable<FrostFsChainTarget>
{
private ChainTarget? chainTarget;
public FrostFsTargetType Type { get; } = type;
public string Name { get; } = name;
internal ChainTarget GetChainTarget()
{
return chainTarget ??= new ChainTarget
{
Type = GetTargetType(Type),
Name = Name
};
}
private static TargetType GetTargetType(FrostFsTargetType type)
{
return type switch
{
FrostFsTargetType.Undefined => TargetType.Undefined,
FrostFsTargetType.Namespace => TargetType.Namespace,
FrostFsTargetType.Container => TargetType.Container,
FrostFsTargetType.User => TargetType.User,
FrostFsTargetType.Group => TargetType.Group,
_ => throw new ArgumentException("Unexpected value for TargetType", nameof(type)),
};
}
public override readonly bool Equals(object obj)
{
var target = (FrostFsChainTarget)obj;
return Equals(target);
}
public override readonly int GetHashCode()
{
return $"{Name}{Type}".GetHashCode();
}
public static bool operator ==(FrostFsChainTarget left, FrostFsChainTarget right)
{
return left.Equals(right);
}
public static bool operator !=(FrostFsChainTarget left, FrostFsChainTarget right)
{
return !(left == right);
}
public readonly bool Equals(FrostFsChainTarget other)
{
return Type == other.Type && Name.Equals(other.Name, StringComparison.Ordinal);
}
}
}

View file

@ -1,42 +0,0 @@
using Google.Protobuf;
namespace FrostFS.SDK.ClientV2
{
public struct FrostFsChain(byte[] raw) : System.IEquatable<FrostFsChain>
{
private ByteString? grpcRaw;
public byte[] Raw { get; } = raw;
internal ByteString GetRaw()
{
return grpcRaw ??= ByteString.CopyFrom(Raw);
}
public override readonly bool Equals(object obj)
{
var chain = (FrostFsChain)obj;
return Equals(chain);
}
public override readonly int GetHashCode()
{
return Raw.GetHashCode();
}
public static bool operator ==(FrostFsChain left, FrostFsChain right)
{
return left.Equals(right);
}
public static bool operator !=(FrostFsChain left, FrostFsChain right)
{
return !(left == right);
}
public readonly bool Equals(FrostFsChain other)
{
return Raw == other.Raw;
}
}
}

View file

@ -1,11 +0,0 @@
namespace FrostFS.SDK.ClientV2
{
public enum FrostFsTargetType
{
Undefined = 0,
Namespace,
Container,
User,
Group
}
}

View file

@ -1,70 +0,0 @@
using System;
using System.Collections.ObjectModel;
using System.Globalization;
using System.Text;
namespace FrostFS.SDK;
public class ClientSettings
{
protected static readonly string errorTemplate = "{0} is required parameter";
public string Host { get; set; } = string.Empty;
public virtual void Validate()
{
var errors = CheckFields();
if (errors != null)
ThrowException(errors);
}
protected Collection<string>? CheckFields()
{
if (string.IsNullOrWhiteSpace(Host))
{
var error = string.Format(CultureInfo.InvariantCulture, errorTemplate, nameof(Host));
return new Collection<string>([error]);
}
return null;
}
protected static void ThrowException(Collection<string> errors)
{
if (errors is null)
{
throw new ArgumentNullException(nameof(errors));
}
StringBuilder messages = new();
foreach (var error in errors)
{
messages.AppendLine(error);
}
throw new ArgumentException(messages.ToString());
}
}
public class SingleOwnerClientSettings : ClientSettings
{
public string Key { get; set; } = string.Empty;
public override void Validate()
{
var errors = CheckFields();
if (errors != null)
ThrowException(errors);
}
protected new Collection<string>? CheckFields()
{
Collection<string>? errors = base.CheckFields();
if (string.IsNullOrWhiteSpace(Key))
(errors ??= []).Add(string.Format(CultureInfo.InvariantCulture, errorTemplate, nameof(Key)));
return errors;
}
}

View file

@ -1,58 +0,0 @@
using FrostFS.Refs;
using FrostFS.SDK.ClientV2;
using FrostFS.SDK.ClientV2.Mappers.GRPC;
using FrostFS.SDK.Cryptography;
namespace FrostFS.SDK;
public class FrostFsContainerId
{
private string? modelId;
private ContainerID? containerID;
public FrostFsContainerId(string id)
{
this.modelId = id;
}
internal FrostFsContainerId(ContainerID id)
{
this.containerID = id;
}
public string GetValue()
{
if (this.modelId != null)
return this.modelId;
if (containerID != null)
{
this.modelId = Base58.Encode(containerID.Value.ToByteArray());
return this.modelId;
}
throw new InvalidObjectException();
}
internal ContainerID ContainerID
{
get
{
if (this.containerID != null)
return this.containerID;
if (modelId != null)
{
this.containerID = this.ToMessage();
return this.containerID;
}
throw new InvalidObjectException();
}
}
public override string ToString()
{
return GetValue();
}
}

View file

@ -1,109 +0,0 @@
using System;
using System.Collections.ObjectModel;
using System.Linq;
using FrostFS.SDK.ClientV2;
using FrostFS.SDK.ClientV2.Mappers.GRPC;
using FrostFS.SDK.Cryptography;
using Google.Protobuf;
namespace FrostFS.SDK;
public class FrostFsContainerInfo
{
private Container.Container.Types.Attribute[]? grpsAttributes;
private ReadOnlyCollection<FrostFsAttributePair>? attributes;
private FrostFsPlacementPolicy? placementPolicy;
private Guid? nonce;
private Container.Container? container;
public FrostFsContainerInfo(
FrostFsPlacementPolicy placementPolicy,
FrostFsAttributePair[]? attributes = null,
FrostFsVersion? version = null,
FrostFsOwner? owner = null,
Guid? nonce = null)
{
this.placementPolicy = placementPolicy;
Version = version;
Owner = owner;
this.nonce = nonce;
if (attributes != null)
this.attributes = new ReadOnlyCollection<FrostFsAttributePair>(attributes);
}
internal FrostFsContainerInfo(Container.Container container)
{
this.container = container;
}
public Guid Nonce
{
get
{
nonce ??= container?.Nonce != null ? container.Nonce.ToUuid() : Guid.NewGuid();
return nonce.Value;
}
}
public FrostFsPlacementPolicy? PlacementPolicy
{
get
{
placementPolicy ??= container?.PlacementPolicy?.ToModel();
return placementPolicy;
}
}
public ReadOnlyCollection<FrostFsAttributePair>? Attributes
{
get
{
if (attributes == null && grpsAttributes != null)
attributes = new ReadOnlyCollection<FrostFsAttributePair>(grpsAttributes.Select(a => new FrostFsAttributePair(a.Key, a.Value)).ToList());
return attributes;
}
}
public FrostFsVersion? Version { get; private set; }
public FrostFsOwner? Owner { get; private set; }
internal Container.Container.Types.Attribute[]? GetGrpsAttributes()
{
grpsAttributes ??= Attributes?
.Select(a => new Container.Container.Types.Attribute { Key = a.Key, Value = a.Value })
.ToArray();
return grpsAttributes;
}
internal Container.Container GetContainer()
{
if (this.container == null)
{
if (PlacementPolicy == null)
{
throw new InvalidObjectException("PlacementPolicy is null");
}
this.container = new Container.Container()
{
PlacementPolicy = PlacementPolicy.Value.GetPolicy(),
Nonce = ByteString.CopyFrom(Nonce.ToBytes()),
OwnerId = Owner?.OwnerID,
Version = Version?.Version
};
var attribs = GetGrpsAttributes();
if (attribs != null)
this.container.Attributes.AddRange(attribs);
}
return this.container;
}
}

View file

@ -1,10 +0,0 @@
namespace FrostFS.SDK;
public enum FrostFsMatchType
{
Unspecified = 0,
Equals = 1,
NotEquals = 2,
KeyAbsent = 3,
StartsWith = 4
}

View file

@ -1,8 +0,0 @@
namespace FrostFS.SDK;
public enum FrostFsObjectType
{
Regular = 0,
Tombstone = 1,
Lock = 3
}

View file

@ -1,9 +0,0 @@
namespace FrostFS.SDK;
public enum NodeState
{
Unspecified = 0,
Online = 1,
Offline = 2,
Maintenance = 3
}

View file

@ -1,8 +0,0 @@
namespace FrostFS.SDK;
public enum SignatureScheme
{
EcdsaSha512,
EcdsaRfc6979Sha256,
EcdsaRfc6979Sha256WalletConnect
}

View file

@ -1,7 +0,0 @@
namespace FrostFS.SDK;
public class CallStatistics
{
public string? MethodName { get; set; }
public long ElapsedMicroSeconds { get; set; }
}

View file

@ -1,21 +0,0 @@
using System;
using FrostFS.SDK.Cryptography;
namespace FrostFS.SDK;
public class CheckSum
{
private byte[]? hash;
private string? text;
public static CheckSum CreateCheckSum(byte[] content)
{
return new CheckSum { hash = content.Sha256() };
}
public override string ToString()
{
return text ??= BitConverter.ToString(hash).Replace("-", "");
}
}

View file

@ -1,52 +0,0 @@
namespace FrostFS.SDK;
public static class Constants
{
public const int ObjectChunkSize = 3 * (1 << 20);
public const int Sha256HashLength = 32;
// HeaderPrefix is a prefix of key to object header value or property.
public const string HeaderPrefix = "$Object:";
// FilterHeaderVersion is a filter key to "version" field of the object header.
public const string FilterHeaderVersion = HeaderPrefix + "version";
// FilterHeaderObjectID is a filter key to "object_id" field of the object.
public const string FilterHeaderObjectID = HeaderPrefix + "objectID";
// FilterHeaderContainerID is a filter key to "container_id" field of the object header.
public const string FilterHeaderContainerID = HeaderPrefix + "containerID";
// FilterHeaderOwnerID is a filter key to "owner_id" field of the object header.
public const string FilterHeaderOwnerID = HeaderPrefix + "ownerID";
// FilterHeaderCreationEpoch is a filter key to "creation_epoch" field of the object header.
public const string FilterHeaderCreationEpoch = HeaderPrefix + "creationEpoch";
// FilterHeaderPayloadLength is a filter key to "payload_length" field of the object header.
public const string FilterHeaderPayloadLength = HeaderPrefix + "payloadLength";
// FilterHeaderPayloadHash is a filter key to "payload_hash" field of the object header.
public const string FilterHeaderPayloadHash = HeaderPrefix + "payloadHash";
// FilterHeaderObjectType is a filter key to "object_type" field of the object header.
public const string FilterHeaderObjectType = HeaderPrefix + "objectType";
// FilterHeaderHomomorphicHash is a filter key to "homomorphic_hash" field of the object header.
public const string FilterHeaderHomomorphicHash = HeaderPrefix + "homomorphicHash";
// FilterHeaderParent is a filter key to "split.parent" field of the object header.
public const string FilterHeaderParent = HeaderPrefix + "split.parent";
// FilterHeaderSplitID is a filter key to "split.splitID" field of the object header.
public const string FilterHeaderSplitID = HeaderPrefix + "split.splitID";
// FilterHeaderECParent is a filter key to "ec.parent" field of the object header.
public const string FilterHeaderECParent = HeaderPrefix + "ec.parent";
// FilterPropertyRoot is a filter key to check if regular object is on top of split hierarchy.
public const string FilterHeaderRoot = HeaderPrefix + "ROOT";
// FilterPropertyPhy is a filter key to check if an object physically stored on a node.
public const string FilterHeaderPhy = HeaderPrefix + "PHY";
}

View file

@ -1,10 +0,0 @@
using System.Collections.Generic;
namespace FrostFS.SDK;
public class FrostFsNetmapSnapshot(ulong epoch, IReadOnlyList<FrostFsNodeInfo> nodeInfoCollection)
{
public ulong Epoch { get; private set; } = epoch;
public IReadOnlyList<FrostFsNodeInfo> NodeInfoCollection { get; private set; } = nodeInfoCollection;
}

View file

@ -1,18 +0,0 @@
using System;
using System.Collections.Generic;
namespace FrostFS.SDK;
public class FrostFsNodeInfo(
FrostFsVersion version,
NodeState state,
IReadOnlyCollection<string> addresses,
IReadOnlyDictionary<string, string> attributes,
ReadOnlyMemory<byte> publicKey)
{
public NodeState State { get; private set; } = state;
public FrostFsVersion Version { get; private set; } = version;
public IReadOnlyCollection<string> Addresses { get; private set; } = addresses;
public IReadOnlyDictionary<string, string> Attributes { get; private set; } = attributes;
public ReadOnlyMemory<byte> PublicKey { get; private set; } = publicKey;
}

View file

@ -1,89 +0,0 @@
using System;
using System.Linq;
using FrostFS.Netmap;
using FrostFS.SDK.ClientV2;
namespace FrostFS.SDK;
public struct FrostFsPlacementPolicy(bool unique, params FrostFsReplica[] replicas)
: IEquatable<FrostFsPlacementPolicy>
{
private PlacementPolicy policy;
public FrostFsReplica[] Replicas { get; private set; } = replicas;
public bool Unique { get; private set; } = unique;
public override readonly bool Equals(object obj)
{
if (obj is null)
return false;
var other = (FrostFsPlacementPolicy)obj;
return Equals(other);
}
public PlacementPolicy GetPolicy()
{
if (policy == null)
{
policy = new PlacementPolicy
{
Filters = { },
Selectors = { },
Replicas = { },
Unique = Unique
};
foreach (var replica in Replicas)
{
policy.Replicas.Add(replica.ToMessage());
}
}
return policy;
}
//public static FrostFsPlacementPolicy ToModel(placementPolicy)
//{
// return new FrostFsPlacementPolicy(
// placementPolicy.Unique,
// placementPolicy.Replicas.Select(replica => replica.ToModel()).ToArray()
// );
//}
public override readonly int GetHashCode()
{
return Unique ? 17 : 0 + Replicas.GetHashCode();
}
public static bool operator ==(FrostFsPlacementPolicy left, FrostFsPlacementPolicy right)
{
return left.Equals(right);
}
public static bool operator !=(FrostFsPlacementPolicy left, FrostFsPlacementPolicy right)
{
return !(left == right);
}
public readonly bool Equals(FrostFsPlacementPolicy other)
{
var notEqual = Unique != other.Unique
|| Replicas.Length != other.Replicas.Length;
if (notEqual)
return false;
foreach (var replica in Replicas)
{
if (!other.Replicas.Any(r => r.Equals(replica)))
return false;
}
return true;
}
}

View file

@ -1,47 +0,0 @@
using System;
namespace FrostFS.SDK;
public struct FrostFsReplica : IEquatable<FrostFsReplica>
{
public int Count { get; set; }
public string Selector { get; set; }
public FrostFsReplica(int count, string? selector = null)
{
selector ??= string.Empty;
Count = count;
Selector = selector;
}
public override readonly bool Equals(object obj)
{
if (obj is null)
return false;
var other = (FrostFsReplica)obj;
return Count == other.Count && Selector == other.Selector;
}
public override readonly int GetHashCode()
{
return Count + Selector.GetHashCode();
}
public static bool operator ==(FrostFsReplica left, FrostFsReplica right)
{
return left.Equals(right);
}
public static bool operator !=(FrostFsReplica left, FrostFsReplica right)
{
return !(left == right);
}
public readonly bool Equals(FrostFsReplica other)
{
return Count == other.Count && Selector == other.Selector;
}
}

View file

@ -1,36 +0,0 @@
using FrostFS.Refs;
using FrostFS.SDK.ClientV2.Mappers.GRPC;
namespace FrostFS.SDK;
public class FrostFsVersion(int major, int minor)
{
private Version? version;
public int Major { get; set; } = major;
public int Minor { get; set; } = minor;
internal Version Version
{
get
{
this.version ??= this.ToMessage();
return this.version;
}
}
public bool IsSupported(FrostFsVersion version)
{
if (version is null)
{
throw new System.ArgumentNullException(nameof(version));
}
return Major == version.Major;
}
public override string ToString()
{
return $"v{Major}.{Minor}";
}
}

View file

@ -1,8 +0,0 @@
namespace FrostFS.SDK;
public class FrostFsAttributePair(string key, string value)
{
public string Key { get; set; } = key;
public string Value { get; set; } = value;
}

View file

@ -1,9 +0,0 @@
namespace FrostFS.SDK;
public class FrostFsLargeObject(FrostFsContainerId container) : FrostFsObject(container)
{
public ulong PayloadLength
{
get { return Header!.PayloadLength; }
}
}

View file

@ -1,21 +0,0 @@
using System.Collections.Generic;
using System.Collections.ObjectModel;
namespace FrostFS.SDK;
public class FrostFsLinkObject : FrostFsObject
{
public FrostFsLinkObject(FrostFsContainerId containerId,
SplitId splitId,
FrostFsObjectHeader largeObjectHeader,
IList<FrostFsObjectId> children)
: base(containerId)
{
Header!.Split = new FrostFsSplit(splitId,
null,
null,
largeObjectHeader,
null,
new ReadOnlyCollection<FrostFsObjectId>(children));
}
}

View file

@ -1,74 +0,0 @@
using FrostFS.SDK.ClientV2;
namespace FrostFS.SDK;
public class FrostFsObject
{
private byte[]? bytes;
/// <summary>
/// Creates new instance from <c>ObjectHeader</c>
/// </summary>
/// <param name="header"></param> <summary>
public FrostFsObject(FrostFsObjectHeader header)
{
Header = header;
}
/// <summary>
/// Creates new instance with specified parameters
/// </summary>
/// <param name="container"></param>
/// <param name="objectType"></param>
public FrostFsObject(FrostFsContainerId container, FrostFsObjectType objectType = FrostFsObjectType.Regular)
{
Header = new FrostFsObjectHeader(containerId: container, type: objectType);
}
/// <summary>
/// Header contains metadata for the object
/// </summary>
/// <value></value>
public FrostFsObjectHeader Header { get; set; }
/// <summary>
/// The value is calculated internally as a hash of ObjectHeader. Do not use pre-calculated value is the object has been changed.
/// </summary>
public FrostFsObjectId? ObjectId
{
get; set;
}
/// <summary>
/// A payload is obtained via stream reader
/// </summary>
/// <value>Reader for received data</value>
public IObjectReader? ObjectReader { get; set; }
internal byte[] SingleObjectPayload
{
get { return bytes ?? []; }
}
/// <summary>
/// The size of payload cannot exceed <c>MaxObjectSize</c> value from <c>NetworkSettings</c>
/// Used only for PutSingleObject method
/// </summary>
/// <value>Buffer for output data</value>
public void SetSingleObjectPayload(byte[] bytes)
{
this.bytes = bytes;
}
/// <summary>
/// Applied only for the last Object in chain in case of manual multipart uploading
/// </summary>
/// <param name="largeObject">Parent for multipart object</param>
public void SetParent(FrostFsObjectHeader largeObjectHeader)
{
if (Header?.Split == null)
throw new InvalidObjectException("The object is not initialized properly");
Header.Split.ParentHeader = largeObjectHeader;
}
}

View file

@ -1,111 +0,0 @@
namespace FrostFS.SDK;
public interface IObjectFilter
{
public FrostFsMatchType MatchType { get; set; }
public string Key { get; set; }
string? GetSerializedValue();
}
public abstract class FrostFsObjectFilter<T>(FrostFsMatchType matchType, string key, T value) : IObjectFilter
{
public FrostFsMatchType MatchType { get; set; } = matchType;
public string Key { get; set; } = key;
public T Value { get; set; } = value;
public string? GetSerializedValue()
{
return Value?.ToString();
}
}
/// <summary>
/// Creates filter to search by Attribute
/// </summary>
/// <param name="matchType">Match type</param>
/// <param name="key">Attribute key</param>
/// <param name="value">Attribute value</param>
public class FilterByAttributePair(FrostFsMatchType matchType, string key, string value) : FrostFsObjectFilter<string>(matchType, key, value) { }
/// <summary>
/// Creates filter to search by ObjectId
/// </summary>
/// <param name="matchType">Match type</param>
/// <param name="objectId">ObjectId</param>
public class FilterByObjectId(FrostFsMatchType matchType, FrostFsObjectId objectId) : FrostFsObjectFilter<FrostFsObjectId>(matchType, Constants.FilterHeaderObjectID, objectId) { }
/// <summary>
/// Creates filter to search by OwnerId
/// </summary>
/// <param name="matchType">Match type</param>
/// <param name="ownerId">ObjectId</param>
public class FilterByOwnerId(FrostFsMatchType matchType, FrostFsOwner ownerId) : FrostFsObjectFilter<FrostFsOwner>(matchType, Constants.FilterHeaderOwnerID, ownerId) { }
/// <summary>
/// Creates filter to search by Version
/// </summary>
/// <param name="matchType">Match type</param>
/// <param name="version">Version</param>
public class FilterByVersion(FrostFsMatchType matchType, FrostFsVersion version) : FrostFsObjectFilter<FrostFsVersion>(matchType, Constants.FilterHeaderVersion, version) { }
/// <summary>
/// Creates filter to search by ContainerId
/// </summary>
/// <param name="matchType">Match type</param>
/// <param name="containerId">ContainerId</param>
public class FilterByContainerId(FrostFsMatchType matchType, FrostFsContainerId containerId) : FrostFsObjectFilter<FrostFsContainerId>(matchType, Constants.FilterHeaderContainerID, containerId) { }
/// <summary>
/// Creates filter to search by creation Epoch
/// </summary>
/// <param name="matchType">Match type</param>
/// <param name="epoch">Creation Epoch</param>
public class FilterByEpoch(FrostFsMatchType matchType, ulong epoch) : FrostFsObjectFilter<ulong>(matchType, Constants.FilterHeaderCreationEpoch, epoch) { }
/// <summary>
/// Creates filter to search by Payload Length
/// </summary>
/// <param name="matchType">Match type</param>
/// <param name="payloadLength">Payload Length</param>
public class FilterByPayloadLength(FrostFsMatchType matchType, ulong payloadLength) : FrostFsObjectFilter<ulong>(matchType, Constants.FilterHeaderPayloadLength, payloadLength) { }
/// <summary>
/// Creates filter to search by Payload Hash
/// </summary>
/// <param name="matchType">Match type</param>
/// <param name="payloadHash">Payload Hash</param>
public class FilterByPayloadHash(FrostFsMatchType matchType, CheckSum payloadHash) : FrostFsObjectFilter<CheckSum>(matchType, Constants.FilterHeaderPayloadHash, payloadHash) { }
/// <summary>
/// Creates filter to search by Parent
/// </summary>
/// <param name="matchType">Match type</param>
/// <param name="parentId">Parent</param>
public class FilterByParent(FrostFsMatchType matchType, FrostFsObjectId parentId) : FrostFsObjectFilter<FrostFsObjectId>(matchType, Constants.FilterHeaderParent, parentId) { }
/// <summary>
/// Creates filter to search by SplitId
/// </summary>
/// <param name="matchType">Match type</param>
/// <param name="splitId">SplitId</param>
public class FilterBySplitId(FrostFsMatchType matchType, SplitId splitId) : FrostFsObjectFilter<SplitId>(matchType, Constants.FilterHeaderSplitID, splitId) { }
/// <summary>
/// Creates filter to search by Payload Hash
/// </summary>
/// <param name="matchType">Match type</param>
/// <param name="ecParentId">Payload Hash</param>
public class FilterByECParent(FrostFsMatchType matchType, FrostFsObjectId ecParentId) : FrostFsObjectFilter<FrostFsObjectId>(matchType, Constants.FilterHeaderECParent, ecParentId) { }
/// <summary>
/// Creates filter to search Root objects
/// </summary>
public class FilterByRootObject() : FrostFsObjectFilter<string>(FrostFsMatchType.Unspecified, Constants.FilterHeaderRoot, string.Empty) { }
/// <summary>
/// Creates filter to search objects that are physically stored on the server
/// </summary
public class FilterByPhysicallyStored() : FrostFsObjectFilter<string>(FrostFsMatchType.Unspecified, Constants.FilterHeaderPhy, string.Empty) { }

View file

@ -1,90 +0,0 @@
using System;
using System.Collections.ObjectModel;
using System.Linq;
using FrostFS.Object;
using FrostFS.SDK.ClientV2.Mappers.GRPC;
namespace FrostFS.SDK;
public class FrostFsObjectHeader(
FrostFsContainerId containerId,
FrostFsObjectType type = FrostFsObjectType.Regular,
FrostFsAttributePair[]? attributes = null,
FrostFsSplit? split = null,
FrostFsOwner? owner = null,
FrostFsVersion? version = null)
{
private Header? header;
private Container.Container.Types.Attribute[]? grpsAttributes;
public ReadOnlyCollection<FrostFsAttributePair>? Attributes { get; internal set; } =
attributes == null ? null :
new ReadOnlyCollection<FrostFsAttributePair>(attributes);
public FrostFsContainerId ContainerId { get; } = containerId;
public ulong PayloadLength { get; set; }
public byte[]? PayloadCheckSum { get; set; }
public FrostFsObjectType ObjectType { get; } = type;
public FrostFsOwner? OwnerId { get; internal set; } = owner;
public FrostFsVersion? Version { get; internal set; } = version;
public FrostFsSplit? Split { get; internal set; } = split;
internal Container.Container.Types.Attribute[]? GetGrpsAttributes()
{
grpsAttributes ??= Attributes?
.Select(a => new Container.Container.Types.Attribute { Key = a.Key, Value = a.Value })
.ToArray();
return grpsAttributes;
}
public Header GetHeader()
{
if (header == null)
{
var objTypeName = ObjectType switch
{
FrostFsObjectType.Regular => Object.ObjectType.Regular,
FrostFsObjectType.Lock => Object.ObjectType.Lock,
FrostFsObjectType.Tombstone => Object.ObjectType.Tombstone,
_ => throw new ArgumentException($"Unknown ObjectType. Value: '{ObjectType}'.")
};
this.header = new Header
{
OwnerId = OwnerId?.ToMessage(),
Version = Version?.ToMessage(),
ContainerId = ContainerId.ToMessage(),
ObjectType = objTypeName,
PayloadLength = PayloadLength
};
if (Attributes != null)
{
foreach (var attribute in Attributes)
{
this.header.Attributes.Add(attribute.ToMessage());
}
}
var split = Split;
if (split != null)
{
this.header.Split = new Header.Types.Split
{
SplitId = split!.SplitId != null ? split.SplitId.GetSplitId() : null
};
}
}
return this.header;
}
}

View file

@ -1,33 +0,0 @@
using System;
using FrostFS.SDK.Cryptography;
namespace FrostFS.SDK;
public class FrostFsObjectId(string id)
{
public string Value { get; } = id;
public static FrostFsObjectId FromHash(byte[] hash)
{
if (hash is null)
{
throw new ArgumentNullException(nameof(hash));
}
if (hash.Length != Constants.Sha256HashLength)
throw new FormatException("ObjectID must be a sha256 hash.");
return new FrostFsObjectId(Base58.Encode(hash));
}
public byte[] ToHash()
{
return Base58.Decode(Value);
}
public override string ToString()
{
return Value;
}
}

View file

@ -1,38 +0,0 @@
using System.Security.Cryptography;
using FrostFS.Refs;
using FrostFS.SDK.ClientV2.Mappers.GRPC;
using FrostFS.SDK.Cryptography;
namespace FrostFS.SDK;
public class FrostFsOwner(string id)
{
private OwnerID? ownerID;
public string Value { get; } = id;
public static FrostFsOwner FromKey(ECDsa key)
{
return new FrostFsOwner(key.PublicKey().PublicKeyToAddress());
}
internal OwnerID OwnerID
{
get
{
ownerID ??= this.ToMessage();
return ownerID;
}
}
public byte[] ToHash()
{
return Base58.Decode(Value);
}
public override string ToString()
{
return Value;
}
}

View file

@ -1,28 +0,0 @@
using System.Collections.ObjectModel;
namespace FrostFS.SDK;
public class FrostFsSplit(SplitId splitId,
FrostFsObjectId? previous = null,
FrostFsObjectId? parent = null,
FrostFsObjectHeader? parentHeader = null,
FrostFsSignature? parentSignature = null,
ReadOnlyCollection<FrostFsObjectId>? children = null)
{
public FrostFsSplit() : this(new SplitId())
{
}
public SplitId SplitId { get; private set; } = splitId;
public FrostFsObjectId? Previous { get; } = previous;
public FrostFsObjectId? Parent { get; } = parent;
public FrostFsSignature? ParentSignature { get; } = parentSignature;
public FrostFsObjectHeader? ParentHeader { get; set; } = parentHeader;
public ReadOnlyCollection<FrostFsObjectId>? Children { get; } = children;
}

View file

@ -1,10 +0,0 @@
using System;
using System.Threading;
using System.Threading.Tasks;
namespace FrostFS.SDK;
public interface IObjectReader : IDisposable
{
Task<ReadOnlyMemory<byte>?> ReadChunk(CancellationToken cancellationToken = default);
}

View file

@ -1,62 +0,0 @@
using System;
using FrostFS.SDK.Cryptography;
using Google.Protobuf;
namespace FrostFS.SDK;
public class SplitId
{
private readonly Guid id;
private ByteString? message;
public SplitId()
{
this.id = Guid.NewGuid();
}
public SplitId(Guid id)
{
this.id = id;
}
private SplitId(byte[] binary)
{
this.id = new Guid(binary);
}
private SplitId(string str)
{
this.id = new Guid(str);
}
public static SplitId CreateFromBinary(byte[] binaryData)
{
return new SplitId(binaryData);
}
public static SplitId CreateFromString(string stringData)
{
return new SplitId(stringData);
}
public override string ToString()
{
return this.id.ToString();
}
public byte[]? ToBinary()
{
if (this.id == Guid.Empty)
return null;
return this.id.ToBytes();
}
public ByteString? GetSplitId()
{
return this.message ??= ByteString.CopyFrom(ToBinary());
}
}

View file

@ -1,14 +0,0 @@
namespace FrostFS.SDK;
public class FrostFsResponseStatus(FrostFsStatusCode code, string? message = null)
{
public FrostFsStatusCode Code { get; set; } = code;
public string Message { get; set; } = message ?? string.Empty;
public bool IsSuccess => Code == FrostFsStatusCode.Success;
public override string ToString()
{
return $"Response status: {Code}. Message: {Message}.";
}
}

View file

@ -1,10 +0,0 @@
namespace FrostFS.SDK;
public class FrostFsSignature()
{
public byte[]? Key { get; set; }
public byte[]? Sign { get; set; }
public SignatureScheme Scheme { get; set; }
}

View file

@ -1,20 +0,0 @@
namespace FrostFS.SDK;
public class MetaHeader(FrostFsVersion version, int epoch, int ttl)
{
public FrostFsVersion Version { get; set; } = version;
public int Epoch { get; set; } = epoch;
public int Ttl { get; set; } = ttl;
public static MetaHeader Default()
{
return new MetaHeader(
new FrostFsVersion(
major: 2,
minor: 13
),
epoch: 0,
ttl: 2
);
}
}

View file

@ -1,6 +0,0 @@
namespace FrostFS.SDK;
public class FrostFsSessionToken(byte[] token)
{
public byte[] Token { get; private set; } = token;
}

View file

@ -1,49 +0,0 @@
using System;
using System.Collections.ObjectModel;
using System.Security.Cryptography;
using System.Threading;
using FrostFS.SDK.Cryptography;
using Google.Protobuf;
using Grpc.Core.Interceptors;
namespace FrostFS.SDK.ClientV2;
public class Context()
{
private ReadOnlyCollection<Interceptor>? interceptors;
private ByteString? publicKeyCache;
public ECDsa? Key { get; set; }
public FrostFsOwner? OwnerId { get; set; }
public FrostFsVersion? Version { get; set; }
public CancellationToken CancellationToken { get; set; }
public TimeSpan Timeout { get; set; }
public DateTime? Deadline => Timeout.Ticks > 0 ? DateTime.UtcNow.Add(Timeout) : null;
public Action<CallStatistics>? Callback { get; set; }
public ReadOnlyCollection<Interceptor>? Interceptors
{
get { return this.interceptors; }
set { this.interceptors = value; }
}
public ByteString? GetPublicKeyCache()
{
if (publicKeyCache == null && Key != null)
{
publicKeyCache = ByteString.CopyFrom(Key.PublicKey());
}
return publicKeyCache;
}
}

View file

@ -1,10 +0,0 @@
using System.Security.Cryptography;
namespace FrostFS.SDK.ClientV2;
public class Credentials(ECDsa key, FrostFsOwner ownerId)
{
public ECDsa Key { get; } = key;
public FrostFsOwner OwnerId { get; } = ownerId;
}

View file

@ -1,11 +0,0 @@
namespace FrostFS.SDK.ClientV2;
public interface IContext
{
/// <summary>
/// The method call can be extended with additional behavior like canceling by timeout or user's request,
/// callbacks, interceptors.
/// </summary>
/// <value>Additional parameters for calling the method</value>
Context? Context { get; set; }
}

View file

@ -1,12 +0,0 @@
namespace FrostFS.SDK.ClientV2;
public interface ISessionToken
{
/// <summary>
/// Object represents token of the FrostFS Object session. A session is opened between any two sides of the
/// system, and implements a mechanism for transferring the power of attorney of actions to another network
/// member. The session has a limited validity period, and applies to a strictly defined set of operations.
/// </summary>
/// <value>Instance of the session obtained from the server</value>
FrostFsSessionToken? SessionToken { get; set; }
}

View file

@ -1,6 +0,0 @@
namespace FrostFS.SDK.ClientV2;
public sealed class PrmApeChainList(FrostFsChainTarget target) : PrmBase
{
public FrostFsChainTarget Target { get; } = target;
}

View file

@ -1,8 +0,0 @@
namespace FrostFS.SDK.ClientV2;
public sealed class PrmApeChainRemove(FrostFsChainTarget target, FrostFsChain chain) : PrmBase
{
public FrostFsChainTarget Target { get; } = target;
public FrostFsChain Chain { get; } = chain;
}

View file

@ -1,8 +0,0 @@
namespace FrostFS.SDK.ClientV2;
public sealed class PrmApeChainAdd(FrostFsChainTarget target, FrostFsChain chain) : PrmBase
{
public FrostFsChainTarget Target { get; } = target;
public FrostFsChain Chain { get; } = chain;
}

View file

@ -1,14 +0,0 @@
using System.Collections.Specialized;
namespace FrostFS.SDK.ClientV2;
public class PrmBase(NameValueCollection? xheaders = null) : IContext
{
/// <summary>
/// FrostFS request X-Headers
/// </summary>
public NameValueCollection XHeaders { get; } = xheaders ?? [];
/// <inheritdoc />
public Context? Context { get; set; }
}

View file

@ -1,17 +0,0 @@
namespace FrostFS.SDK.ClientV2;
public sealed class PrmContainerCreate(FrostFsContainerInfo container) : PrmBase, ISessionToken
{
public FrostFsContainerInfo Container { get; set; } = container;
/// <summary>
/// Since the container becomes available with some delay, it needs to poll the container status
/// </summary>
/// <value>Rules for polling the result</value>
public PrmWait? WaitParams { get; set; }
/// <summary>
/// Blank session token
/// </summary>
public FrostFsSessionToken? SessionToken { get; set; }
}

View file

@ -1,14 +0,0 @@
namespace FrostFS.SDK.ClientV2;
public sealed class PrmContainerDelete(FrostFsContainerId containerId) : PrmBase, ISessionToken
{
public FrostFsContainerId ContainerId { get; set; } = containerId;
/// <summary>
/// Since the container is removed with some delay, it needs to poll the container status
/// </summary>
/// <value>Rules for polling the result</value>
public PrmWait? WaitParams { get; set; }
public FrostFsSessionToken? SessionToken { get; set; }
}

View file

@ -1,6 +0,0 @@
namespace FrostFS.SDK.ClientV2;
public sealed class PrmContainerGet(FrostFsContainerId container) : PrmBase
{
public FrostFsContainerId Container { get; set; } = container;
}

View file

@ -1,5 +0,0 @@
namespace FrostFS.SDK.ClientV2;
public sealed class PrmContainerGetAll() : PrmBase()
{
}

View file

@ -1,5 +0,0 @@
namespace FrostFS.SDK.ClientV2;
public sealed class PrmNetmapSnapshot() : PrmBase
{
}

View file

@ -1,5 +0,0 @@
namespace FrostFS.SDK.ClientV2;
public sealed class PrmNetworkSettings() : PrmBase
{
}

View file

@ -1,5 +0,0 @@
namespace FrostFS.SDK.ClientV2;
public sealed class PrmNodeInfo() : PrmBase
{
}

View file

@ -1,11 +0,0 @@
namespace FrostFS.SDK.ClientV2;
public sealed class PrmObjectDelete(FrostFsContainerId containerId, FrostFsObjectId objectId) : PrmBase, ISessionToken
{
public FrostFsContainerId ContainerId { get; set; } = containerId;
public FrostFsObjectId ObjectId { get; set; } = objectId;
/// <inheritdoc />
public FrostFsSessionToken? SessionToken { get; set; }
}

View file

@ -1,11 +0,0 @@
namespace FrostFS.SDK.ClientV2;
public sealed class PrmObjectGet(FrostFsContainerId containerId, FrostFsObjectId objectId) : PrmBase, ISessionToken
{
public FrostFsContainerId ContainerId { get; set; } = containerId;
public FrostFsObjectId ObjectId { get; set; } = objectId;
/// <inheritdoc />
public FrostFsSessionToken? SessionToken { get; set; }
}

View file

@ -1,11 +0,0 @@
namespace FrostFS.SDK.ClientV2;
public sealed class PrmObjectHeadGet(FrostFsContainerId containerId, FrostFsObjectId objectId) : PrmBase, ISessionToken
{
public FrostFsContainerId ContainerId { get; set; } = containerId;
public FrostFsObjectId ObjectId { get; set; } = objectId;
/// <inheritdoc />
public FrostFsSessionToken? SessionToken { get; set; }
}

View file

@ -1,46 +0,0 @@
using System.IO;
namespace FrostFS.SDK.ClientV2;
public sealed class PrmObjectPut : PrmBase, ISessionToken
{
/// <summary>
/// Need to provide values like <c>ContainerId</c> and <c>ObjectType</c> to create and object.
/// Optional parameters ike <c>Attributes</c> can be provided as well.
/// </summary>
/// <value>Header with required parameters to create an object</value>
public FrostFsObjectHeader? Header { get; set; }
/// <summary>
/// A stream with source data
/// </summary>
public Stream? Payload { get; set; }
/// <summary>
/// Object size is limited. In the data exceeds the limit, the object will be splitted.
/// If the parameter is <c>true</c>, the client side cut is applied. Otherwise, the data is transferred
/// as a stream and will be cut on server side.
/// </summary>
/// <value>Is client cut is applied</value>
public bool ClientCut { get; set; }
/// <summary>
/// Overrides default size of the buffer for stream transferring.
/// </summary>
/// <value>Size of the buffer</value>
public int BufferMaxSize { get; set; }
/// <summary>
/// Allows to define a buffer for chunks to manage by the memory allocation and releasing.
/// </summary>
public byte[]? CustomBuffer { get; set; }
/// <inheritdoc />
public FrostFsSessionToken? SessionToken { get; set; }
internal int MaxObjectSizeCache { get; set; }
internal ulong CurrentStreamPosition { get; set; }
internal ulong FullLength { get; set; }
}

View file

@ -1,21 +0,0 @@
using System.Collections.Generic;
namespace FrostFS.SDK.ClientV2;
public sealed class PrmObjectSearch(FrostFsContainerId containerId, params IObjectFilter[] filters) : PrmBase, ISessionToken
{
/// <summary>
/// Defines container for the search
/// </summary>
/// <value></value>
public FrostFsContainerId ContainerId { get; set; } = containerId;
/// <summary>
/// Defines the search criteria
/// </summary>
/// <value>Collection of filters</value>
public IEnumerable<IObjectFilter> Filters { get; set; } = filters;
/// <inheritdoc />
public FrostFsSessionToken? SessionToken { get; set; }
}

View file

@ -1,6 +0,0 @@
namespace FrostFS.SDK.ClientV2;
public sealed class PrmSessionCreate(ulong expiration) : PrmBase
{
public ulong Expiration { get; set; } = expiration;
}

View file

@ -1,9 +0,0 @@
namespace FrostFS.SDK.ClientV2;
public sealed class PrmSingleObjectPut(FrostFsObject frostFsObject) : PrmBase, ISessionToken
{
public FrostFsObject FrostFsObject { get; set; } = frostFsObject;
/// <inheritdoc />
public FrostFsSessionToken? SessionToken { get; set; }
}

View file

@ -1,24 +0,0 @@
using System;
namespace FrostFS.SDK.ClientV2;
public class PrmWait(TimeSpan timeout, TimeSpan pollInterval)
{
private static TimeSpan DefaultTimeout = TimeSpan.FromSeconds(120);
private static TimeSpan DefaultPollInterval = TimeSpan.FromSeconds(5);
public PrmWait(int timeout, int interval) : this(TimeSpan.FromSeconds(timeout), TimeSpan.FromSeconds(interval))
{
}
public static PrmWait DefaultParams { get; } = new PrmWait(DefaultTimeout, DefaultPollInterval);
public TimeSpan Timeout { get; set; } = timeout.Ticks == 0 ? DefaultTimeout : timeout;
public TimeSpan PollInterval { get; set; } = pollInterval.Ticks == 0 ? DefaultPollInterval : pollInterval;
public DateTime GetDeadline()
{
return DateTime.UtcNow.AddTicks(Timeout.Ticks);
}
}

View file

@ -0,0 +1,40 @@
using System.Security.Cryptography;
using FrostFS.Refs;
using FrostFS.SDK.ClientV2.Mappers.GRPC;
using FrostFS.SDK.ModelsV2;
using FrostFS.Session;
namespace FrostFS.SDK.ClientV2;
public static class RequestConstructor
{
public static void AddMetaHeader(this IRequest request, RequestMetaHeader? metaHeader = null)
{
if (request.MetaHeader is not null) return;
metaHeader ??= MetaHeader.Default().ToGrpcMessage();
request.MetaHeader = metaHeader;
}
public static void AddObjectSessionToken(
this IRequest request,
SessionToken sessionToken,
ContainerID cid,
ObjectID oid,
ObjectSessionContext.Types.Verb verb,
ECDsa key)
{
if (request.MetaHeader.SessionToken is not null) return;
request.MetaHeader.SessionToken = sessionToken;
var ctx = new ObjectSessionContext
{
Target = new ObjectSessionContext.Types.Target
{
Container = cid,
Objects = { oid }
},
Verb = verb
};
request.MetaHeader.SessionToken.Body.Object = ctx;
request.MetaHeader.SessionToken.Signature = key.SignMessagePart(request.MetaHeader.SessionToken.Body);
}
}

View file

@ -0,0 +1,97 @@
using System.Security.Cryptography;
using FrostFS.Refs;
using FrostFS.SDK.Cryptography;
using FrostFS.Session;
using Google.Protobuf;
using Org.BouncyCastle.Asn1.Sec;
using Org.BouncyCastle.Crypto.Digests;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Crypto.Signers;
using Org.BouncyCastle.Math;
namespace FrostFS.SDK.ClientV2
{
public static class RequestSigner
{
public const int RFC6979SignatureSize = 64;
public static byte[] SignRFC6979(this ECDsa key, byte[] data)
{
var digest = new Sha256Digest();
var secp256R1 = SecNamedCurves.GetByName("secp256r1");
var ecParameters = new ECDomainParameters(secp256R1.Curve, secp256R1.G, secp256R1.N);
var privateKey = new ECPrivateKeyParameters(new BigInteger(1, key.PrivateKey()), ecParameters);
var signer = new ECDsaSigner(new HMacDsaKCalculator(digest));
var hash = new byte[digest.GetDigestSize()];
digest.BlockUpdate(data, 0, data.Length);
digest.DoFinal(hash, 0);
signer.Init(true, privateKey);
var rs = signer.GenerateSignature(hash);
var signature = new byte[RFC6979SignatureSize];
var rbytes = rs[0].ToByteArrayUnsigned();
var sbytes = rs[1].ToByteArrayUnsigned();
var index = RFC6979SignatureSize / 2 - rbytes.Length;
rbytes.CopyTo(signature, index);
index = RFC6979SignatureSize - sbytes.Length;
sbytes.CopyTo(signature, index);
return signature;
}
public static SignatureRFC6979 SignRFC6979(this ECDsa key, IMessage message)
{
return new SignatureRFC6979
{
Key = ByteString.CopyFrom(key.PublicKey()),
Sign = ByteString.CopyFrom(key.SignRFC6979(message.ToByteArray())),
};
}
public static SignatureRFC6979 SignRFC6979(this ECDsa key, ByteString data)
{
return new SignatureRFC6979
{
Key = ByteString.CopyFrom(key.PublicKey()),
Sign = ByteString.CopyFrom(key.SignRFC6979(data.ToByteArray())),
};
}
public static byte[] SignData(this ECDsa key, byte[] data)
{
var hash = new byte[65];
hash[0] = 0x04;
key
.SignHash(SHA512.Create().ComputeHash(data))
.CopyTo(hash, 1);
return hash;
}
public static Signature SignMessagePart(this ECDsa key, IMessage? data)
{
var data2Sign = data is null ? Array.Empty<byte>() : data.ToByteArray();
var sig = new Signature
{
Key = ByteString.CopyFrom(key.PublicKey()),
Sign = ByteString.CopyFrom(key.SignData(data2Sign)),
};
return sig;
}
public static void Sign(this IVerificableMessage message, ECDsa key)
{
var meta = message.GetMetaHeader();
IVerificationHeader verify = message switch
{
IRequest => new RequestVerificationHeader(),
IResponse => new ResponseVerificationHeader(),
_ => throw new InvalidOperationException("Unsopported message type")
};
var verifyOrigin = message.GetVerificationHeader();
if (verifyOrigin is null)
verify.BodySignature = key.SignMessagePart(message.GetBody());
verify.MetaSignature = key.SignMessagePart(meta);
verify.OriginSignature = key.SignMessagePart(verifyOrigin);
verify.SetOrigin(verifyOrigin);
message.SetVerificationHeader(verify);
}
}
}

Some files were not shown because too many files have changed in this diff Show more