[#13] Client: Use code analyzers
All checks were successful
DCO / DCO (pull_request) Successful in 35s
All checks were successful
DCO / DCO (pull_request) Successful in 35s
Signed-off-by: Pavel Gross <p.gross@yadro.com>
This commit is contained in:
parent
d7dbbf8da8
commit
d1271df207
102 changed files with 2168 additions and 733 deletions
901
.editorconfig
Normal file
901
.editorconfig
Normal file
|
@ -0,0 +1,901 @@
|
||||||
|
[*.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
|
|
@ -1,6 +1,8 @@
|
||||||
|
|
||||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
# Visual Studio Version 17
|
||||||
VisualStudioVersion = 17.5.002.0
|
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("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FrostFS.SDK.ClientV2", "src\FrostFS.SDK.ClientV2\FrostFS.SDK.ClientV2.csproj", "{50D8F61F-C302-4AC9-8D8A-AB0B8C0988C3}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FrostFS.SDK.Cryptography", "src\FrostFS.SDK.Cryptography\FrostFS.SDK.Cryptography.csproj", "{3D804F4A-B0B2-47A5-B006-BE447BE64B50}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FrostFS.SDK.Cryptography", "src\FrostFS.SDK.Cryptography\FrostFS.SDK.Cryptography.csproj", "{3D804F4A-B0B2-47A5-B006-BE447BE64B50}"
|
||||||
|
@ -9,6 +11,11 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FrostFS.SDK.ProtosV2", "src
|
||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FrostFS.SDK.Tests", "src\FrostFS.SDK.Tests\FrostFS.SDK.Tests.csproj", "{8FDA7E0D-9C75-4874-988E-6592CD28F76C}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FrostFS.SDK.Tests", "src\FrostFS.SDK.Tests\FrostFS.SDK.Tests.csproj", "{8FDA7E0D-9C75-4874-988E-6592CD28F76C}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{2F030ACD-F87C-4E83-9A68-4CC5DF03AD90}"
|
||||||
|
ProjectSection(SolutionItems) = preProject
|
||||||
|
.editorconfig = .editorconfig
|
||||||
|
EndProjectSection
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
@ -32,4 +39,7 @@ Global
|
||||||
{8FDA7E0D-9C75-4874-988E-6592CD28F76C}.Release|Any CPU.ActiveCfg = Release|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
|
{8FDA7E0D-9C75-4874-988E-6592CD28F76C}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
|
HideSolutionNode = FALSE
|
||||||
|
EndGlobalSection
|
||||||
EndGlobal
|
EndGlobal
|
||||||
|
|
18
src/FrostFS.SDK.ClientV2/Exceptions/FrostFsException.cs
Normal file
18
src/FrostFS.SDK.ClientV2/Exceptions/FrostFsException.cs
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,6 +2,17 @@ using System;
|
||||||
|
|
||||||
namespace FrostFS.SDK.ClientV2;
|
namespace FrostFS.SDK.ClientV2;
|
||||||
|
|
||||||
public class InvalidObjectException() : Exception()
|
public class InvalidObjectException : Exception
|
||||||
{
|
{
|
||||||
|
public InvalidObjectException()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public InvalidObjectException(string message) : base(message)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public InvalidObjectException(string message, Exception innerException) : base(message, innerException)
|
||||||
|
{
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -2,7 +2,24 @@ using System;
|
||||||
|
|
||||||
namespace FrostFS.SDK.ClientV2;
|
namespace FrostFS.SDK.ClientV2;
|
||||||
|
|
||||||
public class ResponseException(FrostFsResponseStatus status) : Exception()
|
public class ResponseException : Exception
|
||||||
{
|
{
|
||||||
public FrostFsResponseStatus Status { get; set; } = status;
|
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)
|
||||||
|
{
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -4,14 +4,23 @@
|
||||||
<TargetFramework>netstandard2.0</TargetFramework>
|
<TargetFramework>netstandard2.0</TargetFramework>
|
||||||
<LangVersion>12.0</LangVersion>
|
<LangVersion>12.0</LangVersion>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
|
<AnalysisMode>AllEnabledByDefault</AnalysisMode>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<EnableNETAnalyzers>true</EnableNETAnalyzers>
|
<EnableNETAnalyzers>true</EnableNETAnalyzers>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<CodeAnalysisTreatWarningsAsErrors>true</CodeAnalysisTreatWarningsAsErrors>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="8.0.0" />
|
<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.Abstractions" Version="8.0.0" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Caching.Memory" 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="Microsoft.Extensions.Options" Version="8.0.2" />
|
||||||
|
|
|
@ -3,6 +3,9 @@ using System.Collections.Generic;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
using Frostfs.V2.Ape;
|
||||||
|
using Frostfs.V2.Apemanager;
|
||||||
|
|
||||||
using FrostFS.Container;
|
using FrostFS.Container;
|
||||||
using FrostFS.Netmap;
|
using FrostFS.Netmap;
|
||||||
using FrostFS.Object;
|
using FrostFS.Object;
|
||||||
|
@ -15,35 +18,33 @@ using Grpc.Core.Interceptors;
|
||||||
using Grpc.Net.Client;
|
using Grpc.Net.Client;
|
||||||
|
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using Frostfs.V2.Apemanager;
|
|
||||||
using Frostfs.V2.Ape;
|
|
||||||
|
|
||||||
namespace FrostFS.SDK.ClientV2;
|
namespace FrostFS.SDK.ClientV2;
|
||||||
|
|
||||||
public class Client : IFrostFSClient
|
public class FrostFSClient : IFrostFSClient
|
||||||
{
|
{
|
||||||
private bool isDisposed;
|
private bool isDisposed;
|
||||||
|
|
||||||
internal ContainerService.ContainerServiceClient? ContainerServiceClient { get; set; }
|
internal ContainerService.ContainerServiceClient? ContainerServiceClient { get; set; }
|
||||||
|
|
||||||
internal NetmapService.NetmapServiceClient? NetmapServiceClient { get; set; }
|
internal NetmapService.NetmapServiceClient? NetmapServiceClient { get; set; }
|
||||||
|
|
||||||
internal APEManagerService.APEManagerServiceClient? ApeManagerServiceClient { get; set; }
|
internal APEManagerService.APEManagerServiceClient? ApeManagerServiceClient { get; set; }
|
||||||
|
|
||||||
internal SessionService.SessionServiceClient? SessionServiceClient { get; set; }
|
internal SessionService.SessionServiceClient? SessionServiceClient { get; set; }
|
||||||
|
|
||||||
internal ObjectService.ObjectServiceClient? ObjectServiceClient { get; set; }
|
internal ObjectService.ObjectServiceClient? ObjectServiceClient { get; set; }
|
||||||
|
|
||||||
internal ClientEnvironment ClientCtx { get; set; }
|
internal ClientEnvironment ClientCtx { get; set; }
|
||||||
|
|
||||||
public static IFrostFSClient GetInstance(IOptions<ClientSettings> clientOptions, GrpcChannelOptions? channelOptions = null)
|
public static IFrostFSClient GetInstance(IOptions<ClientSettings> clientOptions, GrpcChannelOptions? channelOptions = null)
|
||||||
{
|
{
|
||||||
return new Client(clientOptions, channelOptions);
|
return new FrostFSClient(clientOptions, channelOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IFrostFSClient GetSingleOwnerInstance(IOptions<SingleOwnerClientSettings> clientOptions, GrpcChannelOptions? channelOptions = null)
|
public static IFrostFSClient GetSingleOwnerInstance(IOptions<SingleOwnerClientSettings> clientOptions, GrpcChannelOptions? channelOptions = null)
|
||||||
{
|
{
|
||||||
return new Client(clientOptions, channelOptions);
|
return new FrostFSClient(clientOptions, channelOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -64,10 +65,15 @@ public class Client : IFrostFSClient
|
||||||
ContainerService.ContainerServiceClient containerService,
|
ContainerService.ContainerServiceClient containerService,
|
||||||
ObjectService.ObjectServiceClient objectService)
|
ObjectService.ObjectServiceClient objectService)
|
||||||
{
|
{
|
||||||
return new Client(clientOptions, channelOptions, containerService, netmapService, sessionService, objectService);
|
if (clientOptions is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(clientOptions));
|
||||||
|
}
|
||||||
|
|
||||||
|
return new FrostFSClient(clientOptions, channelOptions, containerService, netmapService, sessionService, objectService);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Client(
|
private FrostFSClient(
|
||||||
IOptions<SingleOwnerClientSettings> settings,
|
IOptions<SingleOwnerClientSettings> settings,
|
||||||
GrpcChannelOptions? channelOptions,
|
GrpcChannelOptions? channelOptions,
|
||||||
ContainerService.ContainerServiceClient containerService,
|
ContainerService.ContainerServiceClient containerService,
|
||||||
|
@ -75,6 +81,11 @@ public class Client : IFrostFSClient
|
||||||
SessionService.SessionServiceClient sessionService,
|
SessionService.SessionServiceClient sessionService,
|
||||||
ObjectService.ObjectServiceClient objectService)
|
ObjectService.ObjectServiceClient objectService)
|
||||||
{
|
{
|
||||||
|
if (settings is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(settings));
|
||||||
|
}
|
||||||
|
|
||||||
var ecdsaKey = settings.Value.Key.LoadWif();
|
var ecdsaKey = settings.Value.Key.LoadWif();
|
||||||
FrostFsOwner.FromKey(ecdsaKey);
|
FrostFsOwner.FromKey(ecdsaKey);
|
||||||
|
|
||||||
|
@ -85,13 +96,13 @@ public class Client : IFrostFSClient
|
||||||
channel: InitGrpcChannel(settings.Value.Host, channelOptions),
|
channel: InitGrpcChannel(settings.Value.Host, channelOptions),
|
||||||
version: new FrostFsVersion(2, 13));
|
version: new FrostFsVersion(2, 13));
|
||||||
|
|
||||||
ContainerServiceClient = containerService;
|
ContainerServiceClient = containerService ?? throw new ArgumentNullException(nameof(containerService));
|
||||||
NetmapServiceClient = netmapService;
|
NetmapServiceClient = netmapService ?? throw new ArgumentNullException(nameof(netmapService));
|
||||||
SessionServiceClient = sessionService;
|
SessionServiceClient = sessionService ?? throw new ArgumentNullException(nameof(sessionService));
|
||||||
ObjectServiceClient = objectService;
|
ObjectServiceClient = objectService ?? throw new ArgumentNullException(nameof(objectService));
|
||||||
}
|
}
|
||||||
|
|
||||||
private Client(IOptions<ClientSettings> options, GrpcChannelOptions? channelOptions)
|
private FrostFSClient(IOptions<ClientSettings> options, GrpcChannelOptions? channelOptions)
|
||||||
{
|
{
|
||||||
var clientSettings = (options?.Value) ?? throw new ArgumentException("Options must be initialized");
|
var clientSettings = (options?.Value) ?? throw new ArgumentException("Options must be initialized");
|
||||||
|
|
||||||
|
@ -110,14 +121,14 @@ public class Client : IFrostFSClient
|
||||||
// CheckFrostFsVersionSupport(new Context { Timeout = TimeSpan.FromSeconds(20) });
|
// CheckFrostFsVersionSupport(new Context { Timeout = TimeSpan.FromSeconds(20) });
|
||||||
}
|
}
|
||||||
|
|
||||||
private Client(IOptions<SingleOwnerClientSettings> options, GrpcChannelOptions? channelOptions)
|
private FrostFSClient(IOptions<SingleOwnerClientSettings> options, GrpcChannelOptions? channelOptions)
|
||||||
{
|
{
|
||||||
var clientSettings = (options?.Value) ?? throw new ArgumentException("Options must be initialized");
|
var clientSettings = (options?.Value) ?? throw new ArgumentException("Options must be initialized");
|
||||||
|
|
||||||
clientSettings.Validate();
|
clientSettings.Validate();
|
||||||
|
|
||||||
var ecdsaKey = clientSettings.Key.LoadWif();
|
var ecdsaKey = clientSettings.Key.LoadWif();
|
||||||
|
|
||||||
var channel = InitGrpcChannel(clientSettings.Host, channelOptions);
|
var channel = InitGrpcChannel(clientSettings.Host, channelOptions);
|
||||||
|
|
||||||
ClientCtx = new ClientEnvironment(
|
ClientCtx = new ClientEnvironment(
|
||||||
|
@ -128,7 +139,7 @@ public class Client : IFrostFSClient
|
||||||
version: new FrostFsVersion(2, 13));
|
version: new FrostFsVersion(2, 13));
|
||||||
|
|
||||||
// TODO: define timeout logic
|
// TODO: define timeout logic
|
||||||
CheckFrostFsVersionSupport(new Context { Timeout = TimeSpan.FromSeconds(20)});
|
// CheckFrostFsVersionSupport(new Context { Timeout = TimeSpan.FromSeconds(20) });
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
|
@ -149,18 +160,31 @@ public class Client : IFrostFSClient
|
||||||
#region ApeManagerImplementation
|
#region ApeManagerImplementation
|
||||||
public Task<byte[]> AddChainAsync(PrmApeChainAdd args)
|
public Task<byte[]> AddChainAsync(PrmApeChainAdd args)
|
||||||
{
|
{
|
||||||
|
if (args is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(args));
|
||||||
|
}
|
||||||
|
|
||||||
var service = GetApeManagerService(args);
|
var service = GetApeManagerService(args);
|
||||||
return service.AddChainAsync(args);
|
return service.AddChainAsync(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task RemoveChainAsync(PrmApeChainRemove args)
|
public Task RemoveChainAsync(PrmApeChainRemove args)
|
||||||
{
|
{
|
||||||
|
if (args is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(args));
|
||||||
|
}
|
||||||
|
|
||||||
var service = GetApeManagerService(args);
|
var service = GetApeManagerService(args);
|
||||||
return service.RemoveChainAsync(args);
|
return service.RemoveChainAsync(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<Chain[]> ListChainAsync(PrmApeChainList args)
|
public Task<Chain[]> ListChainAsync(PrmApeChainList args)
|
||||||
{
|
{
|
||||||
|
if (args is null)
|
||||||
|
throw new ArgumentNullException(nameof(args));
|
||||||
|
|
||||||
var service = GetApeManagerService(args);
|
var service = GetApeManagerService(args);
|
||||||
return service.ListChainAsync(args);
|
return service.ListChainAsync(args);
|
||||||
}
|
}
|
||||||
|
@ -169,6 +193,9 @@ public class Client : IFrostFSClient
|
||||||
#region ContainerImplementation
|
#region ContainerImplementation
|
||||||
public Task<FrostFsContainerInfo> GetContainerAsync(PrmContainerGet args)
|
public Task<FrostFsContainerInfo> GetContainerAsync(PrmContainerGet args)
|
||||||
{
|
{
|
||||||
|
if (args is null)
|
||||||
|
throw new ArgumentNullException(nameof(args));
|
||||||
|
|
||||||
var service = GetContainerService(args);
|
var service = GetContainerService(args);
|
||||||
return service.GetContainerAsync(args);
|
return service.GetContainerAsync(args);
|
||||||
}
|
}
|
||||||
|
@ -176,18 +203,24 @@ public class Client : IFrostFSClient
|
||||||
public IAsyncEnumerable<FrostFsContainerId> ListContainersAsync(PrmContainerGetAll? args = null)
|
public IAsyncEnumerable<FrostFsContainerId> ListContainersAsync(PrmContainerGetAll? args = null)
|
||||||
{
|
{
|
||||||
args ??= new PrmContainerGetAll();
|
args ??= new PrmContainerGetAll();
|
||||||
var service = GetContainerService(args);
|
var service = GetContainerService(args);
|
||||||
return service.ListContainersAsync(args);
|
return service.ListContainersAsync(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<FrostFsContainerId> CreateContainerAsync(PrmContainerCreate args)
|
public Task<FrostFsContainerId> CreateContainerAsync(PrmContainerCreate args)
|
||||||
{
|
{
|
||||||
|
if (args is null)
|
||||||
|
throw new ArgumentNullException(nameof(args));
|
||||||
|
|
||||||
var service = GetContainerService(args);
|
var service = GetContainerService(args);
|
||||||
return service.CreateContainerAsync(args);
|
return service.CreateContainerAsync(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task DeleteContainerAsync(PrmContainerDelete args)
|
public Task DeleteContainerAsync(PrmContainerDelete args)
|
||||||
{
|
{
|
||||||
|
if (args is null)
|
||||||
|
throw new ArgumentNullException(nameof(args));
|
||||||
|
|
||||||
var service = GetContainerService(args);
|
var service = GetContainerService(args);
|
||||||
return service.DeleteContainerAsync(args);
|
return service.DeleteContainerAsync(args);
|
||||||
}
|
}
|
||||||
|
@ -219,36 +252,54 @@ public class Client : IFrostFSClient
|
||||||
#region ObjectImplementation
|
#region ObjectImplementation
|
||||||
public Task<FrostFsObjectHeader> GetObjectHeadAsync(PrmObjectHeadGet args)
|
public Task<FrostFsObjectHeader> GetObjectHeadAsync(PrmObjectHeadGet args)
|
||||||
{
|
{
|
||||||
|
if (args is null)
|
||||||
|
throw new ArgumentNullException(nameof(args));
|
||||||
|
|
||||||
var service = GetObjectService(args);
|
var service = GetObjectService(args);
|
||||||
return service.GetObjectHeadAsync(args);
|
return service.GetObjectHeadAsync(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<FrostFsObject> GetObjectAsync(PrmObjectGet args)
|
public Task<FrostFsObject> GetObjectAsync(PrmObjectGet args)
|
||||||
{
|
{
|
||||||
|
if (args is null)
|
||||||
|
throw new ArgumentNullException(nameof(args));
|
||||||
|
|
||||||
var service = GetObjectService(args);
|
var service = GetObjectService(args);
|
||||||
return service.GetObjectAsync(args);
|
return service.GetObjectAsync(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<FrostFsObjectId> PutObjectAsync(PrmObjectPut args)
|
public Task<FrostFsObjectId> PutObjectAsync(PrmObjectPut args)
|
||||||
{
|
{
|
||||||
|
if (args is null)
|
||||||
|
throw new ArgumentNullException(nameof(args));
|
||||||
|
|
||||||
var service = GetObjectService(args);
|
var service = GetObjectService(args);
|
||||||
return service.PutObjectAsync(args);
|
return service.PutObjectAsync(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<FrostFsObjectId> PutSingleObjectAsync(PrmSingleObjectPut args)
|
public Task<FrostFsObjectId> PutSingleObjectAsync(PrmSingleObjectPut args)
|
||||||
{
|
{
|
||||||
|
if (args is null)
|
||||||
|
throw new ArgumentNullException(nameof(args));
|
||||||
|
|
||||||
var service = GetObjectService(args);
|
var service = GetObjectService(args);
|
||||||
return service.PutSingleObjectAsync(args);
|
return service.PutSingleObjectAsync(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task DeleteObjectAsync(PrmObjectDelete args)
|
public Task DeleteObjectAsync(PrmObjectDelete args)
|
||||||
{
|
{
|
||||||
|
if (args is null)
|
||||||
|
throw new ArgumentNullException(nameof(args));
|
||||||
|
|
||||||
var service = GetObjectService(args);
|
var service = GetObjectService(args);
|
||||||
return service.DeleteObjectAsync(args);
|
return service.DeleteObjectAsync(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
public IAsyncEnumerable<FrostFsObjectId> SearchObjectsAsync(PrmObjectSearch args)
|
public IAsyncEnumerable<FrostFsObjectId> SearchObjectsAsync(PrmObjectSearch args)
|
||||||
{
|
{
|
||||||
|
if (args is null)
|
||||||
|
throw new ArgumentNullException(nameof(args));
|
||||||
|
|
||||||
var service = GetObjectService(args);
|
var service = GetObjectService(args);
|
||||||
return service.SearchObjectsAsync(args);
|
return service.SearchObjectsAsync(args);
|
||||||
}
|
}
|
||||||
|
@ -257,17 +308,23 @@ public class Client : IFrostFSClient
|
||||||
#region SessionImplementation
|
#region SessionImplementation
|
||||||
public async Task<FrostFsSessionToken> CreateSessionAsync(PrmSessionCreate args)
|
public async Task<FrostFsSessionToken> CreateSessionAsync(PrmSessionCreate args)
|
||||||
{
|
{
|
||||||
var session = await CreateSessionInternalAsync(args);
|
if (args is null)
|
||||||
|
throw new ArgumentNullException(nameof(args));
|
||||||
|
|
||||||
|
var session = await CreateSessionInternalAsync(args).ConfigureAwait(false);
|
||||||
var token = session.Serialize();
|
var token = session.Serialize();
|
||||||
|
|
||||||
return new FrostFsSessionToken(token);
|
return new FrostFsSessionToken(token);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal Task<Session.SessionToken> CreateSessionInternalAsync(PrmSessionCreate args)
|
internal Task<SessionToken> CreateSessionInternalAsync(PrmSessionCreate args)
|
||||||
{
|
{
|
||||||
|
if (args is null)
|
||||||
|
throw new ArgumentNullException(nameof(args));
|
||||||
|
|
||||||
var service = GetSessionService(args);
|
var service = GetSessionService(args);
|
||||||
return service.CreateSessionAsync(args);
|
return service.CreateSessionAsync(args);
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region ToolsImplementation
|
#region ToolsImplementation
|
||||||
|
@ -283,20 +340,24 @@ public class Client : IFrostFSClient
|
||||||
private async void CheckFrostFsVersionSupport(Context? ctx = default)
|
private async void CheckFrostFsVersionSupport(Context? ctx = default)
|
||||||
{
|
{
|
||||||
var args = new PrmNodeInfo { Context = ctx };
|
var args = new PrmNodeInfo { Context = ctx };
|
||||||
|
|
||||||
|
if (ctx?.Version == null)
|
||||||
|
throw new InvalidObjectException(nameof(ctx.Version));
|
||||||
|
|
||||||
var service = GetNetmapService(args);
|
var service = GetNetmapService(args);
|
||||||
var localNodeInfo = await service.GetLocalNodeInfoAsync(args);
|
var localNodeInfo = await service.GetLocalNodeInfoAsync(args).ConfigureAwait(false);
|
||||||
|
|
||||||
if (!localNodeInfo.Version.IsSupported(args.Context!.Version))
|
if (!localNodeInfo.Version.IsSupported(ctx.Version))
|
||||||
{
|
{
|
||||||
var msg = $"FrostFS {localNodeInfo.Version} is not supported.";
|
var msg = $"FrostFS {localNodeInfo.Version} is not supported.";
|
||||||
throw new ApplicationException(msg);
|
throw new FrostFsException(msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private CallInvoker? SetupEnvironment(IContext ctx)
|
private CallInvoker? SetupEnvironment(IContext ctx)
|
||||||
{
|
{
|
||||||
if (isDisposed)
|
if (isDisposed)
|
||||||
throw new Exception("Client is disposed.");
|
throw new InvalidObjectException("Client is disposed.");
|
||||||
|
|
||||||
ctx.Context ??= new Context();
|
ctx.Context ??= new Context();
|
||||||
|
|
||||||
|
@ -304,14 +365,14 @@ public class Client : IFrostFSClient
|
||||||
{
|
{
|
||||||
if (ClientCtx.Key == null)
|
if (ClientCtx.Key == null)
|
||||||
{
|
{
|
||||||
throw new Exception("Key is not initialized.");
|
throw new InvalidObjectException("Key is not initialized.");
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.Context.Key = ClientCtx.Key.ECDsaKey;
|
ctx.Context.Key = ClientCtx.Key.ECDsaKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ctx.Context.OwnerId == null)
|
if (ctx.Context.OwnerId == null)
|
||||||
{
|
{
|
||||||
ctx.Context.OwnerId = ClientCtx.Owner ?? FrostFsOwner.FromKey(ctx.Context.Key);
|
ctx.Context.OwnerId = ClientCtx.Owner ?? FrostFsOwner.FromKey(ctx.Context.Key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -319,7 +380,7 @@ public class Client : IFrostFSClient
|
||||||
{
|
{
|
||||||
if (ClientCtx.Version == null)
|
if (ClientCtx.Version == null)
|
||||||
{
|
{
|
||||||
throw new Exception("Version is not initialized.");
|
throw new InvalidObjectException("Version is not initialized.");
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.Context.Version = ClientCtx.Version;
|
ctx.Context.Version = ClientCtx.Version;
|
||||||
|
@ -336,7 +397,7 @@ public class Client : IFrostFSClient
|
||||||
|
|
||||||
if (ctx.Context.Callback != null)
|
if (ctx.Context.Callback != null)
|
||||||
callInvoker = AddInvoker(callInvoker, new MetricsInterceptor(ctx.Context.Callback));
|
callInvoker = AddInvoker(callInvoker, new MetricsInterceptor(ctx.Context.Callback));
|
||||||
|
|
||||||
return callInvoker;
|
return callInvoker;
|
||||||
|
|
||||||
CallInvoker AddInvoker(CallInvoker? callInvoker, Interceptor interceptor)
|
CallInvoker AddInvoker(CallInvoker? callInvoker, Interceptor interceptor)
|
||||||
|
@ -382,7 +443,7 @@ public class Client : IFrostFSClient
|
||||||
|
|
||||||
private ContainerServiceProvider GetContainerService(IContext ctx)
|
private ContainerServiceProvider GetContainerService(IContext ctx)
|
||||||
{
|
{
|
||||||
var callInvoker = SetupEnvironment(ctx);
|
var callInvoker = SetupEnvironment(ctx);
|
||||||
var client = ContainerServiceClient ?? (callInvoker != null
|
var client = ContainerServiceClient ?? (callInvoker != null
|
||||||
? new ContainerService.ContainerServiceClient(callInvoker)
|
? new ContainerService.ContainerServiceClient(callInvoker)
|
||||||
: new ContainerService.ContainerServiceClient(ClientCtx.Channel));
|
: new ContainerService.ContainerServiceClient(ClientCtx.Channel));
|
||||||
|
@ -408,7 +469,7 @@ public class Client : IFrostFSClient
|
||||||
|
|
||||||
if (channelOptions != null)
|
if (channelOptions != null)
|
||||||
return GrpcChannel.ForAddress(uri, channelOptions);
|
return GrpcChannel.ForAddress(uri, channelOptions);
|
||||||
|
|
||||||
return GrpcChannel.ForAddress(uri, new GrpcChannelOptions
|
return GrpcChannel.ForAddress(uri, new GrpcChannelOptions
|
||||||
{
|
{
|
||||||
HttpHandler = new HttpClientHandler()
|
HttpHandler = new HttpClientHandler()
|
|
@ -14,6 +14,11 @@ public class MetricsInterceptor(Action<CallStatistics> callback) : Interceptor
|
||||||
ClientInterceptorContext<TRequest, TResponse> context,
|
ClientInterceptorContext<TRequest, TResponse> context,
|
||||||
AsyncUnaryCallContinuation<TRequest, TResponse> continuation)
|
AsyncUnaryCallContinuation<TRequest, TResponse> continuation)
|
||||||
{
|
{
|
||||||
|
if (continuation is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(continuation));
|
||||||
|
}
|
||||||
|
|
||||||
var call = continuation(request, context);
|
var call = continuation(request, context);
|
||||||
|
|
||||||
return new AsyncUnaryCall<TResponse>(
|
return new AsyncUnaryCall<TResponse>(
|
||||||
|
@ -28,7 +33,10 @@ public class MetricsInterceptor(Action<CallStatistics> callback) : Interceptor
|
||||||
ClientInterceptorContext<TRequest, TResponse> context,
|
ClientInterceptorContext<TRequest, TResponse> context,
|
||||||
AsyncClientStreamingCallContinuation<TRequest, TResponse> continuation)
|
AsyncClientStreamingCallContinuation<TRequest, TResponse> continuation)
|
||||||
{
|
{
|
||||||
var call = continuation(context);
|
if (continuation is null)
|
||||||
|
throw new ArgumentNullException(nameof(continuation));
|
||||||
|
|
||||||
|
var call = continuation(context);
|
||||||
|
|
||||||
return new AsyncClientStreamingCall<TRequest, TResponse>(
|
return new AsyncClientStreamingCall<TRequest, TResponse>(
|
||||||
call.RequestStream,
|
call.RequestStream,
|
||||||
|
@ -43,31 +51,31 @@ public class MetricsInterceptor(Action<CallStatistics> callback) : Interceptor
|
||||||
{
|
{
|
||||||
var watch = new Stopwatch();
|
var watch = new Stopwatch();
|
||||||
watch.Start();
|
watch.Start();
|
||||||
|
|
||||||
var response = await call.ResponseAsync;
|
var response = await call.ResponseAsync.ConfigureAwait(false);
|
||||||
|
|
||||||
watch.Stop();
|
watch.Stop();
|
||||||
|
|
||||||
var elapsed = watch.ElapsedTicks * 1_000_000/Stopwatch.Frequency;
|
var elapsed = watch.ElapsedTicks * 1_000_000 / Stopwatch.Frequency;
|
||||||
|
|
||||||
callback(new CallStatistics { MethodName = call.ToString(), ElapsedMicroSeconds = elapsed });
|
callback(new CallStatistics { MethodName = call.ToString(), ElapsedMicroSeconds = elapsed });
|
||||||
|
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<TResponse> HandleStreamResponse<TRequest, TResponse>(AsyncClientStreamingCall<TRequest, TResponse> call)
|
private async Task<TResponse> HandleStreamResponse<TRequest, TResponse>(AsyncClientStreamingCall<TRequest, TResponse> call)
|
||||||
{
|
{
|
||||||
var watch = new Stopwatch();
|
var watch = new Stopwatch();
|
||||||
watch.Start();
|
watch.Start();
|
||||||
|
|
||||||
var response = await call.ResponseAsync;
|
var response = await call.ResponseAsync.ConfigureAwait(false);
|
||||||
|
|
||||||
watch.Stop();
|
watch.Stop();
|
||||||
|
|
||||||
var elapsed = watch.ElapsedTicks * 1_000_000/Stopwatch.Frequency;
|
var elapsed = watch.ElapsedTicks * 1_000_000 / Stopwatch.Frequency;
|
||||||
|
|
||||||
callback(new CallStatistics { MethodName = call.ToString(), ElapsedMicroSeconds = elapsed });
|
callback(new CallStatistics { MethodName = call.ToString(), ElapsedMicroSeconds = elapsed });
|
||||||
|
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,21 +36,21 @@ public interface IFrostFSClient : IDisposable
|
||||||
|
|
||||||
Task DeleteContainerAsync(PrmContainerDelete args);
|
Task DeleteContainerAsync(PrmContainerDelete args);
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Object
|
#region Object
|
||||||
Task<FrostFsObjectHeader> GetObjectHeadAsync(PrmObjectHeadGet args);
|
Task<FrostFsObjectHeader> GetObjectHeadAsync(PrmObjectHeadGet args);
|
||||||
|
|
||||||
Task<FrostFsObject> GetObjectAsync(PrmObjectGet args);
|
Task<FrostFsObject> GetObjectAsync(PrmObjectGet args);
|
||||||
|
|
||||||
Task<FrostFsObjectId> PutObjectAsync(PrmObjectPut args);
|
Task<FrostFsObjectId> PutObjectAsync(PrmObjectPut args);
|
||||||
|
|
||||||
Task<FrostFsObjectId> PutSingleObjectAsync(PrmSingleObjectPut args);
|
Task<FrostFsObjectId> PutSingleObjectAsync(PrmSingleObjectPut args);
|
||||||
|
|
||||||
Task DeleteObjectAsync(PrmObjectDelete args);
|
Task DeleteObjectAsync(PrmObjectDelete args);
|
||||||
|
|
||||||
IAsyncEnumerable<FrostFsObjectId> SearchObjectsAsync(PrmObjectSearch args);
|
IAsyncEnumerable<FrostFsObjectId> SearchObjectsAsync(PrmObjectSearch args);
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Tools
|
#region Tools
|
||||||
FrostFsObjectId CalculateObjectId(FrostFsObjectHeader header, Context ctx);
|
FrostFsObjectId CalculateObjectId(FrostFsObjectHeader header, Context ctx);
|
||||||
#endregion
|
#endregion
|
||||||
|
|
|
@ -9,14 +9,12 @@ public static class ContainerMapper
|
||||||
{
|
{
|
||||||
public static FrostFsContainerInfo ToModel(this Container.Container container)
|
public static FrostFsContainerInfo ToModel(this Container.Container container)
|
||||||
{
|
{
|
||||||
if (!Enum.IsDefined(typeof(BasicAcl),(int)container.BasicAcl))
|
if (container == null)
|
||||||
throw new ArgumentException($"Unknown BasicACL rule. Value: '{container.BasicAcl}'.");
|
throw new ArgumentNullException(nameof(container));
|
||||||
|
|
||||||
BasicAcl acl = (BasicAcl)container.BasicAcl;
|
|
||||||
|
|
||||||
return new FrostFsContainerInfo(acl,
|
return new FrostFsContainerInfo(
|
||||||
container.PlacementPolicy.ToModel(),
|
container.PlacementPolicy.ToModel(),
|
||||||
container.Attributes?.Select(a => new FrostFsAttribute(a.Key, a.Value)).ToList(),
|
container.Attributes?.Select(a => new FrostFsAttributePair(a.Key, a.Value)).ToArray(),
|
||||||
container.Version?.ToModel(),
|
container.Version?.ToModel(),
|
||||||
container.OwnerId?.ToModel(),
|
container.OwnerId?.ToModel(),
|
||||||
container.Nonce?.ToUuid());
|
container.Nonce?.ToUuid());
|
||||||
|
|
|
@ -17,19 +17,23 @@ public static class ContainerIdMapper
|
||||||
|
|
||||||
public static ContainerID ToMessage(this FrostFsContainerId model)
|
public static ContainerID ToMessage(this FrostFsContainerId model)
|
||||||
{
|
{
|
||||||
if (model.Value == null)
|
if (model is null)
|
||||||
|
{
|
||||||
throw new ArgumentNullException(nameof(model));
|
throw new ArgumentNullException(nameof(model));
|
||||||
|
}
|
||||||
if (!Cache.Containers.TryGetValue(model.Value, out ContainerID? message))
|
|
||||||
|
var containerId = model.GetValue() ?? throw new ArgumentNullException(nameof(model));
|
||||||
|
|
||||||
|
if (!Cache.Containers.TryGetValue(containerId, out ContainerID? message))
|
||||||
{
|
{
|
||||||
message = new ContainerID
|
message = new ContainerID
|
||||||
{
|
{
|
||||||
Value = ByteString.CopyFrom(Base58.Decode(model.Value))
|
Value = ByteString.CopyFrom(Base58.Decode(containerId))
|
||||||
};
|
};
|
||||||
|
|
||||||
Cache.Containers.Set(model.Value, message, _oneHourExpiration);
|
Cache.Containers.Set(containerId, message, _oneHourExpiration);
|
||||||
}
|
}
|
||||||
|
|
||||||
return message!;
|
return message!;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,3 +1,5 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
using FrostFS.Session;
|
using FrostFS.Session;
|
||||||
|
|
||||||
namespace FrostFS.SDK.ClientV2.Mappers.GRPC;
|
namespace FrostFS.SDK.ClientV2.Mappers.GRPC;
|
||||||
|
@ -6,11 +8,16 @@ public static class MetaHeaderMapper
|
||||||
{
|
{
|
||||||
public static RequestMetaHeader ToMessage(this MetaHeader metaHeader)
|
public static RequestMetaHeader ToMessage(this MetaHeader metaHeader)
|
||||||
{
|
{
|
||||||
|
if (metaHeader is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(metaHeader));
|
||||||
|
}
|
||||||
|
|
||||||
return new RequestMetaHeader
|
return new RequestMetaHeader
|
||||||
{
|
{
|
||||||
Version = metaHeader.Version.ToMessage(),
|
Version = metaHeader.Version.ToMessage(),
|
||||||
Epoch = (uint)metaHeader.Epoch,
|
Epoch = (uint)metaHeader.Epoch,
|
||||||
Ttl = (uint)metaHeader.Ttl
|
Ttl = (uint)metaHeader.Ttl
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,3 +1,4 @@
|
||||||
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
||||||
using FrostFS.Netmap;
|
using FrostFS.Netmap;
|
||||||
|
@ -8,6 +9,11 @@ public static class NetmapMapper
|
||||||
{
|
{
|
||||||
public static FrostFsNetmapSnapshot ToModel(this NetmapSnapshotResponse netmap)
|
public static FrostFsNetmapSnapshot ToModel(this NetmapSnapshotResponse netmap)
|
||||||
{
|
{
|
||||||
|
if (netmap is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(netmap));
|
||||||
|
}
|
||||||
|
|
||||||
return new FrostFsNetmapSnapshot(
|
return new FrostFsNetmapSnapshot(
|
||||||
netmap.Body.Netmap.Epoch,
|
netmap.Body.Netmap.Epoch,
|
||||||
netmap.Body.Netmap.Nodes
|
netmap.Body.Netmap.Nodes
|
||||||
|
|
|
@ -10,11 +10,21 @@ public static class NodeInfoMapper
|
||||||
{
|
{
|
||||||
public static FrostFsNodeInfo ToModel(this LocalNodeInfoResponse.Types.Body node)
|
public static FrostFsNodeInfo ToModel(this LocalNodeInfoResponse.Types.Body node)
|
||||||
{
|
{
|
||||||
|
if (node is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(node));
|
||||||
|
}
|
||||||
|
|
||||||
return node.NodeInfo.ToModel(node.Version);
|
return node.NodeInfo.ToModel(node.Version);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static FrostFsNodeInfo ToModel(this NodeInfo nodeInfo, Refs.Version 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
|
NodeState state = nodeInfo.State switch
|
||||||
{
|
{
|
||||||
NodeInfo.Types.State.Unspecified => NodeState.Unspecified,
|
NodeInfo.Types.State.Unspecified => NodeState.Unspecified,
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
||||||
using FrostFS.Netmap;
|
using FrostFS.Netmap;
|
||||||
|
@ -6,26 +7,13 @@ namespace FrostFS.SDK.ClientV2;
|
||||||
|
|
||||||
public static class PlacementPolicyMapper
|
public static class PlacementPolicyMapper
|
||||||
{
|
{
|
||||||
public static PlacementPolicy ToMessage(this FrostFsPlacementPolicy placementPolicy)
|
|
||||||
{
|
|
||||||
var pp = new PlacementPolicy
|
|
||||||
{
|
|
||||||
Filters = { },
|
|
||||||
Selectors = { },
|
|
||||||
Replicas = { },
|
|
||||||
Unique = placementPolicy.Unique
|
|
||||||
};
|
|
||||||
|
|
||||||
foreach (var replica in placementPolicy.Replicas)
|
|
||||||
{
|
|
||||||
pp.Replicas.Add(replica.ToMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
return pp;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static FrostFsPlacementPolicy ToModel(this PlacementPolicy placementPolicy)
|
public static FrostFsPlacementPolicy ToModel(this PlacementPolicy placementPolicy)
|
||||||
{
|
{
|
||||||
|
if (placementPolicy is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(placementPolicy));
|
||||||
|
}
|
||||||
|
|
||||||
return new FrostFsPlacementPolicy(
|
return new FrostFsPlacementPolicy(
|
||||||
placementPolicy.Unique,
|
placementPolicy.Unique,
|
||||||
placementPolicy.Replicas.Select(replica => replica.ToModel()).ToArray()
|
placementPolicy.Replicas.Select(replica => replica.ToModel()).ToArray()
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
using FrostFS.Netmap;
|
using FrostFS.Netmap;
|
||||||
|
|
||||||
namespace FrostFS.SDK.ClientV2;
|
namespace FrostFS.SDK.ClientV2;
|
||||||
|
@ -15,6 +17,11 @@ public static class ReplicaMapper
|
||||||
|
|
||||||
public static FrostFsReplica ToModel(this Replica replica)
|
public static FrostFsReplica ToModel(this Replica replica)
|
||||||
{
|
{
|
||||||
|
if (replica is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(replica));
|
||||||
|
}
|
||||||
|
|
||||||
return new FrostFsReplica((int)replica.Count, replica.Selector);
|
return new FrostFsReplica((int)replica.Count, replica.Selector);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -8,5 +8,5 @@ internal static class ObjectMapper
|
||||||
{
|
{
|
||||||
ObjectId = FrostFsObjectId.FromHash(obj.ObjectId.Value.ToByteArray())
|
ObjectId = FrostFsObjectId.FromHash(obj.ObjectId.Value.ToByteArray())
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,18 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
using FrostFS.Object;
|
using FrostFS.Object;
|
||||||
|
|
||||||
namespace FrostFS.SDK.ClientV2.Mappers.GRPC;
|
namespace FrostFS.SDK.ClientV2.Mappers.GRPC;
|
||||||
|
|
||||||
public static class ObjectAttributeMapper
|
public static class ObjectAttributeMapper
|
||||||
{
|
{
|
||||||
public static Header.Types.Attribute ToMessage(this FrostFsAttribute attribute)
|
public static Header.Types.Attribute ToMessage(this FrostFsAttributePair attribute)
|
||||||
{
|
{
|
||||||
|
if (attribute is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(attribute));
|
||||||
|
}
|
||||||
|
|
||||||
return new Header.Types.Attribute
|
return new Header.Types.Attribute
|
||||||
{
|
{
|
||||||
Key = attribute.Key,
|
Key = attribute.Key,
|
||||||
|
@ -13,8 +20,13 @@ public static class ObjectAttributeMapper
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public static FrostFsAttribute ToModel(this Header.Types.Attribute attribute)
|
public static FrostFsAttributePair ToModel(this Header.Types.Attribute attribute)
|
||||||
{
|
{
|
||||||
return new FrostFsAttribute(attribute.Key, attribute.Value);
|
if (attribute is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(attribute));
|
||||||
|
}
|
||||||
|
|
||||||
|
return new FrostFsAttributePair(attribute.Key, attribute.Value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,11 @@ public static class ObjectFilterMapper
|
||||||
{
|
{
|
||||||
public static SearchRequest.Types.Body.Types.Filter ToMessage(this IObjectFilter filter)
|
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
|
var objMatchTypeName = filter.MatchType switch
|
||||||
{
|
{
|
||||||
FrostFsMatchType.Unspecified => MatchType.Unspecified,
|
FrostFsMatchType.Unspecified => MatchType.Unspecified,
|
||||||
|
@ -25,5 +30,5 @@ public static class ObjectFilterMapper
|
||||||
Key = filter.Key,
|
Key = filter.Key,
|
||||||
Value = filter.GetSerializedValue()
|
Value = filter.GetSerializedValue()
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
||||||
using FrostFS.Object;
|
using FrostFS.Object;
|
||||||
|
@ -10,6 +11,11 @@ public static class ObjectHeaderMapper
|
||||||
{
|
{
|
||||||
public static FrostFsObjectHeader ToModel(this Header header)
|
public static FrostFsObjectHeader ToModel(this Header header)
|
||||||
{
|
{
|
||||||
|
if (header is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(header));
|
||||||
|
}
|
||||||
|
|
||||||
var objTypeName = header.ObjectType switch
|
var objTypeName = header.ObjectType switch
|
||||||
{
|
{
|
||||||
ObjectType.Regular => FrostFsObjectType.Regular,
|
ObjectType.Regular => FrostFsObjectType.Regular,
|
||||||
|
@ -22,15 +28,15 @@ public static class ObjectHeaderMapper
|
||||||
|
|
||||||
if (header.Split != null)
|
if (header.Split != null)
|
||||||
{
|
{
|
||||||
split = new FrostFsSplit(new SplitId(header.Split.SplitId.ToUuid()))
|
var children = header.Split.Children.Count != 0 ? new ReadOnlyCollection<FrostFsObjectId>(
|
||||||
{
|
header.Split.Children.Select(x => x.ToModel()).ToList()) : null;
|
||||||
Parent = header.Split.Parent?.ToModel(),
|
|
||||||
ParentHeader = header.Split.ParentHeader?.ToModel(),
|
|
||||||
Previous = header.Split.Previous?.ToModel()
|
|
||||||
};
|
|
||||||
|
|
||||||
if (header.Split.Children.Count != 0)
|
split = new FrostFsSplit(new SplitId(header.Split.SplitId.ToUuid()),
|
||||||
split.Children.AddRange(header.Split.Children.Select(x => x.ToModel()));
|
header.Split.Previous?.ToModel(),
|
||||||
|
header.Split.Parent?.ToModel(),
|
||||||
|
header.Split.ParentHeader?.ToModel(),
|
||||||
|
null,
|
||||||
|
children);
|
||||||
}
|
}
|
||||||
|
|
||||||
var model = new FrostFsObjectHeader(
|
var model = new FrostFsObjectHeader(
|
||||||
|
@ -40,10 +46,10 @@ public static class ObjectHeaderMapper
|
||||||
split,
|
split,
|
||||||
header.OwnerId.ToModel(),
|
header.OwnerId.ToModel(),
|
||||||
header.Version.ToModel())
|
header.Version.ToModel())
|
||||||
{
|
{
|
||||||
PayloadLength = header.PayloadLength,
|
PayloadLength = header.PayloadLength,
|
||||||
};
|
};
|
||||||
|
|
||||||
return model;
|
return model;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
using FrostFS.Refs;
|
using FrostFS.Refs;
|
||||||
|
|
||||||
using Google.Protobuf;
|
using Google.Protobuf;
|
||||||
|
@ -8,6 +10,11 @@ public static class ObjectIdMapper
|
||||||
{
|
{
|
||||||
public static ObjectID ToMessage(this FrostFsObjectId objectId)
|
public static ObjectID ToMessage(this FrostFsObjectId objectId)
|
||||||
{
|
{
|
||||||
|
if (objectId is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(objectId));
|
||||||
|
}
|
||||||
|
|
||||||
return new ObjectID
|
return new ObjectID
|
||||||
{
|
{
|
||||||
Value = ByteString.CopyFrom(objectId.ToHash())
|
Value = ByteString.CopyFrom(objectId.ToHash())
|
||||||
|
@ -16,6 +23,11 @@ public static class ObjectIdMapper
|
||||||
|
|
||||||
public static FrostFsObjectId ToModel(this ObjectID objectId)
|
public static FrostFsObjectId ToModel(this ObjectID objectId)
|
||||||
{
|
{
|
||||||
|
if (objectId is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(objectId));
|
||||||
|
}
|
||||||
|
|
||||||
return FrostFsObjectId.FromHash(objectId.Value.ToByteArray());
|
return FrostFsObjectId.FromHash(objectId.Value.ToByteArray());
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -17,6 +17,11 @@ public static class OwnerIdMapper
|
||||||
|
|
||||||
public static OwnerID ToMessage(this FrostFsOwner model)
|
public static OwnerID ToMessage(this FrostFsOwner model)
|
||||||
{
|
{
|
||||||
|
if (model is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(model));
|
||||||
|
}
|
||||||
|
|
||||||
if (!Cache.Owners.TryGetValue(model, out OwnerID? message))
|
if (!Cache.Owners.TryGetValue(model, out OwnerID? message))
|
||||||
{
|
{
|
||||||
message = new OwnerID
|
message = new OwnerID
|
||||||
|
@ -32,10 +37,15 @@ public static class OwnerIdMapper
|
||||||
|
|
||||||
public static FrostFsOwner ToModel(this OwnerID 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))
|
if (!Cache.Owners.TryGetValue(message, out FrostFsOwner? model))
|
||||||
{
|
{
|
||||||
model = new FrostFsOwner(Base58.Encode(message.Value.ToByteArray()));
|
model = new FrostFsOwner(Base58.Encode(message.Value.ToByteArray()));
|
||||||
|
|
||||||
Cache.Owners.Set(message, model, _oneHourExpiration);
|
Cache.Owners.Set(message, model, _oneHourExpiration);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
using Google.Protobuf;
|
using Google.Protobuf;
|
||||||
|
|
||||||
namespace FrostFS.SDK.ClientV2;
|
namespace FrostFS.SDK.ClientV2;
|
||||||
|
@ -6,8 +8,13 @@ public static class SessionMapper
|
||||||
{
|
{
|
||||||
public static byte[] Serialize(this Session.SessionToken token)
|
public static byte[] Serialize(this Session.SessionToken token)
|
||||||
{
|
{
|
||||||
|
if (token is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(token));
|
||||||
|
}
|
||||||
|
|
||||||
byte[] bytes = new byte[token.CalculateSize()];
|
byte[] bytes = new byte[token.CalculateSize()];
|
||||||
CodedOutputStream stream = new(bytes);
|
using CodedOutputStream stream = new(bytes);
|
||||||
token.WriteTo(stream);
|
token.WriteTo(stream);
|
||||||
|
|
||||||
return bytes;
|
return bytes;
|
||||||
|
|
|
@ -8,13 +8,17 @@ public static class SignatureMapper
|
||||||
{
|
{
|
||||||
public static Refs.Signature ToMessage(this FrostFsSignature signature)
|
public static Refs.Signature ToMessage(this FrostFsSignature signature)
|
||||||
{
|
{
|
||||||
|
if (signature is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(signature));
|
||||||
|
}
|
||||||
|
|
||||||
var scheme = signature.Scheme switch
|
var scheme = signature.Scheme switch
|
||||||
{
|
{
|
||||||
SignatureScheme.EcdsaRfc6979Sha256 => Refs.SignatureScheme.EcdsaRfc6979Sha256,
|
SignatureScheme.EcdsaRfc6979Sha256 => Refs.SignatureScheme.EcdsaRfc6979Sha256,
|
||||||
SignatureScheme.EcdsaRfc6979Sha256WalletConnect => Refs.SignatureScheme.EcdsaRfc6979Sha256WalletConnect,
|
SignatureScheme.EcdsaRfc6979Sha256WalletConnect => Refs.SignatureScheme.EcdsaRfc6979Sha256WalletConnect,
|
||||||
SignatureScheme.EcdsaSha512 => Refs.SignatureScheme.EcdsaSha512,
|
SignatureScheme.EcdsaSha512 => Refs.SignatureScheme.EcdsaSha512,
|
||||||
_ => throw new ArgumentException(message: $"Unexpected enum value: {signature.Scheme}",
|
_ => throw new ArgumentException(nameof(signature.Scheme), $"Unexpected enum value: {signature.Scheme}")
|
||||||
paramName: nameof(signature.Scheme))
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return new Refs.Signature
|
return new Refs.Signature
|
||||||
|
|
|
@ -6,7 +6,7 @@ public static class StatusMapper
|
||||||
{
|
{
|
||||||
public static FrostFsResponseStatus ToModel(this Status.Status status)
|
public static FrostFsResponseStatus ToModel(this Status.Status status)
|
||||||
{
|
{
|
||||||
if (status is null)
|
if (status is null)
|
||||||
return new FrostFsResponseStatus(FrostFsStatusCode.Success);
|
return new FrostFsResponseStatus(FrostFsStatusCode.Success);
|
||||||
|
|
||||||
var codeName = Enum.GetName(typeof(FrostFsStatusCode), status.Code);
|
var codeName = Enum.GetName(typeof(FrostFsStatusCode), status.Code);
|
||||||
|
|
|
@ -9,10 +9,15 @@ public static class VersionMapper
|
||||||
{
|
{
|
||||||
private static readonly Hashtable _cacheMessages = [];
|
private static readonly Hashtable _cacheMessages = [];
|
||||||
private static readonly Hashtable _cacheModels = [];
|
private static readonly Hashtable _cacheModels = [];
|
||||||
private static SpinLock _spinlock = new();
|
private static SpinLock _spinlock;
|
||||||
|
|
||||||
public static Version ToMessage(this FrostFsVersion model)
|
public static Version ToMessage(this FrostFsVersion model)
|
||||||
{
|
{
|
||||||
|
if (model is null)
|
||||||
|
{
|
||||||
|
throw new System.ArgumentNullException(nameof(model));
|
||||||
|
}
|
||||||
|
|
||||||
var key = model.Major << 16 + model.Minor;
|
var key = model.Major << 16 + model.Minor;
|
||||||
|
|
||||||
if (!_cacheMessages.ContainsKey(key))
|
if (!_cacheMessages.ContainsKey(key))
|
||||||
|
@ -46,6 +51,11 @@ public static class VersionMapper
|
||||||
|
|
||||||
public static FrostFsVersion ToModel(this Version message)
|
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;
|
var key = (int)message.Major << 16 + (int)message.Minor;
|
||||||
|
|
||||||
if (!_cacheModels.ContainsKey(key))
|
if (!_cacheModels.ContainsKey(key))
|
||||||
|
|
|
@ -4,7 +4,7 @@ using Frostfs.V2.Ape;
|
||||||
|
|
||||||
namespace FrostFS.SDK.ClientV2
|
namespace FrostFS.SDK.ClientV2
|
||||||
{
|
{
|
||||||
public struct FrostFsChainTarget(FrostFsTargetType type, string name)
|
public struct FrostFsChainTarget(FrostFsTargetType type, string name) : IEquatable<FrostFsChainTarget>
|
||||||
{
|
{
|
||||||
private ChainTarget? chainTarget;
|
private ChainTarget? chainTarget;
|
||||||
|
|
||||||
|
@ -33,5 +33,31 @@ namespace FrostFS.SDK.ClientV2
|
||||||
_ => throw new ArgumentException("Unexpected value for TargetType", nameof(type)),
|
_ => 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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
namespace FrostFS.SDK.ClientV2
|
namespace FrostFS.SDK.ClientV2
|
||||||
{
|
{
|
||||||
public struct FrostFsChain (byte[] raw)
|
public struct FrostFsChain(byte[] raw) : System.IEquatable<FrostFsChain>
|
||||||
{
|
{
|
||||||
private ByteString? grpcRaw;
|
private ByteString? grpcRaw;
|
||||||
|
|
||||||
|
@ -12,5 +12,31 @@ namespace FrostFS.SDK.ClientV2
|
||||||
{
|
{
|
||||||
return grpcRaw ??= ByteString.CopyFrom(Raw);
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
namespace FrostFS.SDK.ClientV2
|
namespace FrostFS.SDK.ClientV2
|
||||||
{
|
{
|
||||||
public enum FrostFsTargetType
|
public enum FrostFsTargetType
|
||||||
{
|
{
|
||||||
Undefined = 0,
|
Undefined = 0,
|
||||||
Namespace,
|
Namespace,
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.ObjectModel;
|
||||||
|
using System.Globalization;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace FrostFS.SDK;
|
namespace FrostFS.SDK;
|
||||||
|
@ -17,18 +18,24 @@ public class ClientSettings
|
||||||
ThrowException(errors);
|
ThrowException(errors);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected List<string>? CheckFields()
|
protected Collection<string>? CheckFields()
|
||||||
{
|
{
|
||||||
List<string>? errors = null;
|
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(Host))
|
if (string.IsNullOrWhiteSpace(Host))
|
||||||
(errors ??= []).Add(string.Format(errorTemplate, nameof(Host)));
|
{
|
||||||
|
var error = string.Format(CultureInfo.InvariantCulture, errorTemplate, nameof(Host));
|
||||||
|
return new Collection<string>([error]);
|
||||||
|
}
|
||||||
|
|
||||||
return errors;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static void ThrowException(List<string> errors)
|
protected static void ThrowException(Collection<string> errors)
|
||||||
{
|
{
|
||||||
|
if (errors is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(errors));
|
||||||
|
}
|
||||||
|
|
||||||
StringBuilder messages = new();
|
StringBuilder messages = new();
|
||||||
|
|
||||||
foreach (var error in errors)
|
foreach (var error in errors)
|
||||||
|
@ -51,12 +58,12 @@ public class SingleOwnerClientSettings : ClientSettings
|
||||||
ThrowException(errors);
|
ThrowException(errors);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected new List<string>? CheckFields()
|
protected new Collection<string>? CheckFields()
|
||||||
{
|
{
|
||||||
List<string>? errors = base.CheckFields();
|
Collection<string>? errors = base.CheckFields();
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(Key))
|
if (string.IsNullOrWhiteSpace(Key))
|
||||||
(errors ??= []).Add(string.Format(errorTemplate, nameof(Key)));
|
(errors ??= []).Add(string.Format(CultureInfo.InvariantCulture, errorTemplate, nameof(Key)));
|
||||||
|
|
||||||
return errors;
|
return errors;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
using FrostFS.Refs;
|
using FrostFS.Refs;
|
||||||
using FrostFS.SDK.Cryptography;
|
|
||||||
|
|
||||||
using FrostFS.SDK.ClientV2.Mappers.GRPC;
|
|
||||||
using FrostFS.SDK.ClientV2;
|
using FrostFS.SDK.ClientV2;
|
||||||
|
using FrostFS.SDK.ClientV2.Mappers.GRPC;
|
||||||
|
using FrostFS.SDK.Cryptography;
|
||||||
|
|
||||||
namespace FrostFS.SDK;
|
namespace FrostFS.SDK;
|
||||||
|
|
||||||
|
@ -21,21 +20,18 @@ public class FrostFsContainerId
|
||||||
this.containerID = id;
|
this.containerID = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Value
|
public string GetValue()
|
||||||
{
|
{
|
||||||
get
|
if (this.modelId != null)
|
||||||
|
return this.modelId;
|
||||||
|
|
||||||
|
if (containerID != null)
|
||||||
{
|
{
|
||||||
if (this.modelId != null)
|
this.modelId = Base58.Encode(containerID.Value.ToByteArray());
|
||||||
return this.modelId;
|
return this.modelId;
|
||||||
|
|
||||||
if (containerID != null)
|
|
||||||
{
|
|
||||||
this.modelId = Base58.Encode(containerID.Value.ToByteArray());
|
|
||||||
return this.modelId;
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new InvalidObjectException();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
throw new InvalidObjectException();
|
||||||
}
|
}
|
||||||
|
|
||||||
internal ContainerID ContainerID
|
internal ContainerID ContainerID
|
||||||
|
@ -57,6 +53,6 @@ public class FrostFsContainerId
|
||||||
|
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
{
|
{
|
||||||
return Value;
|
return GetValue();
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,10 +1,10 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.ObjectModel;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
||||||
using FrostFS.SDK.ClientV2;
|
using FrostFS.SDK.ClientV2;
|
||||||
using FrostFS.SDK.Cryptography;
|
|
||||||
using FrostFS.SDK.ClientV2.Mappers.GRPC;
|
using FrostFS.SDK.ClientV2.Mappers.GRPC;
|
||||||
|
using FrostFS.SDK.Cryptography;
|
||||||
|
|
||||||
using Google.Protobuf;
|
using Google.Protobuf;
|
||||||
|
|
||||||
|
@ -12,61 +12,59 @@ namespace FrostFS.SDK;
|
||||||
|
|
||||||
public class FrostFsContainerInfo
|
public class FrostFsContainerInfo
|
||||||
{
|
{
|
||||||
private FrostFS.Container.Container.Types.Attribute[]? grpsAttributes;
|
private Container.Container.Types.Attribute[]? grpsAttributes;
|
||||||
private List<FrostFsAttribute>? attributes;
|
private ReadOnlyCollection<FrostFsAttributePair>? attributes;
|
||||||
private FrostFsPlacementPolicy? placementPolicy;
|
private FrostFsPlacementPolicy? placementPolicy;
|
||||||
private Guid? nonce;
|
private Guid? nonce;
|
||||||
|
|
||||||
private Container.Container container;
|
private Container.Container? container;
|
||||||
|
|
||||||
public FrostFsContainerInfo(
|
public FrostFsContainerInfo(
|
||||||
BasicAcl basicAcl,
|
|
||||||
FrostFsPlacementPolicy placementPolicy,
|
FrostFsPlacementPolicy placementPolicy,
|
||||||
List<FrostFsAttribute>? attributes = null,
|
FrostFsAttributePair[]? attributes = null,
|
||||||
FrostFsVersion? version = null,
|
FrostFsVersion? version = null,
|
||||||
FrostFsOwner? owner = null,
|
FrostFsOwner? owner = null,
|
||||||
Guid? nonce = null)
|
Guid? nonce = null)
|
||||||
{
|
{
|
||||||
BasicAcl = basicAcl;
|
|
||||||
this.placementPolicy = placementPolicy;
|
this.placementPolicy = placementPolicy;
|
||||||
this.attributes = attributes;
|
|
||||||
Version = version;
|
Version = version;
|
||||||
Owner = owner;
|
Owner = owner;
|
||||||
this.nonce = nonce;
|
this.nonce = nonce;
|
||||||
|
|
||||||
|
if (attributes != null)
|
||||||
|
this.attributes = new ReadOnlyCollection<FrostFsAttributePair>(attributes);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal FrostFsContainerInfo(Container.Container container)
|
internal FrostFsContainerInfo(Container.Container container)
|
||||||
{
|
{
|
||||||
this.container = container;
|
this.container = container;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Guid Nonce
|
public Guid Nonce
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
nonce ??= container?.Nonce != null ? container.Nonce.ToUuid() : Guid.NewGuid();
|
nonce ??= container?.Nonce != null ? container.Nonce.ToUuid() : Guid.NewGuid();
|
||||||
return nonce.Value;
|
return nonce.Value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public BasicAcl BasicAcl { get; private set; }
|
|
||||||
|
|
||||||
public FrostFsPlacementPolicy? PlacementPolicy
|
public FrostFsPlacementPolicy? PlacementPolicy
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
placementPolicy ??= container.PlacementPolicy?.ToModel();
|
placementPolicy ??= container?.PlacementPolicy?.ToModel();
|
||||||
return placementPolicy;
|
return placementPolicy;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<FrostFsAttribute>? Attributes
|
public ReadOnlyCollection<FrostFsAttributePair>? Attributes
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
if (attributes == null && grpsAttributes != null)
|
if (attributes == null && grpsAttributes != null)
|
||||||
attributes = grpsAttributes.Select(a => new FrostFsAttribute(a.Key, a.Value)).ToList();
|
attributes = new ReadOnlyCollection<FrostFsAttributePair>(grpsAttributes.Select(a => new FrostFsAttributePair(a.Key, a.Value)).ToList());
|
||||||
|
|
||||||
return attributes;
|
return attributes;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -74,8 +72,8 @@ public class FrostFsContainerInfo
|
||||||
public FrostFsVersion? Version { get; private set; }
|
public FrostFsVersion? Version { get; private set; }
|
||||||
|
|
||||||
public FrostFsOwner? Owner { get; private set; }
|
public FrostFsOwner? Owner { get; private set; }
|
||||||
|
|
||||||
internal Container.Container.Types.Attribute[]? GetGrpsAttributes()
|
internal Container.Container.Types.Attribute[]? GetGrpsAttributes()
|
||||||
{
|
{
|
||||||
grpsAttributes ??= Attributes?
|
grpsAttributes ??= Attributes?
|
||||||
.Select(a => new Container.Container.Types.Attribute { Key = a.Key, Value = a.Value })
|
.Select(a => new Container.Container.Types.Attribute { Key = a.Key, Value = a.Value })
|
||||||
|
@ -88,10 +86,14 @@ public class FrostFsContainerInfo
|
||||||
{
|
{
|
||||||
if (this.container == null)
|
if (this.container == null)
|
||||||
{
|
{
|
||||||
|
if (PlacementPolicy == null)
|
||||||
|
{
|
||||||
|
throw new InvalidObjectException("PlacementPolicy is null");
|
||||||
|
}
|
||||||
|
|
||||||
this.container = new Container.Container()
|
this.container = new Container.Container()
|
||||||
{
|
{
|
||||||
BasicAcl = (uint)BasicAcl,
|
PlacementPolicy = PlacementPolicy.Value.GetPolicy(),
|
||||||
PlacementPolicy = PlacementPolicy.ToMessage(),
|
|
||||||
Nonce = ByteString.CopyFrom(Nonce.ToBytes()),
|
Nonce = ByteString.CopyFrom(Nonce.ToBytes()),
|
||||||
OwnerId = Owner?.OwnerID,
|
OwnerId = Owner?.OwnerID,
|
||||||
Version = Version?.Version
|
Version = Version?.Version
|
||||||
|
|
|
@ -1,21 +0,0 @@
|
||||||
using System.ComponentModel;
|
|
||||||
|
|
||||||
namespace FrostFS.SDK;
|
|
||||||
|
|
||||||
public enum BasicAcl
|
|
||||||
{
|
|
||||||
[Description("Not defined ACL")]
|
|
||||||
NotDefined = 0x00000000,
|
|
||||||
|
|
||||||
[Description("Basic ACL for private container")]
|
|
||||||
Private = 0x1C8C8CCC,
|
|
||||||
|
|
||||||
[Description("Basic ACL for public RO container")]
|
|
||||||
PublicRO = 0x1FBF8CFF,
|
|
||||||
|
|
||||||
[Description("Basic ACL for public RW container")]
|
|
||||||
PublicRW = 0x1FBFBFFF,
|
|
||||||
|
|
||||||
[Description("Basic ACL for public append container")]
|
|
||||||
PublicAppend = 0x1FBF9FFF,
|
|
||||||
}
|
|
|
@ -1,20 +1,21 @@
|
||||||
using FrostFS.SDK.Cryptography;
|
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
|
using FrostFS.SDK.Cryptography;
|
||||||
|
|
||||||
namespace FrostFS.SDK;
|
namespace FrostFS.SDK;
|
||||||
|
|
||||||
public class CheckSum
|
public class CheckSum
|
||||||
{
|
{
|
||||||
// type is always Sha256
|
private byte[]? hash;
|
||||||
public byte[]? Hash { get; set; }
|
private string? text;
|
||||||
|
|
||||||
public static CheckSum CreateCheckSum(byte[] content)
|
public static CheckSum CreateCheckSum(byte[] content)
|
||||||
{
|
{
|
||||||
return new CheckSum { Hash = content.Sha256() };
|
return new CheckSum { hash = content.Sha256() };
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
{
|
{
|
||||||
return BitConverter.ToString(Hash).Replace("-", "");
|
return text ??= BitConverter.ToString(hash).Replace("-", "");
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,8 +1,8 @@
|
||||||
namespace FrostFS.SDK;
|
namespace FrostFS.SDK;
|
||||||
|
|
||||||
public class Constants
|
public static class Constants
|
||||||
{
|
{
|
||||||
public const int ObjectChunkSize = 3 * (1 << 20);
|
public const int ObjectChunkSize = 3 * (1 << 20);
|
||||||
public const int Sha256HashLength = 32;
|
public const int Sha256HashLength = 32;
|
||||||
|
|
||||||
// HeaderPrefix is a prefix of key to object header value or property.
|
// HeaderPrefix is a prefix of key to object header value or property.
|
||||||
|
|
|
@ -1,28 +1,89 @@
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
||||||
|
using FrostFS.Netmap;
|
||||||
|
using FrostFS.SDK.ClientV2;
|
||||||
|
|
||||||
namespace FrostFS.SDK;
|
namespace FrostFS.SDK;
|
||||||
|
|
||||||
public class FrostFsPlacementPolicy(bool unique, params FrostFsReplica[] replicas) : IComparable<FrostFsPlacementPolicy>
|
public struct FrostFsPlacementPolicy(bool unique, params FrostFsReplica[] replicas)
|
||||||
|
: IEquatable<FrostFsPlacementPolicy>
|
||||||
{
|
{
|
||||||
|
private PlacementPolicy policy;
|
||||||
|
|
||||||
public FrostFsReplica[] Replicas { get; private set; } = replicas;
|
public FrostFsReplica[] Replicas { get; private set; } = replicas;
|
||||||
public bool Unique { get; private set; } = unique;
|
public bool Unique { get; private set; } = unique;
|
||||||
|
|
||||||
public int CompareTo(FrostFsPlacementPolicy other)
|
public override readonly bool Equals(object obj)
|
||||||
{
|
{
|
||||||
var notEqual = other == null
|
if (obj is null)
|
||||||
|| Unique != other.Unique
|
return false;
|
||||||
|| Replicas.Length != other.Replicas.Length;
|
|
||||||
|
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)
|
if (notEqual)
|
||||||
return 1;
|
return false;
|
||||||
|
|
||||||
foreach (var replica in Replicas)
|
foreach (var replica in Replicas)
|
||||||
{
|
{
|
||||||
if (!other!.Replicas.Any(r => r.Count == replica.Count && r.Selector == replica.Selector))
|
if (!other.Replicas.Any(r => r.Equals(replica)))
|
||||||
return 1;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,6 +1,8 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
namespace FrostFS.SDK;
|
namespace FrostFS.SDK;
|
||||||
|
|
||||||
public class FrostFsReplica
|
public struct FrostFsReplica : IEquatable<FrostFsReplica>
|
||||||
{
|
{
|
||||||
public int Count { get; set; }
|
public int Count { get; set; }
|
||||||
public string Selector { get; set; }
|
public string Selector { get; set; }
|
||||||
|
@ -12,4 +14,34 @@ public class FrostFsReplica
|
||||||
Count = count;
|
Count = count;
|
||||||
Selector = selector;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -5,7 +5,7 @@ namespace FrostFS.SDK;
|
||||||
|
|
||||||
public class FrostFsVersion(int major, int minor)
|
public class FrostFsVersion(int major, int minor)
|
||||||
{
|
{
|
||||||
public Version version;
|
private Version? version;
|
||||||
|
|
||||||
public int Major { get; set; } = major;
|
public int Major { get; set; } = major;
|
||||||
public int Minor { get; set; } = minor;
|
public int Minor { get; set; } = minor;
|
||||||
|
@ -21,6 +21,11 @@ public class FrostFsVersion(int major, int minor)
|
||||||
|
|
||||||
public bool IsSupported(FrostFsVersion version)
|
public bool IsSupported(FrostFsVersion version)
|
||||||
{
|
{
|
||||||
|
if (version is null)
|
||||||
|
{
|
||||||
|
throw new System.ArgumentNullException(nameof(version));
|
||||||
|
}
|
||||||
|
|
||||||
return Major == version.Major;
|
return Major == version.Major;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
namespace FrostFS.SDK;
|
namespace FrostFS.SDK;
|
||||||
|
|
||||||
public class FrostFsAttribute(string key, string value)
|
public class FrostFsAttributePair(string key, string value)
|
||||||
{
|
{
|
||||||
public string Key { get; set; } = key;
|
public string Key { get; set; } = key;
|
||||||
|
|
|
@ -1,13 +1,21 @@
|
||||||
namespace FrostFS.SDK;
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
|
|
||||||
|
namespace FrostFS.SDK;
|
||||||
|
|
||||||
public class FrostFsLinkObject : FrostFsObject
|
public class FrostFsLinkObject : FrostFsObject
|
||||||
{
|
{
|
||||||
public FrostFsLinkObject(FrostFsContainerId containerId, SplitId splitId, FrostFsObjectHeader largeObjectHeader)
|
public FrostFsLinkObject(FrostFsContainerId containerId,
|
||||||
|
SplitId splitId,
|
||||||
|
FrostFsObjectHeader largeObjectHeader,
|
||||||
|
IList<FrostFsObjectId> children)
|
||||||
: base(containerId)
|
: base(containerId)
|
||||||
{
|
{
|
||||||
Header!.Split = new FrostFsSplit(splitId)
|
Header!.Split = new FrostFsSplit(splitId,
|
||||||
{
|
null,
|
||||||
ParentHeader = largeObjectHeader
|
null,
|
||||||
};
|
largeObjectHeader,
|
||||||
|
null,
|
||||||
|
new ReadOnlyCollection<FrostFsObjectId>(children));
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,9 +1,11 @@
|
||||||
using System;
|
using FrostFS.SDK.ClientV2;
|
||||||
|
|
||||||
namespace FrostFS.SDK;
|
namespace FrostFS.SDK;
|
||||||
|
|
||||||
public class FrostFsObject
|
public class FrostFsObject
|
||||||
{
|
{
|
||||||
|
private byte[]? bytes;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates new instance from <c>ObjectHeader</c>
|
/// Creates new instance from <c>ObjectHeader</c>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -37,19 +39,27 @@ public class FrostFsObject
|
||||||
get; set;
|
get; set;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <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 byte[] Payload { get; set; } = [];
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A payload is obtained via stream reader
|
/// A payload is obtained via stream reader
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <value>Reader for received data</value>
|
/// <value>Reader for received data</value>
|
||||||
public IObjectReader? ObjectReader { get; set; }
|
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>
|
/// <summary>
|
||||||
/// Applied only for the last Object in chain in case of manual multipart uploading
|
/// Applied only for the last Object in chain in case of manual multipart uploading
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -57,7 +67,7 @@ public class FrostFsObject
|
||||||
public void SetParent(FrostFsObjectHeader largeObjectHeader)
|
public void SetParent(FrostFsObjectHeader largeObjectHeader)
|
||||||
{
|
{
|
||||||
if (Header?.Split == null)
|
if (Header?.Split == null)
|
||||||
throw new Exception("The object is not initialized properly");
|
throw new InvalidObjectException("The object is not initialized properly");
|
||||||
|
|
||||||
Header.Split.ParentHeader = largeObjectHeader;
|
Header.Split.ParentHeader = largeObjectHeader;
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,7 @@ public abstract class FrostFsObjectFilter<T>(FrostFsMatchType matchType, string
|
||||||
/// <param name="matchType">Match type</param>
|
/// <param name="matchType">Match type</param>
|
||||||
/// <param name="key">Attribute key</param>
|
/// <param name="key">Attribute key</param>
|
||||||
/// <param name="value">Attribute value</param>
|
/// <param name="value">Attribute value</param>
|
||||||
public class FilterByAttribute(FrostFsMatchType matchType, string key, string value) : FrostFsObjectFilter<string>(matchType, key, value) { }
|
public class FilterByAttributePair(FrostFsMatchType matchType, string key, string value) : FrostFsObjectFilter<string>(matchType, key, value) { }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates filter to search by ObjectId
|
/// Creates filter to search by ObjectId
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.ObjectModel;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
||||||
using FrostFS.Object;
|
using FrostFS.Object;
|
||||||
|
@ -11,15 +11,17 @@ namespace FrostFS.SDK;
|
||||||
public class FrostFsObjectHeader(
|
public class FrostFsObjectHeader(
|
||||||
FrostFsContainerId containerId,
|
FrostFsContainerId containerId,
|
||||||
FrostFsObjectType type = FrostFsObjectType.Regular,
|
FrostFsObjectType type = FrostFsObjectType.Regular,
|
||||||
FrostFsAttribute[]? attributes = null,
|
FrostFsAttributePair[]? attributes = null,
|
||||||
FrostFsSplit? split = null,
|
FrostFsSplit? split = null,
|
||||||
FrostFsOwner? owner = null,
|
FrostFsOwner? owner = null,
|
||||||
FrostFsVersion? version = null)
|
FrostFsVersion? version = null)
|
||||||
{
|
{
|
||||||
private Header header;
|
private Header? header;
|
||||||
private Container.Container.Types.Attribute[]? grpsAttributes;
|
private Container.Container.Types.Attribute[]? grpsAttributes;
|
||||||
|
|
||||||
public List<FrostFsAttribute> Attributes { get; internal set; } = attributes != null ? [.. attributes] : [];
|
public ReadOnlyCollection<FrostFsAttributePair>? Attributes { get; internal set; } =
|
||||||
|
attributes == null ? null :
|
||||||
|
new ReadOnlyCollection<FrostFsAttributePair>(attributes);
|
||||||
|
|
||||||
public FrostFsContainerId ContainerId { get; } = containerId;
|
public FrostFsContainerId ContainerId { get; } = containerId;
|
||||||
|
|
||||||
|
@ -65,9 +67,12 @@ public class FrostFsObjectHeader(
|
||||||
PayloadLength = PayloadLength
|
PayloadLength = PayloadLength
|
||||||
};
|
};
|
||||||
|
|
||||||
foreach (var attribute in Attributes)
|
if (Attributes != null)
|
||||||
{
|
{
|
||||||
this.header.Attributes.Add(attribute.ToMessage());
|
foreach (var attribute in Attributes)
|
||||||
|
{
|
||||||
|
this.header.Attributes.Add(attribute.ToMessage());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var split = Split;
|
var split = Split;
|
||||||
|
|
|
@ -10,6 +10,11 @@ public class FrostFsObjectId(string id)
|
||||||
|
|
||||||
public static FrostFsObjectId FromHash(byte[] hash)
|
public static FrostFsObjectId FromHash(byte[] hash)
|
||||||
{
|
{
|
||||||
|
if (hash is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(hash));
|
||||||
|
}
|
||||||
|
|
||||||
if (hash.Length != Constants.Sha256HashLength)
|
if (hash.Length != Constants.Sha256HashLength)
|
||||||
throw new FormatException("ObjectID must be a sha256 hash.");
|
throw new FormatException("ObjectID must be a sha256 hash.");
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ namespace FrostFS.SDK;
|
||||||
|
|
||||||
public class FrostFsOwner(string id)
|
public class FrostFsOwner(string id)
|
||||||
{
|
{
|
||||||
private OwnerID ownerID;
|
private OwnerID? ownerID;
|
||||||
|
|
||||||
public string Value { get; } = id;
|
public string Value { get; } = id;
|
||||||
|
|
||||||
|
@ -17,9 +17,9 @@ public class FrostFsOwner(string id)
|
||||||
return new FrostFsOwner(key.PublicKey().PublicKeyToAddress());
|
return new FrostFsOwner(key.PublicKey().PublicKeyToAddress());
|
||||||
}
|
}
|
||||||
|
|
||||||
internal OwnerID OwnerID
|
internal OwnerID OwnerID
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
ownerID ??= this.ToMessage();
|
ownerID ??= this.ToMessage();
|
||||||
return ownerID;
|
return ownerID;
|
||||||
|
|
|
@ -1,8 +1,13 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.ObjectModel;
|
||||||
|
|
||||||
namespace FrostFS.SDK;
|
namespace FrostFS.SDK;
|
||||||
|
|
||||||
public class FrostFsSplit(SplitId splitId)
|
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 FrostFsSplit() : this(new SplitId())
|
||||||
{
|
{
|
||||||
|
@ -10,15 +15,14 @@ public class FrostFsSplit(SplitId splitId)
|
||||||
|
|
||||||
public SplitId SplitId { get; private set; } = splitId;
|
public SplitId SplitId { get; private set; } = splitId;
|
||||||
|
|
||||||
public FrostFsObjectId? Parent { get; set; }
|
public FrostFsObjectId? Previous { get; } = previous;
|
||||||
|
|
||||||
public FrostFsObjectId? Previous { get; set; }
|
public FrostFsObjectId? Parent { get; } = parent;
|
||||||
|
|
||||||
public FrostFsSignature? ParentSignature { get; set; }
|
public FrostFsSignature? ParentSignature { get; } = parentSignature;
|
||||||
|
|
||||||
public FrostFsObjectHeader? ParentHeader { get; set; }
|
public FrostFsObjectHeader? ParentHeader { get; set; } = parentHeader;
|
||||||
|
|
||||||
public List<FrostFsObjectId> Children { get; } = [];
|
public ReadOnlyCollection<FrostFsObjectId>? Children { get; } = children;
|
||||||
|
|
||||||
public Refs.Signature ParentSignatureGrpc { get; set; }
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,35 +1,35 @@
|
||||||
using FrostFS.SDK.Cryptography;
|
using System;
|
||||||
|
|
||||||
|
using FrostFS.SDK.Cryptography;
|
||||||
|
|
||||||
using Google.Protobuf;
|
using Google.Protobuf;
|
||||||
|
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace FrostFS.SDK;
|
namespace FrostFS.SDK;
|
||||||
|
|
||||||
public class SplitId
|
public class SplitId
|
||||||
{
|
{
|
||||||
private readonly Guid id;
|
private readonly Guid id;
|
||||||
|
|
||||||
private ByteString? _message;
|
private ByteString? message;
|
||||||
|
|
||||||
public SplitId()
|
public SplitId()
|
||||||
{
|
{
|
||||||
id = Guid.NewGuid();
|
this.id = Guid.NewGuid();
|
||||||
}
|
}
|
||||||
|
|
||||||
public SplitId(Guid guid)
|
public SplitId(Guid id)
|
||||||
{
|
{
|
||||||
id = guid;
|
this.id = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
private SplitId(byte[] binary)
|
private SplitId(byte[] binary)
|
||||||
{
|
{
|
||||||
id = new Guid(binary);
|
this.id = new Guid(binary);
|
||||||
}
|
}
|
||||||
|
|
||||||
private SplitId(string str)
|
private SplitId(string str)
|
||||||
{
|
{
|
||||||
id = new Guid(str);
|
this.id = new Guid(str);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static SplitId CreateFromBinary(byte[] binaryData)
|
public static SplitId CreateFromBinary(byte[] binaryData)
|
||||||
|
@ -44,19 +44,19 @@ public class SplitId
|
||||||
|
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
{
|
{
|
||||||
return id.ToString();
|
return this.id.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[]? ToBinary()
|
public byte[]? ToBinary()
|
||||||
{
|
{
|
||||||
if (id == Guid.Empty)
|
if (this.id == Guid.Empty)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
return id.ToBytes();
|
return this.id.ToBytes();
|
||||||
}
|
}
|
||||||
|
|
||||||
public ByteString? GetSplitId()
|
public ByteString? GetSplitId()
|
||||||
{
|
{
|
||||||
return _message ??= ByteString.CopyFrom(ToBinary());
|
return this.message ??= ByteString.CopyFrom(ToBinary());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
namespace FrostFS.SDK;
|
namespace FrostFS.SDK;
|
||||||
|
|
||||||
public class FrostFsSignature
|
public class FrostFsSignature()
|
||||||
{
|
{
|
||||||
public byte[]? Key { get; set; }
|
public byte[]? Key { get; set; }
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.ObjectModel;
|
||||||
using System.Security.Cryptography;
|
using System.Security.Cryptography;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
|
||||||
|
@ -13,32 +13,32 @@ namespace FrostFS.SDK.ClientV2;
|
||||||
|
|
||||||
public class Context()
|
public class Context()
|
||||||
{
|
{
|
||||||
private List<Interceptor>? interceptors;
|
private ReadOnlyCollection<Interceptor>? interceptors;
|
||||||
|
|
||||||
private ByteString? publicKeyCache;
|
private ByteString? publicKeyCache;
|
||||||
|
|
||||||
public ECDsa Key { get; set; }
|
public ECDsa? Key { get; set; }
|
||||||
|
|
||||||
public FrostFsOwner OwnerId { get; set; }
|
public FrostFsOwner? OwnerId { get; set; }
|
||||||
|
|
||||||
public FrostFsVersion Version { get; set; }
|
public FrostFsVersion? Version { get; set; }
|
||||||
|
|
||||||
|
public CancellationToken CancellationToken { get; set; }
|
||||||
|
|
||||||
|
public TimeSpan Timeout { get; set; }
|
||||||
|
|
||||||
public CancellationToken CancellationToken { get; set; } = default;
|
|
||||||
|
|
||||||
public TimeSpan Timeout { get; set; } = default;
|
|
||||||
|
|
||||||
public DateTime? Deadline => Timeout.Ticks > 0 ? DateTime.UtcNow.Add(Timeout) : null;
|
public DateTime? Deadline => Timeout.Ticks > 0 ? DateTime.UtcNow.Add(Timeout) : null;
|
||||||
|
|
||||||
public Action<CallStatistics>? Callback { get; set; }
|
public Action<CallStatistics>? Callback { get; set; }
|
||||||
|
|
||||||
public List<Interceptor> Interceptors
|
public ReadOnlyCollection<Interceptor>? Interceptors
|
||||||
{
|
{
|
||||||
get { return this.interceptors ??= []; }
|
get { return this.interceptors; }
|
||||||
set { this.interceptors = value; }
|
set { this.interceptors = value; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public ByteString? GetPublicKeyCache()
|
public ByteString? GetPublicKeyCache()
|
||||||
{
|
{
|
||||||
if (publicKeyCache == null && Key != null)
|
if (publicKeyCache == null && Key != null)
|
||||||
{
|
{
|
||||||
publicKeyCache = ByteString.CopyFrom(Key.PublicKey());
|
publicKeyCache = ByteString.CopyFrom(Key.PublicKey());
|
||||||
|
|
|
@ -2,12 +2,12 @@
|
||||||
|
|
||||||
namespace FrostFS.SDK.ClientV2;
|
namespace FrostFS.SDK.ClientV2;
|
||||||
|
|
||||||
public class PrmBase() : IContext
|
public class PrmBase(NameValueCollection? xheaders = null) : IContext
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// FrostFS request X-Headers
|
/// FrostFS request X-Headers
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public NameValueCollection XHeaders { get; set; } = [];
|
public NameValueCollection XHeaders { get; } = xheaders ?? [];
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public Context? Context { get; set; }
|
public Context? Context { get; set; }
|
||||||
|
|
|
@ -9,7 +9,7 @@ public sealed class PrmContainerCreate(FrostFsContainerInfo container) : PrmBase
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <value>Rules for polling the result</value>
|
/// <value>Rules for polling the result</value>
|
||||||
public PrmWait? WaitParams { get; set; }
|
public PrmWait? WaitParams { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Blank session token
|
/// Blank session token
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
namespace FrostFS.SDK.ClientV2;
|
namespace FrostFS.SDK.ClientV2;
|
||||||
|
|
||||||
public sealed class PrmNetmapSnapshot() : PrmBase
|
public sealed class PrmNetmapSnapshot() : PrmBase
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
namespace FrostFS.SDK.ClientV2;
|
namespace FrostFS.SDK.ClientV2;
|
||||||
|
|
||||||
public sealed class PrmNetworkSettings() : PrmBase
|
public sealed class PrmNetworkSettings() : PrmBase
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
namespace FrostFS.SDK.ClientV2;
|
namespace FrostFS.SDK.ClientV2;
|
||||||
|
|
||||||
public sealed class PrmNodeInfo() : PrmBase
|
public sealed class PrmNodeInfo() : PrmBase
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
public sealed class PrmObjectHeadGet(FrostFsContainerId containerId, FrostFsObjectId objectId) : PrmBase, ISessionToken
|
public sealed class PrmObjectHeadGet(FrostFsContainerId containerId, FrostFsObjectId objectId) : PrmBase, ISessionToken
|
||||||
{
|
{
|
||||||
public FrostFsContainerId ContainerId { get; set; } = containerId;
|
public FrostFsContainerId ContainerId { get; set; } = containerId;
|
||||||
|
|
||||||
public FrostFsObjectId ObjectId { get; set; } = objectId;
|
public FrostFsObjectId ObjectId { get; set; } = objectId;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
|
|
@ -28,7 +28,7 @@ public sealed class PrmObjectPut : PrmBase, ISessionToken
|
||||||
/// Overrides default size of the buffer for stream transferring.
|
/// Overrides default size of the buffer for stream transferring.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <value>Size of the buffer</value>
|
/// <value>Size of the buffer</value>
|
||||||
public int BufferMaxSize { get; set; }
|
public int BufferMaxSize { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Allows to define a buffer for chunks to manage by the memory allocation and releasing.
|
/// Allows to define a buffer for chunks to manage by the memory allocation and releasing.
|
||||||
|
@ -40,7 +40,7 @@ public sealed class PrmObjectPut : PrmBase, ISessionToken
|
||||||
|
|
||||||
internal int MaxObjectSizeCache { get; set; }
|
internal int MaxObjectSizeCache { get; set; }
|
||||||
|
|
||||||
internal ulong CurrentStreamPosition { get; set; } = 0;
|
internal ulong CurrentStreamPosition { get; set; }
|
||||||
|
|
||||||
internal ulong FullLength { get; set; } = 0;
|
internal ulong FullLength { get; set; }
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,22 +3,22 @@ using System.Collections.Generic;
|
||||||
using System.Collections.Specialized;
|
using System.Collections.Specialized;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
using FrostFS.SDK.ClientV2;
|
|
||||||
using FrostFS.Container;
|
using FrostFS.Container;
|
||||||
|
using FrostFS.Refs;
|
||||||
|
using FrostFS.SDK.ClientV2;
|
||||||
using FrostFS.SDK.ClientV2.Mappers.GRPC;
|
using FrostFS.SDK.ClientV2.Mappers.GRPC;
|
||||||
using FrostFS.SDK.Cryptography;
|
using FrostFS.SDK.Cryptography;
|
||||||
using FrostFS.Refs;
|
|
||||||
using FrostFS.Session;
|
using FrostFS.Session;
|
||||||
|
|
||||||
namespace FrostFS.SDK.ClientV2;
|
namespace FrostFS.SDK.ClientV2;
|
||||||
|
|
||||||
internal class ContainerServiceProvider(ContainerService.ContainerServiceClient service, ClientEnvironment context) : ContextAccessor(context), ISessionProvider
|
internal sealed class ContainerServiceProvider(ContainerService.ContainerServiceClient service, ClientEnvironment context) : ContextAccessor(context), ISessionProvider
|
||||||
{
|
{
|
||||||
readonly SessionProvider sessions = new(context);
|
readonly SessionProvider sessions = new(context);
|
||||||
|
|
||||||
public async ValueTask<SessionToken> GetOrCreateSession(ISessionToken args, Context ctx)
|
public async ValueTask<SessionToken> GetOrCreateSession(ISessionToken args, Context ctx)
|
||||||
{
|
{
|
||||||
return await sessions.GetOrCreateSession(args, ctx);
|
return await sessions.GetOrCreateSession(args, ctx).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal async Task<FrostFsContainerInfo> GetContainerAsync(PrmContainerGet args)
|
internal async Task<FrostFsContainerInfo> GetContainerAsync(PrmContainerGet args)
|
||||||
|
@ -35,22 +35,29 @@ internal class ContainerServiceProvider(ContainerService.ContainerServiceClient
|
||||||
internal async IAsyncEnumerable<FrostFsContainerId> ListContainersAsync(PrmContainerGetAll args)
|
internal async IAsyncEnumerable<FrostFsContainerId> ListContainersAsync(PrmContainerGetAll args)
|
||||||
{
|
{
|
||||||
var ctx = args.Context!;
|
var ctx = args.Context!;
|
||||||
|
ctx.OwnerId ??= Context.Owner;
|
||||||
|
ctx.Key ??= Context.Key?.ECDsaKey;
|
||||||
|
|
||||||
|
if (ctx.Key == null)
|
||||||
|
throw new InvalidObjectException(nameof(ctx.Key));
|
||||||
|
if (ctx.OwnerId == null)
|
||||||
|
throw new InvalidObjectException(nameof(ctx.OwnerId));
|
||||||
|
|
||||||
var request = new ListRequest
|
var request = new ListRequest
|
||||||
{
|
{
|
||||||
Body = new ()
|
Body = new()
|
||||||
{
|
{
|
||||||
OwnerId = ctx.OwnerId.ToMessage()
|
OwnerId = ctx.OwnerId.ToMessage()
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
request.AddMetaHeader(args.XHeaders);
|
request.AddMetaHeader(args.XHeaders);
|
||||||
request.Sign(ctx.Key);
|
request.Sign(ctx.Key);
|
||||||
|
|
||||||
var response = await service.ListAsync(request, null, ctx.Deadline, ctx.CancellationToken);
|
var response = await service.ListAsync(request, null, ctx.Deadline, ctx.CancellationToken);
|
||||||
|
|
||||||
Verifier.CheckResponse(response);
|
Verifier.CheckResponse(response);
|
||||||
|
|
||||||
foreach (var cid in response.Body.ContainerIds)
|
foreach (var cid in response.Body.ContainerIds)
|
||||||
{
|
{
|
||||||
yield return new FrostFsContainerId(Base58.Encode(cid.Value.ToByteArray()));
|
yield return new FrostFsContainerId(Base58.Encode(cid.Value.ToByteArray()));
|
||||||
|
@ -63,42 +70,52 @@ internal class ContainerServiceProvider(ContainerService.ContainerServiceClient
|
||||||
|
|
||||||
var grpcContainer = args.Container.GetContainer();
|
var grpcContainer = args.Container.GetContainer();
|
||||||
|
|
||||||
grpcContainer.OwnerId ??= ctx.OwnerId.ToMessage();
|
grpcContainer.OwnerId ??= ctx.OwnerId?.ToMessage();
|
||||||
grpcContainer.Version ??= ctx.Version.ToMessage();
|
grpcContainer.Version ??= ctx.Version?.ToMessage();
|
||||||
|
|
||||||
|
if (ctx.Key == null)
|
||||||
|
throw new InvalidObjectException(nameof(ctx.Key));
|
||||||
|
if (grpcContainer.OwnerId == null)
|
||||||
|
throw new InvalidObjectException(nameof(grpcContainer.OwnerId));
|
||||||
|
if (grpcContainer.Version == null)
|
||||||
|
throw new InvalidObjectException(nameof(grpcContainer.Version));
|
||||||
|
|
||||||
var request = new PutRequest
|
var request = new PutRequest
|
||||||
{
|
{
|
||||||
Body = new PutRequest.Types.Body
|
Body = new PutRequest.Types.Body
|
||||||
{
|
{
|
||||||
Container = grpcContainer,
|
Container = grpcContainer,
|
||||||
Signature = ctx.Key.SignRFC6979(grpcContainer)
|
Signature = ctx.Key.SignRFC6979(grpcContainer)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
var sessionToken = await GetOrCreateSession(args, ctx);
|
var sessionToken = await GetOrCreateSession(args, ctx).ConfigureAwait(false);
|
||||||
|
|
||||||
sessionToken.CreateContainerTokenContext(
|
sessionToken.CreateContainerTokenContext(
|
||||||
null,
|
null,
|
||||||
ContainerSessionContext.Types.Verb.Put,
|
ContainerSessionContext.Types.Verb.Put,
|
||||||
ctx.Key,
|
ctx.Key,
|
||||||
ctx.GetPublicKeyCache());
|
ctx.GetPublicKeyCache()!);
|
||||||
|
|
||||||
request.AddMetaHeader(args.XHeaders, sessionToken);
|
request.AddMetaHeader(args.XHeaders, sessionToken);
|
||||||
|
|
||||||
request.Sign(ctx.Key);
|
request.Sign(ctx.Key);
|
||||||
|
|
||||||
var response = await service.PutAsync(request, null, ctx.Deadline, ctx.CancellationToken);
|
var response = await service.PutAsync(request, null, ctx.Deadline, ctx.CancellationToken);
|
||||||
|
|
||||||
Verifier.CheckResponse(response);
|
Verifier.CheckResponse(response);
|
||||||
|
|
||||||
await WaitForContainer(WaitExpects.Exists, response.Body.ContainerId, args.WaitParams, ctx);
|
await WaitForContainer(WaitExpects.Exists, response.Body.ContainerId, args.WaitParams, ctx).ConfigureAwait(false);
|
||||||
|
|
||||||
return new FrostFsContainerId(response.Body.ContainerId);
|
return new FrostFsContainerId(response.Body.ContainerId);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal async Task DeleteContainerAsync(PrmContainerDelete args)
|
internal async Task DeleteContainerAsync(PrmContainerDelete args)
|
||||||
{
|
{
|
||||||
var ctx = args.Context!;
|
var ctx = args.Context!;
|
||||||
|
if (ctx.Key == null)
|
||||||
|
throw new InvalidObjectException(nameof(ctx.Key));
|
||||||
|
|
||||||
var request = new DeleteRequest
|
var request = new DeleteRequest
|
||||||
{
|
{
|
||||||
Body = new DeleteRequest.Types.Body
|
Body = new DeleteRequest.Types.Body
|
||||||
|
@ -108,13 +125,13 @@ internal class ContainerServiceProvider(ContainerService.ContainerServiceClient
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
var sessionToken = await GetOrCreateSession(args, ctx);
|
var sessionToken = await GetOrCreateSession(args, ctx).ConfigureAwait(false);
|
||||||
|
|
||||||
sessionToken.CreateContainerTokenContext(
|
sessionToken.CreateContainerTokenContext(
|
||||||
request.Body.ContainerId,
|
request.Body.ContainerId,
|
||||||
ContainerSessionContext.Types.Verb.Delete,
|
ContainerSessionContext.Types.Verb.Delete,
|
||||||
ctx.Key,
|
ctx.Key,
|
||||||
ctx.GetPublicKeyCache());
|
ctx.GetPublicKeyCache()!);
|
||||||
|
|
||||||
request.AddMetaHeader(args.XHeaders, sessionToken);
|
request.AddMetaHeader(args.XHeaders, sessionToken);
|
||||||
|
|
||||||
|
@ -124,13 +141,17 @@ internal class ContainerServiceProvider(ContainerService.ContainerServiceClient
|
||||||
|
|
||||||
Verifier.CheckResponse(response);
|
Verifier.CheckResponse(response);
|
||||||
|
|
||||||
await WaitForContainer(WaitExpects.Removed, request.Body.ContainerId, args.WaitParams, ctx);
|
await WaitForContainer(WaitExpects.Removed, request.Body.ContainerId, args.WaitParams, ctx)
|
||||||
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
Verifier.CheckResponse(response);
|
Verifier.CheckResponse(response);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static GetRequest GetContainerRequest(ContainerID id, NameValueCollection? xHeaders, Context ctx)
|
private static GetRequest GetContainerRequest(ContainerID id, NameValueCollection? xHeaders, Context ctx)
|
||||||
{
|
{
|
||||||
|
if (ctx.Key == null)
|
||||||
|
throw new InvalidObjectException(nameof(ctx.Key));
|
||||||
|
|
||||||
var request = new GetRequest
|
var request = new GetRequest
|
||||||
{
|
{
|
||||||
Body = new GetRequest.Types.Body
|
Body = new GetRequest.Types.Body
|
||||||
|
@ -146,7 +167,7 @@ internal class ContainerServiceProvider(ContainerService.ContainerServiceClient
|
||||||
}
|
}
|
||||||
|
|
||||||
private enum WaitExpects
|
private enum WaitExpects
|
||||||
{
|
{
|
||||||
Exists,
|
Exists,
|
||||||
Removed
|
Removed
|
||||||
}
|
}
|
||||||
|
@ -161,7 +182,7 @@ internal class ContainerServiceProvider(ContainerService.ContainerServiceClient
|
||||||
Verifier.CheckResponse(response);
|
Verifier.CheckResponse(response);
|
||||||
}
|
}
|
||||||
|
|
||||||
await WaitFor(action, expect, waitParams);
|
await WaitFor(action, expect, waitParams).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task WaitFor(
|
private static async Task WaitFor(
|
||||||
|
@ -176,7 +197,7 @@ internal class ContainerServiceProvider(ContainerService.ContainerServiceClient
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await action();
|
await action().ConfigureAwait(false);
|
||||||
|
|
||||||
if (expect == WaitExpects.Exists)
|
if (expect == WaitExpects.Exists)
|
||||||
return;
|
return;
|
||||||
|
@ -184,20 +205,20 @@ internal class ContainerServiceProvider(ContainerService.ContainerServiceClient
|
||||||
if (DateTime.UtcNow >= deadLine)
|
if (DateTime.UtcNow >= deadLine)
|
||||||
throw new TimeoutException();
|
throw new TimeoutException();
|
||||||
|
|
||||||
await Task.Delay(waitParams.PollInterval);
|
await Task.Delay(waitParams.PollInterval).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
catch (ResponseException ex)
|
catch (ResponseException ex)
|
||||||
{
|
{
|
||||||
if (DateTime.UtcNow >= deadLine)
|
if (DateTime.UtcNow >= deadLine)
|
||||||
throw new TimeoutException();
|
throw new TimeoutException();
|
||||||
|
|
||||||
if (ex.Status.Code != FrostFsStatusCode.ContainerNotFound)
|
if (ex.Status?.Code != FrostFsStatusCode.ContainerNotFound)
|
||||||
throw;
|
throw;
|
||||||
|
|
||||||
if (expect == WaitExpects.Removed)
|
if (expect == WaitExpects.Removed)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
await Task.Delay(waitParams.PollInterval);
|
await Task.Delay(waitParams.PollInterval).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,12 +8,12 @@ using static FrostFS.Netmap.NetworkConfig.Types;
|
||||||
|
|
||||||
namespace FrostFS.SDK.ClientV2;
|
namespace FrostFS.SDK.ClientV2;
|
||||||
|
|
||||||
internal class NetmapServiceProvider : ContextAccessor
|
internal sealed class NetmapServiceProvider : ContextAccessor
|
||||||
{
|
{
|
||||||
private readonly NetmapService.NetmapServiceClient netmapServiceClient;
|
private readonly NetmapService.NetmapServiceClient netmapServiceClient;
|
||||||
|
|
||||||
internal NetmapServiceProvider(NetmapService.NetmapServiceClient netmapServiceClient, ClientEnvironment context)
|
internal NetmapServiceProvider(NetmapService.NetmapServiceClient netmapServiceClient, ClientEnvironment context)
|
||||||
: base(context)
|
: base(context)
|
||||||
{
|
{
|
||||||
this.netmapServiceClient = netmapServiceClient;
|
this.netmapServiceClient = netmapServiceClient;
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,7 @@ internal class NetmapServiceProvider : ContextAccessor
|
||||||
if (Context.NetworkSettings != null)
|
if (Context.NetworkSettings != null)
|
||||||
return Context.NetworkSettings;
|
return Context.NetworkSettings;
|
||||||
|
|
||||||
var info = await GetNetworkInfoAsync(ctx);
|
var info = await GetNetworkInfoAsync(ctx).ConfigureAwait(false);
|
||||||
|
|
||||||
var settings = new NetworkSettings();
|
var settings = new NetworkSettings();
|
||||||
|
|
||||||
|
@ -33,13 +33,18 @@ internal class NetmapServiceProvider : ContextAccessor
|
||||||
}
|
}
|
||||||
|
|
||||||
Context.NetworkSettings = settings;
|
Context.NetworkSettings = settings;
|
||||||
|
|
||||||
return settings;
|
return settings;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal async Task<FrostFsNodeInfo> GetLocalNodeInfoAsync(PrmNodeInfo args)
|
internal async Task<FrostFsNodeInfo> GetLocalNodeInfoAsync(PrmNodeInfo args)
|
||||||
{
|
{
|
||||||
var ctx = args.Context!;
|
var ctx = args.Context!;
|
||||||
|
ctx.Key ??= Context.Key?.ECDsaKey;
|
||||||
|
|
||||||
|
if (ctx.Key == null)
|
||||||
|
throw new InvalidObjectException(nameof(ctx.Key));
|
||||||
|
|
||||||
var request = new LocalNodeInfoRequest
|
var request = new LocalNodeInfoRequest
|
||||||
{
|
{
|
||||||
Body = new LocalNodeInfoRequest.Types.Body { }
|
Body = new LocalNodeInfoRequest.Types.Body { }
|
||||||
|
@ -47,7 +52,7 @@ internal class NetmapServiceProvider : ContextAccessor
|
||||||
|
|
||||||
request.AddMetaHeader(args.XHeaders);
|
request.AddMetaHeader(args.XHeaders);
|
||||||
request.Sign(ctx.Key);
|
request.Sign(ctx.Key);
|
||||||
|
|
||||||
var response = await netmapServiceClient.LocalNodeInfoAsync(request, null, ctx.Deadline, ctx.CancellationToken);
|
var response = await netmapServiceClient.LocalNodeInfoAsync(request, null, ctx.Deadline, ctx.CancellationToken);
|
||||||
|
|
||||||
Verifier.CheckResponse(response);
|
Verifier.CheckResponse(response);
|
||||||
|
@ -57,12 +62,18 @@ internal class NetmapServiceProvider : ContextAccessor
|
||||||
|
|
||||||
internal async Task<NetworkInfoResponse> GetNetworkInfoAsync(Context ctx)
|
internal async Task<NetworkInfoResponse> GetNetworkInfoAsync(Context ctx)
|
||||||
{
|
{
|
||||||
var request = new NetworkInfoRequest();
|
ctx.Key ??= Context.Key?.ECDsaKey;
|
||||||
|
|
||||||
|
if (ctx.Key == null)
|
||||||
|
throw new InvalidObjectException(nameof(ctx.Key));
|
||||||
|
|
||||||
|
var request = new NetworkInfoRequest();
|
||||||
|
|
||||||
request.AddMetaHeader(null);
|
request.AddMetaHeader(null);
|
||||||
request.Sign(ctx.Key);
|
request.Sign(ctx.Key);
|
||||||
|
|
||||||
var response = await netmapServiceClient.NetworkInfoAsync(request, null, ctx.Deadline, ctx.CancellationToken);
|
var response = await netmapServiceClient.NetworkInfoAsync(request, null, ctx.Deadline, ctx.CancellationToken)
|
||||||
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
Verifier.CheckResponse(response);
|
Verifier.CheckResponse(response);
|
||||||
|
|
||||||
|
@ -72,12 +83,16 @@ internal class NetmapServiceProvider : ContextAccessor
|
||||||
internal async Task<FrostFsNetmapSnapshot> GetNetmapSnapshotAsync(PrmNetmapSnapshot args)
|
internal async Task<FrostFsNetmapSnapshot> GetNetmapSnapshotAsync(PrmNetmapSnapshot args)
|
||||||
{
|
{
|
||||||
var ctx = args.Context!;
|
var ctx = args.Context!;
|
||||||
|
ctx.Key ??= Context.Key?.ECDsaKey;
|
||||||
|
|
||||||
|
if (ctx.Key == null)
|
||||||
|
throw new InvalidObjectException(nameof(ctx.Key));
|
||||||
|
|
||||||
var request = new NetmapSnapshotRequest();
|
var request = new NetmapSnapshotRequest();
|
||||||
|
|
||||||
request.AddMetaHeader(args.XHeaders);
|
request.AddMetaHeader(args.XHeaders);
|
||||||
request.Sign(ctx.Key);
|
request.Sign(ctx.Key);
|
||||||
|
|
||||||
var response = await netmapServiceClient.NetmapSnapshotAsync(request, null, ctx.Deadline, ctx.CancellationToken);
|
var response = await netmapServiceClient.NetmapSnapshotAsync(request, null, ctx.Deadline, ctx.CancellationToken);
|
||||||
|
|
||||||
Verifier.CheckResponse(response);
|
Verifier.CheckResponse(response);
|
||||||
|
@ -95,12 +110,12 @@ internal class NetmapServiceProvider : ContextAccessor
|
||||||
ulong val = 0;
|
ulong val = 0;
|
||||||
for (var i = bytes.Length - 1; i >= 0; i--)
|
for (var i = bytes.Length - 1; i >= 0; i--)
|
||||||
val = (val << 8) + bytes[i];
|
val = (val << 8) + bytes[i];
|
||||||
|
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void SetNetworksParam(Parameter param, NetworkSettings settings)
|
private static void SetNetworksParam(Parameter param, NetworkSettings settings)
|
||||||
{
|
{
|
||||||
var key = Encoding.UTF8.GetString(param.Key.ToByteArray());
|
var key = Encoding.UTF8.GetString(param.Key.ToByteArray());
|
||||||
|
|
||||||
var valueBytes = param.Value.ToByteArray();
|
var valueBytes = param.Value.ToByteArray();
|
||||||
|
|
|
@ -6,9 +6,8 @@ using System.Threading.Tasks;
|
||||||
|
|
||||||
using FrostFS.Object;
|
using FrostFS.Object;
|
||||||
using FrostFS.Refs;
|
using FrostFS.Refs;
|
||||||
using FrostFS.SDK.ClientV2.Extensions;
|
|
||||||
using FrostFS.SDK.ClientV2.Mappers.GRPC;
|
|
||||||
using FrostFS.SDK.ClientV2;
|
using FrostFS.SDK.ClientV2;
|
||||||
|
using FrostFS.SDK.ClientV2.Mappers.GRPC;
|
||||||
using FrostFS.SDK.Cryptography;
|
using FrostFS.SDK.Cryptography;
|
||||||
using FrostFS.Session;
|
using FrostFS.Session;
|
||||||
|
|
||||||
|
@ -16,19 +15,30 @@ using Google.Protobuf;
|
||||||
|
|
||||||
namespace FrostFS.SDK.ClientV2;
|
namespace FrostFS.SDK.ClientV2;
|
||||||
|
|
||||||
internal class ObjectServiceProvider(ObjectService.ObjectServiceClient client, ClientEnvironment env)
|
internal sealed class ObjectServiceProvider : ContextAccessor, ISessionProvider
|
||||||
: ContextAccessor(env), ISessionProvider
|
|
||||||
{
|
{
|
||||||
readonly SessionProvider sessions = new (env);
|
private readonly SessionProvider sessions;
|
||||||
|
private ObjectService.ObjectServiceClient client;
|
||||||
|
|
||||||
public async ValueTask<Session.SessionToken> GetOrCreateSession(ISessionToken args, Context ctx)
|
internal ObjectServiceProvider(ObjectService.ObjectServiceClient client, ClientEnvironment env)
|
||||||
|
: base(env)
|
||||||
{
|
{
|
||||||
return await sessions.GetOrCreateSession(args, ctx);
|
this.sessions = new(Context);
|
||||||
|
this.client = client;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async ValueTask<SessionToken> GetOrCreateSession(ISessionToken args, Context ctx)
|
||||||
|
{
|
||||||
|
return await sessions.GetOrCreateSession(args, ctx).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal async Task<FrostFsObjectHeader> GetObjectHeadAsync(PrmObjectHeadGet args)
|
internal async Task<FrostFsObjectHeader> GetObjectHeadAsync(PrmObjectHeadGet args)
|
||||||
{
|
{
|
||||||
var ctx = args.Context!;
|
var ctx = args.Context!;
|
||||||
|
ctx.Key ??= Context.Key?.ECDsaKey;
|
||||||
|
|
||||||
|
if (ctx.Key == null)
|
||||||
|
throw new InvalidObjectException(nameof(ctx.Key));
|
||||||
|
|
||||||
var request = new HeadRequest
|
var request = new HeadRequest
|
||||||
{
|
{
|
||||||
|
@ -42,7 +52,7 @@ internal class ObjectServiceProvider(ObjectService.ObjectServiceClient client, C
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
var sessionToken = await GetOrCreateSession(args, ctx);
|
var sessionToken = await GetOrCreateSession(args, ctx).ConfigureAwait(false);
|
||||||
|
|
||||||
sessionToken.CreateObjectTokenContext(
|
sessionToken.CreateObjectTokenContext(
|
||||||
request.Body.Address,
|
request.Body.Address,
|
||||||
|
@ -53,8 +63,8 @@ internal class ObjectServiceProvider(ObjectService.ObjectServiceClient client, C
|
||||||
|
|
||||||
request.Sign(ctx.Key);
|
request.Sign(ctx.Key);
|
||||||
|
|
||||||
var response = await client!.HeadAsync(request, null, ctx.Deadline, ctx.CancellationToken);
|
var response = await client!.HeadAsync(request, null, ctx.Deadline, ctx.CancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
Verifier.CheckResponse(response);
|
Verifier.CheckResponse(response);
|
||||||
|
|
||||||
return response.Body.Header.Header.ToModel();
|
return response.Body.Header.Header.ToModel();
|
||||||
|
@ -63,7 +73,12 @@ internal class ObjectServiceProvider(ObjectService.ObjectServiceClient client, C
|
||||||
internal async Task<FrostFsObject> GetObjectAsync(PrmObjectGet args)
|
internal async Task<FrostFsObject> GetObjectAsync(PrmObjectGet args)
|
||||||
{
|
{
|
||||||
var ctx = args.Context!;
|
var ctx = args.Context!;
|
||||||
|
|
||||||
|
ctx.Key ??= Context.Key?.ECDsaKey;
|
||||||
|
|
||||||
|
if (ctx.Key == null)
|
||||||
|
throw new InvalidObjectException(nameof(ctx.Key));
|
||||||
|
|
||||||
var request = new GetRequest
|
var request = new GetRequest
|
||||||
{
|
{
|
||||||
Body = new GetRequest.Types.Body
|
Body = new GetRequest.Types.Body
|
||||||
|
@ -76,7 +91,7 @@ internal class ObjectServiceProvider(ObjectService.ObjectServiceClient client, C
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
var sessionToken = await GetOrCreateSession(args, ctx);
|
var sessionToken = await GetOrCreateSession(args, ctx).ConfigureAwait(false);
|
||||||
|
|
||||||
sessionToken.CreateObjectTokenContext(
|
sessionToken.CreateObjectTokenContext(
|
||||||
request.Body.Address,
|
request.Body.Address,
|
||||||
|
@ -87,12 +102,17 @@ internal class ObjectServiceProvider(ObjectService.ObjectServiceClient client, C
|
||||||
|
|
||||||
request.Sign(ctx.Key);
|
request.Sign(ctx.Key);
|
||||||
|
|
||||||
return await GetObject(request, ctx);
|
return await GetObject(request, ctx).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal async Task DeleteObjectAsync(PrmObjectDelete args)
|
internal async Task DeleteObjectAsync(PrmObjectDelete args)
|
||||||
{
|
{
|
||||||
var ctx = args.Context!;
|
var ctx = args.Context!;
|
||||||
|
ctx.Key ??= Context.Key?.ECDsaKey;
|
||||||
|
|
||||||
|
if (ctx.Key == null)
|
||||||
|
throw new InvalidObjectException(nameof(ctx.Key));
|
||||||
|
|
||||||
var request = new DeleteRequest
|
var request = new DeleteRequest
|
||||||
{
|
{
|
||||||
Body = new DeleteRequest.Types.Body
|
Body = new DeleteRequest.Types.Body
|
||||||
|
@ -105,7 +125,7 @@ internal class ObjectServiceProvider(ObjectService.ObjectServiceClient client, C
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
var sessionToken = await GetOrCreateSession(args, ctx);
|
var sessionToken = await GetOrCreateSession(args, ctx).ConfigureAwait(false);
|
||||||
|
|
||||||
sessionToken.CreateObjectTokenContext(
|
sessionToken.CreateObjectTokenContext(
|
||||||
request.Body.Address,
|
request.Body.Address,
|
||||||
|
@ -116,26 +136,29 @@ internal class ObjectServiceProvider(ObjectService.ObjectServiceClient client, C
|
||||||
request.Sign(ctx.Key);
|
request.Sign(ctx.Key);
|
||||||
|
|
||||||
var response = await client.DeleteAsync(request, null, ctx.Deadline, ctx.CancellationToken);
|
var response = await client.DeleteAsync(request, null, ctx.Deadline, ctx.CancellationToken);
|
||||||
|
|
||||||
Verifier.CheckResponse(response);
|
Verifier.CheckResponse(response);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal async IAsyncEnumerable<FrostFsObjectId> SearchObjectsAsync(PrmObjectSearch args)
|
internal async IAsyncEnumerable<FrostFsObjectId> SearchObjectsAsync(PrmObjectSearch args)
|
||||||
{
|
{
|
||||||
var ctx = args.Context!;
|
var ctx = args.Context!;
|
||||||
|
|
||||||
|
if (ctx.Key == null)
|
||||||
|
throw new InvalidObjectException(nameof(ctx.Key));
|
||||||
|
|
||||||
var request = new SearchRequest
|
var request = new SearchRequest
|
||||||
{
|
{
|
||||||
Body = new SearchRequest.Types.Body
|
Body = new SearchRequest.Types.Body
|
||||||
{
|
{
|
||||||
ContainerId = args.ContainerId.ToMessage(),
|
ContainerId = args.ContainerId.ToMessage(),
|
||||||
Filters = { },
|
|
||||||
Version = 1 // TODO: clarify this param
|
Version = 1 // TODO: clarify this param
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
request.Body.Filters.AddRange(args.Filters.Select(f => f.ToMessage()));
|
request.Body.Filters.AddRange(args.Filters.Select(f => f.ToMessage()));
|
||||||
|
|
||||||
var sessionToken = await GetOrCreateSession(args, ctx);
|
var sessionToken = await GetOrCreateSession(args, ctx).ConfigureAwait(false);
|
||||||
|
|
||||||
sessionToken.CreateObjectTokenContext(
|
sessionToken.CreateObjectTokenContext(
|
||||||
new Address { ContainerId = request.Body.ContainerId },
|
new Address { ContainerId = request.Body.ContainerId },
|
||||||
|
@ -143,7 +166,7 @@ internal class ObjectServiceProvider(ObjectService.ObjectServiceClient client, C
|
||||||
ctx.Key);
|
ctx.Key);
|
||||||
|
|
||||||
request.AddMetaHeader(args.XHeaders, sessionToken);
|
request.AddMetaHeader(args.XHeaders, sessionToken);
|
||||||
|
|
||||||
request.Sign(ctx.Key);
|
request.Sign(ctx.Key);
|
||||||
|
|
||||||
var objectsIds = SearchObjects(request, ctx);
|
var objectsIds = SearchObjects(request, ctx);
|
||||||
|
@ -156,14 +179,17 @@ internal class ObjectServiceProvider(ObjectService.ObjectServiceClient client, C
|
||||||
|
|
||||||
internal async Task<FrostFsObjectId> PutObjectAsync(PrmObjectPut args)
|
internal async Task<FrostFsObjectId> PutObjectAsync(PrmObjectPut args)
|
||||||
{
|
{
|
||||||
|
if (args is null)
|
||||||
|
throw new ArgumentNullException(nameof(args));
|
||||||
|
|
||||||
if (args.Header == null)
|
if (args.Header == null)
|
||||||
throw new ArgumentException("Value cannot be null", nameof(args.Header));
|
throw new ArgumentException(nameof(args.Header));
|
||||||
|
|
||||||
if (args.Payload == null)
|
if (args.Payload == null)
|
||||||
throw new ArgumentException("Value cannot be null", nameof(args.Payload));
|
throw new ArgumentException(nameof(args.Payload));
|
||||||
|
|
||||||
if (args.ClientCut)
|
if (args.ClientCut)
|
||||||
return await PutClientCutObject(args);
|
return await PutClientCutObject(args).ConfigureAwait(false);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (args.Header.PayloadLength > 0)
|
if (args.Header.PayloadLength > 0)
|
||||||
|
@ -171,24 +197,28 @@ internal class ObjectServiceProvider(ObjectService.ObjectServiceClient client, C
|
||||||
else if (args.Payload.CanSeek)
|
else if (args.Payload.CanSeek)
|
||||||
args.FullLength = (ulong)args.Payload.Length;
|
args.FullLength = (ulong)args.Payload.Length;
|
||||||
|
|
||||||
return (await PutStreamObject(args)).ObjectId;
|
return (await PutStreamObject(args).ConfigureAwait(false)).ObjectId;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal async Task<FrostFsObjectId> PutSingleObjectAsync(PrmSingleObjectPut args)
|
internal async Task<FrostFsObjectId> PutSingleObjectAsync(PrmSingleObjectPut args)
|
||||||
{
|
{
|
||||||
var ctx = args.Context!;
|
var ctx = args.Context!;
|
||||||
|
|
||||||
|
if (ctx.Key == null)
|
||||||
|
throw new InvalidObjectException(nameof(ctx.Key));
|
||||||
|
|
||||||
var grpcObject = ObjectTools.CreateObject(args.FrostFsObject, ctx);
|
var grpcObject = ObjectTools.CreateObject(args.FrostFsObject, ctx);
|
||||||
|
|
||||||
var request = new PutSingleRequest
|
var request = new PutSingleRequest
|
||||||
{
|
{
|
||||||
Body = new () { Object = grpcObject }
|
Body = new() { Object = grpcObject }
|
||||||
};
|
};
|
||||||
|
|
||||||
var sessionToken = await GetOrCreateSession(args, ctx);
|
var sessionToken = await GetOrCreateSession(args, ctx).ConfigureAwait(false);
|
||||||
|
|
||||||
sessionToken.CreateObjectTokenContext(
|
sessionToken.CreateObjectTokenContext(
|
||||||
new Address { ContainerId = grpcObject.Header.ContainerId, ObjectId = grpcObject.ObjectId},
|
new Address { ContainerId = grpcObject.Header.ContainerId, ObjectId = grpcObject.ObjectId },
|
||||||
ObjectSessionContext.Types.Verb.Put,
|
ObjectSessionContext.Types.Verb.Put,
|
||||||
ctx.Key);
|
ctx.Key);
|
||||||
|
|
||||||
|
@ -196,18 +226,18 @@ internal class ObjectServiceProvider(ObjectService.ObjectServiceClient client, C
|
||||||
|
|
||||||
request.Sign(ctx.Key);
|
request.Sign(ctx.Key);
|
||||||
|
|
||||||
var response = await client.PutSingleAsync(request, null, ctx.Deadline, ctx.CancellationToken);
|
var response = await client.PutSingleAsync(request, null, ctx.Deadline, ctx.CancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
Verifier.CheckResponse(response);
|
Verifier.CheckResponse(response);
|
||||||
|
|
||||||
return FrostFsObjectId.FromHash(grpcObject.ObjectId.Value.ToByteArray());
|
return FrostFsObjectId.FromHash(grpcObject.ObjectId.Value.ToByteArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<FrostFsObjectId> PutClientCutObject(PrmObjectPut args)
|
private async Task<FrostFsObjectId> PutClientCutObject(PrmObjectPut args)
|
||||||
{
|
{
|
||||||
var ctx = args.Context!;
|
var ctx = args.Context!;
|
||||||
|
|
||||||
var tokenRaw = await GetOrCreateSession(args, ctx);
|
var tokenRaw = await GetOrCreateSession(args, ctx).ConfigureAwait(false);
|
||||||
var token = new FrostFsSessionToken(tokenRaw.Serialize());
|
var token = new FrostFsSessionToken(tokenRaw.Serialize());
|
||||||
|
|
||||||
args.SessionToken = token;
|
args.SessionToken = token;
|
||||||
|
@ -216,7 +246,7 @@ internal class ObjectServiceProvider(ObjectService.ObjectServiceClient client, C
|
||||||
var header = args.Header!;
|
var header = args.Header!;
|
||||||
|
|
||||||
var fullLength = header.PayloadLength;
|
var fullLength = header.PayloadLength;
|
||||||
|
|
||||||
if (payloadStream.CanSeek && fullLength == 0)
|
if (payloadStream.CanSeek && fullLength == 0)
|
||||||
fullLength = (ulong)payloadStream.Length;
|
fullLength = (ulong)payloadStream.Length;
|
||||||
|
|
||||||
|
@ -224,12 +254,14 @@ internal class ObjectServiceProvider(ObjectService.ObjectServiceClient client, C
|
||||||
|
|
||||||
if (args.MaxObjectSizeCache == 0)
|
if (args.MaxObjectSizeCache == 0)
|
||||||
{
|
{
|
||||||
var networkSettings = await Context.Client.GetNetworkSettingsAsync(new PrmNetworkSettings() { Context = ctx });
|
var networkSettings = await Context.Client.GetNetworkSettingsAsync(new PrmNetworkSettings() { Context = ctx })
|
||||||
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
args.MaxObjectSizeCache = (int)networkSettings.MaxObjectSize;
|
args.MaxObjectSizeCache = (int)networkSettings.MaxObjectSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
var restBytes = fullLength - args.CurrentStreamPosition;
|
var restBytes = fullLength - args.CurrentStreamPosition;
|
||||||
var objectSize = restBytes > 0 ? (int)Math.Min((ulong)args.MaxObjectSizeCache, restBytes) : args.MaxObjectSizeCache;
|
var objectSize = restBytes > 0 ? (int)Math.Min((ulong)args.MaxObjectSizeCache, restBytes) : args.MaxObjectSizeCache;
|
||||||
|
|
||||||
//define collection capacity
|
//define collection capacity
|
||||||
var restPart = (restBytes % (ulong)objectSize) > 0 ? 1 : 0;
|
var restPart = (restBytes % (ulong)objectSize) > 0 ? 1 : 0;
|
||||||
|
@ -238,23 +270,20 @@ internal class ObjectServiceProvider(ObjectService.ObjectServiceClient client, C
|
||||||
List<FrostFsObjectId> sentObjectIds = new(objectsCount);
|
List<FrostFsObjectId> sentObjectIds = new(objectsCount);
|
||||||
|
|
||||||
FrostFsSplit? split = null;
|
FrostFsSplit? split = null;
|
||||||
|
SplitId splitId = new();
|
||||||
|
|
||||||
// keep attributes for the large object
|
// keep attributes for the large object
|
||||||
var attributes = args.Header!.Attributes;
|
var attributes = args.Header!.Attributes;
|
||||||
|
args.Header!.Attributes = null;
|
||||||
|
|
||||||
// send all parts except the last one as separate Objects
|
// send all parts except the last one as separate Objects
|
||||||
while (restBytes > (ulong)args.MaxObjectSizeCache)
|
while (restBytes > (ulong)args.MaxObjectSizeCache)
|
||||||
{
|
{
|
||||||
if (split == null)
|
split = new FrostFsSplit(splitId, sentObjectIds.LastOrDefault());
|
||||||
{
|
|
||||||
split = new FrostFsSplit();
|
|
||||||
args.Header!.Attributes = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
split!.Previous = sentObjectIds.LastOrDefault();
|
|
||||||
args.Header!.Split = split;
|
args.Header!.Split = split;
|
||||||
|
|
||||||
var result = await PutStreamObject(args);
|
var result = await PutStreamObject(args).ConfigureAwait(false);
|
||||||
|
|
||||||
sentObjectIds.Add(result.ObjectId);
|
sentObjectIds.Add(result.ObjectId);
|
||||||
|
|
||||||
|
@ -264,26 +293,30 @@ internal class ObjectServiceProvider(ObjectService.ObjectServiceClient client, C
|
||||||
// send the last part and create linkObject
|
// send the last part and create linkObject
|
||||||
if (sentObjectIds.Count > 0)
|
if (sentObjectIds.Count > 0)
|
||||||
{
|
{
|
||||||
var largeObjectHeader = new FrostFsObjectHeader(header.ContainerId) { PayloadLength = fullLength };
|
var largeObjectHeader = new FrostFsObjectHeader(header.ContainerId, FrostFsObjectType.Regular, [.. attributes])
|
||||||
|
{
|
||||||
largeObjectHeader.Attributes.AddRange(attributes);
|
PayloadLength = fullLength,
|
||||||
|
};
|
||||||
|
|
||||||
args.Header.Split!.ParentHeader = largeObjectHeader;
|
args.Header.Split!.ParentHeader = largeObjectHeader;
|
||||||
|
|
||||||
var result = await PutStreamObject(args);
|
var result = await PutStreamObject(args).ConfigureAwait(false);
|
||||||
|
|
||||||
sentObjectIds.Add(result.ObjectId);
|
sentObjectIds.Add(result.ObjectId);
|
||||||
|
|
||||||
var linkObject = new FrostFsLinkObject(header.ContainerId, split!.SplitId, largeObjectHeader)
|
var linkObject = new FrostFsLinkObject(header.ContainerId, split!.SplitId, largeObjectHeader, sentObjectIds);
|
||||||
.AddChildren(sentObjectIds);
|
|
||||||
|
|
||||||
_ = await PutSingleObjectAsync(new PrmSingleObjectPut(linkObject) { Context = args.Context});
|
_ = await PutSingleObjectAsync(new PrmSingleObjectPut(linkObject) { Context = args.Context }).ConfigureAwait(false);
|
||||||
|
|
||||||
return split.Parent!;
|
var parentHeader = args.Header.GetHeader();
|
||||||
|
|
||||||
|
return parentHeader.Split!.Parent.ToModel();
|
||||||
}
|
}
|
||||||
|
|
||||||
// We are here if the payload is placed to one Object. It means no cut action, just simple PUT.
|
// We are here if the payload is placed to one Object. It means no cut action, just simple PUT.
|
||||||
var singlePartResult = await PutStreamObject(args);
|
args.Header!.Attributes = attributes;
|
||||||
|
|
||||||
|
var singlePartResult = await PutStreamObject(args).ConfigureAwait(false);
|
||||||
|
|
||||||
return singlePartResult.ObjectId;
|
return singlePartResult.ObjectId;
|
||||||
}
|
}
|
||||||
|
@ -297,6 +330,9 @@ internal class ObjectServiceProvider(ObjectService.ObjectServiceClient client, C
|
||||||
private async Task<PutObjectResult> PutStreamObject(PrmObjectPut args)
|
private async Task<PutObjectResult> PutStreamObject(PrmObjectPut args)
|
||||||
{
|
{
|
||||||
var ctx = args.Context!;
|
var ctx = args.Context!;
|
||||||
|
if (ctx.Key == null)
|
||||||
|
throw new InvalidObjectException(nameof(ctx.Key));
|
||||||
|
|
||||||
var payload = args.Payload!;
|
var payload = args.Payload!;
|
||||||
|
|
||||||
var chunkSize = args.BufferMaxSize > 0 ? args.BufferMaxSize : Constants.ObjectChunkSize;
|
var chunkSize = args.BufferMaxSize > 0 ? args.BufferMaxSize : Constants.ObjectChunkSize;
|
||||||
|
@ -307,7 +343,7 @@ internal class ObjectServiceProvider(ObjectService.ObjectServiceClient client, C
|
||||||
|
|
||||||
bool isRentBuffer = false;
|
bool isRentBuffer = false;
|
||||||
byte[]? chunkBuffer = null;
|
byte[]? chunkBuffer = null;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (args.CustomBuffer != null)
|
if (args.CustomBuffer != null)
|
||||||
|
@ -316,7 +352,7 @@ internal class ObjectServiceProvider(ObjectService.ObjectServiceClient client, C
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
chunkBuffer = env.GetArrayPool(Constants.ObjectChunkSize).Rent(chunkSize);
|
chunkBuffer = Context.GetArrayPool(Constants.ObjectChunkSize).Rent(chunkSize);
|
||||||
isRentBuffer = true;
|
isRentBuffer = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -325,7 +361,7 @@ internal class ObjectServiceProvider(ObjectService.ObjectServiceClient client, C
|
||||||
// 0 means no limit from client, so server side cut is performed
|
// 0 means no limit from client, so server side cut is performed
|
||||||
var objectLimitSize = args.ClientCut ? args.MaxObjectSizeCache : 0;
|
var objectLimitSize = args.ClientCut ? args.MaxObjectSizeCache : 0;
|
||||||
|
|
||||||
var stream = await GetUploadStream(args, ctx);
|
using var stream = await GetUploadStream(args, ctx).ConfigureAwait(false);
|
||||||
|
|
||||||
while (objectLimitSize == 0 || sentBytes < objectLimitSize)
|
while (objectLimitSize == 0 || sentBytes < objectLimitSize)
|
||||||
{
|
{
|
||||||
|
@ -334,7 +370,7 @@ internal class ObjectServiceProvider(ObjectService.ObjectServiceClient client, C
|
||||||
(int)Math.Min(objectLimitSize - sentBytes, chunkSize)
|
(int)Math.Min(objectLimitSize - sentBytes, chunkSize)
|
||||||
: chunkSize;
|
: chunkSize;
|
||||||
|
|
||||||
var bytesCount = await payload.ReadAsync(chunkBuffer, 0, bufferSize, ctx.CancellationToken);
|
var bytesCount = await payload.ReadAsync(chunkBuffer, 0, bufferSize, ctx.CancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
if (bytesCount == 0)
|
if (bytesCount == 0)
|
||||||
break;
|
break;
|
||||||
|
@ -351,10 +387,10 @@ internal class ObjectServiceProvider(ObjectService.ObjectServiceClient client, C
|
||||||
|
|
||||||
chunkRequest.Sign(ctx.Key);
|
chunkRequest.Sign(ctx.Key);
|
||||||
|
|
||||||
await stream.Write(chunkRequest);
|
await stream.Write(chunkRequest).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
var response = await stream.Close();
|
var response = await stream.Close().ConfigureAwait(false);
|
||||||
Verifier.CheckResponse(response);
|
Verifier.CheckResponse(response);
|
||||||
|
|
||||||
return new PutObjectResult(FrostFsObjectId.FromHash(response.Body.ObjectId.Value.ToByteArray()), sentBytes);
|
return new PutObjectResult(FrostFsObjectId.FromHash(response.Body.ObjectId.Value.ToByteArray()), sentBytes);
|
||||||
|
@ -372,6 +408,9 @@ internal class ObjectServiceProvider(ObjectService.ObjectServiceClient client, C
|
||||||
{
|
{
|
||||||
var header = args.Header!;
|
var header = args.Header!;
|
||||||
|
|
||||||
|
if (ctx.Key == null)
|
||||||
|
throw new InvalidObjectException(nameof(ctx.Key));
|
||||||
|
|
||||||
header.OwnerId ??= ctx.OwnerId;
|
header.OwnerId ??= ctx.OwnerId;
|
||||||
header.Version ??= ctx.Version;
|
header.Version ??= ctx.Version;
|
||||||
|
|
||||||
|
@ -395,7 +434,7 @@ internal class ObjectServiceProvider(ObjectService.ObjectServiceClient client, C
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
var sessionToken = await GetOrCreateSession(args, ctx);
|
var sessionToken = await GetOrCreateSession(args, ctx).ConfigureAwait(false);
|
||||||
|
|
||||||
sessionToken.CreateObjectTokenContext(
|
sessionToken.CreateObjectTokenContext(
|
||||||
new Address { ContainerId = grpcHeader.ContainerId, ObjectId = oid },
|
new Address { ContainerId = grpcHeader.ContainerId, ObjectId = oid },
|
||||||
|
@ -407,19 +446,19 @@ internal class ObjectServiceProvider(ObjectService.ObjectServiceClient client, C
|
||||||
|
|
||||||
initRequest.Sign(ctx.Key);
|
initRequest.Sign(ctx.Key);
|
||||||
|
|
||||||
return await PutObjectInit(initRequest, ctx);
|
return await PutObjectInit(initRequest, ctx).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<FrostFsObject> GetObject(GetRequest request, Context ctx)
|
private async Task<FrostFsObject> GetObject(GetRequest request, Context ctx)
|
||||||
{
|
{
|
||||||
var reader = GetObjectInit(request, ctx);
|
var reader = GetObjectInit(request, ctx);
|
||||||
|
|
||||||
var grpcObject = await reader.ReadHeader();
|
var grpcObject = await reader.ReadHeader().ConfigureAwait(false);
|
||||||
var modelObject = grpcObject.ToModel();
|
var modelObject = grpcObject.ToModel();
|
||||||
|
|
||||||
modelObject.ObjectReader = reader;
|
modelObject.ObjectReader = reader;
|
||||||
|
|
||||||
return modelObject;
|
return modelObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ObjectReader GetObjectInit(GetRequest initRequest, Context ctx)
|
private ObjectReader GetObjectInit(GetRequest initRequest, Context ctx)
|
||||||
|
@ -428,7 +467,7 @@ internal class ObjectServiceProvider(ObjectService.ObjectServiceClient client, C
|
||||||
throw new ArgumentNullException(nameof(initRequest));
|
throw new ArgumentNullException(nameof(initRequest));
|
||||||
|
|
||||||
var call = client.Get(initRequest, null, ctx.Deadline, ctx.CancellationToken);
|
var call = client.Get(initRequest, null, ctx.Deadline, ctx.CancellationToken);
|
||||||
|
|
||||||
return new ObjectReader(call);
|
return new ObjectReader(call);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -441,7 +480,7 @@ internal class ObjectServiceProvider(ObjectService.ObjectServiceClient client, C
|
||||||
|
|
||||||
var call = client.Put(null, ctx.Deadline, ctx.CancellationToken);
|
var call = client.Put(null, ctx.Deadline, ctx.CancellationToken);
|
||||||
|
|
||||||
await call.RequestStream.WriteAsync(initRequest);
|
await call.RequestStream.WriteAsync(initRequest).ConfigureAwait(false);
|
||||||
|
|
||||||
return new ObjectStreamer(call);
|
return new ObjectStreamer(call);
|
||||||
}
|
}
|
||||||
|
@ -449,14 +488,14 @@ internal class ObjectServiceProvider(ObjectService.ObjectServiceClient client, C
|
||||||
private async IAsyncEnumerable<ObjectID> SearchObjects(SearchRequest request, Context ctx)
|
private async IAsyncEnumerable<ObjectID> SearchObjects(SearchRequest request, Context ctx)
|
||||||
{
|
{
|
||||||
using var stream = GetSearchReader(request, ctx);
|
using var stream = GetSearchReader(request, ctx);
|
||||||
|
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
var ids = await stream.Read(ctx.CancellationToken);
|
var ids = await stream.Read(ctx.CancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
if (ids == null)
|
if (ids == null)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
foreach (var oid in ids)
|
foreach (var oid in ids)
|
||||||
{
|
{
|
||||||
yield return oid;
|
yield return oid;
|
||||||
|
@ -472,7 +511,7 @@ internal class ObjectServiceProvider(ObjectService.ObjectServiceClient client, C
|
||||||
}
|
}
|
||||||
|
|
||||||
var call = client.Search(initRequest, null, ctx.Deadline, ctx.CancellationToken);
|
var call = client.Search(initRequest, null, ctx.Deadline, ctx.CancellationToken);
|
||||||
|
|
||||||
return new SearchReader(call);
|
return new SearchReader(call);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,17 +1,17 @@
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
using FrostFS.SDK.ClientV2.Mappers.GRPC;
|
|
||||||
using FrostFS.SDK.ClientV2;
|
using FrostFS.SDK.ClientV2;
|
||||||
|
using FrostFS.SDK.ClientV2.Mappers.GRPC;
|
||||||
using FrostFS.Session;
|
using FrostFS.Session;
|
||||||
|
|
||||||
namespace FrostFS.SDK.ClientV2;
|
namespace FrostFS.SDK.ClientV2;
|
||||||
|
|
||||||
internal class SessionServiceProvider : ContextAccessor
|
internal sealed class SessionServiceProvider : ContextAccessor
|
||||||
{
|
{
|
||||||
private readonly SessionService.SessionServiceClient? _sessionServiceClient;
|
private readonly SessionService.SessionServiceClient? _sessionServiceClient;
|
||||||
|
|
||||||
internal SessionServiceProvider(SessionService.SessionServiceClient? sessionServiceClient, ClientEnvironment context)
|
internal SessionServiceProvider(SessionService.SessionServiceClient? sessionServiceClient, ClientEnvironment context)
|
||||||
: base (context)
|
: base(context)
|
||||||
{
|
{
|
||||||
_sessionServiceClient = sessionServiceClient;
|
_sessionServiceClient = sessionServiceClient;
|
||||||
}
|
}
|
||||||
|
@ -19,27 +19,30 @@ internal class SessionServiceProvider : ContextAccessor
|
||||||
internal async Task<SessionToken> CreateSessionAsync(PrmSessionCreate args)
|
internal async Task<SessionToken> CreateSessionAsync(PrmSessionCreate args)
|
||||||
{
|
{
|
||||||
var ctx = args.Context!;
|
var ctx = args.Context!;
|
||||||
|
|
||||||
|
ctx.OwnerId ??= Context.Owner;
|
||||||
|
|
||||||
var request = new CreateRequest
|
var request = new CreateRequest
|
||||||
{
|
{
|
||||||
Body = new CreateRequest.Types.Body
|
Body = new CreateRequest.Types.Body
|
||||||
{
|
{
|
||||||
OwnerId = ctx.OwnerId.ToMessage(),
|
OwnerId = ctx.OwnerId!.ToMessage(),
|
||||||
Expiration = args.Expiration
|
Expiration = args.Expiration
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
request.AddMetaHeader(args.XHeaders);
|
request.AddMetaHeader(args.XHeaders);
|
||||||
request.Sign(ctx.Key);
|
request.Sign(ctx.Key!);
|
||||||
|
|
||||||
return await CreateSession(request, args.Context!);
|
return await CreateSession(request, args.Context!).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal async Task<SessionToken> CreateSession(CreateRequest request, Context ctx)
|
internal async Task<SessionToken> CreateSession(CreateRequest request, Context ctx)
|
||||||
{
|
{
|
||||||
var response = await _sessionServiceClient!.CreateAsync(request, null, ctx.Deadline, ctx.CancellationToken);
|
var response = await _sessionServiceClient!.CreateAsync(request, null, ctx.Deadline, ctx.CancellationToken);
|
||||||
|
|
||||||
Verifier.CheckResponse(response);
|
Verifier.CheckResponse(response);
|
||||||
|
|
||||||
return new SessionToken
|
return new SessionToken
|
||||||
{
|
{
|
||||||
Body = new SessionToken.Types.Body
|
Body = new SessionToken.Types.Body
|
||||||
|
|
|
@ -5,12 +5,12 @@ using Frostfs.V2.Apemanager;
|
||||||
|
|
||||||
namespace FrostFS.SDK.ClientV2;
|
namespace FrostFS.SDK.ClientV2;
|
||||||
|
|
||||||
internal class ApeManagerServiceProvider : ContextAccessor
|
internal sealed class ApeManagerServiceProvider : ContextAccessor
|
||||||
{
|
{
|
||||||
private readonly APEManagerService.APEManagerServiceClient? _apeManagerServiceClient;
|
private readonly APEManagerService.APEManagerServiceClient? _apeManagerServiceClient;
|
||||||
|
|
||||||
internal ApeManagerServiceProvider(APEManagerService.APEManagerServiceClient? apeManagerServiceClient, ClientEnvironment context)
|
internal ApeManagerServiceProvider(APEManagerService.APEManagerServiceClient? apeManagerServiceClient, ClientEnvironment context)
|
||||||
: base (context)
|
: base(context)
|
||||||
{
|
{
|
||||||
_apeManagerServiceClient = apeManagerServiceClient;
|
_apeManagerServiceClient = apeManagerServiceClient;
|
||||||
}
|
}
|
||||||
|
@ -18,12 +18,16 @@ internal class ApeManagerServiceProvider : ContextAccessor
|
||||||
internal async Task<byte[]> AddChainAsync(PrmApeChainAdd args)
|
internal async Task<byte[]> AddChainAsync(PrmApeChainAdd args)
|
||||||
{
|
{
|
||||||
var ctx = args.Context!;
|
var ctx = args.Context!;
|
||||||
|
ctx.Key ??= Context.Key?.ECDsaKey;
|
||||||
|
|
||||||
|
if (ctx.Key == null)
|
||||||
|
throw new InvalidObjectException(nameof(ctx.Key));
|
||||||
|
|
||||||
AddChainRequest request = new()
|
AddChainRequest request = new()
|
||||||
{
|
{
|
||||||
Body = new()
|
Body = new()
|
||||||
{
|
{
|
||||||
Chain = new () { Raw = args.Chain.GetRaw() },
|
Chain = new() { Raw = args.Chain.GetRaw() },
|
||||||
Target = args.Target.GetChainTarget()
|
Target = args.Target.GetChainTarget()
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -41,6 +45,11 @@ internal class ApeManagerServiceProvider : ContextAccessor
|
||||||
internal async Task RemoveChainAsync(PrmApeChainRemove args)
|
internal async Task RemoveChainAsync(PrmApeChainRemove args)
|
||||||
{
|
{
|
||||||
var ctx = args.Context!;
|
var ctx = args.Context!;
|
||||||
|
ctx.Key ??= Context.Key?.ECDsaKey;
|
||||||
|
|
||||||
|
if (ctx.Key == null)
|
||||||
|
throw new InvalidObjectException(nameof(ctx.Key));
|
||||||
|
|
||||||
RemoveChainRequest request = new()
|
RemoveChainRequest request = new()
|
||||||
{
|
{
|
||||||
Body = new()
|
Body = new()
|
||||||
|
@ -61,6 +70,11 @@ internal class ApeManagerServiceProvider : ContextAccessor
|
||||||
internal async Task<Chain[]> ListChainAsync(PrmApeChainList args)
|
internal async Task<Chain[]> ListChainAsync(PrmApeChainList args)
|
||||||
{
|
{
|
||||||
var ctx = args.Context!;
|
var ctx = args.Context!;
|
||||||
|
ctx.Key ??= Context.Key?.ECDsaKey;
|
||||||
|
|
||||||
|
if (ctx.Key == null)
|
||||||
|
throw new InvalidObjectException(nameof(ctx.Key));
|
||||||
|
|
||||||
ListChainsRequest request = new()
|
ListChainsRequest request = new()
|
||||||
{
|
{
|
||||||
Body = new()
|
Body = new()
|
||||||
|
|
|
@ -7,13 +7,14 @@ internal interface ISessionProvider
|
||||||
ValueTask<Session.SessionToken> GetOrCreateSession(ISessionToken args, Context ctx);
|
ValueTask<Session.SessionToken> GetOrCreateSession(ISessionToken args, Context ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class SessionProvider(ClientEnvironment env)
|
internal sealed class SessionProvider(ClientEnvironment env)
|
||||||
{
|
{
|
||||||
public async ValueTask<Session.SessionToken> GetOrCreateSession(ISessionToken args, Context ctx)
|
public async ValueTask<Session.SessionToken> GetOrCreateSession(ISessionToken args, Context ctx)
|
||||||
{
|
{
|
||||||
if (args.SessionToken is null)
|
if (args.SessionToken is null)
|
||||||
{
|
{
|
||||||
return await env.Client.CreateSessionInternalAsync(new PrmSessionCreate(uint.MaxValue) { Context = ctx });
|
return await env.Client.CreateSessionInternalAsync(new PrmSessionCreate(uint.MaxValue) { Context = ctx })
|
||||||
|
.ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Session.SessionToken().Deserialize(args.SessionToken.Token);
|
return new Session.SessionToken().Deserialize(args.SessionToken.Token);
|
||||||
|
|
|
@ -6,9 +6,9 @@ using Grpc.Net.Client;
|
||||||
|
|
||||||
namespace FrostFS.SDK.ClientV2;
|
namespace FrostFS.SDK.ClientV2;
|
||||||
|
|
||||||
public class ClientEnvironment(Client client, ECDsa? key, FrostFsOwner? owner, GrpcChannel channel, FrostFsVersion version) : IDisposable
|
public class ClientEnvironment(FrostFSClient client, ECDsa? key, FrostFsOwner? owner, GrpcChannel channel, FrostFsVersion version) : IDisposable
|
||||||
{
|
{
|
||||||
private ArrayPool<byte> _arrayPool;
|
private ArrayPool<byte>? _arrayPool;
|
||||||
|
|
||||||
internal FrostFsOwner? Owner { get; } = owner;
|
internal FrostFsOwner? Owner { get; } = owner;
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@ public class ClientEnvironment(Client client, ECDsa? key, FrostFsOwner? owner, G
|
||||||
|
|
||||||
internal NetworkSettings? NetworkSettings { get; set; }
|
internal NetworkSettings? NetworkSettings { get; set; }
|
||||||
|
|
||||||
internal Client Client { get; } = client;
|
internal FrostFSClient Client { get; } = client;
|
||||||
|
|
||||||
internal ClientKey? Key { get; } = key != null ? new ClientKey(key) : null;
|
internal ClientKey? Key { get; } = key != null ? new ClientKey(key) : null;
|
||||||
|
|
||||||
|
@ -28,7 +28,7 @@ public class ClientEnvironment(Client client, ECDsa? key, FrostFsOwner? owner, G
|
||||||
internal ArrayPool<byte> GetArrayPool(int size)
|
internal ArrayPool<byte> GetArrayPool(int size)
|
||||||
{
|
{
|
||||||
_arrayPool ??= ArrayPool<byte>.Create(size, 256);
|
_arrayPool ??= ArrayPool<byte>.Create(size, 256);
|
||||||
|
|
||||||
return _arrayPool;
|
return _arrayPool;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,57 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace FrostFS.SDK.ClientV2.Extensions;
|
|
||||||
|
|
||||||
public static class ObjectExtensions
|
|
||||||
{
|
|
||||||
public static FrostFsObject SetPayloadLength(this FrostFsObject obj, ulong length)
|
|
||||||
{
|
|
||||||
obj.Header.PayloadLength = length;
|
|
||||||
return obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static FrostFsObject SetPayload(this FrostFsObject obj, byte[] bytes)
|
|
||||||
{
|
|
||||||
obj.Payload = bytes;
|
|
||||||
return obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static FrostFsObject AddAttribute(this FrostFsObject obj, string key, string value)
|
|
||||||
{
|
|
||||||
obj.AddAttribute(new FrostFsAttribute(key, value));
|
|
||||||
return obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static FrostFsObject AddAttribute(this FrostFsObject obj, FrostFsAttribute attribute)
|
|
||||||
{
|
|
||||||
obj.Header.Attributes.Add(attribute);
|
|
||||||
return obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static FrostFsObject AddAttributes(this FrostFsObject obj, IEnumerable<FrostFsAttribute> attributes)
|
|
||||||
{
|
|
||||||
obj.Header.Attributes.AddRange(attributes);
|
|
||||||
return obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static FrostFsObject SetSplit(this FrostFsObject obj, FrostFsSplit? split)
|
|
||||||
{
|
|
||||||
obj.Header.Split = split;
|
|
||||||
return obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static FrostFsLinkObject AddChildren(this FrostFsLinkObject linkObject, IEnumerable<FrostFsObjectId> objectIds)
|
|
||||||
{
|
|
||||||
linkObject.Header.Split!.Children.AddRange(objectIds);
|
|
||||||
return linkObject;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static FrostFsObject CalculateObjectId(this FrostFsObject obj)
|
|
||||||
{
|
|
||||||
if (obj.Header == null)
|
|
||||||
throw new MissingFieldException("Header cannot be null");
|
|
||||||
|
|
||||||
return obj;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,30 +1,30 @@
|
||||||
using System;
|
using System;
|
||||||
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
using FrostFS.Object;
|
||||||
|
|
||||||
using Grpc.Core;
|
using Grpc.Core;
|
||||||
|
|
||||||
using FrostFS.Object;
|
|
||||||
using System.Threading;
|
|
||||||
|
|
||||||
namespace FrostFS.SDK.ClientV2;
|
namespace FrostFS.SDK.ClientV2;
|
||||||
|
|
||||||
public class ObjectReader(AsyncServerStreamingCall<GetResponse> call) : IObjectReader
|
public sealed class ObjectReader(AsyncServerStreamingCall<GetResponse> call) : IObjectReader
|
||||||
{
|
{
|
||||||
private bool disposed = false;
|
private bool disposed;
|
||||||
|
|
||||||
public AsyncServerStreamingCall<GetResponse> Call { get; private set; } = call;
|
public AsyncServerStreamingCall<GetResponse> Call { get; private set; } = call;
|
||||||
|
|
||||||
internal async Task<Object.Object> ReadHeader()
|
internal async Task<Object.Object> ReadHeader()
|
||||||
{
|
{
|
||||||
if (!await Call.ResponseStream.MoveNext())
|
if (!await Call.ResponseStream.MoveNext().ConfigureAwait(false))
|
||||||
throw new InvalidOperationException("unexpected end of stream");
|
throw new InvalidOperationException("unexpected end of stream");
|
||||||
|
|
||||||
var response = Call.ResponseStream.Current;
|
var response = Call.ResponseStream.Current;
|
||||||
Verifier.CheckResponse(response);
|
Verifier.CheckResponse(response);
|
||||||
|
|
||||||
if (response.Body.ObjectPartCase != GetResponse.Types.Body.ObjectPartOneofCase.Init)
|
if (response.Body.ObjectPartCase != GetResponse.Types.Body.ObjectPartOneofCase.Init)
|
||||||
throw new InvalidOperationException("unexpected message type");
|
throw new InvalidOperationException("unexpected message type");
|
||||||
|
|
||||||
return new Object.Object
|
return new Object.Object
|
||||||
{
|
{
|
||||||
ObjectId = response.Body.Init.ObjectId,
|
ObjectId = response.Body.Init.ObjectId,
|
||||||
|
@ -34,12 +34,12 @@ public class ObjectReader(AsyncServerStreamingCall<GetResponse> call) : IObjectR
|
||||||
|
|
||||||
public async Task<ReadOnlyMemory<byte>?> ReadChunk(CancellationToken cancellationToken = default)
|
public async Task<ReadOnlyMemory<byte>?> ReadChunk(CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
if (!await Call.ResponseStream.MoveNext(cancellationToken))
|
if (!await Call.ResponseStream.MoveNext(cancellationToken).ConfigureAwait(false))
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
var response = Call.ResponseStream.Current;
|
var response = Call.ResponseStream.Current;
|
||||||
Verifier.CheckResponse(response);
|
Verifier.CheckResponse(response);
|
||||||
|
|
||||||
if (response.Body.ObjectPartCase != GetResponse.Types.Body.ObjectPartOneofCase.Chunk)
|
if (response.Body.ObjectPartCase != GetResponse.Types.Body.ObjectPartOneofCase.Chunk)
|
||||||
throw new InvalidOperationException("unexpected message type");
|
throw new InvalidOperationException("unexpected message type");
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
using Grpc.Core;
|
|
||||||
|
|
||||||
using FrostFS.Object;
|
using FrostFS.Object;
|
||||||
|
|
||||||
|
using Grpc.Core;
|
||||||
|
|
||||||
namespace FrostFS.SDK.ClientV2;
|
namespace FrostFS.SDK.ClientV2;
|
||||||
|
|
||||||
internal class ObjectStreamer(AsyncClientStreamingCall<PutRequest, PutResponse> call) : IDisposable
|
internal sealed class ObjectStreamer(AsyncClientStreamingCall<PutRequest, PutResponse> call) : IDisposable
|
||||||
{
|
{
|
||||||
public AsyncClientStreamingCall<PutRequest, PutResponse> Call { get; private set; } = call;
|
public AsyncClientStreamingCall<PutRequest, PutResponse> Call { get; private set; } = call;
|
||||||
|
|
||||||
|
@ -18,14 +18,14 @@ internal class ObjectStreamer(AsyncClientStreamingCall<PutRequest, PutResponse>
|
||||||
throw new ArgumentNullException(nameof(request));
|
throw new ArgumentNullException(nameof(request));
|
||||||
}
|
}
|
||||||
|
|
||||||
await Call.RequestStream.WriteAsync(request);
|
await Call.RequestStream.WriteAsync(request).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<PutResponse> Close()
|
public async Task<PutResponse> Close()
|
||||||
{
|
{
|
||||||
await Call.RequestStream.CompleteAsync();
|
await Call.RequestStream.CompleteAsync().ConfigureAwait(false);
|
||||||
|
|
||||||
return await Call.ResponseAsync;
|
return await Call.ResponseAsync.ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
|
|
|
@ -1,35 +1,35 @@
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
||||||
using Google.Protobuf;
|
|
||||||
|
|
||||||
using FrostFS.Object;
|
using FrostFS.Object;
|
||||||
using FrostFS.Refs;
|
using FrostFS.Refs;
|
||||||
using FrostFS.SDK.ClientV2.Mappers.GRPC;
|
using FrostFS.SDK.ClientV2.Mappers.GRPC;
|
||||||
using FrostFS.SDK.Cryptography;
|
using FrostFS.SDK.Cryptography;
|
||||||
|
|
||||||
|
using Google.Protobuf;
|
||||||
|
|
||||||
namespace FrostFS.SDK.ClientV2;
|
namespace FrostFS.SDK.ClientV2;
|
||||||
|
|
||||||
internal class ObjectTools
|
internal static class ObjectTools
|
||||||
{
|
{
|
||||||
internal static FrostFsObjectId CalculateObjectId(FrostFsObjectHeader header, Context ctx)
|
internal static FrostFsObjectId CalculateObjectId(FrostFsObjectHeader header, Context ctx)
|
||||||
{
|
{
|
||||||
var grpcHeader = CreateHeader(header, [], ctx);
|
var grpcHeader = CreateHeader(header, [], ctx);
|
||||||
|
|
||||||
if (header.Split != null)
|
if (header.Split != null)
|
||||||
SetSplitValues(grpcHeader, header.Split, ctx);
|
SetSplitValues(grpcHeader, header.Split, ctx);
|
||||||
|
|
||||||
return new ObjectID { Value = grpcHeader.Sha256() }.ToModel();
|
return new ObjectID { Value = grpcHeader.Sha256() }.ToModel();
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static Object.Object CreateObject(FrostFsObject @object, Context ctx)
|
internal static Object.Object CreateObject(FrostFsObject @object, Context ctx)
|
||||||
{
|
{
|
||||||
@object.Header.OwnerId ??= ctx.OwnerId;
|
@object.Header.OwnerId ??= ctx.OwnerId;
|
||||||
@object.Header.Version ??= ctx.Version;
|
@object.Header.Version ??= ctx.Version;
|
||||||
|
|
||||||
var grpcHeader = @object.Header.GetHeader();
|
var grpcHeader = @object.Header.GetHeader();
|
||||||
|
|
||||||
grpcHeader.PayloadLength = (ulong)@object.Payload.Length;
|
grpcHeader.PayloadLength = (ulong)@object.SingleObjectPayload.Length;
|
||||||
grpcHeader.PayloadHash = Sha256Checksum(@object.Payload);
|
grpcHeader.PayloadHash = Sha256Checksum(@object.SingleObjectPayload);
|
||||||
|
|
||||||
var split = @object.Header.Split;
|
var split = @object.Header.Split;
|
||||||
if (split != null)
|
if (split != null)
|
||||||
|
@ -41,15 +41,15 @@ internal class ObjectTools
|
||||||
{
|
{
|
||||||
Header = grpcHeader,
|
Header = grpcHeader,
|
||||||
ObjectId = new ObjectID { Value = grpcHeader.Sha256() },
|
ObjectId = new ObjectID { Value = grpcHeader.Sha256() },
|
||||||
Payload = ByteString.CopyFrom(@object.Payload)
|
Payload = ByteString.CopyFrom(@object.SingleObjectPayload)
|
||||||
};
|
};
|
||||||
|
|
||||||
obj.Signature = new Refs.Signature
|
obj.Signature = new Signature
|
||||||
{
|
{
|
||||||
Key = ctx.GetPublicKeyCache(),
|
Key = ctx.GetPublicKeyCache(),
|
||||||
Sign = ByteString.CopyFrom(ctx.Key.SignData(obj.ObjectId.ToByteArray())),
|
Sign = ByteString.CopyFrom(ctx.Key!.SignData(obj.ObjectId.ToByteArray())),
|
||||||
};
|
};
|
||||||
|
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,6 +58,9 @@ internal class ObjectTools
|
||||||
if (split == null)
|
if (split == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (ctx.Key == null)
|
||||||
|
throw new InvalidObjectException(nameof(ctx.Key));
|
||||||
|
|
||||||
grpcHeader.Split = new Header.Types.Split
|
grpcHeader.Split = new Header.Types.Split
|
||||||
{
|
{
|
||||||
SplitId = split.SplitId?.GetSplitId()
|
SplitId = split.SplitId?.GetSplitId()
|
||||||
|
@ -72,13 +75,11 @@ internal class ObjectTools
|
||||||
|
|
||||||
grpcHeader.Split.Parent = new ObjectID { Value = grpcParentHeader.Sha256() };
|
grpcHeader.Split.Parent = new ObjectID { Value = grpcParentHeader.Sha256() };
|
||||||
grpcHeader.Split.ParentHeader = grpcParentHeader;
|
grpcHeader.Split.ParentHeader = grpcParentHeader;
|
||||||
grpcHeader.Split.ParentSignature = new Refs.Signature
|
grpcHeader.Split.ParentSignature = new Signature
|
||||||
{
|
{
|
||||||
Key = ctx.GetPublicKeyCache(),
|
Key = ctx.GetPublicKeyCache(),
|
||||||
Sign = ByteString.CopyFrom(ctx.Key.SignData(grpcHeader.Split.Parent.ToByteArray())),
|
Sign = ByteString.CopyFrom(ctx.Key.SignData(grpcHeader.Split.Parent.ToByteArray())),
|
||||||
};
|
};
|
||||||
|
|
||||||
split.Parent = grpcHeader.Split.Parent.ToModel();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
grpcHeader.Split.Previous = split.Previous?.ToMessage();
|
grpcHeader.Split.Previous = split.Previous?.ToMessage();
|
||||||
|
@ -90,10 +91,10 @@ internal class ObjectTools
|
||||||
header.Version ??= ctx.Version;
|
header.Version ??= ctx.Version;
|
||||||
|
|
||||||
var grpcHeader = header.GetHeader();
|
var grpcHeader = header.GetHeader();
|
||||||
|
|
||||||
if (payload != null) // && payload.Length > 0
|
if (payload != null) // && payload.Length > 0
|
||||||
grpcHeader.PayloadHash = Sha256Checksum(payload);
|
grpcHeader.PayloadHash = Sha256Checksum(payload);
|
||||||
|
|
||||||
return grpcHeader;
|
return grpcHeader;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,7 @@ namespace System
|
||||||
{
|
{
|
||||||
if (value < 0)
|
if (value < 0)
|
||||||
throw new ArgumentOutOfRangeException(nameof(value), "value must be non-negative");
|
throw new ArgumentOutOfRangeException(nameof(value), "value must be non-negative");
|
||||||
|
|
||||||
if (fromEnd)
|
if (fromEnd)
|
||||||
_value = ~value;
|
_value = ~value;
|
||||||
else
|
else
|
||||||
|
@ -51,7 +51,7 @@ namespace System
|
||||||
{
|
{
|
||||||
if (value < 0)
|
if (value < 0)
|
||||||
throw new ArgumentOutOfRangeException(nameof(value), "value must be non-negative");
|
throw new ArgumentOutOfRangeException(nameof(value), "value must be non-negative");
|
||||||
|
|
||||||
return new Index(value);
|
return new Index(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,7 +62,7 @@ namespace System
|
||||||
{
|
{
|
||||||
if (value < 0)
|
if (value < 0)
|
||||||
throw new ArgumentOutOfRangeException(nameof(value), "value must be non-negative");
|
throw new ArgumentOutOfRangeException(nameof(value), "value must be non-negative");
|
||||||
|
|
||||||
return new Index(~value);
|
return new Index(~value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -119,9 +119,9 @@ namespace System
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
{
|
{
|
||||||
if (IsFromEnd)
|
if (IsFromEnd)
|
||||||
return "^" + ((uint)Value).ToString();
|
return $"^{(uint)Value}";
|
||||||
|
|
||||||
return ((uint)Value).ToString();
|
return $"{(uint)Value}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -189,7 +189,7 @@ namespace System
|
||||||
{
|
{
|
||||||
int start;
|
int start;
|
||||||
var startIndex = Start;
|
var startIndex = Start;
|
||||||
|
|
||||||
if (startIndex.IsFromEnd)
|
if (startIndex.IsFromEnd)
|
||||||
start = length - startIndex.Value;
|
start = length - startIndex.Value;
|
||||||
else
|
else
|
||||||
|
@ -205,7 +205,7 @@ namespace System
|
||||||
|
|
||||||
if ((uint)end > (uint)length || (uint)start > (uint)end)
|
if ((uint)end > (uint)length || (uint)start > (uint)end)
|
||||||
throw new ArgumentOutOfRangeException(nameof(length));
|
throw new ArgumentOutOfRangeException(nameof(length));
|
||||||
|
|
||||||
return (start, end - start);
|
return (start, end - start);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -222,7 +222,7 @@ namespace System.Runtime.CompilerServices
|
||||||
{
|
{
|
||||||
if (array == null)
|
if (array == null)
|
||||||
throw new ArgumentNullException(nameof(array));
|
throw new ArgumentNullException(nameof(array));
|
||||||
|
|
||||||
(int offset, int length) = range.GetOffsetAndLength(array.Length);
|
(int offset, int length) = range.GetOffsetAndLength(array.Length);
|
||||||
|
|
||||||
if (default(T) != null || typeof(T[]) == array.GetType())
|
if (default(T) != null || typeof(T[]) == array.GetType())
|
||||||
|
@ -231,7 +231,7 @@ namespace System.Runtime.CompilerServices
|
||||||
|
|
||||||
if (length == 0)
|
if (length == 0)
|
||||||
return [];
|
return [];
|
||||||
|
|
||||||
var dest = new T[length];
|
var dest = new T[length];
|
||||||
Array.Copy(array, offset, dest, 0, length);
|
Array.Copy(array, offset, dest, 0, length);
|
||||||
return dest;
|
return dest;
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
using System;
|
||||||
using System.Collections.Specialized;
|
using System.Collections.Specialized;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Security.Cryptography;
|
using System.Security.Cryptography;
|
||||||
|
@ -12,9 +13,14 @@ namespace FrostFS.SDK.ClientV2;
|
||||||
|
|
||||||
public static class RequestConstructor
|
public static class RequestConstructor
|
||||||
{
|
{
|
||||||
public static void AddMetaHeader(this IRequest request, NameValueCollection? xHeaders, Session.SessionToken? sessionToken = null)
|
public static void AddMetaHeader(this IRequest request,
|
||||||
|
NameValueCollection? xHeaders,
|
||||||
|
SessionToken? sessionToken = null)
|
||||||
{
|
{
|
||||||
if (request.MetaHeader is not null)
|
if (request is null)
|
||||||
|
throw new ArgumentNullException(nameof(request));
|
||||||
|
|
||||||
|
if (request.MetaHeader is not null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
request.MetaHeader = MetaHeader.Default().ToMessage();
|
request.MetaHeader = MetaHeader.Default().ToMessage();
|
||||||
|
@ -28,11 +34,21 @@ public static class RequestConstructor
|
||||||
(k, v) => new XHeader { Key = k, Value = v }));
|
(k, v) => new XHeader { Key = k, Value = v }));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void CreateObjectTokenContext(this Session.SessionToken sessionToken,
|
public static void CreateObjectTokenContext(this SessionToken sessionToken,
|
||||||
Address address,
|
Address address,
|
||||||
ObjectSessionContext.Types.Verb verb,
|
ObjectSessionContext.Types.Verb verb,
|
||||||
ECDsa key)
|
ECDsa key)
|
||||||
{
|
{
|
||||||
|
if (sessionToken is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(sessionToken));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (address is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(address));
|
||||||
|
}
|
||||||
|
|
||||||
if (sessionToken.Body.Object?.Target != null)
|
if (sessionToken.Body.Object?.Target != null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -52,7 +68,7 @@ public static class RequestConstructor
|
||||||
sessionToken.Signature = key.SignMessagePart(sessionToken.Body);
|
sessionToken.Signature = key.SignMessagePart(sessionToken.Body);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void CreateContainerTokenContext(this Session.SessionToken sessionToken,
|
internal static void CreateContainerTokenContext(this SessionToken sessionToken,
|
||||||
ContainerID? containerId,
|
ContainerID? containerId,
|
||||||
ContainerSessionContext.Types.Verb verb,
|
ContainerSessionContext.Types.Verb verb,
|
||||||
ECDsa key,
|
ECDsa key,
|
||||||
|
@ -61,7 +77,7 @@ public static class RequestConstructor
|
||||||
if (sessionToken.Body.Container?.ContainerId != null)
|
if (sessionToken.Body.Container?.ContainerId != null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
sessionToken.Body.Container = new (){ Verb = verb };
|
sessionToken.Body.Container = new() { Verb = verb };
|
||||||
|
|
||||||
if (containerId != null)
|
if (containerId != null)
|
||||||
sessionToken.Body.Container.ContainerId = containerId;
|
sessionToken.Body.Container.ContainerId = containerId;
|
||||||
|
@ -69,7 +85,7 @@ public static class RequestConstructor
|
||||||
sessionToken.Body.Container.Wildcard = true;
|
sessionToken.Body.Container.Wildcard = true;
|
||||||
|
|
||||||
sessionToken.Body.SessionKey = publicKey;
|
sessionToken.Body.SessionKey = publicKey;
|
||||||
|
|
||||||
sessionToken.Signature = key.SignMessagePart(sessionToken.Body);
|
sessionToken.Signature = key.SignMessagePart(sessionToken.Body);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,35 +18,45 @@ namespace FrostFS.SDK.ClientV2;
|
||||||
|
|
||||||
public static class RequestSigner
|
public static class RequestSigner
|
||||||
{
|
{
|
||||||
public const int RFC6979SignatureSize = 64;
|
internal const int RFC6979SignatureSize = 64;
|
||||||
|
|
||||||
public static byte[] SignRFC6979(this ECDsa key, byte[] data)
|
internal static byte[] SignRFC6979(this ECDsa key, byte[] data)
|
||||||
{
|
{
|
||||||
|
if (key is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(key));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(data));
|
||||||
|
}
|
||||||
|
|
||||||
var digest = new Sha256Digest();
|
var digest = new Sha256Digest();
|
||||||
var secp256R1 = SecNamedCurves.GetByName("secp256r1");
|
var secp256R1 = SecNamedCurves.GetByName("secp256r1");
|
||||||
var ecParameters = new ECDomainParameters(secp256R1.Curve, secp256R1.G, secp256R1.N);
|
var ecParameters = new ECDomainParameters(secp256R1.Curve, secp256R1.G, secp256R1.N);
|
||||||
var privateKey = new ECPrivateKeyParameters(new BigInteger(1, key.PrivateKey()), ecParameters);
|
var privateKey = new ECPrivateKeyParameters(new BigInteger(1, key.PrivateKey()), ecParameters);
|
||||||
var signer = new ECDsaSigner(new HMacDsaKCalculator(digest));
|
var signer = new ECDsaSigner(new HMacDsaKCalculator(digest));
|
||||||
var hash = new byte[digest.GetDigestSize()];
|
var hash = new byte[digest.GetDigestSize()];
|
||||||
|
|
||||||
digest.BlockUpdate(data, 0, data.Length);
|
digest.BlockUpdate(data, 0, data.Length);
|
||||||
digest.DoFinal(hash, 0);
|
digest.DoFinal(hash, 0);
|
||||||
signer.Init(true, privateKey);
|
signer.Init(true, privateKey);
|
||||||
|
|
||||||
var rs = signer.GenerateSignature(hash);
|
var rs = signer.GenerateSignature(hash);
|
||||||
var signature = new byte[RFC6979SignatureSize];
|
var signature = new byte[RFC6979SignatureSize];
|
||||||
var rbytes = rs[0].ToByteArrayUnsigned();
|
var rbytes = rs[0].ToByteArrayUnsigned();
|
||||||
var sbytes = rs[1].ToByteArrayUnsigned();
|
var sbytes = rs[1].ToByteArrayUnsigned();
|
||||||
var index = RFC6979SignatureSize / 2 - rbytes.Length;
|
var index = RFC6979SignatureSize / 2 - rbytes.Length;
|
||||||
|
|
||||||
rbytes.CopyTo(signature, index);
|
rbytes.CopyTo(signature, index);
|
||||||
index = RFC6979SignatureSize - sbytes.Length;
|
index = RFC6979SignatureSize - sbytes.Length;
|
||||||
sbytes.CopyTo(signature, index);
|
sbytes.CopyTo(signature, index);
|
||||||
|
|
||||||
return signature;
|
return signature;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static SignatureRFC6979 SignRFC6979(this ECDsa key, IMessage message)
|
internal static SignatureRFC6979 SignRFC6979(this ECDsa key, IMessage message)
|
||||||
{
|
{
|
||||||
return new SignatureRFC6979
|
return new SignatureRFC6979
|
||||||
{
|
{
|
||||||
|
@ -54,8 +64,8 @@ public static class RequestSigner
|
||||||
Sign = ByteString.CopyFrom(key.SignRFC6979(message.ToByteArray())),
|
Sign = ByteString.CopyFrom(key.SignRFC6979(message.ToByteArray())),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public static SignatureRFC6979 SignRFC6979(this ECDsa key, ByteString data)
|
internal static SignatureRFC6979 SignRFC6979(this ECDsa key, ByteString data)
|
||||||
{
|
{
|
||||||
return new SignatureRFC6979
|
return new SignatureRFC6979
|
||||||
{
|
{
|
||||||
|
@ -74,7 +84,7 @@ public static class RequestSigner
|
||||||
return hash;
|
return hash;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Signature SignMessagePart(this ECDsa key, IMessage? data)
|
internal static Signature SignMessagePart(this ECDsa key, IMessage? data)
|
||||||
{
|
{
|
||||||
var data2Sign = data is null ? [] : data.ToByteArray();
|
var data2Sign = data is null ? [] : data.ToByteArray();
|
||||||
var sig = new Signature
|
var sig = new Signature
|
||||||
|
@ -86,7 +96,7 @@ public static class RequestSigner
|
||||||
return sig;
|
return sig;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Sign(this IVerifiableMessage message, ECDsa key)
|
internal static void Sign(this IVerifiableMessage message, ECDsa key)
|
||||||
{
|
{
|
||||||
var meta = message.GetMetaHeader();
|
var meta = message.GetMetaHeader();
|
||||||
IVerificationHeader verify = message switch
|
IVerificationHeader verify = message switch
|
||||||
|
@ -95,17 +105,17 @@ public static class RequestSigner
|
||||||
IResponse => new ResponseVerificationHeader(),
|
IResponse => new ResponseVerificationHeader(),
|
||||||
_ => throw new InvalidOperationException("Unsupported message type")
|
_ => throw new InvalidOperationException("Unsupported message type")
|
||||||
};
|
};
|
||||||
|
|
||||||
var verifyOrigin = message.GetVerificationHeader();
|
var verifyOrigin = message.GetVerificationHeader();
|
||||||
|
|
||||||
if (verifyOrigin is null)
|
if (verifyOrigin is null)
|
||||||
verify.BodySignature = key.SignMessagePart(message.GetBody());
|
verify.BodySignature = key.SignMessagePart(message.GetBody());
|
||||||
else
|
else
|
||||||
verify.SetOrigin(verifyOrigin);
|
verify.SetOrigin(verifyOrigin);
|
||||||
|
|
||||||
verify.MetaSignature = key.SignMessagePart(meta);
|
verify.MetaSignature = key.SignMessagePart(meta);
|
||||||
verify.OriginSignature = key.SignMessagePart(verifyOrigin);
|
verify.OriginSignature = key.SignMessagePart(verifyOrigin);
|
||||||
|
|
||||||
message.SetVerificationHeader(verify);
|
message.SetVerificationHeader(verify);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,17 +11,17 @@ using Grpc.Core;
|
||||||
|
|
||||||
namespace FrostFS.SDK.ClientV2;
|
namespace FrostFS.SDK.ClientV2;
|
||||||
|
|
||||||
internal class SearchReader(AsyncServerStreamingCall<SearchResponse> call) : IDisposable
|
internal sealed class SearchReader(AsyncServerStreamingCall<SearchResponse> call) : IDisposable
|
||||||
{
|
{
|
||||||
public AsyncServerStreamingCall<SearchResponse> Call { get; private set; } = call;
|
public AsyncServerStreamingCall<SearchResponse> Call { get; private set; } = call;
|
||||||
|
|
||||||
public async Task<List<ObjectID>?> Read(CancellationToken cancellationToken)
|
public async Task<List<ObjectID>?> Read(CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
if (!await Call.ResponseStream.MoveNext(cancellationToken))
|
if (!await Call.ResponseStream.MoveNext(cancellationToken).ConfigureAwait(false))
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
var response = Call.ResponseStream.Current;
|
var response = Call.ResponseStream.Current;
|
||||||
|
|
||||||
Verifier.CheckResponse(response);
|
Verifier.CheckResponse(response);
|
||||||
|
|
||||||
return response.Body?.IdList.ToList();
|
return response.Body?.IdList.ToList();
|
||||||
|
|
|
@ -45,7 +45,7 @@ public static class Verifier
|
||||||
var ecParameters = new ECDomainParameters(secp256R1.Curve, secp256R1.G, secp256R1.N);
|
var ecParameters = new ECDomainParameters(secp256R1.Curve, secp256R1.G, secp256R1.N);
|
||||||
var bcPublicKey = new ECPublicKeyParameters(secp256R1.Curve.DecodePoint(publicKey), ecParameters);
|
var bcPublicKey = new ECPublicKeyParameters(secp256R1.Curve.DecodePoint(publicKey), ecParameters);
|
||||||
var hash = new byte[digest.GetDigestSize()];
|
var hash = new byte[digest.GetDigestSize()];
|
||||||
|
|
||||||
digest.BlockUpdate(data, 0, data.Length);
|
digest.BlockUpdate(data, 0, data.Length);
|
||||||
digest.DoFinal(hash, 0);
|
digest.DoFinal(hash, 0);
|
||||||
signer.Init(false, bcPublicKey);
|
signer.Init(false, bcPublicKey);
|
||||||
|
@ -55,11 +55,25 @@ public static class Verifier
|
||||||
|
|
||||||
public static bool VerifyRFC6979(this SignatureRFC6979 signature, IMessage message)
|
public static bool VerifyRFC6979(this SignatureRFC6979 signature, IMessage message)
|
||||||
{
|
{
|
||||||
|
if (signature is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(signature));
|
||||||
|
}
|
||||||
|
|
||||||
return signature.Key.ToByteArray().VerifyRFC6979(message.ToByteArray(), signature.Sign.ToByteArray());
|
return signature.Key.ToByteArray().VerifyRFC6979(message.ToByteArray(), signature.Sign.ToByteArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool VerifyData(this ECDsa key, byte[] data, byte[] sig)
|
public static bool VerifyData(this ECDsa key, byte[] data, byte[] sig)
|
||||||
{
|
{
|
||||||
|
if (key is null)
|
||||||
|
throw new ArgumentNullException(nameof(key));
|
||||||
|
|
||||||
|
if (data is null)
|
||||||
|
throw new ArgumentNullException(nameof(data));
|
||||||
|
|
||||||
|
if (sig is null)
|
||||||
|
throw new ArgumentNullException(nameof(sig));
|
||||||
|
|
||||||
return key.VerifyHash(data.Sha512(), sig[1..]);
|
return key.VerifyHash(data.Sha512(), sig[1..]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,36 +84,41 @@ public static class Verifier
|
||||||
|
|
||||||
using var key = sig.Key.ToByteArray().LoadPublicKey();
|
using var key = sig.Key.ToByteArray().LoadPublicKey();
|
||||||
var data2Verify = data is null ? [] : data.ToByteArray();
|
var data2Verify = data is null ? [] : data.ToByteArray();
|
||||||
|
|
||||||
return key.VerifyData(data2Verify, sig.Sign.ToByteArray());
|
return key.VerifyData(data2Verify, sig.Sign.ToByteArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool VerifyMatryoskaLevel(IMessage body, IMetaHeader meta, IVerificationHeader verification)
|
internal static bool VerifyMatryoskaLevel(IMessage body, IMetaHeader meta, IVerificationHeader verification)
|
||||||
{
|
{
|
||||||
if (!verification.MetaSignature.VerifyMessagePart(meta))
|
if (!verification.MetaSignature.VerifyMessagePart(meta))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
var origin = verification.GetOrigin();
|
var origin = verification.GetOrigin();
|
||||||
|
|
||||||
if (!verification.OriginSignature.VerifyMessagePart(origin))
|
if (!verification.OriginSignature.VerifyMessagePart(origin))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (origin is null)
|
if (origin is null)
|
||||||
return verification.BodySignature.VerifyMessagePart(body);
|
return verification.BodySignature.VerifyMessagePart(body);
|
||||||
|
|
||||||
return verification.BodySignature is null && VerifyMatryoskaLevel(body, meta.GetOrigin(), origin);
|
return verification.BodySignature is null && VerifyMatryoskaLevel(body, meta.GetOrigin(), origin);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool Verify(this IVerifiableMessage message)
|
public static bool Verify(this IVerifiableMessage message)
|
||||||
{
|
{
|
||||||
|
if (message is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(message));
|
||||||
|
}
|
||||||
|
|
||||||
return VerifyMatryoskaLevel(message.GetBody(), message.GetMetaHeader(), message.GetVerificationHeader());
|
return VerifyMatryoskaLevel(message.GetBody(), message.GetMetaHeader(), message.GetVerificationHeader());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void CheckResponse(IResponse resp)
|
internal static void CheckResponse(IResponse resp)
|
||||||
{
|
{
|
||||||
if (!resp.Verify())
|
if (!resp.Verify())
|
||||||
throw new FormatException($"invalid response, type={resp.GetType()}");
|
throw new FormatException($"invalid response, type={resp.GetType()}");
|
||||||
|
|
||||||
var status = resp.MetaHeader.Status.ToModel();
|
var status = resp.MetaHeader.Status.ToModel();
|
||||||
|
|
||||||
if (status != null && !status.IsSuccess)
|
if (status != null && !status.IsSuccess)
|
||||||
|
@ -112,6 +131,11 @@ public static class Verifier
|
||||||
/// <param name="request">Created by SDK request to gRpc proxy</param>
|
/// <param name="request">Created by SDK request to gRpc proxy</param>
|
||||||
public static void CheckRequest(IRequest request)
|
public static void CheckRequest(IRequest request)
|
||||||
{
|
{
|
||||||
|
if (request is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(request));
|
||||||
|
}
|
||||||
|
|
||||||
if (!request.Verify())
|
if (!request.Verify())
|
||||||
throw new FormatException($"invalid response, type={request.GetType()}");
|
throw new FormatException($"invalid response, type={request.GetType()}");
|
||||||
}
|
}
|
||||||
|
|
8
src/FrostFS.SDK.ClientV2/Ростелеком.txt
Normal file
8
src/FrostFS.SDK.ClientV2/Ростелеком.txt
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
Для возврата денег потребуются документы:
|
||||||
|
1. Заполненное заявление
|
||||||
|
Форму заявления можно скачать с сайта
|
||||||
|
Шаблон заявления скачайте на сайте rt.ru. Внизу страницы перейдите в Договоры и соглашения -> «Бланки и заявления»
|
||||||
|
2. Скан-фото паспорта владельца договора (2, 3, 5 страница: кем и когда выдан, адрес регистрации)
|
||||||
|
3. Реквизиты счета владельца, выданные банком, на которые будет выполнен возврат
|
||||||
|
4. Чек об оплате
|
||||||
|
Сканы документов должны быть хорошо читаемые
|
|
@ -13,17 +13,17 @@ public static class Base58
|
||||||
{
|
{
|
||||||
if (input is null)
|
if (input is null)
|
||||||
throw new ArgumentNullException(nameof(input));
|
throw new ArgumentNullException(nameof(input));
|
||||||
|
|
||||||
byte[] buffer = Decode(input);
|
byte[] buffer = Decode(input);
|
||||||
|
|
||||||
if (buffer.Length < 4)
|
if (buffer.Length < 4)
|
||||||
throw new FormatException();
|
throw new FormatException();
|
||||||
|
|
||||||
byte[] checksum = buffer[0..(buffer.Length - 4)].Sha256().Sha256();
|
byte[] checksum = buffer[0..(buffer.Length - 4)].Sha256().Sha256();
|
||||||
|
|
||||||
if (!buffer.AsSpan(buffer.Length - 4).SequenceEqual(checksum[..4].AsSpan()))
|
if (!buffer.AsSpan(buffer.Length - 4).SequenceEqual(checksum[..4].AsSpan()))
|
||||||
throw new FormatException();
|
throw new FormatException();
|
||||||
|
|
||||||
var ret = buffer[..^4];
|
var ret = buffer[..^4];
|
||||||
Array.Clear(buffer, 0, buffer.Length);
|
Array.Clear(buffer, 0, buffer.Length);
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -34,7 +34,7 @@ public static class Base58
|
||||||
byte[] checksum = data.ToArray().Sha256().Sha256();
|
byte[] checksum = data.ToArray().Sha256().Sha256();
|
||||||
Span<byte> buffer = stackalloc byte[data.Length + 4];
|
Span<byte> buffer = stackalloc byte[data.Length + 4];
|
||||||
data.CopyTo(buffer);
|
data.CopyTo(buffer);
|
||||||
|
|
||||||
checksum[..4].AsSpan().CopyTo(buffer[data.Length..]);
|
checksum[..4].AsSpan().CopyTo(buffer[data.Length..]);
|
||||||
var ret = Encode(buffer);
|
var ret = Encode(buffer);
|
||||||
buffer.Clear();
|
buffer.Clear();
|
||||||
|
@ -44,6 +44,9 @@ public static class Base58
|
||||||
|
|
||||||
public static byte[] Decode(string input)
|
public static byte[] Decode(string input)
|
||||||
{
|
{
|
||||||
|
if (input == null)
|
||||||
|
throw new ArgumentNullException(nameof(input));
|
||||||
|
|
||||||
// Decode Base58 string to BigInteger
|
// Decode Base58 string to BigInteger
|
||||||
var bi = BigInteger.Zero;
|
var bi = BigInteger.Zero;
|
||||||
for (int i = 0; i < input.Length; i++)
|
for (int i = 0; i < input.Length; i++)
|
||||||
|
@ -61,7 +64,7 @@ public static class Base58
|
||||||
if (bi.IsZero)
|
if (bi.IsZero)
|
||||||
return leadingZeros;
|
return leadingZeros;
|
||||||
|
|
||||||
var bytesBigEndian = bi.ToByteArray().Reverse();
|
var bytesBigEndian = bi.ToByteArray().Reverse().ToArray();
|
||||||
|
|
||||||
var firstNonZeroIndex = 0;
|
var firstNonZeroIndex = 0;
|
||||||
|
|
||||||
|
|
|
@ -1,17 +1,19 @@
|
||||||
using Google.Protobuf;
|
|
||||||
using Org.BouncyCastle.Crypto.Digests;
|
|
||||||
using System.Security.Cryptography;
|
using System.Security.Cryptography;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
|
||||||
|
using Google.Protobuf;
|
||||||
|
|
||||||
|
using Org.BouncyCastle.Crypto.Digests;
|
||||||
|
|
||||||
namespace FrostFS.SDK.Cryptography;
|
namespace FrostFS.SDK.Cryptography;
|
||||||
|
|
||||||
public static class Extentions
|
public static class Extentions
|
||||||
{
|
{
|
||||||
private static readonly SHA256 _sha256 = SHA256.Create();
|
private static readonly SHA256 _sha256 = SHA256.Create();
|
||||||
private static SpinLock _spinlockSha256 = new();
|
private static SpinLock _spinlockSha256;
|
||||||
|
|
||||||
private static readonly SHA512 _sha512 = SHA512.Create();
|
private static readonly SHA512 _sha512 = SHA512.Create();
|
||||||
private static SpinLock _spinlockSha512 = new();
|
private static SpinLock _spinlockSha512;
|
||||||
|
|
||||||
internal static byte[] RIPEMD160(this byte[] value)
|
internal static byte[] RIPEMD160(this byte[] value)
|
||||||
{
|
{
|
||||||
|
@ -22,7 +24,7 @@ public static class Extentions
|
||||||
digest.DoFinal(hash, 0);
|
digest.DoFinal(hash, 0);
|
||||||
return hash;
|
return hash;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ByteString Sha256(this IMessage data)
|
public static ByteString Sha256(this IMessage data)
|
||||||
{
|
{
|
||||||
return ByteString.CopyFrom(data.ToByteArray().Sha256());
|
return ByteString.CopyFrom(data.ToByteArray().Sha256());
|
||||||
|
|
|
@ -13,6 +13,10 @@
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="BouncyCastle.Cryptography" Version="2.4.0" />
|
<PackageReference Include="BouncyCastle.Cryptography" Version="2.4.0" />
|
||||||
<PackageReference Include="Google.Protobuf" Version="3.27.0" />
|
<PackageReference Include="Google.Protobuf" Version="3.27.0" />
|
||||||
|
<PackageReference Include="Microsoft.CodeAnalysis.NetAnalyzers" Version="8.0.0">
|
||||||
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
|
</PackageReference>
|
||||||
<PackageReference Include="System.Memory" Version="4.5.5" />
|
<PackageReference Include="System.Memory" Version="4.5.5" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,9 @@ public static class KeyExtension
|
||||||
|
|
||||||
public static byte[] Compress(this byte[] publicKey)
|
public static byte[] Compress(this byte[] publicKey)
|
||||||
{
|
{
|
||||||
|
if (publicKey == null)
|
||||||
|
throw new ArgumentNullException(nameof(publicKey));
|
||||||
|
|
||||||
if (publicKey.Length != UncompressedPublicKeyLength)
|
if (publicKey.Length != UncompressedPublicKeyLength)
|
||||||
throw new FormatException(
|
throw new FormatException(
|
||||||
$"{nameof(Compress)} argument isn't uncompressed public key. " +
|
$"{nameof(Compress)} argument isn't uncompressed public key. " +
|
||||||
|
@ -34,6 +37,9 @@ public static class KeyExtension
|
||||||
|
|
||||||
public static byte[] Decompress(this byte[] publicKey)
|
public static byte[] Decompress(this byte[] publicKey)
|
||||||
{
|
{
|
||||||
|
if (publicKey == null)
|
||||||
|
throw new ArgumentNullException(nameof(publicKey));
|
||||||
|
|
||||||
if (publicKey.Length != CompressedPublicKeyLength)
|
if (publicKey.Length != CompressedPublicKeyLength)
|
||||||
throw new FormatException(
|
throw new FormatException(
|
||||||
$"{nameof(Decompress)} argument isn't compressed public key. " +
|
$"{nameof(Decompress)} argument isn't compressed public key. " +
|
||||||
|
@ -64,6 +70,9 @@ public static class KeyExtension
|
||||||
|
|
||||||
public static byte[] GetScriptHash(this byte[] publicKey)
|
public static byte[] GetScriptHash(this byte[] publicKey)
|
||||||
{
|
{
|
||||||
|
if (publicKey == null)
|
||||||
|
throw new ArgumentNullException(nameof(publicKey));
|
||||||
|
|
||||||
var script = publicKey.CreateSignatureRedeemScript();
|
var script = publicKey.CreateSignatureRedeemScript();
|
||||||
return script.Sha256().RIPEMD160();
|
return script.Sha256().RIPEMD160();
|
||||||
}
|
}
|
||||||
|
@ -79,14 +88,14 @@ public static class KeyExtension
|
||||||
|
|
||||||
private static byte[] GetPrivateKeyFromWIF(string wif)
|
private static byte[] GetPrivateKeyFromWIF(string wif)
|
||||||
{
|
{
|
||||||
if (wif == null)
|
if (wif == null)
|
||||||
throw new ArgumentNullException(nameof(wif));
|
throw new ArgumentNullException(nameof(wif));
|
||||||
|
|
||||||
var data = wif.Base58CheckDecode();
|
var data = wif.Base58CheckDecode();
|
||||||
|
|
||||||
if (data.Length != 34 || data[0] != 0x80 || data[33] != 0x01)
|
if (data.Length != 34 || data[0] != 0x80 || data[33] != 0x01)
|
||||||
throw new FormatException();
|
throw new FormatException();
|
||||||
|
|
||||||
var privateKey = new byte[32];
|
var privateKey = new byte[32];
|
||||||
Buffer.BlockCopy(data, 1, privateKey, 0, privateKey.Length);
|
Buffer.BlockCopy(data, 1, privateKey, 0, privateKey.Length);
|
||||||
Array.Clear(data, 0, data.Length);
|
Array.Clear(data, 0, data.Length);
|
||||||
|
@ -100,6 +109,9 @@ public static class KeyExtension
|
||||||
|
|
||||||
public static string PublicKeyToAddress(this byte[] publicKey)
|
public static string PublicKeyToAddress(this byte[] publicKey)
|
||||||
{
|
{
|
||||||
|
if (publicKey == null)
|
||||||
|
throw new ArgumentNullException(nameof(publicKey));
|
||||||
|
|
||||||
if (publicKey.Length != CompressedPublicKeyLength)
|
if (publicKey.Length != CompressedPublicKeyLength)
|
||||||
throw new FormatException(
|
throw new FormatException(
|
||||||
nameof(publicKey) +
|
nameof(publicKey) +
|
||||||
|
@ -112,6 +124,9 @@ public static class KeyExtension
|
||||||
|
|
||||||
public static byte[] PublicKey(this ECDsa key)
|
public static byte[] PublicKey(this ECDsa key)
|
||||||
{
|
{
|
||||||
|
if (key == null)
|
||||||
|
throw new ArgumentNullException(nameof(key));
|
||||||
|
|
||||||
var param = key.ExportParameters(false);
|
var param = key.ExportParameters(false);
|
||||||
var pubkey = new byte[33];
|
var pubkey = new byte[33];
|
||||||
var pos = 33 - param.Q.X.Length;
|
var pos = 33 - param.Q.X.Length;
|
||||||
|
@ -127,6 +142,9 @@ public static class KeyExtension
|
||||||
|
|
||||||
public static byte[] PrivateKey(this ECDsa key)
|
public static byte[] PrivateKey(this ECDsa key)
|
||||||
{
|
{
|
||||||
|
if (key == null)
|
||||||
|
throw new ArgumentNullException(nameof(key));
|
||||||
|
|
||||||
return key.ExportParameters(true).D;
|
return key.ExportParameters(true).D;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -153,7 +171,7 @@ public static class KeyExtension
|
||||||
public static ECDsa LoadWif(this string wif)
|
public static ECDsa LoadWif(this string wif)
|
||||||
{
|
{
|
||||||
var privateKey = GetPrivateKeyFromWIF(wif);
|
var privateKey = GetPrivateKeyFromWIF(wif);
|
||||||
|
|
||||||
return LoadPrivateKey(privateKey);
|
return LoadPrivateKey(privateKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,7 @@ internal class Murmur3_128 : HashAlgorithm
|
||||||
length += cbSize;
|
length += cbSize;
|
||||||
int remainder = cbSize & 15;
|
int remainder = cbSize & 15;
|
||||||
int alignedLength = ibStart + (cbSize - remainder);
|
int alignedLength = ibStart + (cbSize - remainder);
|
||||||
|
|
||||||
for (int i = ibStart; i < alignedLength; i += 16)
|
for (int i = ibStart; i < alignedLength; i += 16)
|
||||||
{
|
{
|
||||||
ulong k1 = BinaryPrimitives.ReadUInt64LittleEndian(array.AsSpan(i));
|
ulong k1 = BinaryPrimitives.ReadUInt64LittleEndian(array.AsSpan(i));
|
||||||
|
@ -50,7 +50,7 @@ internal class Murmur3_128 : HashAlgorithm
|
||||||
h2 += h1;
|
h2 += h1;
|
||||||
h2 = h2 * m + n2;
|
h2 = h2 * m + n2;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (remainder > 0)
|
if (remainder > 0)
|
||||||
{
|
{
|
||||||
ulong k1 = 0, k2 = 0;
|
ulong k1 = 0, k2 = 0;
|
||||||
|
@ -101,7 +101,7 @@ internal class Murmur3_128 : HashAlgorithm
|
||||||
h2 = Fimix64(h2);
|
h2 = Fimix64(h2);
|
||||||
h1 += h2;
|
h1 += h2;
|
||||||
h2 += h1;
|
h2 += h1;
|
||||||
|
|
||||||
return BitConverter.GetBytes(h1);
|
return BitConverter.GetBytes(h1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -122,9 +122,9 @@ namespace System
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
{
|
{
|
||||||
if (IsFromEnd)
|
if (IsFromEnd)
|
||||||
return "^" + ((uint)Value).ToString();
|
return $"^{(uint)Value}";
|
||||||
|
|
||||||
return ((uint)Value).ToString();
|
return $"{(uint)Value}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -140,7 +140,7 @@ namespace System
|
||||||
/// <remarks>Construct a Range object using the start and end indexes.</remarks>
|
/// <remarks>Construct a Range object using the start and end indexes.</remarks>
|
||||||
/// <param name="start">Represent the inclusive start index of the range.</param>
|
/// <param name="start">Represent the inclusive start index of the range.</param>
|
||||||
/// <param name="end">Represent the exclusive end index of the range.</param>
|
/// <param name="end">Represent the exclusive end index of the range.</param>
|
||||||
internal readonly struct Range (Index start, Index end) : IEquatable<Range>
|
internal readonly struct Range(Index start, Index end) : IEquatable<Range>
|
||||||
{
|
{
|
||||||
/// <summary>Represent the inclusive start index of the Range.</summary>
|
/// <summary>Represent the inclusive start index of the Range.</summary>
|
||||||
public Index Start { get; } = start;
|
public Index Start { get; } = start;
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
using Google.Protobuf;
|
using System;
|
||||||
using System;
|
|
||||||
|
using Google.Protobuf;
|
||||||
|
|
||||||
namespace FrostFS.SDK.Cryptography;
|
namespace FrostFS.SDK.Cryptography;
|
||||||
|
|
||||||
|
@ -7,13 +8,16 @@ public static class UUIDExtension
|
||||||
{
|
{
|
||||||
public static Guid ToUuid(this ByteString id)
|
public static Guid ToUuid(this ByteString id)
|
||||||
{
|
{
|
||||||
|
if (id == null)
|
||||||
|
throw new ArgumentNullException(nameof(id));
|
||||||
|
|
||||||
var bytes = id.ToByteArray();
|
var bytes = id.ToByteArray();
|
||||||
|
|
||||||
var orderedBytes = GetGuidBytesDirectOrder(bytes);
|
var orderedBytes = GetGuidBytesDirectOrder(bytes);
|
||||||
|
|
||||||
return new Guid(orderedBytes);
|
return new Guid(orderedBytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Serializes Guid to binary representation in direct order bytes format
|
/// Serializes Guid to binary representation in direct order bytes format
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using FrostFS.Refs;
|
using FrostFS.Refs;
|
||||||
|
|
||||||
using Google.Protobuf;
|
using Google.Protobuf;
|
||||||
|
|
||||||
namespace FrostFS.Session;
|
namespace FrostFS.Session;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
using Google.Protobuf;
|
|
||||||
|
|
||||||
using FrostFS.Session;
|
|
||||||
using FrostFS.SDK.ProtosV2.Interfaces;
|
using FrostFS.SDK.ProtosV2.Interfaces;
|
||||||
|
using FrostFS.Session;
|
||||||
|
|
||||||
|
using Google.Protobuf;
|
||||||
|
|
||||||
namespace Frostfs.V2.Apemanager;
|
namespace Frostfs.V2.Apemanager;
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
using Google.Protobuf;
|
|
||||||
|
|
||||||
using FrostFS.Session;
|
|
||||||
using FrostFS.SDK.ProtosV2.Interfaces;
|
using FrostFS.SDK.ProtosV2.Interfaces;
|
||||||
|
using FrostFS.Session;
|
||||||
|
|
||||||
|
using Google.Protobuf;
|
||||||
|
|
||||||
namespace FrostFS.Container;
|
namespace FrostFS.Container;
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
using FrostFS.SDK.ProtosV2.Interfaces;
|
using FrostFS.SDK.ProtosV2.Interfaces;
|
||||||
using FrostFS.Session;
|
using FrostFS.Session;
|
||||||
|
|
||||||
using Google.Protobuf;
|
using Google.Protobuf;
|
||||||
|
|
||||||
namespace FrostFS.Netmap;
|
namespace FrostFS.Netmap;
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
|
||||||
using FrostFS.SDK.ProtosV2.Interfaces;
|
using FrostFS.SDK.ProtosV2.Interfaces;
|
||||||
using FrostFS.Session;
|
using FrostFS.Session;
|
||||||
|
|
||||||
using Google.Protobuf;
|
using Google.Protobuf;
|
||||||
|
|
||||||
namespace FrostFS.Object
|
namespace FrostFS.Object
|
||||||
|
@ -117,7 +119,7 @@ namespace FrostFS.Object
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public partial class PutSingleRequest : IRequest
|
public partial class PutSingleRequest : IRequest
|
||||||
{
|
{
|
||||||
IMetaHeader IVerifiableMessage.GetMetaHeader()
|
IMetaHeader IVerifiableMessage.GetMetaHeader()
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using FrostFS.SDK.ProtosV2.Interfaces;
|
using FrostFS.SDK.ProtosV2.Interfaces;
|
||||||
|
|
||||||
using Google.Protobuf;
|
using Google.Protobuf;
|
||||||
|
|
||||||
namespace FrostFS.Session;
|
namespace FrostFS.Session;
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
using FrostFS.SDK.ClientV2;
|
using FrostFS.SDK.ClientV2;
|
||||||
using FrostFS.SDK.ClientV2.Mappers.GRPC;
|
|
||||||
using FrostFS.SDK.ClientV2.Interfaces;
|
using FrostFS.SDK.ClientV2.Interfaces;
|
||||||
using FrostFS.SDK.ClientV2;
|
using FrostFS.SDK.ClientV2.Mappers.GRPC;
|
||||||
using FrostFS.SDK.Cryptography;
|
using FrostFS.SDK.Cryptography;
|
||||||
|
|
||||||
using Microsoft.Extensions.Options;
|
|
||||||
using Google.Protobuf;
|
using Google.Protobuf;
|
||||||
|
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
|
|
||||||
namespace FrostFS.SDK.Tests;
|
namespace FrostFS.SDK.Tests;
|
||||||
|
|
||||||
public abstract class ContainerTestsBase
|
public abstract class ContainerTestsBase
|
||||||
|
@ -34,7 +34,7 @@ public abstract class ContainerTestsBase
|
||||||
|
|
||||||
protected IFrostFSClient GetClient()
|
protected IFrostFSClient GetClient()
|
||||||
{
|
{
|
||||||
return ClientV2.Client.GetTestInstance(
|
return ClientV2.FrostFSClient.GetTestInstance(
|
||||||
Settings,
|
Settings,
|
||||||
null,
|
null,
|
||||||
new NetworkMocker(this.key).GetMock().Object,
|
new NetworkMocker(this.key).GetMock().Object,
|
||||||
|
@ -45,17 +45,17 @@ public abstract class ContainerTestsBase
|
||||||
}
|
}
|
||||||
|
|
||||||
public class ContainerTest : ContainerTestsBase
|
public class ContainerTest : ContainerTestsBase
|
||||||
{
|
{
|
||||||
[Fact]
|
[Fact]
|
||||||
public async void CreateContainerTest()
|
public async void CreateContainerTest()
|
||||||
{
|
{
|
||||||
var param = new PrmContainerCreate(new FrostFsContainerInfo(BasicAcl.PublicRW, Mocker.PlacementPolicy));
|
var param = new PrmContainerCreate(new FrostFsContainerInfo(Mocker.PlacementPolicy));
|
||||||
|
|
||||||
var result = await GetClient().CreateContainerAsync(param);
|
var result = await GetClient().CreateContainerAsync(param);
|
||||||
|
|
||||||
Assert.NotNull(result);
|
Assert.NotNull(result);
|
||||||
Assert.NotNull(result.Value);
|
Assert.NotNull(result.GetValue());
|
||||||
Assert.True(Base58.Encode(Mocker.ContainerGuid.ToBytes()) == result.Value);
|
Assert.True(Base58.Encode(Mocker.ContainerGuid.ToBytes()) == result.GetValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
@ -63,14 +63,11 @@ public class ContainerTest : ContainerTestsBase
|
||||||
{
|
{
|
||||||
var cid = new FrostFsContainerId(Base58.Encode(Mocker.ContainerGuid.ToBytes()));
|
var cid = new FrostFsContainerId(Base58.Encode(Mocker.ContainerGuid.ToBytes()));
|
||||||
|
|
||||||
Mocker.Acl = BasicAcl.PublicRO;
|
|
||||||
|
|
||||||
var result = await GetClient().GetContainerAsync(new PrmContainerGet(cid));
|
var result = await GetClient().GetContainerAsync(new PrmContainerGet(cid));
|
||||||
|
|
||||||
Assert.NotNull(result);
|
Assert.NotNull(result);
|
||||||
Assert.Equal(Mocker.Acl, result.BasicAcl);
|
|
||||||
Assert.Equal(Mocker.ContainerGuid, result.Nonce);
|
Assert.Equal(Mocker.ContainerGuid, result.Nonce);
|
||||||
Assert.Equal(0, Mocker.PlacementPolicy.CompareTo(result.PlacementPolicy));
|
Assert.Equal(Mocker.PlacementPolicy, result.PlacementPolicy);
|
||||||
Assert.Equal(Mocker.Version.ToString(), result.Version!.ToString());
|
Assert.Equal(Mocker.Version.ToString(), result.Version!.ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,7 +86,7 @@ public class ContainerTest : ContainerTestsBase
|
||||||
await foreach (var cid in result)
|
await foreach (var cid in result)
|
||||||
{
|
{
|
||||||
var val = Base58.Encode(ByteString.CopyFrom(Mocker.ContainerIds[i++]).ToByteArray());
|
var val = Base58.Encode(ByteString.CopyFrom(Mocker.ContainerIds[i++]).ToByteArray());
|
||||||
Assert.Equal(val, cid.Value);
|
Assert.Equal(val, cid.GetValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
Assert.Equal(3, i);
|
Assert.Equal(3, i);
|
||||||
|
@ -106,7 +103,7 @@ public class ContainerTest : ContainerTestsBase
|
||||||
Assert.Single(Mocker.Requests);
|
Assert.Single(Mocker.Requests);
|
||||||
|
|
||||||
var request = Mocker.Requests.First();
|
var request = Mocker.Requests.First();
|
||||||
|
|
||||||
Assert.Equal(cid.ToMessage(), request.Request.Body.ContainerId);
|
Assert.Equal(cid.ToMessage(), request.Request.Body.ContainerId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
using Grpc.Core;
|
using System.Diagnostics;
|
||||||
using Grpc.Core.Interceptors;
|
|
||||||
|
|
||||||
using System.Diagnostics;
|
using Grpc.Core;
|
||||||
|
using Grpc.Core.Interceptors;
|
||||||
|
|
||||||
namespace FrostFS.SDK.SmokeTests;
|
namespace FrostFS.SDK.SmokeTests;
|
||||||
|
|
||||||
|
@ -21,12 +21,12 @@ public class MetricsInterceptor() : Interceptor
|
||||||
call.GetTrailers,
|
call.GetTrailers,
|
||||||
call.Dispose);
|
call.Dispose);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task<TResponse> HandleUnaryResponse<TResponse>(AsyncUnaryCall<TResponse> call)
|
private static async Task<TResponse> HandleUnaryResponse<TResponse>(AsyncUnaryCall<TResponse> call)
|
||||||
{
|
{
|
||||||
var watch = new Stopwatch();
|
var watch = new Stopwatch();
|
||||||
watch.Start();
|
watch.Start();
|
||||||
|
|
||||||
var response = await call.ResponseAsync;
|
var response = await call.ResponseAsync;
|
||||||
|
|
||||||
watch.Stop();
|
watch.Stop();
|
||||||
|
@ -34,6 +34,6 @@ public class MetricsInterceptor() : Interceptor
|
||||||
// Do something with call info
|
// Do something with call info
|
||||||
// var elapsed = watch.ElapsedTicks * 1_000_000/Stopwatch.Frequency;
|
// var elapsed = watch.ElapsedTicks * 1_000_000/Stopwatch.Frequency;
|
||||||
|
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,7 @@ public class AsyncStreamReaderMock(string key, FrostFsObjectHeader objectHeader)
|
||||||
{
|
{
|
||||||
var header = new Header
|
var header = new Header
|
||||||
{
|
{
|
||||||
ContainerId = objectHeader.ContainerId.ToMessage(),
|
ContainerId = objectHeader.ContainerId.ToMessage(),
|
||||||
PayloadLength = objectHeader.PayloadLength,
|
PayloadLength = objectHeader.PayloadLength,
|
||||||
Version = objectHeader.Version!.ToMessage(),
|
Version = objectHeader.Version!.ToMessage(),
|
||||||
OwnerId = objectHeader.OwnerId!.ToMessage()
|
OwnerId = objectHeader.OwnerId!.ToMessage()
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
using Grpc.Core;
|
|
||||||
using FrostFS.SDK.ProtosV2.Interfaces;
|
using FrostFS.SDK.ProtosV2.Interfaces;
|
||||||
|
|
||||||
|
using Grpc.Core;
|
||||||
|
|
||||||
namespace FrostFS.SDK.Tests;
|
namespace FrostFS.SDK.Tests;
|
||||||
|
|
||||||
public class ClientStreamWriter : IClientStreamWriter<IRequest>
|
public class ClientStreamWriter : IClientStreamWriter<IRequest>
|
||||||
|
@ -17,13 +18,13 @@ public class ClientStreamWriter : IClientStreamWriter<IRequest>
|
||||||
public Task CompleteAsync()
|
public Task CompleteAsync()
|
||||||
{
|
{
|
||||||
CompletedTask = true;
|
CompletedTask = true;
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task WriteAsync(IRequest message)
|
public Task WriteAsync(IRequest message)
|
||||||
{
|
{
|
||||||
Object.PutRequest pr = new((Object.PutRequest)message);
|
Object.PutRequest pr = new((Object.PutRequest)message);
|
||||||
Messages.Add(pr);
|
Messages.Add(pr);
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,15 +1,17 @@
|
||||||
using System.Security.Cryptography;
|
using System.Security.Cryptography;
|
||||||
using FrostFS.Container;
|
|
||||||
using Moq;
|
|
||||||
|
|
||||||
|
using FrostFS.Container;
|
||||||
|
using FrostFS.Object;
|
||||||
|
using FrostFS.SDK.ClientV2;
|
||||||
|
using FrostFS.SDK.ClientV2.Mappers.GRPC;
|
||||||
using FrostFS.SDK.Cryptography;
|
using FrostFS.SDK.Cryptography;
|
||||||
using FrostFS.Session;
|
using FrostFS.Session;
|
||||||
|
|
||||||
using Google.Protobuf;
|
using Google.Protobuf;
|
||||||
|
|
||||||
using FrostFS.SDK.ClientV2;
|
|
||||||
using FrostFS.Object;
|
|
||||||
using Grpc.Core;
|
using Grpc.Core;
|
||||||
using FrostFS.SDK.ClientV2.Mappers.GRPC;
|
|
||||||
|
using Moq;
|
||||||
|
|
||||||
namespace FrostFS.SDK.Tests;
|
namespace FrostFS.SDK.Tests;
|
||||||
|
|
||||||
|
@ -18,11 +20,9 @@ public abstract class ServiceBase(string key)
|
||||||
public string StringKey { get; private set; } = key;
|
public string StringKey { get; private set; } = key;
|
||||||
public ECDsa Key { get; private set; } = key.LoadWif();
|
public ECDsa Key { get; private set; } = key.LoadWif();
|
||||||
public FrostFsVersion Version { get; set; } = DefaultVersion;
|
public FrostFsVersion Version { get; set; } = DefaultVersion;
|
||||||
public BasicAcl Acl { get; set; } = DefaultAcl;
|
|
||||||
public FrostFsPlacementPolicy PlacementPolicy { get; set; } = DefaultPlacementPolicy;
|
public FrostFsPlacementPolicy PlacementPolicy { get; set; } = DefaultPlacementPolicy;
|
||||||
|
|
||||||
public static FrostFsVersion DefaultVersion { get; } = new(2, 13);
|
public static FrostFsVersion DefaultVersion { get; } = new(2, 13);
|
||||||
public static BasicAcl DefaultAcl { get; } = BasicAcl.PublicRW;
|
|
||||||
public static FrostFsPlacementPolicy DefaultPlacementPolicy { get; } = new FrostFsPlacementPolicy(true, new FrostFsReplica(1));
|
public static FrostFsPlacementPolicy DefaultPlacementPolicy { get; } = new FrostFsPlacementPolicy(true, new FrostFsReplica(1));
|
||||||
|
|
||||||
public Metadata Metadata { get; protected set; }
|
public Metadata Metadata { get; protected set; }
|
||||||
|
@ -61,23 +61,23 @@ public abstract class ServiceBase(string key)
|
||||||
}
|
}
|
||||||
|
|
||||||
public ResponseMetaHeader ResponseMetaHeader => new()
|
public ResponseMetaHeader ResponseMetaHeader => new()
|
||||||
{
|
{
|
||||||
Version = Version.ToMessage(),
|
Version = Version.ToMessage(),
|
||||||
Epoch = 100,
|
Epoch = 100,
|
||||||
Ttl = 1
|
Ttl = 1
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract class ContainerServiceBase(string key) : ServiceBase (key)
|
public abstract class ContainerServiceBase(string key) : ServiceBase(key)
|
||||||
{
|
{
|
||||||
public Guid ContainerGuid { get; set; } = Guid.NewGuid();
|
public Guid ContainerGuid { get; set; } = Guid.NewGuid();
|
||||||
|
|
||||||
public abstract Mock<ContainerService.ContainerServiceClient> GetMock();
|
public abstract Mock<ContainerService.ContainerServiceClient> GetMock();
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract class ObjectServiceBase(string key) : ServiceBase (key)
|
public abstract class ObjectServiceBase(string key) : ServiceBase(key)
|
||||||
{
|
{
|
||||||
public abstract Mock<ObjectService.ObjectServiceClient> GetMock();
|
public abstract Mock<ObjectService.ObjectServiceClient> GetMock();
|
||||||
|
|
||||||
public Guid ContainerGuid { get; set; } = Guid.NewGuid();
|
public Guid ContainerGuid { get; set; } = Guid.NewGuid();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using FrostFS.Container;
|
using FrostFS.Container;
|
||||||
|
|
||||||
using Moq;
|
using Moq;
|
||||||
|
|
||||||
namespace FrostFS.SDK.Tests;
|
namespace FrostFS.SDK.Tests;
|
||||||
|
|
|
@ -1,14 +1,15 @@
|
||||||
using FrostFS.Container;
|
using FrostFS.Container;
|
||||||
using Google.Protobuf;
|
|
||||||
using Grpc.Core;
|
|
||||||
using Moq;
|
|
||||||
|
|
||||||
using FrostFS.SDK.Cryptography;
|
|
||||||
using FrostFS.SDK.ClientV2;
|
|
||||||
|
|
||||||
using FrostFS.SDK.ClientV2.Mappers.GRPC;
|
|
||||||
using FrostFS.Session;
|
|
||||||
using FrostFS.Refs;
|
using FrostFS.Refs;
|
||||||
|
using FrostFS.SDK.ClientV2;
|
||||||
|
using FrostFS.SDK.ClientV2.Mappers.GRPC;
|
||||||
|
using FrostFS.SDK.Cryptography;
|
||||||
|
using FrostFS.Session;
|
||||||
|
|
||||||
|
using Google.Protobuf;
|
||||||
|
|
||||||
|
using Grpc.Core;
|
||||||
|
|
||||||
|
using Moq;
|
||||||
|
|
||||||
namespace FrostFS.SDK.Tests;
|
namespace FrostFS.SDK.Tests;
|
||||||
|
|
||||||
|
@ -67,8 +68,7 @@ public class ContainerMocker(string key) : ContainerServiceBase(key)
|
||||||
{
|
{
|
||||||
Version = grpcVersion,
|
Version = grpcVersion,
|
||||||
Nonce = ByteString.CopyFrom(ContainerGuid.ToBytes()),
|
Nonce = ByteString.CopyFrom(ContainerGuid.ToBytes()),
|
||||||
BasicAcl = (uint)Acl,
|
PlacementPolicy = PlacementPolicy.GetPolicy()
|
||||||
PlacementPolicy = PlacementPolicy.ToMessage()
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
MetaHeader = ResponseMetaHeader
|
MetaHeader = ResponseMetaHeader
|
||||||
|
@ -78,10 +78,10 @@ public class ContainerMocker(string key) : ContainerServiceBase(key)
|
||||||
|
|
||||||
var getNoContainerResponse = new GetResponse
|
var getNoContainerResponse = new GetResponse
|
||||||
{
|
{
|
||||||
Body = new (),
|
Body = new(),
|
||||||
MetaHeader = new ResponseMetaHeader
|
MetaHeader = new ResponseMetaHeader
|
||||||
{
|
{
|
||||||
Status = new Status.Status
|
Status = new Status.Status
|
||||||
{
|
{
|
||||||
Code = 3072,
|
Code = 3072,
|
||||||
Message = "container not found"
|
Message = "container not found"
|
||||||
|
@ -107,7 +107,7 @@ public class ContainerMocker(string key) : ContainerServiceBase(key)
|
||||||
Task.FromResult(ResponseMetaData),
|
Task.FromResult(ResponseMetaData),
|
||||||
() => new Grpc.Core.Status(StatusCode.NotFound, string.Empty),
|
() => new Grpc.Core.Status(StatusCode.NotFound, string.Empty),
|
||||||
() => ResponseMetaData,
|
() => ResponseMetaData,
|
||||||
() => { });
|
() => { });
|
||||||
}
|
}
|
||||||
|
|
||||||
return new AsyncUnaryCall<GetResponse>(
|
return new AsyncUnaryCall<GetResponse>(
|
||||||
|
@ -115,7 +115,7 @@ public class ContainerMocker(string key) : ContainerServiceBase(key)
|
||||||
Task.FromResult(ResponseMetaData),
|
Task.FromResult(ResponseMetaData),
|
||||||
() => new Grpc.Core.Status(StatusCode.OK, string.Empty),
|
() => new Grpc.Core.Status(StatusCode.OK, string.Empty),
|
||||||
() => ResponseMetaData,
|
() => ResponseMetaData,
|
||||||
() => { });
|
() => { });
|
||||||
});
|
});
|
||||||
|
|
||||||
var listResponse = new ListResponse
|
var listResponse = new ListResponse
|
||||||
|
|
|
@ -9,4 +9,3 @@ public class RequestData<T>(T request, Metadata m, DateTime? dt, CancellationTok
|
||||||
public DateTime? Deadline => dt;
|
public DateTime? Deadline => dt;
|
||||||
public CancellationToken CancellationToken => ct;
|
public CancellationToken CancellationToken => ct;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,11 @@
|
||||||
using Moq;
|
|
||||||
using FrostFS.Netmap;
|
using FrostFS.Netmap;
|
||||||
using Grpc.Core;
|
|
||||||
using Google.Protobuf;
|
using Google.Protobuf;
|
||||||
|
|
||||||
|
using Grpc.Core;
|
||||||
|
|
||||||
|
using Moq;
|
||||||
|
|
||||||
namespace FrostFS.SDK.Tests;
|
namespace FrostFS.SDK.Tests;
|
||||||
|
|
||||||
public class NetworkMocker(string key) : ServiceBase(key)
|
public class NetworkMocker(string key) : ServiceBase(key)
|
||||||
|
|
|
@ -1,12 +1,16 @@
|
||||||
using Google.Protobuf;
|
|
||||||
using Grpc.Core;
|
|
||||||
using Moq;
|
|
||||||
using FrostFS.SDK.ClientV2;
|
|
||||||
using FrostFS.Object;
|
|
||||||
using FrostFS.SDK.ClientV2.Mappers.GRPC;
|
|
||||||
using System.Security.Cryptography;
|
using System.Security.Cryptography;
|
||||||
|
|
||||||
|
using FrostFS.Object;
|
||||||
|
using FrostFS.SDK.ClientV2;
|
||||||
|
using FrostFS.SDK.ClientV2.Mappers.GRPC;
|
||||||
using FrostFS.SDK.Cryptography;
|
using FrostFS.SDK.Cryptography;
|
||||||
|
|
||||||
|
using Google.Protobuf;
|
||||||
|
|
||||||
|
using Grpc.Core;
|
||||||
|
|
||||||
|
using Moq;
|
||||||
|
|
||||||
namespace FrostFS.SDK.Tests;
|
namespace FrostFS.SDK.Tests;
|
||||||
|
|
||||||
public class ObjectMocker(string key) : ObjectServiceBase(key)
|
public class ObjectMocker(string key) : ObjectServiceBase(key)
|
||||||
|
@ -183,7 +187,7 @@ public class ObjectMocker(string key) : ObjectServiceBase(key)
|
||||||
() => { });
|
() => { });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return mock;
|
return mock;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -195,7 +199,7 @@ public class ObjectMocker(string key) : ObjectServiceBase(key)
|
||||||
|
|
||||||
public List<byte[]>? ResultObjectIds { get; set; }
|
public List<byte[]>? ResultObjectIds { get; set; }
|
||||||
|
|
||||||
public ClientStreamWriter? ClientStreamWriter { get; private set; } = new ();
|
public ClientStreamWriter? ClientStreamWriter { get; private set; } = new();
|
||||||
|
|
||||||
public List<PutSingleRequest> PutSingleRequests { get; private set; } = [];
|
public List<PutSingleRequest> PutSingleRequests { get; private set; } = [];
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
using FrostFS.Session;
|
using FrostFS.Session;
|
||||||
|
|
||||||
using Google.Protobuf;
|
using Google.Protobuf;
|
||||||
|
|
||||||
using Grpc.Core;
|
using Grpc.Core;
|
||||||
|
|
||||||
using Moq;
|
using Moq;
|
||||||
|
|
||||||
namespace FrostFS.SDK.Tests;
|
namespace FrostFS.SDK.Tests;
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
|
||||||
using FrostFS.Netmap;
|
using FrostFS.Netmap;
|
||||||
using FrostFS.SDK.ClientV2;
|
using FrostFS.SDK.ClientV2;
|
||||||
using FrostFS.SDK.ClientV2.Interfaces;
|
using FrostFS.SDK.ClientV2.Interfaces;
|
||||||
|
@ -8,8 +10,6 @@ using Google.Protobuf;
|
||||||
|
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
|
|
||||||
using System.Security.Cryptography;
|
|
||||||
|
|
||||||
namespace FrostFS.SDK.Tests;
|
namespace FrostFS.SDK.Tests;
|
||||||
|
|
||||||
public abstract class NetworkTestsBase
|
public abstract class NetworkTestsBase
|
||||||
|
@ -40,7 +40,7 @@ public abstract class NetworkTestsBase
|
||||||
|
|
||||||
protected IFrostFSClient GetClient()
|
protected IFrostFSClient GetClient()
|
||||||
{
|
{
|
||||||
return ClientV2.Client.GetTestInstance(
|
return ClientV2.FrostFSClient.GetTestInstance(
|
||||||
Settings,
|
Settings,
|
||||||
null,
|
null,
|
||||||
Mocker.GetMock().Object,
|
Mocker.GetMock().Object,
|
||||||
|
@ -88,9 +88,9 @@ public class NetworkTest : NetworkTestsBase
|
||||||
}
|
}
|
||||||
|
|
||||||
var validTimeoutFrom = DateTime.UtcNow.AddSeconds(20);
|
var validTimeoutFrom = DateTime.UtcNow.AddSeconds(20);
|
||||||
|
|
||||||
var result = await GetClient().GetNetworkSettingsAsync(param);
|
var result = await GetClient().GetNetworkSettingsAsync(param);
|
||||||
|
|
||||||
var validTimeoutTo = DateTime.UtcNow.AddSeconds(20);
|
var validTimeoutTo = DateTime.UtcNow.AddSeconds(20);
|
||||||
|
|
||||||
Assert.NotNull(result);
|
Assert.NotNull(result);
|
||||||
|
@ -105,7 +105,7 @@ public class NetworkTest : NetworkTestsBase
|
||||||
Assert.Equal(Mocker.Parameters["MaxECParityCount"], [(byte)result.MaxECParityCount]);
|
Assert.Equal(Mocker.Parameters["MaxECParityCount"], [(byte)result.MaxECParityCount]);
|
||||||
Assert.Equal(Mocker.Parameters["MaxObjectSize"], [(byte)result.MaxObjectSize]);
|
Assert.Equal(Mocker.Parameters["MaxObjectSize"], [(byte)result.MaxObjectSize]);
|
||||||
Assert.Equal(Mocker.Parameters["WithdrawFee"], [(byte)result.WithdrawFee]);
|
Assert.Equal(Mocker.Parameters["WithdrawFee"], [(byte)result.WithdrawFee]);
|
||||||
|
|
||||||
Assert.True(result.HomomorphicHashingDisabled);
|
Assert.True(result.HomomorphicHashingDisabled);
|
||||||
Assert.True(result.MaintenanceModeAllowed);
|
Assert.True(result.MaintenanceModeAllowed);
|
||||||
|
|
||||||
|
@ -142,13 +142,13 @@ public class NetworkTest : NetworkTestsBase
|
||||||
|
|
||||||
nodeInfo1.Addresses.Add("address1");
|
nodeInfo1.Addresses.Add("address1");
|
||||||
nodeInfo1.Addresses.Add("address2");
|
nodeInfo1.Addresses.Add("address2");
|
||||||
nodeInfo1.Attributes.Add(new NodeInfo.Types.Attribute { Key = "key1", Value = "value1"});
|
nodeInfo1.Attributes.Add(new NodeInfo.Types.Attribute { Key = "key1", Value = "value1" });
|
||||||
nodeInfo1.Attributes.Add(new NodeInfo.Types.Attribute { Key = "key2", Value = "value2" });
|
nodeInfo1.Attributes.Add(new NodeInfo.Types.Attribute { Key = "key2", Value = "value2" });
|
||||||
|
|
||||||
var nodeInfo2 = new NodeInfo
|
var nodeInfo2 = new NodeInfo
|
||||||
{
|
{
|
||||||
State = NodeInfo.Types.State.Offline,
|
State = NodeInfo.Types.State.Offline,
|
||||||
PublicKey = ByteString.CopyFrom([3,4,5])
|
PublicKey = ByteString.CopyFrom([3, 4, 5])
|
||||||
};
|
};
|
||||||
|
|
||||||
nodeInfo2.Addresses.Add("address3");
|
nodeInfo2.Addresses.Add("address3");
|
||||||
|
@ -190,7 +190,7 @@ public class NetworkTest : NetworkTestsBase
|
||||||
Assert.Equal(2, node1.Addresses.Count);
|
Assert.Equal(2, node1.Addresses.Count);
|
||||||
Assert.Equal("address1", node1.Addresses.ElementAt(0));
|
Assert.Equal("address1", node1.Addresses.ElementAt(0));
|
||||||
Assert.Equal("address2", node1.Addresses.ElementAt(1));
|
Assert.Equal("address2", node1.Addresses.ElementAt(1));
|
||||||
|
|
||||||
Assert.Equal(2, node1.Attributes.Count);
|
Assert.Equal(2, node1.Attributes.Count);
|
||||||
|
|
||||||
Assert.Equal("key1", node1.Attributes.ElementAt(0).Key);
|
Assert.Equal("key1", node1.Attributes.ElementAt(0).Key);
|
||||||
|
@ -202,7 +202,7 @@ public class NetworkTest : NetworkTestsBase
|
||||||
Assert.Equal(NodeState.Offline, node2.State);
|
Assert.Equal(NodeState.Offline, node2.State);
|
||||||
Assert.Single(node2.Addresses);
|
Assert.Single(node2.Addresses);
|
||||||
Assert.Equal("address3", node2.Addresses.ElementAt(0));
|
Assert.Equal("address3", node2.Addresses.ElementAt(0));
|
||||||
|
|
||||||
Assert.Single(node2.Attributes);
|
Assert.Single(node2.Attributes);
|
||||||
|
|
||||||
Assert.Equal("key3", node2.Attributes.ElementAt(0).Key);
|
Assert.Equal("key3", node2.Attributes.ElementAt(0).Key);
|
||||||
|
@ -241,10 +241,10 @@ public class NetworkTest : NetworkTestsBase
|
||||||
},
|
},
|
||||||
Version = new Refs.Version { Major = 2, Minor = 12 }
|
Version = new Refs.Version { Major = 2, Minor = 12 }
|
||||||
};
|
};
|
||||||
|
|
||||||
body.NodeInfo.Addresses.Add("address1");
|
body.NodeInfo.Addresses.Add("address1");
|
||||||
body.NodeInfo.Addresses.Add("address2");
|
body.NodeInfo.Addresses.Add("address2");
|
||||||
body.NodeInfo.Attributes.Add(new NodeInfo.Types.Attribute { Key = "key1", Value = "value1"});
|
body.NodeInfo.Attributes.Add(new NodeInfo.Types.Attribute { Key = "key1", Value = "value1" });
|
||||||
body.NodeInfo.Attributes.Add(new NodeInfo.Types.Attribute { Key = "key2", Value = "value2" });
|
body.NodeInfo.Attributes.Add(new NodeInfo.Types.Attribute { Key = "key2", Value = "value2" });
|
||||||
|
|
||||||
Mocker.NodeInfoResponse = new LocalNodeInfoResponse { Body = body };
|
Mocker.NodeInfoResponse = new LocalNodeInfoResponse { Body = body };
|
||||||
|
@ -273,11 +273,11 @@ public class NetworkTest : NetworkTestsBase
|
||||||
Assert.NotNull(result);
|
Assert.NotNull(result);
|
||||||
|
|
||||||
Assert.Equal(NodeState.Online, result.State);
|
Assert.Equal(NodeState.Online, result.State);
|
||||||
|
|
||||||
Assert.Equal(2, result.Addresses.Count);
|
Assert.Equal(2, result.Addresses.Count);
|
||||||
Assert.Equal("address1", result.Addresses.ElementAt(0));
|
Assert.Equal("address1", result.Addresses.ElementAt(0));
|
||||||
Assert.Equal("address2", result.Addresses.ElementAt(1));
|
Assert.Equal("address2", result.Addresses.ElementAt(1));
|
||||||
|
|
||||||
Assert.Equal(2, result.Attributes.Count);
|
Assert.Equal(2, result.Attributes.Count);
|
||||||
Assert.Equal("value1", result.Attributes["key1"]);
|
Assert.Equal("value1", result.Attributes["key1"]);
|
||||||
Assert.Equal("value2", result.Attributes["key2"]);
|
Assert.Equal("value2", result.Attributes["key2"]);
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
using FrostFS.Refs;
|
using FrostFS.Refs;
|
||||||
using FrostFS.SDK.ClientV2;
|
using FrostFS.SDK.ClientV2;
|
||||||
using FrostFS.SDK.ClientV2.Interfaces;
|
using FrostFS.SDK.ClientV2.Interfaces;
|
||||||
|
@ -9,9 +12,6 @@ using Google.Protobuf;
|
||||||
|
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
|
|
||||||
using System.Security.Cryptography;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace FrostFS.SDK.Tests;
|
namespace FrostFS.SDK.Tests;
|
||||||
|
|
||||||
public abstract class ObjectTestsBase
|
public abstract class ObjectTestsBase
|
||||||
|
@ -29,7 +29,7 @@ public abstract class ObjectTestsBase
|
||||||
protected ObjectTestsBase()
|
protected ObjectTestsBase()
|
||||||
{
|
{
|
||||||
var ecdsaKey = key.LoadWif();
|
var ecdsaKey = key.LoadWif();
|
||||||
|
|
||||||
Settings = Options.Create(new SingleOwnerClientSettings
|
Settings = Options.Create(new SingleOwnerClientSettings
|
||||||
{
|
{
|
||||||
Key = key,
|
Key = key,
|
||||||
|
@ -46,17 +46,17 @@ public abstract class ObjectTestsBase
|
||||||
ContainerId = new FrostFsContainerId(Base58.Encode(Mocker.ContainerGuid.ToBytes()));
|
ContainerId = new FrostFsContainerId(Base58.Encode(Mocker.ContainerGuid.ToBytes()));
|
||||||
|
|
||||||
Mocker.ObjectHeader = new(
|
Mocker.ObjectHeader = new(
|
||||||
ContainerId,
|
ContainerId,
|
||||||
FrostFsObjectType.Regular,
|
FrostFsObjectType.Regular,
|
||||||
[new FrostFsAttribute("k", "v")],
|
[new FrostFsAttributePair("k", "v")],
|
||||||
null,
|
null,
|
||||||
FrostFsOwner.FromKey(ecdsaKey),
|
FrostFsOwner.FromKey(ecdsaKey),
|
||||||
new FrostFsVersion(2, 13));
|
new FrostFsVersion(2, 13));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected IFrostFSClient GetClient()
|
protected IFrostFSClient GetClient()
|
||||||
{
|
{
|
||||||
return Client.GetTestInstance(
|
return FrostFSClient.GetTestInstance(
|
||||||
Settings,
|
Settings,
|
||||||
null,
|
null,
|
||||||
NetworkMocker.GetMock().Object,
|
NetworkMocker.GetMock().Object,
|
||||||
|
@ -75,30 +75,32 @@ public class ObjectTest : ObjectTestsBase
|
||||||
|
|
||||||
var ecdsaKey = key.LoadWif();
|
var ecdsaKey = key.LoadWif();
|
||||||
|
|
||||||
var ctx = new Context {
|
var ctx = new Context
|
||||||
Key = ecdsaKey,
|
{
|
||||||
OwnerId = FrostFsOwner.FromKey(ecdsaKey),
|
Key = ecdsaKey,
|
||||||
Version = new FrostFsVersion(2, 13) };
|
OwnerId = FrostFsOwner.FromKey(ecdsaKey),
|
||||||
|
Version = new FrostFsVersion(2, 13)
|
||||||
|
};
|
||||||
|
|
||||||
var objectId = client.CalculateObjectId(Mocker.ObjectHeader!, ctx);
|
var objectId = client.CalculateObjectId(Mocker.ObjectHeader!, ctx);
|
||||||
|
|
||||||
var result = await client.GetObjectAsync(new PrmObjectGet(ContainerId, objectId) { Context = ctx });
|
var result = await client.GetObjectAsync(new PrmObjectGet(ContainerId, objectId) { Context = ctx });
|
||||||
|
|
||||||
Assert.NotNull(result);
|
Assert.NotNull(result);
|
||||||
|
|
||||||
Assert.Equal(Mocker.ObjectHeader!.ContainerId.Value, result.Header.ContainerId.Value);
|
Assert.Equal(Mocker.ObjectHeader!.ContainerId.GetValue(), result.Header.ContainerId.GetValue());
|
||||||
Assert.Equal(Mocker.ObjectHeader!.OwnerId!.Value, result.Header.OwnerId!.Value);
|
Assert.Equal(Mocker.ObjectHeader!.OwnerId!.Value, result.Header.OwnerId!.Value);
|
||||||
Assert.Equal(Mocker.ObjectHeader.PayloadLength, result.Header.PayloadLength);
|
Assert.Equal(Mocker.ObjectHeader.PayloadLength, result.Header.PayloadLength);
|
||||||
Assert.Single(result.Header.Attributes);
|
Assert.Single(result.Header.Attributes);
|
||||||
Assert.Equal(Mocker.ObjectHeader.Attributes[0].Key, result.Header.Attributes[0].Key);
|
Assert.Equal(Mocker.ObjectHeader.Attributes[0].Key, result.Header.Attributes[0].Key);
|
||||||
Assert.Equal(Mocker.ObjectHeader.Attributes[0].Value,result.Header.Attributes[0].Value);
|
Assert.Equal(Mocker.ObjectHeader.Attributes[0].Value, result.Header.Attributes[0].Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async void PutObjectTest()
|
public async void PutObjectTest()
|
||||||
{
|
{
|
||||||
Mocker.ResultObjectIds = new([SHA256.HashData([])]);
|
Mocker.ResultObjectIds = new([SHA256.HashData([])]);
|
||||||
|
|
||||||
Random rnd = new();
|
Random rnd = new();
|
||||||
var bytes = new byte[1024];
|
var bytes = new byte[1024];
|
||||||
rnd.NextBytes(bytes);
|
rnd.NextBytes(bytes);
|
||||||
|
@ -119,20 +121,20 @@ public class ObjectTest : ObjectTestsBase
|
||||||
|
|
||||||
Assert.NotNull(result);
|
Assert.NotNull(result);
|
||||||
Assert.Equal(Mocker.ResultObjectIds.First(), result.ToHash());
|
Assert.Equal(Mocker.ResultObjectIds.First(), result.ToHash());
|
||||||
|
|
||||||
Assert.True(Mocker.ClientStreamWriter.CompletedTask);
|
Assert.True(Mocker.ClientStreamWriter.CompletedTask);
|
||||||
|
|
||||||
Assert.Equal(0, body1!.Chunk.Length);
|
Assert.Equal(0, body1!.Chunk.Length);
|
||||||
Assert.Equal(Object.PutRequest.Types.Body.ObjectPartOneofCase.Init, body1!.ObjectPartCase);
|
Assert.Equal(Object.PutRequest.Types.Body.ObjectPartOneofCase.Init, body1!.ObjectPartCase);
|
||||||
|
|
||||||
Assert.Equal(1024, body2!.Chunk.Length);
|
Assert.Equal(1024, body2!.Chunk.Length);
|
||||||
Assert.Equal(Object.PutRequest.Types.Body.ObjectPartOneofCase.Chunk, body2!.ObjectPartCase);
|
Assert.Equal(Object.PutRequest.Types.Body.ObjectPartOneofCase.Chunk, body2!.ObjectPartCase);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async void ClientCutTest()
|
public async void ClientCutTest()
|
||||||
{
|
{
|
||||||
NetworkMocker.Parameters = new Dictionary<string, byte[]>() { { "MaxObjectSize", [0x0, 0xa] } };
|
NetworkMocker.Parameters = new Dictionary<string, byte[]>() { { "MaxObjectSize", [0x0, 0xa] } };
|
||||||
|
|
||||||
var blockSize = 2560;
|
var blockSize = 2560;
|
||||||
byte[] bytes = File.ReadAllBytes(@".\..\..\..\TestData\cat.jpg");
|
byte[] bytes = File.ReadAllBytes(@".\..\..\..\TestData\cat.jpg");
|
||||||
|
@ -251,11 +253,11 @@ public class ObjectTest : ObjectTestsBase
|
||||||
Assert.Equal(Mocker.ObjectId.ToMessage(), request.Body.Address.ObjectId);
|
Assert.Equal(Mocker.ObjectId.ToMessage(), request.Body.Address.ObjectId);
|
||||||
|
|
||||||
Assert.NotNull(response);
|
Assert.NotNull(response);
|
||||||
Assert.Equal(ContainerId.Value, response.ContainerId.Value);
|
Assert.Equal(ContainerId.GetValue(), response.ContainerId.GetValue());
|
||||||
|
|
||||||
Assert.Equal(Mocker.ObjectHeader!.OwnerId!.Value, response.OwnerId!.Value);
|
Assert.Equal(Mocker.ObjectHeader!.OwnerId!.Value, response.OwnerId!.Value);
|
||||||
Assert.Equal(Mocker.ObjectHeader!.Version!.ToString(), response.Version!.ToString());
|
Assert.Equal(Mocker.ObjectHeader!.Version!.ToString(), response.Version!.ToString());
|
||||||
|
|
||||||
Assert.Equal(Mocker.HeadResponse!.PayloadLength, response.PayloadLength);
|
Assert.Equal(Mocker.HeadResponse!.PayloadLength, response.PayloadLength);
|
||||||
|
|
||||||
Assert.Equal(FrostFsObjectType.Regular, response.ObjectType);
|
Assert.Equal(FrostFsObjectType.Regular, response.ObjectType);
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
|
||||||
using FrostFS.SDK.ClientV2;
|
using FrostFS.SDK.ClientV2;
|
||||||
using FrostFS.SDK.ClientV2.Interfaces;
|
using FrostFS.SDK.ClientV2.Interfaces;
|
||||||
using FrostFS.SDK.ClientV2.Mappers.GRPC;
|
using FrostFS.SDK.ClientV2.Mappers.GRPC;
|
||||||
|
@ -6,8 +8,6 @@ using FrostFS.SDK.Cryptography;
|
||||||
|
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
|
|
||||||
using System.Security.Cryptography;
|
|
||||||
|
|
||||||
namespace FrostFS.SDK.Tests;
|
namespace FrostFS.SDK.Tests;
|
||||||
|
|
||||||
public abstract class SessionTestsBase
|
public abstract class SessionTestsBase
|
||||||
|
@ -16,7 +16,7 @@ public abstract class SessionTestsBase
|
||||||
|
|
||||||
protected IOptions<SingleOwnerClientSettings> Settings { get; set; }
|
protected IOptions<SingleOwnerClientSettings> Settings { get; set; }
|
||||||
|
|
||||||
|
|
||||||
protected ECDsa ECDsaKey { get; set; }
|
protected ECDsa ECDsaKey { get; set; }
|
||||||
protected FrostFsOwner OwnerId { get; set; }
|
protected FrostFsOwner OwnerId { get; set; }
|
||||||
protected SessionMocker Mocker { get; set; }
|
protected SessionMocker Mocker { get; set; }
|
||||||
|
@ -41,7 +41,7 @@ public abstract class SessionTestsBase
|
||||||
|
|
||||||
protected IFrostFSClient GetClient()
|
protected IFrostFSClient GetClient()
|
||||||
{
|
{
|
||||||
return ClientV2.Client.GetTestInstance(
|
return ClientV2.FrostFSClient.GetTestInstance(
|
||||||
Settings,
|
Settings,
|
||||||
null,
|
null,
|
||||||
new NetworkMocker(this.key).GetMock().Object,
|
new NetworkMocker(this.key).GetMock().Object,
|
||||||
|
@ -100,8 +100,8 @@ public class SessionTest : SessionTestsBase
|
||||||
Assert.Equal(exp, Mocker.CreateSessionRequest.Body.Expiration);
|
Assert.Equal(exp, Mocker.CreateSessionRequest.Body.Expiration);
|
||||||
Assert.NotNull(Mocker.CreateSessionRequest.MetaHeader);
|
Assert.NotNull(Mocker.CreateSessionRequest.MetaHeader);
|
||||||
Assert.Equal(Mocker.Version.ToMessage(), Mocker.CreateSessionRequest.MetaHeader.Version);
|
Assert.Equal(Mocker.Version.ToMessage(), Mocker.CreateSessionRequest.MetaHeader.Version);
|
||||||
|
|
||||||
|
|
||||||
Assert.Null(Mocker.Metadata);
|
Assert.Null(Mocker.Metadata);
|
||||||
|
|
||||||
if (useContext)
|
if (useContext)
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue