Compare commits
No commits in common. "master" and "master" have entirely different histories.
282 changed files with 3830 additions and 16901 deletions
901
.editorconfig
901
.editorconfig
|
@ -1,901 +0,0 @@
|
|||
[*.cs]
|
||||
|
||||
# CA1001: Types that own disposable fields should be disposable
|
||||
dotnet_diagnostic.CA1001.severity = warning
|
||||
|
||||
# CA1000: Do not declare static members on generic types
|
||||
dotnet_diagnostic.CA1000.severity = warning
|
||||
|
||||
# CA1002: Do not expose generic lists
|
||||
dotnet_diagnostic.CA1002.severity = warning
|
||||
|
||||
# CA1003: Use generic event handler instances
|
||||
dotnet_diagnostic.CA1003.severity = warning
|
||||
|
||||
# CA1005: Avoid excessive parameters on generic types
|
||||
dotnet_diagnostic.CA1005.severity = warning
|
||||
|
||||
# CA1008: Enums should have zero value
|
||||
dotnet_diagnostic.CA1008.severity = warning
|
||||
|
||||
# CA1010: Generic interface should also be implemented
|
||||
dotnet_diagnostic.CA1010.severity = warning
|
||||
|
||||
# CA1012: Abstract types should not have public constructors
|
||||
dotnet_diagnostic.CA1012.severity = warning
|
||||
|
||||
# CA1014: Mark assemblies with CLSCompliant
|
||||
dotnet_diagnostic.CA1014.severity = warning
|
||||
|
||||
# CA1016: Mark assemblies with assembly version
|
||||
dotnet_diagnostic.CA1016.severity = warning
|
||||
|
||||
# CA1017: Mark assemblies with ComVisible
|
||||
dotnet_diagnostic.CA1017.severity = warning
|
||||
|
||||
# CA1018: Mark attributes with AttributeUsageAttribute
|
||||
dotnet_diagnostic.CA1018.severity = warning
|
||||
|
||||
# CA1019: Define accessors for attribute arguments
|
||||
dotnet_diagnostic.CA1019.severity = warning
|
||||
|
||||
# CA1021: Avoid out parameters
|
||||
dotnet_diagnostic.CA1021.severity = warning
|
||||
|
||||
# CA1024: Use properties where appropriate
|
||||
dotnet_diagnostic.CA1024.severity = warning
|
||||
|
||||
# CA1027: Mark enums with FlagsAttribute
|
||||
dotnet_diagnostic.CA1027.severity = warning
|
||||
|
||||
# CA1028: Enum Storage should be Int32
|
||||
dotnet_diagnostic.CA1028.severity = warning
|
||||
|
||||
# CA1030: Use events where appropriate
|
||||
dotnet_diagnostic.CA1030.severity = warning
|
||||
|
||||
# CA1031: Do not catch general exception types
|
||||
dotnet_diagnostic.CA1031.severity = warning
|
||||
|
||||
# CA1033: Interface methods should be callable by child types
|
||||
dotnet_diagnostic.CA1033.severity = warning
|
||||
|
||||
# CA1034: Nested types should not be visible
|
||||
dotnet_diagnostic.CA1034.severity = warning
|
||||
|
||||
# CA1036: Override methods on comparable types
|
||||
dotnet_diagnostic.CA1036.severity = warning
|
||||
|
||||
# CA1040: Avoid empty interfaces
|
||||
dotnet_diagnostic.CA1040.severity = warning
|
||||
|
||||
# CA1041: Provide ObsoleteAttribute message
|
||||
dotnet_diagnostic.CA1041.severity = warning
|
||||
|
||||
# CA1043: Use Integral Or String Argument For Indexers
|
||||
dotnet_diagnostic.CA1043.severity = warning
|
||||
|
||||
# CA1044: Properties should not be write only
|
||||
dotnet_diagnostic.CA1044.severity = warning
|
||||
|
||||
# CA1045: Do not pass types by reference
|
||||
dotnet_diagnostic.CA1045.severity = warning
|
||||
|
||||
# CA1046: Do not overload equality operator on reference types
|
||||
dotnet_diagnostic.CA1046.severity = warning
|
||||
|
||||
# CA1050: Declare types in namespaces
|
||||
dotnet_diagnostic.CA1050.severity = warning
|
||||
|
||||
# CA1051: Do not declare visible instance fields
|
||||
dotnet_diagnostic.CA1051.severity = warning
|
||||
|
||||
# CA1052: Static holder types should be Static or NotInheritable
|
||||
dotnet_diagnostic.CA1052.severity = warning
|
||||
|
||||
# CA1054: URI-like parameters should not be strings
|
||||
dotnet_diagnostic.CA1054.severity = warning
|
||||
|
||||
# CA1055: URI-like return values should not be strings
|
||||
dotnet_diagnostic.CA1055.severity = warning
|
||||
|
||||
# CA1056: URI-like properties should not be strings
|
||||
dotnet_diagnostic.CA1056.severity = warning
|
||||
|
||||
# CA1058: Types should not extend certain base types
|
||||
dotnet_diagnostic.CA1058.severity = warning
|
||||
|
||||
# CA1060: Move pinvokes to native methods class
|
||||
dotnet_diagnostic.CA1060.severity = warning
|
||||
|
||||
# CA1061: Do not hide base class methods
|
||||
dotnet_diagnostic.CA1061.severity = warning
|
||||
|
||||
# CA1062: Validate arguments of public methods
|
||||
dotnet_diagnostic.CA1062.severity = warning
|
||||
|
||||
# CA1063: Implement IDisposable Correctly
|
||||
dotnet_diagnostic.CA1063.severity = warning
|
||||
|
||||
# CA1064: Exceptions should be public
|
||||
dotnet_diagnostic.CA1064.severity = warning
|
||||
|
||||
# CA1065: Do not raise exceptions in unexpected locations
|
||||
dotnet_diagnostic.CA1065.severity = warning
|
||||
|
||||
# CA1066: Implement IEquatable when overriding Object.Equals
|
||||
dotnet_diagnostic.CA1066.severity = warning
|
||||
|
||||
# CA1067: Override Object.Equals(object) when implementing IEquatable<T>
|
||||
dotnet_diagnostic.CA1067.severity = warning
|
||||
|
||||
# CA1068: CancellationToken parameters must come last
|
||||
dotnet_diagnostic.CA1068.severity = warning
|
||||
|
||||
# CA1069: Enums values should not be duplicated
|
||||
dotnet_diagnostic.CA1069.severity = warning
|
||||
|
||||
# CA1070: Do not declare event fields as virtual
|
||||
dotnet_diagnostic.CA1070.severity = warning
|
||||
|
||||
# CA1303: Do not pass literals as localized parameters
|
||||
dotnet_diagnostic.CA1303.severity = warning
|
||||
|
||||
# CA1304: Specify CultureInfo
|
||||
dotnet_diagnostic.CA1304.severity = warning
|
||||
|
||||
# CA1305: Specify IFormatProvider
|
||||
dotnet_diagnostic.CA1305.severity = warning
|
||||
|
||||
# CA1307: Specify StringComparison for clarity
|
||||
dotnet_diagnostic.CA1307.severity = warning
|
||||
|
||||
# CA1308: Normalize strings to uppercase
|
||||
dotnet_diagnostic.CA1308.severity = warning
|
||||
|
||||
# CA1310: Specify StringComparison for correctness
|
||||
dotnet_diagnostic.CA1310.severity = warning
|
||||
|
||||
# CA1401: P/Invokes should not be visible
|
||||
dotnet_diagnostic.CA1401.severity = warning
|
||||
|
||||
# CA1416: Validate platform compatibility
|
||||
dotnet_diagnostic.CA1416.severity = warning
|
||||
|
||||
# CA1417: Do not use 'OutAttribute' on string parameters for P/Invokes
|
||||
dotnet_diagnostic.CA1417.severity = warning
|
||||
|
||||
# CA1418: Use valid platform string
|
||||
dotnet_diagnostic.CA1418.severity = warning
|
||||
|
||||
# CA1419: Provide a parameterless constructor that is as visible as the containing type for concrete types derived from 'System.Runtime.InteropServices.SafeHandle'
|
||||
dotnet_diagnostic.CA1419.severity = warning
|
||||
|
||||
# CA1420: Property, type, or attribute requires runtime marshalling
|
||||
dotnet_diagnostic.CA1420.severity = warning
|
||||
|
||||
# CA1421: This method uses runtime marshalling even when the 'DisableRuntimeMarshallingAttribute' is applied
|
||||
dotnet_diagnostic.CA1421.severity = warning
|
||||
|
||||
# CA1422: Validate platform compatibility
|
||||
dotnet_diagnostic.CA1422.severity = warning
|
||||
|
||||
# CA1501: Avoid excessive inheritance
|
||||
dotnet_diagnostic.CA1501.severity = warning
|
||||
|
||||
# CA1502: Avoid excessive complexity
|
||||
dotnet_diagnostic.CA1502.severity = warning
|
||||
|
||||
# CA1505: Avoid unmaintainable code
|
||||
dotnet_diagnostic.CA1505.severity = warning
|
||||
|
||||
# CA1506: Avoid excessive class coupling
|
||||
# dotnet_diagnostic.CA1506.severity = warning
|
||||
|
||||
# CA1509: Invalid entry in code metrics rule specification file
|
||||
dotnet_diagnostic.CA1509.severity = warning
|
||||
|
||||
# CA1510: Use ArgumentNullException throw helper
|
||||
dotnet_diagnostic.CA1510.severity = warning
|
||||
|
||||
# CA1511: Use ArgumentException throw helper
|
||||
dotnet_diagnostic.CA1511.severity = warning
|
||||
|
||||
# CA1512: Use ArgumentOutOfRangeException throw helper
|
||||
dotnet_diagnostic.CA1512.severity = warning
|
||||
|
||||
# CA1513: Use ObjectDisposedException throw helper
|
||||
dotnet_diagnostic.CA1513.severity = warning
|
||||
|
||||
# CA1700: Do not name enum values 'Reserved'
|
||||
dotnet_diagnostic.CA1700.severity = warning
|
||||
|
||||
# CA1707: Identifiers should not contain underscores
|
||||
dotnet_diagnostic.CA1707.severity = warning
|
||||
|
||||
# CA1708: Identifiers should differ by more than case
|
||||
dotnet_diagnostic.CA1708.severity = none
|
||||
|
||||
# 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 = none
|
||||
|
||||
# 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,22 +0,0 @@
|
|||
name: lint-build
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
lint-build:
|
||||
name: dotnet${{ matrix.dotnet }}
|
||||
runs-on: docker
|
||||
container: git.frostfs.info/truecloudlab/env:dotnet-${{ matrix.dotnet }}
|
||||
strategy:
|
||||
matrix:
|
||||
dotnet:
|
||||
- '8.0'
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
# Dotnet runs code analyzers on build (if configured):
|
||||
# https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/overview?tabs=net-8#enable-on-build
|
||||
- run: dotnet build
|
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -4,7 +4,6 @@
|
|||
*.dll
|
||||
*.so
|
||||
*.dylib
|
||||
*.pdb
|
||||
|
||||
# Test binary, built with `go test -c`
|
||||
*.test
|
||||
|
@ -18,7 +17,6 @@ vendor/
|
|||
# IDE
|
||||
.idea
|
||||
.vscode
|
||||
.vs
|
||||
|
||||
# coverage
|
||||
coverage.txt
|
||||
|
@ -33,4 +31,3 @@ antlr-*.jar
|
|||
# binary
|
||||
bin/
|
||||
release/
|
||||
obj/
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
.* @PavelGrossSpb
|
||||
.forgejo/.* @potyarkin
|
||||
Makefile @potyarkin
|
|
@ -1,20 +1,12 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.5.002.0
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FrostFS.SDK.Client", "src\FrostFS.SDK.Client\FrostFS.SDK.Client.csproj", "{50D8F61F-C302-4AC9-8D8A-AB0B8C0988C3}"
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FrostFS.SDK.ProtosV2", "src\FrostFS.SDK.ProtosV2\FrostFS.SDK.ProtosV2.csproj", "{A087047E-2505-4137-97CC-689A5AD58A0C}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FrostFS.SDK.Cryptography", "src\FrostFS.SDK.Cryptography\FrostFS.SDK.Cryptography.csproj", "{3D804F4A-B0B2-47A5-B006-BE447BE64B50}"
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FrostFS.SDK.ClientV2", "src\FrostFS.SDK.ClientV2\FrostFS.SDK.ClientV2.csproj", "{F9CE6347-111A-4CE6-8BB2-545469838F47}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FrostFS.SDK.Protos", "src\FrostFS.SDK.Protos\FrostFS.SDK.Protos.csproj", "{5012EF96-9C9E-4E77-BC78-B4111EE54107}"
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FrostFS.SDK.Cryptography", "src\FrostFS.SDK.Cryptography\FrostFS.SDK.Cryptography.csproj", "{599E2FF8-12C0-414D-B295-4C971A0A1A63}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FrostFS.SDK.Tests", "src\FrostFS.SDK.Tests\FrostFS.SDK.Tests.csproj", "{8FDA7E0D-9C75-4874-988E-6592CD28F76C}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{2F030ACD-F87C-4E83-9A68-4CC5DF03AD90}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
.editorconfig = .editorconfig
|
||||
EndProjectSection
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FrostFS.SDK.ModelsV2", "src\FrostFS.SDK.ModelsV2\FrostFS.SDK.ModelsV2.csproj", "{3F6E5EE6-2AAC-45BE-A5E2-B83D11F90CC3}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
|
@ -22,24 +14,25 @@ Global
|
|||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{50D8F61F-C302-4AC9-8D8A-AB0B8C0988C3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{50D8F61F-C302-4AC9-8D8A-AB0B8C0988C3}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{50D8F61F-C302-4AC9-8D8A-AB0B8C0988C3}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{50D8F61F-C302-4AC9-8D8A-AB0B8C0988C3}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{3D804F4A-B0B2-47A5-B006-BE447BE64B50}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{3D804F4A-B0B2-47A5-B006-BE447BE64B50}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{3D804F4A-B0B2-47A5-B006-BE447BE64B50}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{3D804F4A-B0B2-47A5-B006-BE447BE64B50}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{5012EF96-9C9E-4E77-BC78-B4111EE54107}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{5012EF96-9C9E-4E77-BC78-B4111EE54107}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{5012EF96-9C9E-4E77-BC78-B4111EE54107}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{5012EF96-9C9E-4E77-BC78-B4111EE54107}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{8FDA7E0D-9C75-4874-988E-6592CD28F76C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{8FDA7E0D-9C75-4874-988E-6592CD28F76C}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{8FDA7E0D-9C75-4874-988E-6592CD28F76C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{8FDA7E0D-9C75-4874-988E-6592CD28F76C}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
{A087047E-2505-4137-97CC-689A5AD58A0C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{A087047E-2505-4137-97CC-689A5AD58A0C}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{A087047E-2505-4137-97CC-689A5AD58A0C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{A087047E-2505-4137-97CC-689A5AD58A0C}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{F9CE6347-111A-4CE6-8BB2-545469838F47}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{F9CE6347-111A-4CE6-8BB2-545469838F47}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{F9CE6347-111A-4CE6-8BB2-545469838F47}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{F9CE6347-111A-4CE6-8BB2-545469838F47}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{B04EBDF5-A446-49D6-B1D7-7D729D94E8E0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{B04EBDF5-A446-49D6-B1D7-7D729D94E8E0}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{B04EBDF5-A446-49D6-B1D7-7D729D94E8E0}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{B04EBDF5-A446-49D6-B1D7-7D729D94E8E0}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{599E2FF8-12C0-414D-B295-4C971A0A1A63}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{599E2FF8-12C0-414D-B295-4C971A0A1A63}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{599E2FF8-12C0-414D-B295-4C971A0A1A63}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{599E2FF8-12C0-414D-B295-4C971A0A1A63}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{3F6E5EE6-2AAC-45BE-A5E2-B83D11F90CC3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{3F6E5EE6-2AAC-45BE-A5E2-B83D11F90CC3}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{3F6E5EE6-2AAC-45BE-A5E2-B83D11F90CC3}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{3F6E5EE6-2AAC-45BE-A5E2-B83D11F90CC3}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
|
102
README.md
102
README.md
|
@ -21,62 +21,60 @@ neo-go wallet export -w <path_to_your_wallet> -d <address_from_p1>
|
|||
### Container
|
||||
|
||||
```csharp
|
||||
using FrostFS.SDK;
|
||||
using FrostFS.SDK.ClientV2;
|
||||
using FrostFS.SDK.ModelsV2;
|
||||
using FrostFS.SDK.ModelsV2.Enums;
|
||||
using FrostFS.SDK.ModelsV2.Netmap;
|
||||
|
||||
using Microsoft.Extensions.Options;
|
||||
var fsClient = new Client(<your_key>, <your_host>);
|
||||
|
||||
var Key = "KwHDAJ66o8FoLBjVbjP2sWBmgBMGjt7Vv4boA7xQrBoAYBE397Aq";
|
||||
var Host = "http://172.22.33.44:8080";
|
||||
// List containers
|
||||
var containersIds = await fsClient.ListContainersAsync();
|
||||
|
||||
var options = Options.Create(new SingleOwnerClientSettings
|
||||
{
|
||||
Key = Key,
|
||||
Host = Host
|
||||
});
|
||||
// Create container
|
||||
var placementPolicy = new PlacementPolicy(true, new Replica(1));
|
||||
var containerId = await fsClient.CreateContainerAsync(
|
||||
new Container(
|
||||
BasicAcl.PublicRW,
|
||||
placementPolicy
|
||||
)
|
||||
);
|
||||
|
||||
using var client = Client.GetSingleOwnerInstance(options);
|
||||
// Get container
|
||||
var container = await fsClient.GetContainerAsync(cId);
|
||||
|
||||
await foreach (var cid in client.ListContainersAsync())
|
||||
{
|
||||
await client.DeleteContainerAsync(new PrmContainerDelete(cid));
|
||||
}
|
||||
|
||||
var placementPolicy = new FrostFsPlacementPolicy(true, new FrostFsReplica(1));
|
||||
|
||||
var createContainerParam = new PrmContainerCreate(
|
||||
new FrostFsContainerInfo(BasicAcl.PublicRW, new FrostFsPlacementPolicy(true, new FrostFsReplica(1))));
|
||||
|
||||
var containerId = await client.CreateContainerAsync(createContainerParam);
|
||||
|
||||
using var fileStream = File.OpenRead(@"C:\Users\Paul\Pictures\cat.jpeg");
|
||||
|
||||
var param = new PrmObjectPut
|
||||
{
|
||||
Header = new FrostFsObjectHeader(
|
||||
containerId: containerId,
|
||||
type: FrostFsObjectType.Regular,
|
||||
[new FrostFsAttribute("fileName", "test")]),
|
||||
Payload = fileStream
|
||||
};
|
||||
|
||||
FrostFsObjectId objectId = await client.PutObjectAsync(param);
|
||||
|
||||
var filter = new FilterByAttribute(FrostFsMatchType.Equals, "fileName", "test");
|
||||
|
||||
await foreach (var objId in client.SearchObjectsAsync(new PrmObjectSearch(containerId) { Filters = [filter] }))
|
||||
{
|
||||
var objHeader = await client.GetObjectHeadAsync(new PrmObjectHeadGet(containerId, objId));
|
||||
}
|
||||
|
||||
var @object = await client.GetObjectAsync(new PrmObjectGet(containerId, objectId));
|
||||
|
||||
var downloadedBytes = new byte[@object.Header.PayloadLength];
|
||||
MemoryStream ms = new(downloadedBytes);
|
||||
|
||||
ReadOnlyMemory<byte>? chunk = null;
|
||||
while ((chunk = await @object.ObjectReader!.ReadChunk()) != null)
|
||||
{
|
||||
ms.Write(chunk.Value.Span);
|
||||
}
|
||||
// Delete container
|
||||
await fsClient.DeleteContainerAsync(containerId);
|
||||
```
|
||||
|
||||
### Object
|
||||
|
||||
```csharp
|
||||
using FrostFS.SDK.ClientV2;
|
||||
using FrostFS.SDK.ModelsV2;
|
||||
using FrostFS.SDK.ModelsV2.Enums;
|
||||
using FrostFS.SDK.ModelsV2.Netmap;
|
||||
|
||||
var fsClient = new Client(<your_key>, <your_host>);
|
||||
|
||||
// Search regular objects
|
||||
var objectsIds = await fsClient.SearchObjectAsync(
|
||||
cId,
|
||||
ObjectFilter.RootFilter()
|
||||
);
|
||||
|
||||
// Put object
|
||||
var f = File.OpenRead("cat.jpg");
|
||||
var cat = new ObjectHeader(
|
||||
containerId: cId,
|
||||
type: ObjectType.Regular,
|
||||
new ObjectAttribute("Filename", "cat.jpg")
|
||||
);
|
||||
var oId = await fsClient.PutObjectAsync(cat, f);
|
||||
|
||||
// Get object header
|
||||
var objHeader = await fsClient.GetObjectHeadAsync(cId, oId);
|
||||
|
||||
// Get object
|
||||
var obj = await fsClient.GetObjectAsync(cId, oId);
|
||||
```
|
|
@ -1,22 +0,0 @@
|
|||
using Microsoft.Extensions.Caching.Memory;
|
||||
|
||||
namespace FrostFS.SDK.Client;
|
||||
|
||||
internal static class Caches
|
||||
{
|
||||
private static readonly IMemoryCache _ownersCache = new MemoryCache(new MemoryCacheOptions
|
||||
{
|
||||
// TODO: get from options?
|
||||
SizeLimit = 256
|
||||
});
|
||||
|
||||
private static readonly IMemoryCache _containersCache = new MemoryCache(new MemoryCacheOptions
|
||||
{
|
||||
// TODO: get from options?
|
||||
SizeLimit = 1024
|
||||
});
|
||||
|
||||
internal static IMemoryCache Owners => _ownersCache;
|
||||
|
||||
internal static IMemoryCache Containers => _containersCache;
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
using System.Security.Cryptography;
|
||||
|
||||
using FrostFS.SDK.Cryptography;
|
||||
|
||||
using Google.Protobuf;
|
||||
|
||||
namespace FrostFS.SDK.Client;
|
||||
|
||||
public class ClientKey(ECDsa key)
|
||||
{
|
||||
internal ECDsa ECDsaKey { get; } = key;
|
||||
|
||||
internal ByteString PublicKeyProto { get; } = ByteString.CopyFrom(key.PublicKey());
|
||||
|
||||
internal string PublicKey { get; } = key.PublicKey().ToString();
|
||||
|
||||
internal FrostFsOwner Owner { get; } = new FrostFsOwner(key.PublicKey().PublicKeyToAddress());
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
using System;
|
||||
|
||||
namespace FrostFS.SDK.Client;
|
||||
|
||||
public class FrostFsException : Exception
|
||||
{
|
||||
public FrostFsException()
|
||||
{
|
||||
}
|
||||
|
||||
public FrostFsException(string message) : base(message)
|
||||
{
|
||||
}
|
||||
|
||||
public FrostFsException(string message, Exception innerException) : base(message, innerException)
|
||||
{
|
||||
}
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
using System;
|
||||
|
||||
namespace FrostFS.SDK.Client;
|
||||
|
||||
public class FrostFsInvalidObjectException : FrostFsException
|
||||
{
|
||||
public FrostFsInvalidObjectException()
|
||||
{
|
||||
}
|
||||
|
||||
public FrostFsInvalidObjectException(string message) : base(message)
|
||||
{
|
||||
}
|
||||
|
||||
public FrostFsInvalidObjectException(string message, Exception innerException) : base(message, innerException)
|
||||
{
|
||||
}
|
||||
}
|
|
@ -1,25 +0,0 @@
|
|||
using System;
|
||||
|
||||
namespace FrostFS.SDK.Client;
|
||||
|
||||
public class FrostFsResponseException : FrostFsException
|
||||
{
|
||||
public FrostFsResponseStatus? Status { get; private set; }
|
||||
|
||||
public FrostFsResponseException()
|
||||
{
|
||||
}
|
||||
|
||||
public FrostFsResponseException(FrostFsResponseStatus status)
|
||||
{
|
||||
Status = status;
|
||||
}
|
||||
|
||||
public FrostFsResponseException(string message) : base(message)
|
||||
{
|
||||
}
|
||||
|
||||
public FrostFsResponseException(string message, Exception innerException) : base(message, innerException)
|
||||
{
|
||||
}
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
using System;
|
||||
|
||||
namespace FrostFS.SDK.Client;
|
||||
|
||||
public class FrostFsStreamException : FrostFsException
|
||||
{
|
||||
public FrostFsStreamException()
|
||||
{
|
||||
}
|
||||
|
||||
public FrostFsStreamException(string message) : base(message)
|
||||
{
|
||||
}
|
||||
|
||||
public FrostFsStreamException(string message, Exception innerException) : base(message, innerException)
|
||||
{
|
||||
}
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
using System;
|
||||
|
||||
namespace FrostFS.SDK.Client;
|
||||
|
||||
public class SessionExpiredException : FrostFsException
|
||||
{
|
||||
public SessionExpiredException()
|
||||
{
|
||||
}
|
||||
|
||||
public SessionExpiredException(string message) : base(message)
|
||||
{
|
||||
}
|
||||
|
||||
public SessionExpiredException(string message, Exception innerException) : base(message, innerException)
|
||||
{
|
||||
}
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
using System;
|
||||
|
||||
namespace FrostFS.SDK.Client;
|
||||
|
||||
public class SessionNotFoundException : FrostFsException
|
||||
{
|
||||
public SessionNotFoundException()
|
||||
{
|
||||
}
|
||||
|
||||
public SessionNotFoundException(string message) : base(message)
|
||||
{
|
||||
}
|
||||
|
||||
public SessionNotFoundException(string message, Exception innerException) : base(message, innerException)
|
||||
{
|
||||
}
|
||||
}
|
|
@ -1,62 +0,0 @@
|
|||
using System;
|
||||
|
||||
using Google.Protobuf;
|
||||
|
||||
namespace FrostFS.SDK.Cryptography;
|
||||
|
||||
public static class FrostFsExtensions
|
||||
{
|
||||
public static ByteString Sha256(this IMessage data)
|
||||
{
|
||||
return ByteString.CopyFrom(data.ToByteArray().Sha256());
|
||||
}
|
||||
|
||||
public static Guid ToUuid(this ByteString id)
|
||||
{
|
||||
if (id == null)
|
||||
throw new ArgumentNullException(nameof(id));
|
||||
|
||||
var orderedBytes = GetGuidBytesDirectOrder(id.Span);
|
||||
|
||||
return new Guid(orderedBytes);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Serializes Guid to binary representation in direct order bytes format
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <returns></returns>
|
||||
public static byte[] ToBytes(this Guid id)
|
||||
{
|
||||
var bytes = id.ToByteArray();
|
||||
|
||||
var orderedBytes = GetGuidBytesDirectOrder(bytes);
|
||||
|
||||
return orderedBytes;
|
||||
}
|
||||
|
||||
private static byte[] GetGuidBytesDirectOrder(ReadOnlySpan<byte> source)
|
||||
{
|
||||
if (source.Length != 16)
|
||||
throw new ArgumentException("Wrong uuid binary format");
|
||||
|
||||
return [
|
||||
source[3],
|
||||
source[2],
|
||||
source[1],
|
||||
source[0],
|
||||
source[5],
|
||||
source[4],
|
||||
source[7],
|
||||
source[6],
|
||||
source[8],
|
||||
source[9],
|
||||
source[10],
|
||||
source[11],
|
||||
source[12],
|
||||
source[13],
|
||||
source[14],
|
||||
source[15]
|
||||
];
|
||||
}
|
||||
}
|
|
@ -1,44 +0,0 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
<LangVersion>12.0</LangVersion>
|
||||
<Nullable>enable</Nullable>
|
||||
<AnalysisMode>AllEnabledByDefault</AnalysisMode>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<EnableNETAnalyzers>true</EnableNETAnalyzers>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<CodeAnalysisTreatWarningsAsErrors>true</CodeAnalysisTreatWarningsAsErrors>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<_SkipUpgradeNetAnalyzersNuGetWarning>true</_SkipUpgradeNetAnalyzersNuGetWarning>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="7.0.0" />
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.NetAnalyzers" Version="7.0.4">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.Extensions.Caching.Abstractions" Version="7.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="7.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Options" Version="7.0.1" />
|
||||
<PackageReference Include="System.Diagnostics.DiagnosticSource" Version="7.0.0" />
|
||||
<PackageReference Include="System.Runtime.Caching" Version="7.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\FrostFS.SDK.Cryptography\FrostFS.SDK.Cryptography.csproj" />
|
||||
<ProjectReference Include="..\FrostFS.SDK.Protos\FrostFS.SDK.Protos.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
|
@ -1,473 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Frostfs.V2.Ape;
|
||||
|
||||
using FrostFS.SDK.Client.Interfaces;
|
||||
using FrostFS.SDK.Client.Services;
|
||||
using FrostFS.SDK.Cryptography;
|
||||
using FrostFS.Session;
|
||||
|
||||
using Grpc.Core;
|
||||
using Grpc.Core.Interceptors;
|
||||
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
using static Frostfs.V2.Apemanager.APEManagerService;
|
||||
using static FrostFS.Accounting.AccountingService;
|
||||
using static FrostFS.Container.ContainerService;
|
||||
using static FrostFS.Netmap.NetmapService;
|
||||
using static FrostFS.Object.ObjectService;
|
||||
using static FrostFS.Session.SessionService;
|
||||
|
||||
namespace FrostFS.SDK.Client;
|
||||
|
||||
public class FrostFSClient : IFrostFSClient
|
||||
{
|
||||
internal ContainerServiceClient? ContainerServiceClient { get; set; }
|
||||
internal ContainerServiceProvider? ContainerServiceProvider { get; set; }
|
||||
|
||||
internal NetmapServiceClient? NetmapServiceClient { get; set; }
|
||||
internal NetmapServiceProvider? NetmapServiceProvider { get; set; }
|
||||
|
||||
internal APEManagerServiceClient? ApeManagerServiceClient { get; set; }
|
||||
internal ApeManagerServiceProvider? ApeManagerServiceProvider { get; set; }
|
||||
|
||||
internal SessionServiceClient? SessionServiceClient { get; set; }
|
||||
internal SessionServiceProvider? SessionServiceProvider { get; set; }
|
||||
|
||||
internal ObjectServiceClient? ObjectServiceClient { get; set; }
|
||||
internal ObjectServiceProvider? ObjectServiceProvider { get; set; }
|
||||
|
||||
internal AccountingServiceClient? AccountingServiceClient { get; set; }
|
||||
internal AccountingServiceProvider? AccountingServiceProvider { get; set; }
|
||||
|
||||
internal ClientContext ClientCtx { get; set; }
|
||||
|
||||
public static IFrostFSClient GetInstance(IOptions<ClientSettings> clientOptions, Func<string, ChannelBase> grpcChannelFactory)
|
||||
{
|
||||
if (clientOptions is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(clientOptions));
|
||||
}
|
||||
|
||||
if (grpcChannelFactory is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(grpcChannelFactory));
|
||||
}
|
||||
|
||||
return new FrostFSClient(clientOptions, grpcChannelFactory);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// For test only. Provide custom implementation or mock object to inject required logic instead of internal gRPC client.
|
||||
/// </summary>
|
||||
/// <param name="clientOptions">Global setting for client</param>
|
||||
/// <param name="channelOptions">Setting for gRPC channel</param>
|
||||
/// <param name="containerService">ContainerService.ContainerServiceClient implementation</param>
|
||||
/// <param name="netmapService">Netmap.NetmapService.NetmapServiceClient implementation</param>
|
||||
/// <param name="sessionService">Session.SessionService.SessionServiceClient implementation</param>
|
||||
/// <param name="objectService">Object.ObjectService.ObjectServiceClient implementation</param>
|
||||
/// <returns></returns>
|
||||
public static IFrostFSClient GetTestInstance(
|
||||
IOptions<ClientSettings> settings,
|
||||
Func<string, ChannelBase> grpcChannelFactory,
|
||||
NetmapServiceClient netmapService,
|
||||
SessionServiceClient sessionService,
|
||||
ContainerServiceClient containerService,
|
||||
ObjectServiceClient objectService)
|
||||
{
|
||||
if (settings is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(settings));
|
||||
}
|
||||
|
||||
if (grpcChannelFactory is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(grpcChannelFactory));
|
||||
}
|
||||
|
||||
if (netmapService is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(netmapService));
|
||||
}
|
||||
|
||||
if (sessionService is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(sessionService));
|
||||
}
|
||||
|
||||
if (containerService is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(containerService));
|
||||
}
|
||||
|
||||
if (objectService is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(objectService));
|
||||
}
|
||||
|
||||
return new FrostFSClient(
|
||||
settings, channel: grpcChannelFactory(settings.Value.Host), containerService, netmapService, sessionService, objectService);
|
||||
}
|
||||
|
||||
private FrostFSClient(
|
||||
IOptions<ClientSettings> settings,
|
||||
ChannelBase channel,
|
||||
ContainerServiceClient containerService,
|
||||
NetmapServiceClient netmapService,
|
||||
SessionServiceClient sessionService,
|
||||
ObjectServiceClient objectService)
|
||||
{
|
||||
if (settings is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(settings));
|
||||
}
|
||||
|
||||
var ecdsaKey = settings.Value.Key.LoadWif();
|
||||
|
||||
ClientCtx = new ClientContext(
|
||||
client: this,
|
||||
key: new ClientKey(ecdsaKey),
|
||||
owner: FrostFsOwner.FromKey(ecdsaKey),
|
||||
channel: channel,
|
||||
version: new FrostFsVersion(2, 13))
|
||||
{
|
||||
SessionCache = new SessionCache(0),
|
||||
Callback = settings.Value.Callback,
|
||||
Interceptors = settings.Value.Interceptors
|
||||
};
|
||||
|
||||
ContainerServiceClient = containerService ?? throw new ArgumentNullException(nameof(containerService));
|
||||
NetmapServiceClient = netmapService ?? throw new ArgumentNullException(nameof(netmapService));
|
||||
SessionServiceClient = sessionService ?? throw new ArgumentNullException(nameof(sessionService));
|
||||
ObjectServiceClient = objectService ?? throw new ArgumentNullException(nameof(objectService));
|
||||
}
|
||||
|
||||
private FrostFSClient(IOptions<ClientSettings> settings, Func<string, ChannelBase> grpcChannelFactory)
|
||||
{
|
||||
var clientSettings = (settings?.Value) ?? throw new ArgumentNullException(nameof(settings), "Options value must be initialized");
|
||||
|
||||
clientSettings.Validate();
|
||||
|
||||
var ecdsaKey = clientSettings.Key.LoadWif();
|
||||
|
||||
ClientCtx = new ClientContext(
|
||||
this,
|
||||
key: new ClientKey(ecdsaKey),
|
||||
owner: FrostFsOwner.FromKey(ecdsaKey),
|
||||
channel: grpcChannelFactory(settings.Value.Host),
|
||||
version: new FrostFsVersion(2, 13))
|
||||
{
|
||||
SessionCache = new SessionCache(0),
|
||||
Callback = settings.Value.Callback,
|
||||
Interceptors = settings.Value.Interceptors
|
||||
};
|
||||
|
||||
// TODO: define timeout logic
|
||||
// CheckFrostFsVersionSupport(new Context { Timeout = TimeSpan.FromSeconds(20) });
|
||||
}
|
||||
|
||||
internal FrostFSClient(WrapperPrm prm, SessionCache cache)
|
||||
{
|
||||
ClientCtx = new ClientContext(
|
||||
client: this,
|
||||
key: new ClientKey(prm.Key),
|
||||
owner: FrostFsOwner.FromKey(prm.Key!),
|
||||
channel: prm.GrpcChannelFactory(prm.Address),
|
||||
version: new FrostFsVersion(2, 13))
|
||||
{
|
||||
SessionCache = cache,
|
||||
Interceptors = prm.Interceptors,
|
||||
Callback = prm.Callback
|
||||
};
|
||||
}
|
||||
|
||||
#region ApeManagerImplementation
|
||||
public Task<ReadOnlyMemory<byte>> AddChainAsync(PrmApeChainAdd args, CallContext ctx)
|
||||
{
|
||||
return GetApeManagerService().AddChainAsync(args, ctx);
|
||||
}
|
||||
|
||||
public Task RemoveChainAsync(PrmApeChainRemove args, CallContext ctx)
|
||||
{
|
||||
return GetApeManagerService().RemoveChainAsync(args, ctx);
|
||||
}
|
||||
|
||||
public Task<Chain[]> ListChainAsync(PrmApeChainList args, CallContext ctx)
|
||||
{
|
||||
return GetApeManagerService().ListChainAsync(args, ctx);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region ContainerImplementation
|
||||
public Task<FrostFsContainerInfo> GetContainerAsync(PrmContainerGet args, CallContext ctx)
|
||||
{
|
||||
return GetContainerService().GetContainerAsync(args, ctx);
|
||||
}
|
||||
|
||||
public IAsyncEnumerable<FrostFsContainerId> ListContainersAsync(PrmContainerGetAll args, CallContext ctx)
|
||||
{
|
||||
return GetContainerService().ListContainersAsync(args, ctx);
|
||||
}
|
||||
|
||||
public Task<FrostFsContainerId> CreateContainerAsync(PrmContainerCreate args, CallContext ctx)
|
||||
{
|
||||
return GetContainerService().CreateContainerAsync(args, ctx);
|
||||
}
|
||||
|
||||
public Task DeleteContainerAsync(PrmContainerDelete args, CallContext ctx)
|
||||
{
|
||||
return GetContainerService().DeleteContainerAsync(args, ctx);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region NetworkImplementation
|
||||
public Task<FrostFsNetmapSnapshot> GetNetmapSnapshotAsync(CallContext ctx)
|
||||
{
|
||||
return GetNetmapService().GetNetmapSnapshotAsync(ctx);
|
||||
}
|
||||
|
||||
public Task<FrostFsNodeInfo> GetNodeInfoAsync(CallContext ctx)
|
||||
{
|
||||
return GetNetmapService().GetLocalNodeInfoAsync(ctx);
|
||||
}
|
||||
|
||||
public Task<NetworkSettings> GetNetworkSettingsAsync(CallContext ctx)
|
||||
{
|
||||
return GetNetmapService().GetNetworkSettingsAsync(ctx);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region ObjectImplementation
|
||||
public Task<FrostFsHeaderResult> GetObjectHeadAsync(PrmObjectHeadGet args, CallContext ctx)
|
||||
{
|
||||
return GetObjectService().GetObjectHeadAsync(args, ctx);
|
||||
}
|
||||
|
||||
public Task<FrostFsObject> GetObjectAsync(PrmObjectGet args, CallContext ctx)
|
||||
{
|
||||
return GetObjectService().GetObjectAsync(args, ctx);
|
||||
}
|
||||
|
||||
public Task<RangeReader> GetRangeAsync(PrmRangeGet args, CallContext ctx)
|
||||
{
|
||||
return GetObjectService().GetRangeAsync(args, ctx);
|
||||
}
|
||||
|
||||
public Task<ReadOnlyMemory<byte>[]> GetRangeHashAsync(PrmRangeHashGet args, CallContext ctx)
|
||||
{
|
||||
return GetObjectService().GetRangeHashAsync(args, ctx);
|
||||
}
|
||||
|
||||
public Task<IObjectWriter> PutObjectAsync(PrmObjectPut args, CallContext ctx)
|
||||
{
|
||||
return GetObjectService().PutStreamObjectAsync(args, ctx);
|
||||
}
|
||||
|
||||
public Task<FrostFsObjectId> PutClientCutObjectAsync(PrmObjectClientCutPut args, CallContext ctx)
|
||||
{
|
||||
return GetObjectService().PutClientCutObjectAsync(args, ctx);
|
||||
}
|
||||
|
||||
public Task<FrostFsObjectId> PutSingleObjectAsync(PrmSingleObjectPut args, CallContext ctx)
|
||||
{
|
||||
return GetObjectService().PutSingleObjectAsync(args, ctx);
|
||||
}
|
||||
|
||||
public Task<FrostFsObjectId> PatchObjectAsync(PrmObjectPatch args, CallContext ctx)
|
||||
{
|
||||
return GetObjectService().PatchObjectAsync(args, ctx);
|
||||
}
|
||||
|
||||
public Task DeleteObjectAsync(PrmObjectDelete args, CallContext ctx)
|
||||
{
|
||||
return GetObjectService().DeleteObjectAsync(args, ctx);
|
||||
}
|
||||
|
||||
public IAsyncEnumerable<FrostFsObjectId> SearchObjectsAsync(PrmObjectSearch args, CallContext ctx)
|
||||
{
|
||||
return GetObjectService().SearchObjectsAsync(args, ctx);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Session Implementation
|
||||
public async Task<FrostFsSessionToken> CreateSessionAsync(PrmSessionCreate args, CallContext ctx)
|
||||
{
|
||||
var token = await CreateSessionInternalAsync(args, ctx).ConfigureAwait(false);
|
||||
|
||||
return new FrostFsSessionToken(token);
|
||||
}
|
||||
|
||||
internal Task<SessionToken> CreateSessionInternalAsync(PrmSessionCreate args, CallContext ctx)
|
||||
{
|
||||
var service = GetSessionService();
|
||||
return service.CreateSessionAsync(args, ctx);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Accounting Implementation
|
||||
public async Task<Accounting.Decimal> GetBalanceAsync(CallContext ctx)
|
||||
{
|
||||
return await GetAccouningService().GetBallance(ctx).ConfigureAwait(false);
|
||||
}
|
||||
#endregion
|
||||
|
||||
private async void CheckFrostFsVersionSupport(CallContext ctx)
|
||||
{
|
||||
var service = GetNetmapService();
|
||||
var localNodeInfo = await service.GetLocalNodeInfoAsync(ctx).ConfigureAwait(false);
|
||||
|
||||
if (!localNodeInfo.Version.IsSupported(ClientCtx.Version))
|
||||
{
|
||||
var msg = $"FrostFS {localNodeInfo.Version} is not supported.";
|
||||
throw new FrostFsException(msg);
|
||||
}
|
||||
}
|
||||
|
||||
private CallInvoker? CreateInvoker()
|
||||
{
|
||||
CallInvoker? callInvoker = null;
|
||||
|
||||
if (ClientCtx.Interceptors != null)
|
||||
{
|
||||
foreach (var interceptor in ClientCtx.Interceptors)
|
||||
callInvoker = AddInvoker(callInvoker, interceptor);
|
||||
}
|
||||
|
||||
if (ClientCtx.Callback != null)
|
||||
callInvoker = AddInvoker(callInvoker, new MetricsInterceptor(ClientCtx.Callback));
|
||||
|
||||
if (ClientCtx.PoolErrorHandler != null)
|
||||
callInvoker = AddInvoker(callInvoker, new ErrorInterceptor(ClientCtx.PoolErrorHandler));
|
||||
|
||||
return callInvoker;
|
||||
|
||||
CallInvoker AddInvoker(CallInvoker? callInvoker, Interceptor interceptor)
|
||||
{
|
||||
if (callInvoker == null)
|
||||
callInvoker = ClientCtx.Channel.Intercept(interceptor);
|
||||
else
|
||||
callInvoker = callInvoker.Intercept(interceptor);
|
||||
|
||||
return callInvoker;
|
||||
}
|
||||
}
|
||||
|
||||
private NetmapServiceProvider GetNetmapService()
|
||||
{
|
||||
if (NetmapServiceProvider == null)
|
||||
{
|
||||
var invoker = CreateInvoker();
|
||||
|
||||
NetmapServiceClient = NetmapServiceClient ?? (
|
||||
invoker != null
|
||||
? new NetmapServiceClient(invoker)
|
||||
: new NetmapServiceClient(ClientCtx.Channel));
|
||||
|
||||
NetmapServiceProvider = new NetmapServiceProvider(NetmapServiceClient, ClientCtx);
|
||||
}
|
||||
|
||||
return NetmapServiceProvider;
|
||||
}
|
||||
|
||||
private SessionServiceProvider GetSessionService()
|
||||
{
|
||||
if (SessionServiceProvider == null)
|
||||
{
|
||||
var invoker = CreateInvoker();
|
||||
|
||||
SessionServiceClient = SessionServiceClient ?? (
|
||||
invoker != null
|
||||
? new SessionServiceClient(invoker)
|
||||
: new SessionServiceClient(ClientCtx.Channel));
|
||||
|
||||
SessionServiceProvider = new SessionServiceProvider(SessionServiceClient, ClientCtx);
|
||||
}
|
||||
|
||||
return SessionServiceProvider;
|
||||
|
||||
}
|
||||
|
||||
private ApeManagerServiceProvider GetApeManagerService()
|
||||
{
|
||||
if (ApeManagerServiceProvider == null)
|
||||
{
|
||||
var invoker = CreateInvoker();
|
||||
|
||||
ApeManagerServiceClient = ApeManagerServiceClient ?? (
|
||||
invoker != null
|
||||
? new APEManagerServiceClient(invoker)
|
||||
: new APEManagerServiceClient(ClientCtx.Channel));
|
||||
|
||||
ApeManagerServiceProvider = new ApeManagerServiceProvider(ApeManagerServiceClient, ClientCtx);
|
||||
}
|
||||
|
||||
return ApeManagerServiceProvider;
|
||||
}
|
||||
|
||||
private AccountingServiceProvider GetAccouningService()
|
||||
{
|
||||
if (this.AccountingServiceProvider == null)
|
||||
{
|
||||
var invoker = CreateInvoker();
|
||||
|
||||
AccountingServiceClient = AccountingServiceClient ?? (
|
||||
invoker != null
|
||||
? new AccountingServiceClient(invoker)
|
||||
: new AccountingServiceClient(ClientCtx.Channel));
|
||||
|
||||
AccountingServiceProvider = new AccountingServiceProvider(AccountingServiceClient, ClientCtx);
|
||||
}
|
||||
|
||||
return AccountingServiceProvider;
|
||||
}
|
||||
|
||||
private ContainerServiceProvider GetContainerService()
|
||||
{
|
||||
if (this.ContainerServiceProvider == null)
|
||||
{
|
||||
var invoker = CreateInvoker();
|
||||
|
||||
ContainerServiceClient = ContainerServiceClient ?? (
|
||||
invoker != null
|
||||
? new ContainerServiceClient(invoker)
|
||||
: new ContainerServiceClient(ClientCtx.Channel));
|
||||
|
||||
ContainerServiceProvider = new ContainerServiceProvider(ContainerServiceClient, ClientCtx);
|
||||
}
|
||||
|
||||
return ContainerServiceProvider;
|
||||
}
|
||||
|
||||
private ObjectServiceProvider GetObjectService()
|
||||
{
|
||||
if (this.ObjectServiceProvider == null)
|
||||
{
|
||||
var invoker = CreateInvoker();
|
||||
|
||||
ObjectServiceClient = ObjectServiceClient ?? (
|
||||
invoker != null
|
||||
? new ObjectServiceClient(invoker)
|
||||
: new ObjectServiceClient(ClientCtx.Channel));
|
||||
|
||||
ObjectServiceProvider = new ObjectServiceProvider(ObjectServiceClient, ClientCtx);
|
||||
}
|
||||
|
||||
return ObjectServiceProvider;
|
||||
}
|
||||
|
||||
public async Task<string?> Dial(CallContext ctx)
|
||||
{
|
||||
var service = GetAccouningService();
|
||||
_ = await service.GetBallance(ctx).ConfigureAwait(false);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public bool RestartIfUnhealthy(CallContext ctx)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
// This file is used by Code Analysis to maintain SuppressMessage
|
||||
// attributes that are applied to this project.
|
||||
// Project-level suppressions either have no target or are given
|
||||
// a specific target and scoped to a namespace, type, member, etc.
|
||||
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
[assembly: SuppressMessage("Security", "CA5394:Do not use insecure randomness", Justification = "<Pending>", Scope = "member", Target = "~M:FrostFS.SDK.Client.Sampler.Next~System.Int32")]
|
|
@ -1,68 +0,0 @@
|
|||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Grpc.Core;
|
||||
using Grpc.Core.Interceptors;
|
||||
|
||||
namespace FrostFS.SDK.Client;
|
||||
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1062:Validate arguments of public methods",
|
||||
Justification = "parameters are provided by GRPC infrastructure")]
|
||||
public class ErrorInterceptor(Action<Exception> handler) : Interceptor
|
||||
{
|
||||
public override AsyncUnaryCall<TResponse> AsyncUnaryCall<TRequest, TResponse>(
|
||||
TRequest request,
|
||||
ClientInterceptorContext<TRequest, TResponse> context,
|
||||
AsyncUnaryCallContinuation<TRequest, TResponse> continuation)
|
||||
{
|
||||
var call = continuation(request, context);
|
||||
|
||||
return new AsyncUnaryCall<TResponse>(
|
||||
HandleUnaryResponse(call),
|
||||
call.ResponseHeadersAsync,
|
||||
call.GetStatus,
|
||||
call.GetTrailers,
|
||||
call.Dispose);
|
||||
}
|
||||
|
||||
public override AsyncClientStreamingCall<TRequest, TResponse> AsyncClientStreamingCall<TRequest, TResponse>(
|
||||
ClientInterceptorContext<TRequest, TResponse> context,
|
||||
AsyncClientStreamingCallContinuation<TRequest, TResponse> continuation)
|
||||
{
|
||||
var call = continuation(context);
|
||||
|
||||
return new AsyncClientStreamingCall<TRequest, TResponse>(
|
||||
call.RequestStream,
|
||||
HandleStreamResponse(call),
|
||||
call.ResponseHeadersAsync,
|
||||
call.GetStatus,
|
||||
call.GetTrailers,
|
||||
call.Dispose);
|
||||
}
|
||||
|
||||
private async Task<TResponse> HandleUnaryResponse<TResponse>(AsyncUnaryCall<TResponse> call)
|
||||
{
|
||||
try
|
||||
{
|
||||
return await call;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
handler(ex);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<TResponse> HandleStreamResponse<TRequest, TResponse>(AsyncClientStreamingCall<TRequest, TResponse> call)
|
||||
{
|
||||
try
|
||||
{
|
||||
return await call;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
handler(ex);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,75 +0,0 @@
|
|||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Grpc.Core;
|
||||
using Grpc.Core.Interceptors;
|
||||
|
||||
namespace FrostFS.SDK.Client;
|
||||
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1062:Validate arguments of public methods",
|
||||
Justification = "parameters are provided by GRPC infrastructure")]
|
||||
public class MetricsInterceptor(Action<CallStatistics> callback) : Interceptor
|
||||
{
|
||||
public override AsyncUnaryCall<TResponse> AsyncUnaryCall<TRequest, TResponse>(
|
||||
TRequest request,
|
||||
ClientInterceptorContext<TRequest, TResponse> context,
|
||||
AsyncUnaryCallContinuation<TRequest, TResponse> continuation)
|
||||
{
|
||||
var call = continuation(request, context);
|
||||
|
||||
return new AsyncUnaryCall<TResponse>(
|
||||
HandleUnaryResponse(call),
|
||||
call.ResponseHeadersAsync,
|
||||
call.GetStatus,
|
||||
call.GetTrailers,
|
||||
call.Dispose);
|
||||
}
|
||||
|
||||
public override AsyncClientStreamingCall<TRequest, TResponse> AsyncClientStreamingCall<TRequest, TResponse>(
|
||||
ClientInterceptorContext<TRequest, TResponse> context,
|
||||
AsyncClientStreamingCallContinuation<TRequest, TResponse> continuation)
|
||||
{
|
||||
var call = continuation(context);
|
||||
|
||||
return new AsyncClientStreamingCall<TRequest, TResponse>(
|
||||
call.RequestStream,
|
||||
HandleStreamResponse(call),
|
||||
call.ResponseHeadersAsync,
|
||||
call.GetStatus,
|
||||
call.GetTrailers,
|
||||
call.Dispose);
|
||||
}
|
||||
|
||||
private async Task<TResponse> HandleUnaryResponse<TResponse>(AsyncUnaryCall<TResponse> call)
|
||||
{
|
||||
var watch = new Stopwatch();
|
||||
watch.Start();
|
||||
|
||||
var response = await call;
|
||||
|
||||
watch.Stop();
|
||||
|
||||
var elapsed = watch.ElapsedTicks * 1_000_000 / Stopwatch.Frequency;
|
||||
|
||||
callback(new CallStatistics { MethodName = call.ToString(), ElapsedMicroSeconds = elapsed });
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
private async Task<TResponse> HandleStreamResponse<TRequest, TResponse>(AsyncClientStreamingCall<TRequest, TResponse> call)
|
||||
{
|
||||
var watch = new Stopwatch();
|
||||
watch.Start();
|
||||
|
||||
var response = await call;
|
||||
|
||||
watch.Stop();
|
||||
|
||||
var elapsed = watch.ElapsedTicks * 1_000_000 / Stopwatch.Frequency;
|
||||
|
||||
callback(new CallStatistics { MethodName = call.ToString(), ElapsedMicroSeconds = elapsed });
|
||||
|
||||
return response;
|
||||
}
|
||||
}
|
|
@ -1,68 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Frostfs.V2.Ape;
|
||||
|
||||
namespace FrostFS.SDK.Client.Interfaces;
|
||||
|
||||
public interface IFrostFSClient
|
||||
{
|
||||
#region Network
|
||||
Task<FrostFsNetmapSnapshot> GetNetmapSnapshotAsync(CallContext ctx);
|
||||
|
||||
Task<FrostFsNodeInfo> GetNodeInfoAsync(CallContext ctx);
|
||||
|
||||
Task<NetworkSettings> GetNetworkSettingsAsync(CallContext ctx);
|
||||
#endregion
|
||||
|
||||
#region Session
|
||||
Task<FrostFsSessionToken> CreateSessionAsync(PrmSessionCreate args, CallContext ctx);
|
||||
#endregion
|
||||
|
||||
#region ApeManager
|
||||
Task<ReadOnlyMemory<byte>> AddChainAsync(PrmApeChainAdd args, CallContext ctx);
|
||||
|
||||
Task RemoveChainAsync(PrmApeChainRemove args, CallContext ctx);
|
||||
|
||||
Task<Chain[]> ListChainAsync(PrmApeChainList args, CallContext ctx);
|
||||
#endregion
|
||||
|
||||
#region Container
|
||||
Task<FrostFsContainerInfo> GetContainerAsync(PrmContainerGet args, CallContext ctx);
|
||||
|
||||
IAsyncEnumerable<FrostFsContainerId> ListContainersAsync(PrmContainerGetAll args, CallContext ctx);
|
||||
|
||||
Task<FrostFsContainerId> CreateContainerAsync(PrmContainerCreate args, CallContext ctx);
|
||||
|
||||
Task DeleteContainerAsync(PrmContainerDelete args, CallContext ctx);
|
||||
#endregion
|
||||
|
||||
#region Object
|
||||
Task<FrostFsHeaderResult> GetObjectHeadAsync(PrmObjectHeadGet args, CallContext ctx);
|
||||
|
||||
Task<FrostFsObject> GetObjectAsync(PrmObjectGet args, CallContext ctx);
|
||||
|
||||
Task<RangeReader> GetRangeAsync(PrmRangeGet args, CallContext ctx);
|
||||
|
||||
Task<ReadOnlyMemory<byte>[]> GetRangeHashAsync(PrmRangeHashGet args, CallContext ctx);
|
||||
|
||||
Task<IObjectWriter> PutObjectAsync(PrmObjectPut args, CallContext ctx);
|
||||
|
||||
Task<FrostFsObjectId> PutClientCutObjectAsync(PrmObjectClientCutPut args, CallContext ctx);
|
||||
|
||||
Task<FrostFsObjectId> PutSingleObjectAsync(PrmSingleObjectPut args, CallContext ctx);
|
||||
|
||||
Task<FrostFsObjectId> PatchObjectAsync(PrmObjectPatch args, CallContext ctx);
|
||||
|
||||
Task DeleteObjectAsync(PrmObjectDelete args, CallContext ctx);
|
||||
|
||||
IAsyncEnumerable<FrostFsObjectId> SearchObjectsAsync(PrmObjectSearch args, CallContext ctx);
|
||||
#endregion
|
||||
|
||||
#region Account
|
||||
Task<Accounting.Decimal> GetBalanceAsync(CallContext ctx);
|
||||
#endregion
|
||||
|
||||
public Task<string?> Dial(CallContext ctx);
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace FrostFS.SDK.Client.Interfaces
|
||||
{
|
||||
public interface IObjectWriter : IDisposable
|
||||
{
|
||||
Task WriteAsync(ReadOnlyMemory<byte> memory);
|
||||
|
||||
Task<FrostFsObjectId> CompleteAsync();
|
||||
}
|
||||
}
|
|
@ -1,24 +0,0 @@
|
|||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace FrostFS.SDK.Client;
|
||||
|
||||
internal static partial class FrostFsMessages
|
||||
{
|
||||
[LoggerMessage(100,
|
||||
LogLevel.Warning,
|
||||
"Failed to create frostfs session token for client. Address {address}, {error}",
|
||||
EventName = nameof(SessionCreationError))]
|
||||
internal static partial void SessionCreationError(ILogger logger, string address, string error);
|
||||
|
||||
[LoggerMessage(101,
|
||||
LogLevel.Warning,
|
||||
"Error threshold reached. Address {address}, threshold {threshold}",
|
||||
EventName = nameof(ErrorЕhresholdReached))]
|
||||
internal static partial void ErrorЕhresholdReached(ILogger logger, string address, uint threshold);
|
||||
|
||||
[LoggerMessage(102,
|
||||
LogLevel.Warning,
|
||||
"Health has changed: {address} healthy {healthy}, reason {error}",
|
||||
EventName = nameof(HealthChanged))]
|
||||
internal static partial void HealthChanged(ILogger logger, string address, bool healthy, string error);
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
|
||||
using FrostFS.SDK.Cryptography;
|
||||
|
||||
namespace FrostFS.SDK.Client.Mappers.GRPC;
|
||||
|
||||
public static class ContainerMapper
|
||||
{
|
||||
public static FrostFsContainerInfo ToModel(this Container.Container container)
|
||||
{
|
||||
if (container == null)
|
||||
throw new ArgumentNullException(nameof(container));
|
||||
|
||||
return new FrostFsContainerInfo(
|
||||
container.PlacementPolicy.ToModel(),
|
||||
container.Attributes?.Select(a => new FrostFsAttributePair(a.Key, a.Value)).ToArray(),
|
||||
container.Version?.ToModel(),
|
||||
container.OwnerId?.ToModel(),
|
||||
container.Nonce?.ToUuid());
|
||||
}
|
||||
}
|
|
@ -1,48 +0,0 @@
|
|||
using System;
|
||||
|
||||
using FrostFS.Refs;
|
||||
using FrostFS.SDK.Cryptography;
|
||||
|
||||
using Google.Protobuf;
|
||||
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
|
||||
namespace FrostFS.SDK.Client.Mappers.GRPC;
|
||||
|
||||
public static class ContainerIdMapper
|
||||
{
|
||||
private static readonly MemoryCacheEntryOptions _oneHourExpiration = new MemoryCacheEntryOptions()
|
||||
.SetSlidingExpiration(TimeSpan.FromHours(1))
|
||||
.SetSize(1);
|
||||
|
||||
public static ContainerID ToMessage(this FrostFsContainerId model)
|
||||
{
|
||||
if (model is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(model));
|
||||
}
|
||||
|
||||
var containerId = model.GetValue() ?? throw new ArgumentNullException(nameof(model));
|
||||
|
||||
if (!Caches.Containers.TryGetValue(containerId, out ContainerID? message))
|
||||
{
|
||||
message = new ContainerID
|
||||
{
|
||||
Value = ByteString.CopyFrom(Base58.Decode(containerId))
|
||||
};
|
||||
|
||||
Caches.Containers.Set(containerId, message, _oneHourExpiration);
|
||||
}
|
||||
return message!;
|
||||
}
|
||||
|
||||
public static FrostFsContainerId ToModel(this ContainerID message)
|
||||
{
|
||||
if (message is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(message));
|
||||
}
|
||||
|
||||
return new FrostFsContainerId(Base58.Encode(message.Value.Span));
|
||||
}
|
||||
}
|
|
@ -1,23 +0,0 @@
|
|||
using System;
|
||||
|
||||
using FrostFS.Session;
|
||||
|
||||
namespace FrostFS.SDK.Client.Mappers.GRPC;
|
||||
|
||||
public static class MetaHeaderMapper
|
||||
{
|
||||
public static RequestMetaHeader ToMessage(this MetaHeader metaHeader)
|
||||
{
|
||||
if (metaHeader is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(metaHeader));
|
||||
}
|
||||
|
||||
return new RequestMetaHeader
|
||||
{
|
||||
Version = metaHeader.Version.ToMessage(),
|
||||
Epoch = (uint)metaHeader.Epoch,
|
||||
Ttl = (uint)metaHeader.Ttl
|
||||
};
|
||||
}
|
||||
}
|
|
@ -1,23 +0,0 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
|
||||
using FrostFS.Netmap;
|
||||
|
||||
namespace FrostFS.SDK.Client;
|
||||
|
||||
public static class NetmapMapper
|
||||
{
|
||||
public static FrostFsNetmapSnapshot ToModel(this NetmapSnapshotResponse netmap)
|
||||
{
|
||||
if (netmap is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(netmap));
|
||||
}
|
||||
|
||||
return new FrostFsNetmapSnapshot(
|
||||
netmap.Body.Netmap.Epoch,
|
||||
netmap.Body.Netmap.Nodes
|
||||
.Select(n => n.ToModel(netmap.MetaHeader.Version))
|
||||
.ToArray());
|
||||
}
|
||||
}
|
|
@ -1,45 +0,0 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
|
||||
using FrostFS.Netmap;
|
||||
using FrostFS.SDK.Client.Mappers.GRPC;
|
||||
|
||||
namespace FrostFS.SDK.Client;
|
||||
|
||||
public static class NodeInfoMapper
|
||||
{
|
||||
public static FrostFsNodeInfo ToModel(this LocalNodeInfoResponse.Types.Body node)
|
||||
{
|
||||
if (node is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(node));
|
||||
}
|
||||
|
||||
return node.NodeInfo.ToModel(node.Version);
|
||||
}
|
||||
|
||||
public static FrostFsNodeInfo ToModel(this NodeInfo nodeInfo, Refs.Version version)
|
||||
{
|
||||
if (nodeInfo is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(nodeInfo));
|
||||
}
|
||||
|
||||
NodeState state = nodeInfo.State switch
|
||||
{
|
||||
NodeInfo.Types.State.Unspecified => NodeState.Unspecified,
|
||||
NodeInfo.Types.State.Online => NodeState.Online,
|
||||
NodeInfo.Types.State.Offline => NodeState.Offline,
|
||||
NodeInfo.Types.State.Maintenance => NodeState.Maintenance,
|
||||
_ => throw new ArgumentException($"Unknown NodeState. Value: '{nodeInfo.State}'.")
|
||||
};
|
||||
|
||||
return new FrostFsNodeInfo(
|
||||
version: version.ToModel(),
|
||||
state: state,
|
||||
addresses: [.. nodeInfo.Addresses],
|
||||
attributes: nodeInfo.Attributes.ToDictionary(n => n.Key, n => n.Value),
|
||||
publicKey: nodeInfo.PublicKey.Memory
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
|
||||
using FrostFS.Netmap;
|
||||
|
||||
namespace FrostFS.SDK.Client;
|
||||
|
||||
public static class PlacementPolicyMapper
|
||||
{
|
||||
public static FrostFsPlacementPolicy ToModel(this PlacementPolicy placementPolicy)
|
||||
{
|
||||
if (placementPolicy is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(placementPolicy));
|
||||
}
|
||||
|
||||
return new FrostFsPlacementPolicy(
|
||||
placementPolicy.Unique,
|
||||
placementPolicy.Replicas.Select(replica => replica.ToModel()).ToArray()
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,27 +0,0 @@
|
|||
using System;
|
||||
|
||||
using FrostFS.Netmap;
|
||||
|
||||
namespace FrostFS.SDK.Client;
|
||||
|
||||
public static class ReplicaMapper
|
||||
{
|
||||
public static Replica ToMessage(this FrostFsReplica replica)
|
||||
{
|
||||
return new Replica
|
||||
{
|
||||
Count = (uint)replica.Count,
|
||||
Selector = replica.Selector
|
||||
};
|
||||
}
|
||||
|
||||
public static FrostFsReplica ToModel(this Replica replica)
|
||||
{
|
||||
if (replica is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(replica));
|
||||
}
|
||||
|
||||
return new FrostFsReplica((int)replica.Count, replica.Selector);
|
||||
}
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
namespace FrostFS.SDK.Client.Mappers.GRPC;
|
||||
|
||||
internal static class ObjectMapper
|
||||
{
|
||||
internal static FrostFsObject ToModel(this Object.Object obj)
|
||||
{
|
||||
return new FrostFsObject(obj.Header.ToModel())
|
||||
{
|
||||
ObjectId = FrostFsObjectId.FromHash(obj.ObjectId.Value.Span)
|
||||
};
|
||||
}
|
||||
}
|
|
@ -1,32 +0,0 @@
|
|||
using System;
|
||||
|
||||
using FrostFS.Object;
|
||||
|
||||
namespace FrostFS.SDK.Client.Mappers.GRPC;
|
||||
|
||||
public static class ObjectAttributeMapper
|
||||
{
|
||||
public static Header.Types.Attribute ToMessage(this FrostFsAttributePair attribute)
|
||||
{
|
||||
if (attribute is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(attribute));
|
||||
}
|
||||
|
||||
return new Header.Types.Attribute
|
||||
{
|
||||
Key = attribute.Key,
|
||||
Value = attribute.Value
|
||||
};
|
||||
}
|
||||
|
||||
public static FrostFsAttributePair ToModel(this Header.Types.Attribute attribute)
|
||||
{
|
||||
if (attribute is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(attribute));
|
||||
}
|
||||
|
||||
return new FrostFsAttributePair(attribute.Key, attribute.Value);
|
||||
}
|
||||
}
|
|
@ -1,34 +0,0 @@
|
|||
using System;
|
||||
|
||||
using FrostFS.Object;
|
||||
|
||||
namespace FrostFS.SDK.Client.Mappers.GRPC;
|
||||
|
||||
public static class ObjectFilterMapper
|
||||
{
|
||||
public static SearchRequest.Types.Body.Types.Filter ToMessage(this IObjectFilter filter)
|
||||
{
|
||||
if (filter is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(filter));
|
||||
}
|
||||
|
||||
var objMatchTypeName = filter.MatchType switch
|
||||
{
|
||||
FrostFsMatchType.Unspecified => MatchType.Unspecified,
|
||||
FrostFsMatchType.Equals => MatchType.StringEqual,
|
||||
FrostFsMatchType.NotEquals => MatchType.StringNotEqual,
|
||||
FrostFsMatchType.KeyAbsent => MatchType.NotPresent,
|
||||
FrostFsMatchType.StartsWith => MatchType.CommonPrefix,
|
||||
|
||||
_ => throw new ArgumentException($"Unknown MatchType. Value: '{filter.MatchType}'.")
|
||||
};
|
||||
|
||||
return new SearchRequest.Types.Body.Types.Filter
|
||||
{
|
||||
MatchType = objMatchTypeName,
|
||||
Key = filter.Key,
|
||||
Value = filter.GetSerializedValue()
|
||||
};
|
||||
}
|
||||
}
|
|
@ -1,55 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
|
||||
using FrostFS.Object;
|
||||
using FrostFS.SDK.Cryptography;
|
||||
|
||||
namespace FrostFS.SDK.Client.Mappers.GRPC;
|
||||
|
||||
public static class ObjectHeaderMapper
|
||||
{
|
||||
public static FrostFsObjectHeader ToModel(this Header header)
|
||||
{
|
||||
if (header is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(header));
|
||||
}
|
||||
|
||||
var objTypeName = header.ObjectType switch
|
||||
{
|
||||
ObjectType.Regular => FrostFsObjectType.Regular,
|
||||
ObjectType.Lock => FrostFsObjectType.Lock,
|
||||
ObjectType.Tombstone => FrostFsObjectType.Tombstone,
|
||||
_ => throw new ArgumentException($"Unknown ObjectType. Value: '{header.ObjectType}'.")
|
||||
};
|
||||
|
||||
FrostFsSplit? split = null;
|
||||
|
||||
if (header.Split != null)
|
||||
{
|
||||
var children = header.Split.Children.Count != 0 ? new ReadOnlyCollection<FrostFsObjectId>(
|
||||
header.Split.Children.Select(x => x.ToModel()).ToList()) : null;
|
||||
|
||||
split = new FrostFsSplit(new SplitId(header.Split.SplitId.ToUuid()),
|
||||
header.Split.Previous?.ToModel(),
|
||||
header.Split.Parent?.ToModel(),
|
||||
header.Split.ParentHeader?.ToModel(),
|
||||
null,
|
||||
children);
|
||||
}
|
||||
|
||||
var model = new FrostFsObjectHeader(
|
||||
new FrostFsContainerId(Base58.Encode(header.ContainerId.Value.Span)),
|
||||
objTypeName,
|
||||
header.Attributes.Select(attribute => attribute.ToModel()).ToArray(),
|
||||
split,
|
||||
header.OwnerId.ToModel(),
|
||||
header.Version.ToModel())
|
||||
{
|
||||
PayloadLength = header.PayloadLength,
|
||||
};
|
||||
|
||||
return model;
|
||||
}
|
||||
}
|
|
@ -1,33 +0,0 @@
|
|||
using System;
|
||||
|
||||
using FrostFS.Refs;
|
||||
|
||||
using Google.Protobuf;
|
||||
|
||||
namespace FrostFS.SDK.Client.Mappers.GRPC;
|
||||
|
||||
public static class ObjectIdMapper
|
||||
{
|
||||
public static ObjectID ToMessage(this FrostFsObjectId objectId)
|
||||
{
|
||||
if (objectId is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(objectId));
|
||||
}
|
||||
|
||||
return new ObjectID
|
||||
{
|
||||
Value = ByteString.CopyFrom(objectId.ToHash())
|
||||
};
|
||||
}
|
||||
|
||||
public static FrostFsObjectId ToModel(this ObjectID objectId)
|
||||
{
|
||||
if (objectId is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(objectId));
|
||||
}
|
||||
|
||||
return FrostFsObjectId.FromHash(objectId.Value.Span);
|
||||
}
|
||||
}
|
|
@ -1,54 +0,0 @@
|
|||
using System;
|
||||
|
||||
using FrostFS.Refs;
|
||||
using FrostFS.SDK.Cryptography;
|
||||
|
||||
using Google.Protobuf;
|
||||
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
|
||||
namespace FrostFS.SDK.Client.Mappers.GRPC;
|
||||
|
||||
public static class OwnerIdMapper
|
||||
{
|
||||
private static readonly MemoryCacheEntryOptions _oneHourExpiration = new MemoryCacheEntryOptions()
|
||||
.SetSlidingExpiration(TimeSpan.FromHours(1))
|
||||
.SetSize(1);
|
||||
|
||||
public static OwnerID ToMessage(this FrostFsOwner model)
|
||||
{
|
||||
if (model is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(model));
|
||||
}
|
||||
|
||||
if (!Caches.Owners.TryGetValue(model, out OwnerID? message))
|
||||
{
|
||||
message = new OwnerID
|
||||
{
|
||||
Value = ByteString.CopyFrom(model.ToHash())
|
||||
};
|
||||
|
||||
Caches.Owners.Set(model, message, _oneHourExpiration);
|
||||
}
|
||||
|
||||
return message!;
|
||||
}
|
||||
|
||||
public static FrostFsOwner ToModel(this OwnerID message)
|
||||
{
|
||||
if (message is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(message));
|
||||
}
|
||||
|
||||
if (!Caches.Owners.TryGetValue(message, out FrostFsOwner? model))
|
||||
{
|
||||
model = new FrostFsOwner(Base58.Encode(message.Value.Span));
|
||||
|
||||
Caches.Owners.Set(message, model, _oneHourExpiration);
|
||||
}
|
||||
|
||||
return model!;
|
||||
}
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
using System;
|
||||
|
||||
using Google.Protobuf;
|
||||
|
||||
namespace FrostFS.SDK.Client;
|
||||
|
||||
public static class SessionMapper
|
||||
{
|
||||
public static byte[] Serialize(this Session.SessionToken token)
|
||||
{
|
||||
if (token is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(token));
|
||||
}
|
||||
|
||||
byte[] bytes = new byte[token.CalculateSize()];
|
||||
using CodedOutputStream stream = new(bytes);
|
||||
token.WriteTo(stream);
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
public static Session.SessionToken Deserialize(this Session.SessionToken token, byte[] bytes)
|
||||
{
|
||||
token.MergeFrom(bytes);
|
||||
return token;
|
||||
}
|
||||
}
|
|
@ -1,31 +0,0 @@
|
|||
using System;
|
||||
|
||||
using Google.Protobuf;
|
||||
|
||||
namespace FrostFS.SDK.Client.Mappers.GRPC;
|
||||
|
||||
public static class SignatureMapper
|
||||
{
|
||||
public static Refs.Signature ToMessage(this FrostFsSignature signature)
|
||||
{
|
||||
if (signature is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(signature));
|
||||
}
|
||||
|
||||
var scheme = signature.Scheme switch
|
||||
{
|
||||
SignatureScheme.EcdsaRfc6979Sha256 => Refs.SignatureScheme.EcdsaRfc6979Sha256,
|
||||
SignatureScheme.EcdsaRfc6979Sha256WalletConnect => Refs.SignatureScheme.EcdsaRfc6979Sha256WalletConnect,
|
||||
SignatureScheme.EcdsaSha512 => Refs.SignatureScheme.EcdsaSha512,
|
||||
_ => throw new ArgumentException(nameof(signature.Scheme), $"Unexpected enum value: {signature.Scheme}")
|
||||
};
|
||||
|
||||
return new Refs.Signature
|
||||
{
|
||||
Key = ByteString.CopyFrom(signature.Key),
|
||||
Scheme = scheme,
|
||||
Sign = ByteString.CopyFrom(signature.Sign)
|
||||
};
|
||||
}
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
using System;
|
||||
|
||||
namespace FrostFS.SDK.Client.Mappers.GRPC;
|
||||
|
||||
public static class StatusMapper
|
||||
{
|
||||
public static FrostFsResponseStatus ToModel(this Status.Status status)
|
||||
{
|
||||
if (status is null)
|
||||
return new FrostFsResponseStatus(FrostFsStatusCode.Success);
|
||||
|
||||
var codeName = Enum.GetName(typeof(FrostFsStatusCode), status.Code);
|
||||
|
||||
return codeName is null
|
||||
? throw new ArgumentException($"Unknown StatusCode. Value: '{status.Code}'.")
|
||||
: new FrostFsResponseStatus((FrostFsStatusCode)status.Code, status.Message);
|
||||
}
|
||||
}
|
|
@ -1,85 +0,0 @@
|
|||
using System.Collections;
|
||||
using System.Threading;
|
||||
|
||||
using FrostFS.Refs;
|
||||
|
||||
namespace FrostFS.SDK.Client.Mappers.GRPC;
|
||||
|
||||
public static class VersionMapper
|
||||
{
|
||||
private static readonly Hashtable _cacheMessages = [];
|
||||
private static readonly Hashtable _cacheModels = [];
|
||||
private static SpinLock _spinlock;
|
||||
|
||||
public static Version ToMessage(this FrostFsVersion model)
|
||||
{
|
||||
if (model is null)
|
||||
{
|
||||
throw new System.ArgumentNullException(nameof(model));
|
||||
}
|
||||
|
||||
var key = model.Major << 16 + model.Minor;
|
||||
|
||||
if (!_cacheMessages.ContainsKey(key))
|
||||
{
|
||||
bool lockTaken = false;
|
||||
try
|
||||
{
|
||||
_spinlock.Enter(ref lockTaken);
|
||||
var message = new Version
|
||||
{
|
||||
Major = (uint)model.Major,
|
||||
Minor = (uint)model.Minor
|
||||
};
|
||||
|
||||
_cacheMessages.Add(key, message);
|
||||
return message;
|
||||
}
|
||||
catch (System.ArgumentException)
|
||||
{
|
||||
// ignore attempt to add duplicate
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (lockTaken)
|
||||
_spinlock.Exit(false);
|
||||
}
|
||||
}
|
||||
|
||||
return (Version)_cacheMessages[key];
|
||||
}
|
||||
|
||||
public static FrostFsVersion ToModel(this Version message)
|
||||
{
|
||||
if (message is null)
|
||||
{
|
||||
throw new System.ArgumentNullException(nameof(message));
|
||||
}
|
||||
|
||||
var key = (int)message.Major << 16 + (int)message.Minor;
|
||||
|
||||
if (!_cacheModels.ContainsKey(key))
|
||||
{
|
||||
bool lockTaken = false;
|
||||
try
|
||||
{
|
||||
_spinlock.Enter(ref lockTaken);
|
||||
var model = new FrostFsVersion((int)message.Major, (int)message.Minor);
|
||||
|
||||
_cacheModels.Add(key, model);
|
||||
return model;
|
||||
}
|
||||
catch (System.ArgumentException)
|
||||
{
|
||||
// ignore attempt to add duplicate
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (lockTaken)
|
||||
_spinlock.Exit(false);
|
||||
}
|
||||
}
|
||||
|
||||
return (FrostFsVersion)_cacheModels[key];
|
||||
}
|
||||
}
|
|
@ -1,63 +0,0 @@
|
|||
using System;
|
||||
|
||||
using Frostfs.V2.Ape;
|
||||
|
||||
namespace FrostFS.SDK.Client;
|
||||
|
||||
public struct FrostFsChainTarget(FrostFsTargetType type, string name) : IEquatable<FrostFsChainTarget>
|
||||
{
|
||||
private ChainTarget? chainTarget;
|
||||
|
||||
public FrostFsTargetType Type { get; } = type;
|
||||
|
||||
public string Name { get; } = name;
|
||||
|
||||
internal ChainTarget GetChainTarget()
|
||||
{
|
||||
return chainTarget ??= new ChainTarget
|
||||
{
|
||||
Type = GetTargetType(Type),
|
||||
Name = Name
|
||||
};
|
||||
}
|
||||
|
||||
private static TargetType GetTargetType(FrostFsTargetType type)
|
||||
{
|
||||
return type switch
|
||||
{
|
||||
FrostFsTargetType.Undefined => TargetType.Undefined,
|
||||
FrostFsTargetType.Namespace => TargetType.Namespace,
|
||||
FrostFsTargetType.Container => TargetType.Container,
|
||||
FrostFsTargetType.User => TargetType.User,
|
||||
FrostFsTargetType.Group => TargetType.Group,
|
||||
_ => throw new ArgumentException("Unexpected value for TargetType", nameof(type)),
|
||||
};
|
||||
}
|
||||
|
||||
public override readonly bool Equals(object obj)
|
||||
{
|
||||
if (obj == null || obj is not FrostFsChainTarget)
|
||||
return false;
|
||||
|
||||
return Equals((FrostFsChainTarget)obj);
|
||||
}
|
||||
public readonly bool Equals(FrostFsChainTarget other)
|
||||
{
|
||||
return Type == other.Type && Name.Equals(other.Name, StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
public override readonly int GetHashCode()
|
||||
{
|
||||
return Name.GetHashCode() ^ (int)Type;
|
||||
}
|
||||
|
||||
public static bool operator ==(FrostFsChainTarget left, FrostFsChainTarget right)
|
||||
{
|
||||
return left.Equals(right);
|
||||
}
|
||||
|
||||
public static bool operator !=(FrostFsChainTarget left, FrostFsChainTarget right)
|
||||
{
|
||||
return !(left == right);
|
||||
}
|
||||
}
|
|
@ -1,41 +0,0 @@
|
|||
using Google.Protobuf;
|
||||
|
||||
namespace FrostFS.SDK.Client;
|
||||
|
||||
public struct FrostFsChain(byte[] raw) : System.IEquatable<FrostFsChain>
|
||||
{
|
||||
private ByteString? grpcRaw;
|
||||
|
||||
public byte[] Raw { get; } = raw;
|
||||
|
||||
internal ByteString GetRaw()
|
||||
{
|
||||
return grpcRaw ??= ByteString.CopyFrom(Raw);
|
||||
}
|
||||
|
||||
public override readonly bool Equals(object obj)
|
||||
{
|
||||
var chain = (FrostFsChain)obj;
|
||||
return Equals(chain);
|
||||
}
|
||||
|
||||
public override readonly int GetHashCode()
|
||||
{
|
||||
return Raw.GetHashCode();
|
||||
}
|
||||
|
||||
public static bool operator ==(FrostFsChain left, FrostFsChain right)
|
||||
{
|
||||
return left.Equals(right);
|
||||
}
|
||||
|
||||
public static bool operator !=(FrostFsChain left, FrostFsChain right)
|
||||
{
|
||||
return !(left == right);
|
||||
}
|
||||
|
||||
public readonly bool Equals(FrostFsChain other)
|
||||
{
|
||||
return Raw == other.Raw;
|
||||
}
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
namespace FrostFS.SDK.Client;
|
||||
|
||||
public enum FrostFsTargetType
|
||||
{
|
||||
Undefined = 0,
|
||||
Namespace,
|
||||
Container,
|
||||
User,
|
||||
Group
|
||||
}
|
|
@ -1,37 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Globalization;
|
||||
using System.Text;
|
||||
|
||||
using Grpc.Core.Interceptors;
|
||||
|
||||
namespace FrostFS.SDK;
|
||||
|
||||
public class ClientSettings
|
||||
{
|
||||
protected static readonly string errorTemplate = "{0} is required parameter";
|
||||
|
||||
public string Host { get; set; } = string.Empty;
|
||||
|
||||
public string Key { get; set; } = string.Empty;
|
||||
|
||||
public Action<CallStatistics>? Callback { get; set; }
|
||||
|
||||
public Collection<Interceptor> Interceptors { get; } = [];
|
||||
|
||||
public void Validate()
|
||||
{
|
||||
StringBuilder? errors = null;
|
||||
|
||||
if (string.IsNullOrWhiteSpace(Host))
|
||||
(errors = new StringBuilder(128)).AppendLine(string.Format(CultureInfo.InvariantCulture, errorTemplate, nameof(Host)));
|
||||
|
||||
if (string.IsNullOrWhiteSpace(Key))
|
||||
(errors ??= new StringBuilder(128)).AppendLine(string.Format(CultureInfo.InvariantCulture, errorTemplate, nameof(Key)));
|
||||
|
||||
if (errors != null)
|
||||
{
|
||||
throw new ArgumentException(errors.ToString());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,58 +0,0 @@
|
|||
using FrostFS.Refs;
|
||||
using FrostFS.SDK.Client;
|
||||
using FrostFS.SDK.Client.Mappers.GRPC;
|
||||
using FrostFS.SDK.Cryptography;
|
||||
|
||||
namespace FrostFS.SDK;
|
||||
|
||||
public class FrostFsContainerId
|
||||
{
|
||||
private string? modelId;
|
||||
private ContainerID? containerID;
|
||||
|
||||
public FrostFsContainerId(string id)
|
||||
{
|
||||
this.modelId = id;
|
||||
}
|
||||
|
||||
internal FrostFsContainerId(ContainerID id)
|
||||
{
|
||||
this.containerID = id;
|
||||
}
|
||||
|
||||
public string GetValue()
|
||||
{
|
||||
if (this.modelId != null)
|
||||
return this.modelId;
|
||||
|
||||
if (containerID != null)
|
||||
{
|
||||
this.modelId = Base58.Encode(containerID.Value.Span);
|
||||
return this.modelId;
|
||||
}
|
||||
|
||||
throw new FrostFsInvalidObjectException();
|
||||
}
|
||||
|
||||
internal ContainerID ContainerID
|
||||
{
|
||||
get
|
||||
{
|
||||
if (this.containerID != null)
|
||||
return this.containerID;
|
||||
|
||||
if (modelId != null)
|
||||
{
|
||||
this.containerID = this.ToMessage();
|
||||
return this.containerID;
|
||||
}
|
||||
|
||||
throw new FrostFsInvalidObjectException();
|
||||
}
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return GetValue();
|
||||
}
|
||||
}
|
|
@ -1,109 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
|
||||
using FrostFS.SDK.Client;
|
||||
using FrostFS.SDK.Client.Mappers.GRPC;
|
||||
using FrostFS.SDK.Cryptography;
|
||||
|
||||
using Google.Protobuf;
|
||||
|
||||
namespace FrostFS.SDK;
|
||||
|
||||
public class FrostFsContainerInfo
|
||||
{
|
||||
private Container.Container.Types.Attribute[]? grpsAttributes;
|
||||
private ReadOnlyCollection<FrostFsAttributePair>? attributes;
|
||||
private FrostFsPlacementPolicy? placementPolicy;
|
||||
private Guid? nonce;
|
||||
|
||||
private Container.Container? container;
|
||||
|
||||
public FrostFsContainerInfo(
|
||||
FrostFsPlacementPolicy placementPolicy,
|
||||
FrostFsAttributePair[]? attributes = null,
|
||||
FrostFsVersion? version = null,
|
||||
FrostFsOwner? owner = null,
|
||||
Guid? nonce = null)
|
||||
{
|
||||
this.placementPolicy = placementPolicy;
|
||||
Version = version;
|
||||
Owner = owner;
|
||||
this.nonce = nonce;
|
||||
|
||||
if (attributes != null)
|
||||
this.attributes = new ReadOnlyCollection<FrostFsAttributePair>(attributes);
|
||||
}
|
||||
|
||||
internal FrostFsContainerInfo(Container.Container container)
|
||||
{
|
||||
this.container = container;
|
||||
}
|
||||
|
||||
public Guid Nonce
|
||||
{
|
||||
get
|
||||
{
|
||||
nonce ??= container?.Nonce != null ? container.Nonce.ToUuid() : Guid.NewGuid();
|
||||
return nonce.Value;
|
||||
}
|
||||
}
|
||||
|
||||
public FrostFsPlacementPolicy? PlacementPolicy
|
||||
{
|
||||
get
|
||||
{
|
||||
placementPolicy ??= container?.PlacementPolicy?.ToModel();
|
||||
return placementPolicy;
|
||||
}
|
||||
}
|
||||
|
||||
public ReadOnlyCollection<FrostFsAttributePair>? Attributes
|
||||
{
|
||||
get
|
||||
{
|
||||
if (attributes == null && grpsAttributes != null)
|
||||
attributes = new ReadOnlyCollection<FrostFsAttributePair>(grpsAttributes.Select(a => new FrostFsAttributePair(a.Key, a.Value)).ToList());
|
||||
|
||||
return attributes;
|
||||
}
|
||||
}
|
||||
|
||||
public FrostFsVersion? Version { get; private set; }
|
||||
|
||||
public FrostFsOwner? Owner { get; private set; }
|
||||
|
||||
internal Container.Container.Types.Attribute[]? GetGrpsAttributes()
|
||||
{
|
||||
grpsAttributes ??= Attributes?
|
||||
.Select(a => new Container.Container.Types.Attribute { Key = a.Key, Value = a.Value })
|
||||
.ToArray();
|
||||
|
||||
return grpsAttributes;
|
||||
}
|
||||
|
||||
internal Container.Container GetContainer()
|
||||
{
|
||||
if (this.container == null)
|
||||
{
|
||||
if (PlacementPolicy == null)
|
||||
{
|
||||
throw new ArgumentNullException("PlacementPolicy is null");
|
||||
}
|
||||
|
||||
this.container = new Container.Container()
|
||||
{
|
||||
PlacementPolicy = PlacementPolicy.Value.GetPolicy(),
|
||||
Nonce = ByteString.CopyFrom(Nonce.ToBytes()),
|
||||
OwnerId = Owner?.OwnerID,
|
||||
Version = Version?.VersionID
|
||||
};
|
||||
|
||||
var attribs = GetGrpsAttributes();
|
||||
if (attribs != null)
|
||||
this.container.Attributes.AddRange(attribs);
|
||||
}
|
||||
|
||||
return this.container;
|
||||
}
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
namespace FrostFS.SDK;
|
||||
|
||||
public enum FrostFsObjectType
|
||||
{
|
||||
Regular = 0,
|
||||
Tombstone = 1,
|
||||
Lock = 3
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
namespace FrostFS.SDK;
|
||||
|
||||
public enum SignatureScheme
|
||||
{
|
||||
EcdsaSha512,
|
||||
EcdsaRfc6979Sha256,
|
||||
EcdsaRfc6979Sha256WalletConnect
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
namespace FrostFS.SDK;
|
||||
|
||||
public class CallStatistics
|
||||
{
|
||||
public string? MethodName { get; set; }
|
||||
public long ElapsedMicroSeconds { get; set; }
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
using System;
|
||||
|
||||
using FrostFS.SDK.Cryptography;
|
||||
|
||||
namespace FrostFS.SDK;
|
||||
|
||||
public class CheckSum
|
||||
{
|
||||
private byte[]? hash;
|
||||
private string? text;
|
||||
|
||||
public static CheckSum CreateCheckSum(byte[] content)
|
||||
{
|
||||
return new CheckSum { hash = content.Sha256() };
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return text ??= BitConverter.ToString(hash).Replace("-", "");
|
||||
}
|
||||
}
|
|
@ -1,52 +0,0 @@
|
|||
namespace FrostFS.SDK;
|
||||
|
||||
public static class Constants
|
||||
{
|
||||
public const int ObjectChunkSize = 3 * (1 << 20);
|
||||
public const int Sha256HashLength = 32;
|
||||
|
||||
// HeaderPrefix is a prefix of key to object header value or property.
|
||||
public const string HeaderPrefix = "$Object:";
|
||||
|
||||
// FilterHeaderVersion is a filter key to "version" field of the object header.
|
||||
public const string FilterHeaderVersion = HeaderPrefix + "version";
|
||||
|
||||
// FilterHeaderObjectID is a filter key to "object_id" field of the object.
|
||||
public const string FilterHeaderObjectID = HeaderPrefix + "objectID";
|
||||
|
||||
// FilterHeaderContainerID is a filter key to "container_id" field of the object header.
|
||||
public const string FilterHeaderContainerID = HeaderPrefix + "containerID";
|
||||
|
||||
// FilterHeaderOwnerID is a filter key to "owner_id" field of the object header.
|
||||
public const string FilterHeaderOwnerID = HeaderPrefix + "ownerID";
|
||||
|
||||
// FilterHeaderCreationEpoch is a filter key to "creation_epoch" field of the object header.
|
||||
public const string FilterHeaderCreationEpoch = HeaderPrefix + "creationEpoch";
|
||||
|
||||
// FilterHeaderPayloadLength is a filter key to "payload_length" field of the object header.
|
||||
public const string FilterHeaderPayloadLength = HeaderPrefix + "payloadLength";
|
||||
|
||||
// FilterHeaderPayloadHash is a filter key to "payload_hash" field of the object header.
|
||||
public const string FilterHeaderPayloadHash = HeaderPrefix + "payloadHash";
|
||||
|
||||
// FilterHeaderObjectType is a filter key to "object_type" field of the object header.
|
||||
public const string FilterHeaderObjectType = HeaderPrefix + "objectType";
|
||||
|
||||
// FilterHeaderHomomorphicHash is a filter key to "homomorphic_hash" field of the object header.
|
||||
public const string FilterHeaderHomomorphicHash = HeaderPrefix + "homomorphicHash";
|
||||
|
||||
// FilterHeaderParent is a filter key to "split.parent" field of the object header.
|
||||
public const string FilterHeaderParent = HeaderPrefix + "split.parent";
|
||||
|
||||
// FilterHeaderSplitID is a filter key to "split.splitID" field of the object header.
|
||||
public const string FilterHeaderSplitID = HeaderPrefix + "split.splitID";
|
||||
|
||||
// FilterHeaderECParent is a filter key to "ec.parent" field of the object header.
|
||||
public const string FilterHeaderECParent = HeaderPrefix + "ec.parent";
|
||||
|
||||
// FilterPropertyRoot is a filter key to check if regular object is on top of split hierarchy.
|
||||
public const string FilterHeaderRoot = HeaderPrefix + "ROOT";
|
||||
|
||||
// FilterPropertyPhy is a filter key to check if an object physically stored on a node.
|
||||
public const string FilterHeaderPhy = HeaderPrefix + "PHY";
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
namespace FrostFS.SDK;
|
||||
|
||||
public class FrostFsFilter(string name, string key, int operation, string value, FrostFsFilter[] filters) : IFrostFsFilter
|
||||
{
|
||||
public string Name { get; } = name;
|
||||
public string Key { get; } = key;
|
||||
public int Operation { get; } = operation;
|
||||
public string Value { get; } = value;
|
||||
public FrostFsFilter[] Filters { get; } = filters;
|
||||
}
|
|
@ -1,265 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
|
||||
using FrostFS.SDK.Client;
|
||||
using FrostFS.SDK.Client.Models.Netmap.Placement;
|
||||
using FrostFS.SDK.Cryptography;
|
||||
|
||||
namespace FrostFS.SDK;
|
||||
|
||||
public class FrostFsNetmapSnapshot(ulong epoch, IReadOnlyList<FrostFsNodeInfo> nodeInfoCollection)
|
||||
{
|
||||
public ulong Epoch { get; private set; } = epoch;
|
||||
|
||||
public IReadOnlyList<FrostFsNodeInfo> NodeInfoCollection { get; private set; } = nodeInfoCollection;
|
||||
|
||||
internal static INormalizer NewReverseMinNorm(double minV)
|
||||
{
|
||||
return new ReverseMinNorm { min = minV };
|
||||
}
|
||||
|
||||
// newSigmoidNorm returns a normalizer which
|
||||
// normalize values in range of 0.0 to 1.0 to a scaled sigmoid.
|
||||
internal static INormalizer NewSigmoidNorm(double scale)
|
||||
{
|
||||
return new SigmoidNorm(scale);
|
||||
}
|
||||
|
||||
// PlacementVectors sorts container nodes returned by ContainerNodes method
|
||||
// and returns placement vectors for the entity identified by the given pivot.
|
||||
// For example, in order to build node list to store the object, binary-encoded
|
||||
// object identifier can be used as pivot. Result is deterministic for
|
||||
// the fixed NetMap and parameters.
|
||||
public FrostFsNodeInfo[][] PlacementVectors(FrostFsNodeInfo[][] vectors, byte[] pivot)
|
||||
{
|
||||
if (vectors is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(vectors));
|
||||
}
|
||||
|
||||
using var murmur3 = new Murmur3(0);
|
||||
var hash = murmur3.GetCheckSum64(pivot);
|
||||
|
||||
var wf = Tools.DefaultWeightFunc(NodeInfoCollection.ToArray());
|
||||
|
||||
var result = new FrostFsNodeInfo[vectors.Length][];
|
||||
var maxSize = vectors.Max(x => x.Length);
|
||||
|
||||
var spanWeigths = new double[maxSize];
|
||||
|
||||
for (int i = 0; i < vectors.Length; i++)
|
||||
{
|
||||
result[i] = new FrostFsNodeInfo[vectors[i].Length];
|
||||
|
||||
for (int j = 0; j < vectors[i].Length; j++)
|
||||
{
|
||||
result[i][j] = vectors[i][j];
|
||||
}
|
||||
|
||||
Tools.AppendWeightsTo(result[i], wf, spanWeigths);
|
||||
|
||||
Tools.SortHasherSliceByWeightValue(result[i].ToList<FrostFsNodeInfo>(), spanWeigths, hash);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// SelectFilterNodes returns a two-dimensional list of nodes as a result of applying the
|
||||
// given SelectFilterExpr to the NetMap.
|
||||
// If the SelectFilterExpr contains only filters, the result contains a single row with the
|
||||
// result of the last filter application.
|
||||
// If the SelectFilterExpr contains only selectors, the result contains the selection rows
|
||||
// of the last select application.
|
||||
List<List<FrostFsNodeInfo>> SelectFilterNodes(SelectFilterExpr expr)
|
||||
{
|
||||
var policy = new FrostFsPlacementPolicy(false);
|
||||
|
||||
foreach (var f in expr.Filters)
|
||||
policy.Filters.Add(f);
|
||||
|
||||
policy.Selectors.Add(expr.Selector);
|
||||
|
||||
var ctx = new Context(this)
|
||||
{
|
||||
Cbf = expr.Cbf
|
||||
};
|
||||
|
||||
ctx.ProcessFilters(policy);
|
||||
ctx.ProcessSelectors(policy);
|
||||
|
||||
var ret = new List<List<FrostFsNodeInfo>>();
|
||||
|
||||
if (expr.Selector == null)
|
||||
{
|
||||
var lastFilter = expr.Filters[^1];
|
||||
|
||||
var subCollestion = new List<FrostFsNodeInfo>();
|
||||
ret.Add(subCollestion);
|
||||
|
||||
foreach (var nodeInfo in NodeInfoCollection)
|
||||
{
|
||||
if (ctx.Match(ctx.ProcessedFilters[lastFilter.Name], nodeInfo))
|
||||
{
|
||||
subCollestion.Add(nodeInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (expr.Selector.Name != null)
|
||||
{
|
||||
var sel = ctx.GetSelection(ctx.ProcessedSelectors[expr.Selector.Name]);
|
||||
|
||||
foreach (var ns in sel)
|
||||
{
|
||||
var subCollestion = new List<FrostFsNodeInfo>();
|
||||
ret.Add(subCollestion);
|
||||
foreach (var n in ns)
|
||||
{
|
||||
subCollestion.Add(n);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
internal static Func<FrostFsNodeInfo, double> NewWeightFunc(INormalizer capNorm, INormalizer priceNorm)
|
||||
{
|
||||
return new Func<FrostFsNodeInfo, double>((FrostFsNodeInfo nodeInfo) =>
|
||||
{
|
||||
return capNorm.Normalize(nodeInfo.GetCapacity()) * priceNorm.Normalize(nodeInfo.Price);
|
||||
});
|
||||
}
|
||||
|
||||
private static FrostFsNodeInfo[] FlattenNodes(List<List<FrostFsNodeInfo>> nodes)
|
||||
{
|
||||
int sz = 0;
|
||||
foreach (var ns in nodes)
|
||||
{
|
||||
sz += ns.Count;
|
||||
}
|
||||
|
||||
var result = new FrostFsNodeInfo[sz];
|
||||
|
||||
int i = 0;
|
||||
foreach (var ns in nodes)
|
||||
{
|
||||
foreach (var n in ns)
|
||||
{
|
||||
result[i++] = n;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// ContainerNodes returns two-dimensional list of nodes as a result of applying
|
||||
// given PlacementPolicy to the NetMap. Each line of the list corresponds to a
|
||||
// replica descriptor. Line order corresponds to order of ReplicaDescriptor list
|
||||
// in the policy. Nodes are pre-filtered according to the Filter list from
|
||||
// the policy, and then selected by Selector list. Result is deterministic for
|
||||
// the fixed NetMap and parameters.
|
||||
//
|
||||
// Result can be used in PlacementVectors.
|
||||
public FrostFsNodeInfo[][] ContainerNodes(FrostFsPlacementPolicy p, byte[]? pivot)
|
||||
{
|
||||
var c = new Context(this)
|
||||
{
|
||||
Cbf = p.BackupFactor
|
||||
};
|
||||
|
||||
if (pivot != null && pivot.Length > 0)
|
||||
{
|
||||
c.HrwSeed = pivot;
|
||||
|
||||
using var murmur = new Murmur3(0);
|
||||
c.HrwSeedHash = murmur.GetCheckSum64(pivot);
|
||||
}
|
||||
|
||||
c.ProcessFilters(p);
|
||||
c.ProcessSelectors(p);
|
||||
|
||||
var unique = p.IsUnique();
|
||||
|
||||
var result = new List<List<FrostFsNodeInfo>>(p.Replicas.Length);
|
||||
for (int i = 0; i < p.Replicas.Length; i++)
|
||||
{
|
||||
result.Add([]);
|
||||
}
|
||||
|
||||
// Note that the cached selectors are not used when the policy contains the UNIQUE flag.
|
||||
// This is necessary because each selection vector affects potentially the subsequent vectors
|
||||
// and thus we call getSelection in such case, in order to take into account nodes previously
|
||||
// marked as used by earlier replicas.
|
||||
for (int i = 0; i < p.Replicas.Length; i++)
|
||||
{
|
||||
var sName = p.Replicas[i].Selector;
|
||||
|
||||
if (string.IsNullOrEmpty(sName) && !(p.Replicas.Length == 1 && p.Selectors.Count == 1))
|
||||
{
|
||||
var s = new FrostFsSelector(Context.mainFilterName)
|
||||
{
|
||||
Count = p.Replicas[i].CountNodes()
|
||||
};
|
||||
|
||||
var nodes = c.GetSelection(s);
|
||||
|
||||
var arg = new List<List<FrostFsNodeInfo>>(nodes.Count);
|
||||
for (int j = 0; j < nodes.Count; j++)
|
||||
{
|
||||
arg[i] = nodes[j];
|
||||
}
|
||||
|
||||
result[i].AddRange(FlattenNodes(arg));
|
||||
|
||||
if (unique)
|
||||
{
|
||||
foreach (var n in result[i])
|
||||
{
|
||||
c.UsedNodes[n.Hash()] = true;
|
||||
}
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (unique)
|
||||
{
|
||||
if (!c.ProcessedSelectors.TryGetValue(sName, out var s) || s == null)
|
||||
{
|
||||
throw new FrostFsException($"selector not found: {sName}");
|
||||
}
|
||||
|
||||
var nodes = c.GetSelection(c.ProcessedSelectors[sName]);
|
||||
|
||||
result[i].AddRange(FlattenNodes(nodes));
|
||||
|
||||
foreach (var n in result[i])
|
||||
{
|
||||
c.UsedNodes[n.Hash()] = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var nodes = c.Selections[sName];
|
||||
|
||||
var arg = new List<List<FrostFsNodeInfo>>(nodes.Count);
|
||||
for (int j = 0; j < nodes.Count; j++)
|
||||
{
|
||||
arg[i] = nodes[j];
|
||||
}
|
||||
|
||||
result[i].AddRange(FlattenNodes(arg));
|
||||
}
|
||||
}
|
||||
|
||||
var collection = new FrostFsNodeInfo[result.Count][];
|
||||
for(int i =0; i < result.Count; i++)
|
||||
{
|
||||
collection[i] = [.. result[i]];
|
||||
}
|
||||
|
||||
return collection;
|
||||
}
|
||||
}
|
|
@ -1,80 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
|
||||
using FrostFS.SDK.Client.Models.Netmap.Placement;
|
||||
using FrostFS.SDK.Cryptography;
|
||||
|
||||
namespace FrostFS.SDK;
|
||||
|
||||
public class FrostFsNodeInfo(
|
||||
FrostFsVersion version,
|
||||
NodeState state,
|
||||
IReadOnlyCollection<string> addresses,
|
||||
IReadOnlyDictionary<string, string> attributes,
|
||||
ReadOnlyMemory<byte> publicKey) : IHasher
|
||||
{
|
||||
private ulong _hash;
|
||||
|
||||
// attrPrice is a key to the node attribute that indicates the
|
||||
// price in GAS tokens for storing one GB of data during one Epoch.
|
||||
internal const string AttrPrice = "Price";
|
||||
|
||||
// attrCapacity is a key to the node attribute that indicates the
|
||||
// total available disk space in Gigabytes.
|
||||
internal const string AttrCapacity = "Capacity";
|
||||
|
||||
// attrExternalAddr is a key for the attribute storing node external addresses.
|
||||
internal const string AttrExternalAddr = "ExternalAddr";
|
||||
|
||||
// sepExternalAddr is a separator for multi-value ExternalAddr attribute.
|
||||
internal const string SepExternalAddr = ",";
|
||||
|
||||
private ulong price = ulong.MaxValue;
|
||||
|
||||
public NodeState State { get; } = state;
|
||||
|
||||
public FrostFsVersion Version { get; } = version;
|
||||
|
||||
public IReadOnlyCollection<string> Addresses { get; } = addresses;
|
||||
|
||||
public IReadOnlyDictionary<string, string> Attributes { get; } = attributes;
|
||||
|
||||
public ReadOnlyMemory<byte> PublicKey { get; } = publicKey;
|
||||
|
||||
public ulong Hash()
|
||||
{
|
||||
if (_hash == 0)
|
||||
{
|
||||
using var murmur3 = new Murmur3(0);
|
||||
murmur3.Initialize();
|
||||
_hash = murmur3.GetCheckSum64(PublicKey.ToArray());
|
||||
}
|
||||
|
||||
return _hash;
|
||||
}
|
||||
|
||||
internal ulong GetCapacity()
|
||||
{
|
||||
if (!Attributes.TryGetValue(AttrCapacity, out var val))
|
||||
return 0;
|
||||
|
||||
return ulong.Parse(val, CultureInfo.InvariantCulture);
|
||||
}
|
||||
|
||||
internal ulong Price
|
||||
{
|
||||
get
|
||||
{
|
||||
if (price == ulong.MaxValue)
|
||||
{
|
||||
if (!Attributes.TryGetValue(AttrPrice, out var val))
|
||||
price = 0;
|
||||
else
|
||||
price = uint.Parse(val, CultureInfo.InvariantCulture);
|
||||
}
|
||||
|
||||
return price;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,94 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
|
||||
using FrostFS.Netmap;
|
||||
using FrostFS.SDK.Client;
|
||||
|
||||
namespace FrostFS.SDK;
|
||||
|
||||
public struct FrostFsPlacementPolicy(bool unique, params FrostFsReplica[] replicas)
|
||||
: IEquatable<FrostFsPlacementPolicy>
|
||||
{
|
||||
private PlacementPolicy policy;
|
||||
|
||||
public FrostFsReplica[] Replicas { get; private set; } = replicas;
|
||||
|
||||
public Collection<FrostFsSelector> Selectors { get; } = [];
|
||||
|
||||
public Collection<FrostFsFilter> Filters { get; } = [];
|
||||
|
||||
public bool Unique { get; private set; } = unique;
|
||||
|
||||
public uint BackupFactor { get; set; }
|
||||
|
||||
public override readonly bool Equals(object obj)
|
||||
{
|
||||
if (obj is null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var other = (FrostFsPlacementPolicy)obj;
|
||||
|
||||
return Equals(other);
|
||||
}
|
||||
|
||||
public PlacementPolicy GetPolicy()
|
||||
{
|
||||
if (policy == null)
|
||||
{
|
||||
policy = new PlacementPolicy
|
||||
{
|
||||
Filters = { },
|
||||
Selectors = { },
|
||||
Replicas = { },
|
||||
Unique = Unique
|
||||
};
|
||||
|
||||
foreach (var replica in Replicas)
|
||||
{
|
||||
policy.Replicas.Add(replica.ToMessage());
|
||||
}
|
||||
}
|
||||
|
||||
return policy;
|
||||
}
|
||||
|
||||
internal readonly bool IsUnique()
|
||||
{
|
||||
return Unique || Replicas.Any(r => r.EcDataCount != 0 || r.EcParityCount != 0);
|
||||
}
|
||||
|
||||
public override readonly int GetHashCode()
|
||||
{
|
||||
return Unique ? 17 : 0 + Replicas.GetHashCode();
|
||||
}
|
||||
|
||||
public static bool operator ==(FrostFsPlacementPolicy left, FrostFsPlacementPolicy right)
|
||||
{
|
||||
return left.Equals(right);
|
||||
}
|
||||
|
||||
public static bool operator !=(FrostFsPlacementPolicy left, FrostFsPlacementPolicy right)
|
||||
{
|
||||
return !(left == right);
|
||||
}
|
||||
|
||||
public readonly bool Equals(FrostFsPlacementPolicy other)
|
||||
{
|
||||
var notEqual = Unique != other.Unique
|
||||
|| Replicas.Length != other.Replicas.Length;
|
||||
|
||||
if (notEqual)
|
||||
return false;
|
||||
|
||||
foreach (var replica in Replicas)
|
||||
{
|
||||
if (!other.Replicas.Any(r => r.Equals(replica)))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -1,59 +0,0 @@
|
|||
using System;
|
||||
|
||||
namespace FrostFS.SDK;
|
||||
|
||||
public struct FrostFsReplica : IEquatable<FrostFsReplica>
|
||||
{
|
||||
public int Count { get; set; }
|
||||
public string Selector { get; set; }
|
||||
public uint EcDataCount { get; set; }
|
||||
public uint EcParityCount { get; set; }
|
||||
|
||||
public FrostFsReplica(int count, string? selector = null)
|
||||
{
|
||||
selector ??= string.Empty;
|
||||
|
||||
Count = count;
|
||||
Selector = selector;
|
||||
}
|
||||
|
||||
public override readonly bool Equals(object obj)
|
||||
{
|
||||
if (obj is null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var other = (FrostFsReplica)obj;
|
||||
|
||||
return Count == other.Count && Selector == other.Selector;
|
||||
}
|
||||
|
||||
public readonly uint CountNodes()
|
||||
{
|
||||
return Count != 0 ? (uint)Count : EcDataCount + EcParityCount;
|
||||
}
|
||||
|
||||
public override readonly int GetHashCode()
|
||||
{
|
||||
return (Count + Selector.GetHashCode()) ^ (int)EcDataCount ^ (int)EcParityCount;
|
||||
}
|
||||
|
||||
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
|
||||
&& EcDataCount == other.EcDataCount
|
||||
&& EcParityCount == other.EcParityCount;
|
||||
}
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
namespace FrostFS.SDK;
|
||||
|
||||
public class FrostFsSelector(string name)
|
||||
{
|
||||
public string Name { get; } = name;
|
||||
public uint Count { get; set; }
|
||||
public uint Clause { get; set; }
|
||||
public string? Attribute { get; set; }
|
||||
public string? Filter { get; set; }
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
using FrostFS.Refs;
|
||||
using FrostFS.SDK.Client.Mappers.GRPC;
|
||||
|
||||
namespace FrostFS.SDK;
|
||||
|
||||
public class FrostFsVersion(int major, int minor)
|
||||
{
|
||||
private Version? version;
|
||||
|
||||
public int Major { get; set; } = major;
|
||||
public int Minor { get; set; } = minor;
|
||||
|
||||
internal Version VersionID
|
||||
{
|
||||
get
|
||||
{
|
||||
this.version ??= this.ToMessage();
|
||||
return this.version;
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsSupported(FrostFsVersion version)
|
||||
{
|
||||
if (version is null)
|
||||
{
|
||||
throw new System.ArgumentNullException(nameof(version));
|
||||
}
|
||||
|
||||
return Major == version.Major;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"v{Major}.{Minor}";
|
||||
}
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
namespace FrostFS.SDK
|
||||
{
|
||||
public interface IFrostFsFilter
|
||||
{
|
||||
FrostFsFilter[] Filters { get; }
|
||||
string Key { get; }
|
||||
string Name { get; }
|
||||
int Operation { get; }
|
||||
string Value { get; }
|
||||
}
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
namespace FrostFS.SDK;
|
||||
|
||||
struct NodeAttrPair
|
||||
{
|
||||
internal string attr;
|
||||
internal FrostFsNodeInfo[] nodes;
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
namespace FrostFS.SDK.Client.Models.Netmap.Placement;
|
||||
|
||||
public enum FrostFsClause
|
||||
{
|
||||
Unspecified = 0,
|
||||
Same,
|
||||
Distinct
|
||||
}
|
|
@ -1,433 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
|
||||
namespace FrostFS.SDK.Client.Models.Netmap.Placement;
|
||||
|
||||
internal struct Context
|
||||
{
|
||||
private const string errInvalidFilterName = "filter name is invalid";
|
||||
private const string errInvalidFilterOp = "invalid filter operation";
|
||||
private const string errFilterNotFound = "filter not found";
|
||||
private const string errNonEmptyFilters = "simple filter contains sub-filters";
|
||||
private const string errNotEnoughNodes = "not enough nodes to SELECT from";
|
||||
private const string errUnnamedTopFilter = "unnamed top-level filter";
|
||||
|
||||
internal const string mainFilterName = "*";
|
||||
internal const string likeWildcard = "*";
|
||||
|
||||
// network map to operate on
|
||||
internal FrostFsNetmapSnapshot NetMap { get; }
|
||||
|
||||
// cache of processed filters
|
||||
internal Dictionary<string, FrostFsFilter> ProcessedFilters { get; } = [];
|
||||
|
||||
// cache of processed selectors
|
||||
internal Dictionary<string, FrostFsSelector> ProcessedSelectors { get; } = [];
|
||||
|
||||
// stores results of selector processing
|
||||
internal Dictionary<string, List<List<FrostFsNodeInfo>>> Selections { get; } = [];
|
||||
|
||||
// cache of parsed numeric values
|
||||
internal Dictionary<string, ulong> NumCache { get; } = [];
|
||||
|
||||
internal byte[]? HrwSeed { get; set; }
|
||||
|
||||
// hrw.Hash of hrwSeed
|
||||
internal ulong HrwSeedHash { get; set; }
|
||||
|
||||
// container backup factor
|
||||
internal uint Cbf { get; set; }
|
||||
|
||||
// nodes already used in previous selections, which is needed when the placement
|
||||
// policy uses the UNIQUE flag. Nodes marked as used are not used in subsequent
|
||||
// base selections.
|
||||
internal Dictionary<ulong, bool> UsedNodes { get; } = [];
|
||||
|
||||
// If true, returns an error when netmap does not contain enough nodes for selection.
|
||||
// By default best effort is taken.
|
||||
internal bool Strict { get; set; }
|
||||
|
||||
// weightFunc is a weighting function for determining node priority
|
||||
// which combines low price and high performance
|
||||
private readonly Func<FrostFsNodeInfo, double> weightFunc;
|
||||
|
||||
public Context(FrostFsNetmapSnapshot netMap)
|
||||
{
|
||||
NetMap = netMap;
|
||||
weightFunc = Tools.DefaultWeightFunc(NetMap.NodeInfoCollection);
|
||||
}
|
||||
|
||||
internal void ProcessFilters(FrostFsPlacementPolicy policy)
|
||||
{
|
||||
foreach (var filter in policy.Filters)
|
||||
{
|
||||
ProcessFilter(filter, true);
|
||||
}
|
||||
}
|
||||
|
||||
readonly void ProcessFilter(FrostFsFilter filter, bool top)
|
||||
{
|
||||
var filterName = filter.Name;
|
||||
if (filterName == mainFilterName)
|
||||
{
|
||||
throw new FrostFsException($"{errInvalidFilterName}: '{errInvalidFilterName}' is reserved");
|
||||
}
|
||||
|
||||
if (top && string.IsNullOrEmpty(filterName))
|
||||
{
|
||||
throw new FrostFsException(errUnnamedTopFilter);
|
||||
}
|
||||
|
||||
if (!top && !string.IsNullOrEmpty(filterName) && !ProcessedFilters.ContainsKey(filterName))
|
||||
{
|
||||
throw new FrostFsException(errFilterNotFound);
|
||||
}
|
||||
|
||||
if (filter.Operation == (int)Operation.AND ||
|
||||
filter.Operation == (int)Operation.OR ||
|
||||
filter.Operation == (int)Operation.NOT)
|
||||
{
|
||||
foreach (var f in filter.Filters)
|
||||
ProcessFilter(f, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (filter.Filters.Length != 0)
|
||||
{
|
||||
throw new FrostFsException(errNonEmptyFilters);
|
||||
}
|
||||
else if (!top && !string.IsNullOrEmpty(filterName))
|
||||
{
|
||||
// named reference
|
||||
return;
|
||||
}
|
||||
|
||||
if (filter.Operation == (int)Operation.EQ ||
|
||||
filter.Operation == (int)Operation.NE ||
|
||||
filter.Operation == (int)Operation.LIKE ||
|
||||
filter.Operation == (int)Operation.GT ||
|
||||
filter.Operation == (int)Operation.GE ||
|
||||
filter.Operation == (int)Operation.LT ||
|
||||
filter.Operation == (int)Operation.LE)
|
||||
{
|
||||
var n = uint.Parse(filter.Value, CultureInfo.InvariantCulture);
|
||||
NumCache[filter.Value] = n;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new FrostFsException($"{errInvalidFilterOp}: {filter.Operation}");
|
||||
}
|
||||
}
|
||||
|
||||
if (top)
|
||||
{
|
||||
ProcessedFilters[filterName] = filter;
|
||||
}
|
||||
}
|
||||
|
||||
// processSelectors processes selectors and returns error is any of them is invalid.
|
||||
internal void ProcessSelectors(FrostFsPlacementPolicy policy)
|
||||
{
|
||||
foreach (var selector in policy.Selectors)
|
||||
{
|
||||
var filterName = selector.Filter;
|
||||
if (filterName != mainFilterName)
|
||||
{
|
||||
if (selector.Filter == null || !ProcessedFilters.ContainsKey(selector.Filter))
|
||||
{
|
||||
throw new FrostFsException($"{errFilterNotFound}: SELECT FROM '{filterName}'");
|
||||
}
|
||||
}
|
||||
|
||||
ProcessedSelectors[selector.Name] = selector;
|
||||
|
||||
var selection = GetSelection(selector);
|
||||
|
||||
Selections[selector.Name] = selection;
|
||||
}
|
||||
}
|
||||
|
||||
// calcNodesCount returns number of buckets and minimum number of nodes in every bucket
|
||||
// for the given selector.
|
||||
static (int bucketCount, int nodesInBucket) CalcNodesCount(FrostFsSelector selector)
|
||||
{
|
||||
return selector.Clause == (uint)FrostFsClause.Same
|
||||
? (1, (int)selector.Count)
|
||||
: ((int)selector.Count, 1);
|
||||
}
|
||||
|
||||
// getSelectionBase returns nodes grouped by selector attribute.
|
||||
// It it guaranteed that each pair will contain at least one node.
|
||||
internal NodeAttrPair[] GetSelectionBase(FrostFsSelector selector)
|
||||
{
|
||||
var fName = selector.Filter ?? throw new FrostFsException("Filter name for selector is empty");
|
||||
|
||||
_ = ProcessedFilters.TryGetValue(fName, out var f);
|
||||
|
||||
var isMain = fName == mainFilterName;
|
||||
var result = new List<NodeAttrPair>();
|
||||
|
||||
var nodeMap = new Dictionary<string, List<FrostFsNodeInfo>>();
|
||||
var attr = selector.Attribute;
|
||||
|
||||
foreach (var node in NetMap.NodeInfoCollection)
|
||||
{
|
||||
if (UsedNodes.ContainsKey(node.Hash()))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isMain || Match(f, node))
|
||||
{
|
||||
if (attr == null)
|
||||
{
|
||||
// Default attribute is transparent identifier which is different for every node.
|
||||
result.Add(new NodeAttrPair { attr = "", nodes = [node] });
|
||||
}
|
||||
else
|
||||
{
|
||||
var v = node.Attributes[attr];
|
||||
if (!nodeMap.TryGetValue(v, out var nodes) || nodes == null)
|
||||
{
|
||||
nodeMap[v] = [];
|
||||
}
|
||||
|
||||
nodeMap[v].Add(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(attr))
|
||||
{
|
||||
foreach (var v in nodeMap)
|
||||
{
|
||||
result.Add(new NodeAttrPair() { attr = v.Key, nodes = [.. v.Value] });
|
||||
}
|
||||
}
|
||||
|
||||
if (HrwSeed != null && HrwSeed.Length != 0)
|
||||
{
|
||||
double[] ws = [];
|
||||
|
||||
foreach (var res in result)
|
||||
{
|
||||
Tools.AppendWeightsTo(res.nodes, weightFunc, ws);
|
||||
Tools.SortHasherSliceByWeightValue(res.nodes.ToList(), ws, HrwSeedHash);
|
||||
}
|
||||
}
|
||||
return [.. result];
|
||||
}
|
||||
|
||||
static double CalcBucketWeight(List<FrostFsNodeInfo> ns, IAggregator a, Func<FrostFsNodeInfo, double> wf)
|
||||
{
|
||||
foreach (var node in ns)
|
||||
{
|
||||
a.Add(wf(node));
|
||||
}
|
||||
|
||||
return a.Compute();
|
||||
}
|
||||
|
||||
// getSelection returns nodes grouped by s.attribute.
|
||||
// Last argument specifies if more buckets can be used to fulfill CBF.
|
||||
internal List<List<FrostFsNodeInfo>> GetSelection(FrostFsSelector s)
|
||||
{
|
||||
var (bucketCount, nodesInBucket) = CalcNodesCount(s);
|
||||
|
||||
var buckets = GetSelectionBase(s);
|
||||
|
||||
if (Strict && buckets.Length < bucketCount)
|
||||
throw new FrostFsException($"errNotEnoughNodes: '{s.Name}'");
|
||||
|
||||
// We need deterministic output in case there is no pivot.
|
||||
// If pivot is set, buckets are sorted by HRW.
|
||||
// However, because initial order influences HRW order for buckets with equal weights,
|
||||
// we also need to have deterministic input to HRW sorting routine.
|
||||
if (HrwSeed == null || HrwSeed.Length == 0)
|
||||
{
|
||||
buckets = string.IsNullOrEmpty(s.Attribute)
|
||||
? [.. buckets.OrderBy(b => b.nodes[0].Hash())]
|
||||
: [.. buckets.OrderBy(b => b.attr)];
|
||||
}
|
||||
|
||||
var maxNodesInBucket = nodesInBucket * (int)Cbf;
|
||||
|
||||
var res = new List<List<FrostFsNodeInfo>>(buckets.Length);
|
||||
var fallback = new List<List<FrostFsNodeInfo>>(buckets.Length);
|
||||
|
||||
for (int i = 0; i < buckets.Length; i++)
|
||||
{
|
||||
var ns = buckets[i].nodes;
|
||||
if (ns.Length >= maxNodesInBucket)
|
||||
{
|
||||
res.Add(new List<FrostFsNodeInfo>(ns[..maxNodesInBucket]));
|
||||
}
|
||||
else if (ns.Length >= nodesInBucket)
|
||||
{
|
||||
fallback.Add(new List<FrostFsNodeInfo>(ns));
|
||||
}
|
||||
}
|
||||
|
||||
if (res.Count < bucketCount)
|
||||
{
|
||||
// Fallback to using minimum allowed backup factor (1).
|
||||
res = fallback;
|
||||
|
||||
if (Strict && res.Count < bucketCount)
|
||||
{
|
||||
throw new FrostFsException($"{errNotEnoughNodes}: {s}");
|
||||
}
|
||||
}
|
||||
|
||||
if (HrwSeed != null && HrwSeed.Length != 0)
|
||||
{
|
||||
var weights = new double[res.Count];
|
||||
var a = new MeanIQRAgg();
|
||||
|
||||
for (int i = 0; i < res.Count; i++)
|
||||
{
|
||||
a.Clear();
|
||||
weights[i] = CalcBucketWeight(res[i], a, weightFunc);
|
||||
}
|
||||
|
||||
var hashers = res.Select(r => new HasherList(r)).ToList();
|
||||
Tools.SortHasherSliceByWeightValue(hashers, weights, HrwSeedHash);
|
||||
}
|
||||
|
||||
if (res.Count < bucketCount)
|
||||
{
|
||||
if (Strict && res.Count == 0)
|
||||
{
|
||||
throw new FrostFsException(errNotEnoughNodes);
|
||||
}
|
||||
|
||||
bucketCount = res.Count;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(s.Attribute))
|
||||
{
|
||||
fallback = res.Skip(bucketCount).ToList();
|
||||
res = res.Take(bucketCount).ToList();
|
||||
|
||||
for (int i = 0; i < fallback.Count; i++)
|
||||
{
|
||||
var index = i % bucketCount;
|
||||
if (res[index].Count >= maxNodesInBucket)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
res[index].AddRange(fallback[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return res.Take(bucketCount).ToList();
|
||||
}
|
||||
|
||||
internal bool MatchKeyValue(FrostFsFilter f, FrostFsNodeInfo nodeInfo)
|
||||
{
|
||||
switch (f.Operation)
|
||||
{
|
||||
case (int)Operation.EQ:
|
||||
return nodeInfo.Attributes[f.Key] == f.Value;
|
||||
case (int)Operation.LIKE:
|
||||
{
|
||||
var hasPrefix = f.Value.StartsWith(likeWildcard, StringComparison.Ordinal);
|
||||
var hasSuffix = f.Value.EndsWith(likeWildcard, StringComparison.Ordinal);
|
||||
|
||||
var start = hasPrefix ? likeWildcard.Length : 0;
|
||||
var end = hasSuffix ? f.Value.Length - likeWildcard.Length : f.Value.Length;
|
||||
var str = f.Value[start..end];
|
||||
|
||||
if (hasPrefix && hasSuffix)
|
||||
return nodeInfo.Attributes[f.Key].Contains(str);
|
||||
|
||||
if (hasPrefix && !hasSuffix)
|
||||
return nodeInfo.Attributes[f.Key].EndsWith(str, StringComparison.Ordinal);
|
||||
|
||||
if (!hasPrefix && hasSuffix)
|
||||
return nodeInfo.Attributes[f.Key].StartsWith(str, StringComparison.Ordinal);
|
||||
|
||||
|
||||
return nodeInfo.Attributes[f.Key] == f.Value;
|
||||
}
|
||||
case (int)Operation.NE:
|
||||
return nodeInfo.Attributes[f.Key] != f.Value;
|
||||
default:
|
||||
{
|
||||
var attr = f.Key switch
|
||||
{
|
||||
FrostFsNodeInfo.AttrPrice => nodeInfo.Price,
|
||||
FrostFsNodeInfo.AttrCapacity => nodeInfo.GetCapacity(),
|
||||
_ => uint.Parse(nodeInfo.Attributes[f.Key], CultureInfo.InvariantCulture),
|
||||
};
|
||||
|
||||
switch (f.Operation)
|
||||
{
|
||||
case (int)Operation.GT:
|
||||
return attr > NumCache[f.Value];
|
||||
case (int)Operation.GE:
|
||||
return attr >= NumCache[f.Value];
|
||||
case (int)Operation.LT:
|
||||
return attr < NumCache[f.Value];
|
||||
case (int)Operation.LE:
|
||||
return attr <= NumCache[f.Value];
|
||||
default:
|
||||
// do nothing and return false
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// will not happen if context was created from f (maybe panic?)
|
||||
return false;
|
||||
}
|
||||
|
||||
// match matches f against b. It returns no errors because
|
||||
// filter should have been parsed during context creation
|
||||
// and missing node properties are considered as a regular fail.
|
||||
internal bool Match(FrostFsFilter f, FrostFsNodeInfo nodeInfo)
|
||||
{
|
||||
switch (f.Operation)
|
||||
{
|
||||
case (int)Operation.NOT:
|
||||
{
|
||||
var inner = f.Filters;
|
||||
var fSub = inner[0];
|
||||
|
||||
if (!string.IsNullOrEmpty(inner[0].Name))
|
||||
{
|
||||
fSub = ProcessedFilters[inner[0].Name];
|
||||
}
|
||||
return !Match(fSub, nodeInfo);
|
||||
}
|
||||
case (int)Operation.AND:
|
||||
case (int)Operation.OR:
|
||||
{
|
||||
for (int i = 0; i < f.Filters.Length; i++)
|
||||
{
|
||||
var fSub = f.Filters[i];
|
||||
|
||||
if (!string.IsNullOrEmpty(f.Filters[i].Name))
|
||||
{
|
||||
fSub = ProcessedFilters[f.Filters[i].Name];
|
||||
}
|
||||
|
||||
var ok = Match(fSub, nodeInfo);
|
||||
|
||||
if (ok == (f.Operation == (int)Operation.OR))
|
||||
{
|
||||
return ok;
|
||||
}
|
||||
}
|
||||
|
||||
return f.Operation == (int)Operation.AND;
|
||||
}
|
||||
default:
|
||||
return MatchKeyValue(f, nodeInfo);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
namespace FrostFS.SDK.Client.Models.Netmap.Placement;
|
||||
|
||||
internal sealed class HasherList : IHasher
|
||||
{
|
||||
private readonly List<FrostFsNodeInfo> _nodes;
|
||||
|
||||
internal HasherList(List<FrostFsNodeInfo> nodes)
|
||||
{
|
||||
_nodes = nodes;
|
||||
}
|
||||
|
||||
public ulong Hash()
|
||||
{
|
||||
return _nodes.Count > 0 ? _nodes[0].Hash() : 0;
|
||||
}
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
namespace FrostFS.SDK.Client.Models.Netmap.Placement;
|
||||
|
||||
internal interface IAggregator
|
||||
{
|
||||
void Add(double d);
|
||||
|
||||
double Compute();
|
||||
}
|
|
@ -1,6 +0,0 @@
|
|||
namespace FrostFS.SDK.Client.Models.Netmap.Placement;
|
||||
|
||||
internal interface IHasher
|
||||
{
|
||||
ulong Hash();
|
||||
}
|
|
@ -1,6 +0,0 @@
|
|||
namespace FrostFS.SDK.Client.Models.Netmap.Placement;
|
||||
|
||||
interface INormalizer
|
||||
{
|
||||
double Normalize(double w);
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
namespace FrostFS.SDK.Client.Models.Netmap.Placement;
|
||||
|
||||
internal struct MeanAgg
|
||||
{
|
||||
private double mean;
|
||||
private int count;
|
||||
|
||||
internal void Add(double n)
|
||||
{
|
||||
int c = count + 1;
|
||||
mean *= (double)count / c + n / c;
|
||||
|
||||
count++;
|
||||
}
|
||||
|
||||
internal readonly double Compute()
|
||||
{
|
||||
return mean;
|
||||
}
|
||||
}
|
|
@ -1,65 +0,0 @@
|
|||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
|
||||
namespace FrostFS.SDK.Client.Models.Netmap.Placement;
|
||||
|
||||
internal struct MeanIQRAgg : IAggregator
|
||||
{
|
||||
private const int minLn = 4;
|
||||
internal Collection<double> arr = [];
|
||||
|
||||
public MeanIQRAgg()
|
||||
{
|
||||
}
|
||||
|
||||
public readonly void Add(double d)
|
||||
{
|
||||
arr.Add(d);
|
||||
}
|
||||
|
||||
public readonly double Compute()
|
||||
{
|
||||
var length = arr.Count;
|
||||
if (length == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
var sorted = arr.OrderBy(p => p).ToArray();
|
||||
|
||||
double minV, maxV;
|
||||
|
||||
if (arr.Count < minLn)
|
||||
{
|
||||
minV = sorted[0];
|
||||
maxV = sorted[length - 1];
|
||||
}
|
||||
else
|
||||
{
|
||||
var start = length / minLn;
|
||||
var end = length * 3 / minLn - 1;
|
||||
|
||||
minV = sorted[start];
|
||||
maxV = sorted[end];
|
||||
}
|
||||
|
||||
var count = 0;
|
||||
double sum = 0;
|
||||
|
||||
foreach (var e in sorted)
|
||||
{
|
||||
if (e >= minV && e <= maxV)
|
||||
{
|
||||
sum += e;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
return sum / count;
|
||||
}
|
||||
|
||||
internal readonly void Clear()
|
||||
{
|
||||
arr.Clear();
|
||||
}
|
||||
}
|
|
@ -1,27 +0,0 @@
|
|||
namespace FrostFS.SDK.Client.Models.Netmap.Placement;
|
||||
|
||||
internal struct MinAgg
|
||||
{
|
||||
private double min;
|
||||
private bool minFound;
|
||||
|
||||
internal void Add(double n)
|
||||
{
|
||||
if (!minFound)
|
||||
{
|
||||
min = n;
|
||||
minFound = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (n < min)
|
||||
{
|
||||
min = n;
|
||||
}
|
||||
}
|
||||
|
||||
internal readonly double Compute()
|
||||
{
|
||||
return min;
|
||||
}
|
||||
}
|
|
@ -1,16 +0,0 @@
|
|||
namespace FrostFS.SDK.Client.Models.Netmap.Placement;
|
||||
|
||||
public enum Operation
|
||||
{
|
||||
Unspecified = 0,
|
||||
EQ,
|
||||
NE,
|
||||
GT,
|
||||
GE,
|
||||
LT,
|
||||
LE,
|
||||
OR,
|
||||
AND,
|
||||
NOT,
|
||||
LIKE
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
namespace FrostFS.SDK.Client.Models.Netmap.Placement;
|
||||
|
||||
internal struct ReverseMinNorm : INormalizer
|
||||
{
|
||||
internal double min;
|
||||
|
||||
public readonly double Normalize(double w) => (min + 1) / (w + 1);
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
using System.Collections.ObjectModel;
|
||||
|
||||
namespace FrostFS.SDK.Client.Models.Netmap.Placement;
|
||||
|
||||
internal struct SelectFilterExpr(uint cbf, FrostFsSelector selector, Collection<FrostFsFilter> filters)
|
||||
{
|
||||
internal uint Cbf { get; } = cbf;
|
||||
internal FrostFsSelector Selector { get; } = selector;
|
||||
internal Collection<FrostFsFilter> Filters { get; } = filters;
|
||||
}
|
|
@ -1,23 +0,0 @@
|
|||
namespace FrostFS.SDK.Client.Models.Netmap.Placement;
|
||||
|
||||
internal readonly struct SigmoidNorm : INormalizer
|
||||
{
|
||||
private readonly double _scale;
|
||||
|
||||
internal SigmoidNorm(double scale)
|
||||
{
|
||||
_scale = scale;
|
||||
}
|
||||
|
||||
public readonly double Normalize(double w)
|
||||
{
|
||||
if (_scale == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
var x = w / _scale;
|
||||
|
||||
return x / (1 + x);
|
||||
}
|
||||
}
|
|
@ -1,140 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
using static FrostFS.SDK.FrostFsNetmapSnapshot;
|
||||
|
||||
namespace FrostFS.SDK.Client.Models.Netmap.Placement;
|
||||
|
||||
public static class Tools
|
||||
{
|
||||
internal static ulong Distance(ulong x, ulong y)
|
||||
{
|
||||
var acc = x ^ y;
|
||||
acc ^= acc >> 33;
|
||||
acc *= 0xff51afd7ed558ccd;
|
||||
acc ^= acc >> 33;
|
||||
acc *= 0xc4ceb9fe1a85ec53;
|
||||
acc ^= acc >> 33;
|
||||
|
||||
return acc;
|
||||
}
|
||||
|
||||
internal static double ReverceNormalize(double r, double w)
|
||||
{
|
||||
return (r + 1) / (w + 1);
|
||||
}
|
||||
|
||||
internal static double Normalize(double r, double w)
|
||||
{
|
||||
if (r == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
var x = w / r;
|
||||
return x / (1 + x);
|
||||
}
|
||||
|
||||
internal static void AppendWeightsTo(FrostFsNodeInfo[] nodes, Func<FrostFsNodeInfo, double> wf, double[] weights)
|
||||
{
|
||||
if (weights.Length < nodes.Length)
|
||||
{
|
||||
weights = new double[nodes.Length];
|
||||
}
|
||||
|
||||
for (int i = 0; i < nodes.Length; i++)
|
||||
{
|
||||
weights[i] = wf(nodes[i]);
|
||||
}
|
||||
}
|
||||
|
||||
internal static void SortHasherSliceByWeightValue<T>(List<T> nodes, Span<double> weights, ulong hash) where T : IHasher
|
||||
{
|
||||
if (nodes.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var allEquals = true;
|
||||
|
||||
if (weights.Length > 1)
|
||||
{
|
||||
for (int i = 1; i < weights.Length; i++)
|
||||
{
|
||||
if (weights[i] != weights[0])
|
||||
{
|
||||
allEquals = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var dist = new ulong[nodes.Count];
|
||||
|
||||
if (allEquals)
|
||||
{
|
||||
for (int i = 0; i < dist.Length; i++)
|
||||
{
|
||||
var x = nodes[i].Hash();
|
||||
dist[i] = Distance(x, hash);
|
||||
}
|
||||
|
||||
SortHasherByDistance(nodes, dist, true);
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < dist.Length; i++)
|
||||
{
|
||||
var d = Distance(nodes[i].Hash(), hash);
|
||||
dist[i] = ulong.MaxValue - (ulong)(d * weights[i]);
|
||||
}
|
||||
|
||||
SortHasherByDistance(nodes, dist, false);
|
||||
}
|
||||
|
||||
internal static void SortHasherByDistance<T, N>(List<T> nodes, N[] dist, bool asc)
|
||||
{
|
||||
IndexedValue<T, N>[] indexes = new IndexedValue<T, N>[nodes.Count];
|
||||
for (int i = 0; i < dist.Length; i++)
|
||||
{
|
||||
indexes[i] = new IndexedValue<T, N>() { nodeInfo = nodes[i], dist = dist[i] };
|
||||
}
|
||||
|
||||
if (asc)
|
||||
{
|
||||
nodes = new List<T>(indexes
|
||||
.OrderBy(x => x.dist)
|
||||
.Select(x => x.nodeInfo).ToArray());
|
||||
}
|
||||
else
|
||||
{
|
||||
nodes = new List<T>(indexes
|
||||
.OrderByDescending(x => x.dist)
|
||||
.Select(x => x.nodeInfo)
|
||||
.ToArray());
|
||||
}
|
||||
}
|
||||
|
||||
internal static Func<FrostFsNodeInfo, double> DefaultWeightFunc(IReadOnlyList<FrostFsNodeInfo> nodes)
|
||||
{
|
||||
MeanAgg mean = new();
|
||||
MinAgg minV = new();
|
||||
|
||||
foreach (var node in nodes)
|
||||
{
|
||||
mean.Add(node.GetCapacity());
|
||||
minV.Add(node.Price);
|
||||
}
|
||||
|
||||
return NewWeightFunc(
|
||||
NewSigmoidNorm(mean.Compute()),
|
||||
NewReverseMinNorm(minV.Compute()));
|
||||
}
|
||||
|
||||
private struct IndexedValue<T, N>
|
||||
{
|
||||
internal T nodeInfo;
|
||||
internal N dist;
|
||||
}
|
||||
}
|
|
@ -1,48 +0,0 @@
|
|||
using FrostFS.Refs;
|
||||
using FrostFS.SDK.Client.Mappers.GRPC;
|
||||
|
||||
namespace FrostFS.SDK;
|
||||
|
||||
public class FrostFsAddress
|
||||
{
|
||||
private FrostFsObjectId? frostFsObjectId;
|
||||
private FrostFsContainerId? frostFsContainerId;
|
||||
private ObjectID? objectId;
|
||||
private ContainerID? containerId;
|
||||
|
||||
public FrostFsAddress(FrostFsContainerId frostFsContainerId, FrostFsObjectId frostFsObjectId)
|
||||
{
|
||||
FrostFsObjectId = frostFsObjectId ?? throw new System.ArgumentNullException(nameof(frostFsObjectId));
|
||||
FrostFsContainerId = frostFsContainerId ?? throw new System.ArgumentNullException(nameof(frostFsContainerId));
|
||||
}
|
||||
|
||||
internal FrostFsAddress(ObjectID objectId, ContainerID containerId)
|
||||
{
|
||||
ObjectId = objectId ?? throw new System.ArgumentNullException(nameof(objectId));
|
||||
ContainerId = containerId ?? throw new System.ArgumentNullException(nameof(containerId));
|
||||
}
|
||||
|
||||
public FrostFsObjectId FrostFsObjectId
|
||||
{
|
||||
get => frostFsObjectId ??= objectId!.ToModel();
|
||||
set => frostFsObjectId = value;
|
||||
}
|
||||
|
||||
public FrostFsContainerId FrostFsContainerId
|
||||
{
|
||||
get => frostFsContainerId ??= containerId!.ToModel();
|
||||
set => frostFsContainerId = value;
|
||||
}
|
||||
|
||||
public ObjectID ObjectId
|
||||
{
|
||||
get => objectId ??= frostFsObjectId!.ToMessage();
|
||||
set => objectId = value;
|
||||
}
|
||||
|
||||
public ContainerID ContainerId
|
||||
{
|
||||
get => containerId ??= frostFsContainerId!.ToMessage();
|
||||
set => containerId = value;
|
||||
}
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
namespace FrostFS.SDK;
|
||||
|
||||
public class FrostFsAttributePair(string key, string value)
|
||||
{
|
||||
public string Key { get; set; } = key;
|
||||
|
||||
public string Value { get; set; } = value;
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
namespace FrostFS.SDK;
|
||||
|
||||
public class FrostFsHeaderResult
|
||||
{
|
||||
public FrostFsObjectHeader? HeaderInfo { get; internal set; }
|
||||
|
||||
public FrostFsSplitInfo? SplitInfo { get; internal set; }
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
namespace FrostFS.SDK;
|
||||
|
||||
public class FrostFsLargeObject(FrostFsContainerId container) : FrostFsObject(container)
|
||||
{
|
||||
public ulong PayloadLength
|
||||
{
|
||||
get { return Header!.PayloadLength; }
|
||||
}
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
|
||||
namespace FrostFS.SDK;
|
||||
|
||||
public class FrostFsLinkObject : FrostFsObject
|
||||
{
|
||||
public FrostFsLinkObject(FrostFsContainerId containerId,
|
||||
SplitId splitId,
|
||||
FrostFsObjectHeader largeObjectHeader,
|
||||
IList<FrostFsObjectId> children)
|
||||
: base(containerId)
|
||||
{
|
||||
Header!.Split = new FrostFsSplit(splitId,
|
||||
null,
|
||||
null,
|
||||
largeObjectHeader,
|
||||
null,
|
||||
new ReadOnlyCollection<FrostFsObjectId>(children));
|
||||
}
|
||||
}
|
|
@ -1,74 +0,0 @@
|
|||
using System;
|
||||
|
||||
namespace FrostFS.SDK;
|
||||
|
||||
public class FrostFsObject
|
||||
{
|
||||
private byte[]? bytes;
|
||||
|
||||
/// <summary>
|
||||
/// Creates new instance from <c>ObjectHeader</c>
|
||||
/// </summary>
|
||||
/// <param name="header"></param> <summary>
|
||||
public FrostFsObject(FrostFsObjectHeader header)
|
||||
{
|
||||
Header = header;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates new instance with specified parameters
|
||||
/// </summary>
|
||||
/// <param name="container"></param>
|
||||
/// <param name="objectType"></param>
|
||||
public FrostFsObject(FrostFsContainerId container, FrostFsObjectType objectType = FrostFsObjectType.Regular)
|
||||
{
|
||||
Header = new FrostFsObjectHeader(containerId: container, type: objectType);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Header contains metadata for the object
|
||||
/// </summary>
|
||||
/// <value></value>
|
||||
public FrostFsObjectHeader Header { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The value is calculated internally as a hash of ObjectHeader. Do not use pre-calculated value is the object has been changed.
|
||||
/// </summary>
|
||||
public FrostFsObjectId? ObjectId
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A payload is obtained via stream reader
|
||||
/// </summary>
|
||||
/// <value>Reader for received data</value>
|
||||
public IObjectReader? ObjectReader { get; set; }
|
||||
|
||||
internal byte[] SingleObjectPayload
|
||||
{
|
||||
get { return bytes ?? []; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The size of payload cannot exceed <c>MaxObjectSize</c> value from <c>NetworkSettings</c>
|
||||
/// Used only for PutSingleObject method
|
||||
/// </summary>
|
||||
/// <value>Buffer for output data</value>
|
||||
public void SetSingleObjectPayload(byte[] bytes)
|
||||
{
|
||||
this.bytes = bytes;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Applied only for the last Object in chain in case of manual multipart uploading
|
||||
/// </summary>
|
||||
/// <param name="largeObject">Parent for multipart object</param>
|
||||
public void SetParent(FrostFsObjectHeader largeObjectHeader)
|
||||
{
|
||||
if (Header?.Split == null)
|
||||
throw new ArgumentNullException(nameof(largeObjectHeader), "Split value must not be null");
|
||||
|
||||
Header.Split.ParentHeader = largeObjectHeader;
|
||||
}
|
||||
}
|
|
@ -1,111 +0,0 @@
|
|||
namespace FrostFS.SDK;
|
||||
|
||||
public interface IObjectFilter
|
||||
{
|
||||
public FrostFsMatchType MatchType { get; set; }
|
||||
public string Key { get; set; }
|
||||
|
||||
string? GetSerializedValue();
|
||||
}
|
||||
|
||||
public abstract class FrostFsObjectFilter<T>(FrostFsMatchType matchType, string key, T value) : IObjectFilter
|
||||
{
|
||||
public FrostFsMatchType MatchType { get; set; } = matchType;
|
||||
public string Key { get; set; } = key;
|
||||
|
||||
public T Value { get; set; } = value;
|
||||
|
||||
public string? GetSerializedValue()
|
||||
{
|
||||
return Value?.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates filter to search by Attribute
|
||||
/// </summary>
|
||||
/// <param name="matchType">Match type</param>
|
||||
/// <param name="key">Attribute key</param>
|
||||
/// <param name="value">Attribute value</param>
|
||||
public class FilterByAttributePair(FrostFsMatchType matchType, string key, string value) : FrostFsObjectFilter<string>(matchType, key, value) { }
|
||||
|
||||
/// <summary>
|
||||
/// Creates filter to search by ObjectId
|
||||
/// </summary>
|
||||
/// <param name="matchType">Match type</param>
|
||||
/// <param name="objectId">ObjectId</param>
|
||||
public class FilterByObjectId(FrostFsMatchType matchType, FrostFsObjectId objectId) : FrostFsObjectFilter<FrostFsObjectId>(matchType, Constants.FilterHeaderObjectID, objectId) { }
|
||||
|
||||
/// <summary>
|
||||
/// Creates filter to search by OwnerId
|
||||
/// </summary>
|
||||
/// <param name="matchType">Match type</param>
|
||||
/// <param name="ownerId">ObjectId</param>
|
||||
public class FilterByOwnerId(FrostFsMatchType matchType, FrostFsOwner ownerId) : FrostFsObjectFilter<FrostFsOwner>(matchType, Constants.FilterHeaderOwnerID, ownerId) { }
|
||||
|
||||
/// <summary>
|
||||
/// Creates filter to search by Version
|
||||
/// </summary>
|
||||
/// <param name="matchType">Match type</param>
|
||||
/// <param name="version">Version</param>
|
||||
public class FilterByVersion(FrostFsMatchType matchType, FrostFsVersion version) : FrostFsObjectFilter<FrostFsVersion>(matchType, Constants.FilterHeaderVersion, version) { }
|
||||
|
||||
/// <summary>
|
||||
/// Creates filter to search by ContainerId
|
||||
/// </summary>
|
||||
/// <param name="matchType">Match type</param>
|
||||
/// <param name="containerId">ContainerId</param>
|
||||
public class FilterByContainerId(FrostFsMatchType matchType, FrostFsContainerId containerId) : FrostFsObjectFilter<FrostFsContainerId>(matchType, Constants.FilterHeaderContainerID, containerId) { }
|
||||
|
||||
/// <summary>
|
||||
/// Creates filter to search by creation Epoch
|
||||
/// </summary>
|
||||
/// <param name="matchType">Match type</param>
|
||||
/// <param name="epoch">Creation Epoch</param>
|
||||
public class FilterByEpoch(FrostFsMatchType matchType, ulong epoch) : FrostFsObjectFilter<ulong>(matchType, Constants.FilterHeaderCreationEpoch, epoch) { }
|
||||
|
||||
/// <summary>
|
||||
/// Creates filter to search by Payload Length
|
||||
/// </summary>
|
||||
/// <param name="matchType">Match type</param>
|
||||
/// <param name="payloadLength">Payload Length</param>
|
||||
public class FilterByPayloadLength(FrostFsMatchType matchType, ulong payloadLength) : FrostFsObjectFilter<ulong>(matchType, Constants.FilterHeaderPayloadLength, payloadLength) { }
|
||||
|
||||
/// <summary>
|
||||
/// Creates filter to search by Payload Hash
|
||||
/// </summary>
|
||||
/// <param name="matchType">Match type</param>
|
||||
/// <param name="payloadHash">Payload Hash</param>
|
||||
public class FilterByPayloadHash(FrostFsMatchType matchType, CheckSum payloadHash) : FrostFsObjectFilter<CheckSum>(matchType, Constants.FilterHeaderPayloadHash, payloadHash) { }
|
||||
|
||||
/// <summary>
|
||||
/// Creates filter to search by Parent
|
||||
/// </summary>
|
||||
/// <param name="matchType">Match type</param>
|
||||
/// <param name="parentId">Parent</param>
|
||||
public class FilterByParent(FrostFsMatchType matchType, FrostFsObjectId parentId) : FrostFsObjectFilter<FrostFsObjectId>(matchType, Constants.FilterHeaderParent, parentId) { }
|
||||
|
||||
/// <summary>
|
||||
/// Creates filter to search by SplitId
|
||||
/// </summary>
|
||||
/// <param name="matchType">Match type</param>
|
||||
/// <param name="splitId">SplitId</param>
|
||||
public class FilterBySplitId(FrostFsMatchType matchType, SplitId splitId) : FrostFsObjectFilter<SplitId>(matchType, Constants.FilterHeaderSplitID, splitId) { }
|
||||
|
||||
/// <summary>
|
||||
/// Creates filter to search by Payload Hash
|
||||
/// </summary>
|
||||
/// <param name="matchType">Match type</param>
|
||||
/// <param name="ecParentId">Payload Hash</param>
|
||||
public class FilterByECParent(FrostFsMatchType matchType, FrostFsObjectId ecParentId) : FrostFsObjectFilter<FrostFsObjectId>(matchType, Constants.FilterHeaderECParent, ecParentId) { }
|
||||
|
||||
/// <summary>
|
||||
/// Creates filter to search Root objects
|
||||
/// </summary>
|
||||
public class FilterByRootObject() : FrostFsObjectFilter<string>(FrostFsMatchType.Unspecified, Constants.FilterHeaderRoot, string.Empty) { }
|
||||
|
||||
/// <summary>
|
||||
/// Creates filter to search objects that are physically stored on the server
|
||||
/// </summary
|
||||
public class FilterByPhysicallyStored() : FrostFsObjectFilter<string>(FrostFsMatchType.Unspecified, Constants.FilterHeaderPhy, string.Empty) { }
|
||||
|
|
@ -1,90 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
|
||||
using FrostFS.Object;
|
||||
|
||||
using FrostFS.SDK.Client.Mappers.GRPC;
|
||||
|
||||
namespace FrostFS.SDK;
|
||||
|
||||
public class FrostFsObjectHeader(
|
||||
FrostFsContainerId containerId,
|
||||
FrostFsObjectType type = FrostFsObjectType.Regular,
|
||||
FrostFsAttributePair[]? attributes = null,
|
||||
FrostFsSplit? split = null,
|
||||
FrostFsOwner? owner = null,
|
||||
FrostFsVersion? version = null)
|
||||
{
|
||||
private Header? header;
|
||||
private Container.Container.Types.Attribute[]? grpsAttributes;
|
||||
|
||||
public ReadOnlyCollection<FrostFsAttributePair>? Attributes { get; internal set; } =
|
||||
attributes == null ? null :
|
||||
new ReadOnlyCollection<FrostFsAttributePair>(attributes);
|
||||
|
||||
public FrostFsContainerId ContainerId { get; } = containerId;
|
||||
|
||||
public ulong PayloadLength { get; set; }
|
||||
|
||||
public byte[]? PayloadCheckSum { get; set; }
|
||||
|
||||
public FrostFsObjectType ObjectType { get; } = type;
|
||||
|
||||
public FrostFsOwner? OwnerId { get; internal set; } = owner;
|
||||
|
||||
public FrostFsVersion? Version { get; internal set; } = version;
|
||||
|
||||
public FrostFsSplit? Split { get; internal set; } = split;
|
||||
|
||||
internal Container.Container.Types.Attribute[]? GetGrpsAttributes()
|
||||
{
|
||||
grpsAttributes ??= Attributes?
|
||||
.Select(a => new Container.Container.Types.Attribute { Key = a.Key, Value = a.Value })
|
||||
.ToArray();
|
||||
|
||||
return grpsAttributes;
|
||||
}
|
||||
|
||||
public Header GetHeader()
|
||||
{
|
||||
if (header == null)
|
||||
{
|
||||
var objTypeName = ObjectType switch
|
||||
{
|
||||
FrostFsObjectType.Regular => Object.ObjectType.Regular,
|
||||
FrostFsObjectType.Lock => Object.ObjectType.Lock,
|
||||
FrostFsObjectType.Tombstone => Object.ObjectType.Tombstone,
|
||||
_ => throw new ArgumentException($"Unknown ObjectType. Value: '{ObjectType}'.")
|
||||
};
|
||||
|
||||
this.header = new Header
|
||||
{
|
||||
OwnerId = OwnerId?.ToMessage(),
|
||||
Version = Version?.ToMessage(),
|
||||
ContainerId = ContainerId.ToMessage(),
|
||||
ObjectType = objTypeName,
|
||||
PayloadLength = PayloadLength
|
||||
};
|
||||
|
||||
if (Attributes != null)
|
||||
{
|
||||
foreach (var attribute in Attributes)
|
||||
{
|
||||
this.header.Attributes.Add(attribute.ToMessage());
|
||||
}
|
||||
}
|
||||
|
||||
var split = Split;
|
||||
if (split != null)
|
||||
{
|
||||
this.header.Split = new Header.Types.Split
|
||||
{
|
||||
SplitId = split!.SplitId != null ? split.SplitId.GetSplitId() : null
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return this.header;
|
||||
}
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
using System;
|
||||
|
||||
using FrostFS.SDK.Cryptography;
|
||||
|
||||
namespace FrostFS.SDK;
|
||||
|
||||
public class FrostFsObjectId(string id)
|
||||
{
|
||||
public string Value { get; } = id;
|
||||
|
||||
public static FrostFsObjectId FromHash(ReadOnlySpan<byte> hash)
|
||||
{
|
||||
if (hash.Length != Constants.Sha256HashLength)
|
||||
throw new FormatException("ObjectID must be a sha256 hash.");
|
||||
|
||||
return new FrostFsObjectId(Base58.Encode(hash));
|
||||
}
|
||||
|
||||
public byte[] ToHash()
|
||||
{
|
||||
return Base58.Decode(Value);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Value;
|
||||
}
|
||||
}
|
|
@ -1,39 +0,0 @@
|
|||
using System.Security.Cryptography;
|
||||
|
||||
using FrostFS.Refs;
|
||||
using FrostFS.SDK.Client.Mappers.GRPC;
|
||||
using FrostFS.SDK.Cryptography;
|
||||
|
||||
|
||||
namespace FrostFS.SDK;
|
||||
|
||||
public class FrostFsOwner(string id)
|
||||
{
|
||||
private OwnerID? ownerID;
|
||||
|
||||
public string Value { get; } = id;
|
||||
|
||||
public static FrostFsOwner FromKey(ECDsa key)
|
||||
{
|
||||
return new FrostFsOwner(key.PublicKey().PublicKeyToAddress());
|
||||
}
|
||||
|
||||
internal OwnerID OwnerID
|
||||
{
|
||||
get
|
||||
{
|
||||
ownerID ??= this.ToMessage();
|
||||
return ownerID;
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] ToHash()
|
||||
{
|
||||
return Base58.Decode(Value);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Value;
|
||||
}
|
||||
}
|
|
@ -1,27 +0,0 @@
|
|||
namespace FrostFS.SDK;
|
||||
|
||||
public readonly struct FrostFsRange(ulong offset, ulong length) : System.IEquatable<FrostFsRange>
|
||||
{
|
||||
public ulong Offset { get; } = offset;
|
||||
|
||||
public ulong Length { get; } = length;
|
||||
|
||||
public override readonly bool Equals(object obj) => this == (FrostFsRange)obj;
|
||||
|
||||
public override readonly int GetHashCode() => $"{Offset}{Length}".GetHashCode();
|
||||
|
||||
public static bool operator ==(FrostFsRange left, FrostFsRange right)
|
||||
{
|
||||
return left.Equals(right);
|
||||
}
|
||||
|
||||
public static bool operator !=(FrostFsRange left, FrostFsRange right)
|
||||
{
|
||||
return !(left == right);
|
||||
}
|
||||
|
||||
public readonly bool Equals(FrostFsRange other)
|
||||
{
|
||||
return this == other;
|
||||
}
|
||||
}
|
|
@ -1,27 +0,0 @@
|
|||
using System.Collections.ObjectModel;
|
||||
|
||||
namespace FrostFS.SDK;
|
||||
|
||||
public class FrostFsSplit(SplitId splitId,
|
||||
FrostFsObjectId? previous = null,
|
||||
FrostFsObjectId? parent = null,
|
||||
FrostFsObjectHeader? parentHeader = null,
|
||||
FrostFsSignature? parentSignature = null,
|
||||
ReadOnlyCollection<FrostFsObjectId>? children = null)
|
||||
{
|
||||
public FrostFsSplit() : this(new SplitId())
|
||||
{
|
||||
}
|
||||
|
||||
public SplitId SplitId { get; private set; } = splitId;
|
||||
|
||||
public FrostFsObjectId? Previous { get; } = previous;
|
||||
|
||||
public FrostFsObjectId? Parent { get; } = parent;
|
||||
|
||||
public FrostFsSignature? ParentSignature { get; } = parentSignature;
|
||||
|
||||
public FrostFsObjectHeader? ParentHeader { get; set; } = parentHeader;
|
||||
|
||||
public ReadOnlyCollection<FrostFsObjectId>? Children { get; } = children;
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
using FrostFS.Object;
|
||||
using FrostFS.SDK.Cryptography;
|
||||
|
||||
namespace FrostFS.SDK;
|
||||
|
||||
public class FrostFsSplitInfo
|
||||
{
|
||||
private readonly SplitInfo _splitInfo;
|
||||
|
||||
private SplitId? _splitId;
|
||||
|
||||
private FrostFsObjectId? _link;
|
||||
|
||||
private FrostFsObjectId? _lastPart;
|
||||
|
||||
internal FrostFsSplitInfo(SplitInfo splitInfo)
|
||||
{
|
||||
_splitInfo = splitInfo;
|
||||
}
|
||||
|
||||
public SplitId SplitId => _splitId ??= new SplitId(_splitInfo.SplitId.ToUuid());
|
||||
|
||||
public FrostFsObjectId? Link => _link ??= _splitInfo.Link == null
|
||||
? null : FrostFsObjectId.FromHash(_splitInfo.Link.Value.Span);
|
||||
|
||||
public FrostFsObjectId? LastPart => _lastPart ??= _splitInfo.LastPart == null
|
||||
? null : FrostFsObjectId.FromHash(_splitInfo.LastPart.Value.Span);
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace FrostFS.SDK;
|
||||
|
||||
public interface IObjectReader : IDisposable
|
||||
{
|
||||
ValueTask<ReadOnlyMemory<byte>?> ReadChunk(CancellationToken cancellationToken = default);
|
||||
}
|
|
@ -1,62 +0,0 @@
|
|||
using System;
|
||||
|
||||
using FrostFS.SDK.Cryptography;
|
||||
|
||||
using Google.Protobuf;
|
||||
|
||||
namespace FrostFS.SDK;
|
||||
|
||||
public class SplitId
|
||||
{
|
||||
private readonly Guid id;
|
||||
|
||||
private ByteString? message;
|
||||
|
||||
public SplitId()
|
||||
{
|
||||
this.id = Guid.NewGuid();
|
||||
}
|
||||
|
||||
public SplitId(Guid id)
|
||||
{
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
private SplitId(byte[] binary)
|
||||
{
|
||||
this.id = new Guid(binary);
|
||||
}
|
||||
|
||||
private SplitId(string str)
|
||||
{
|
||||
this.id = new Guid(str);
|
||||
}
|
||||
|
||||
public static SplitId CreateFromBinary(byte[] binaryData)
|
||||
{
|
||||
return new SplitId(binaryData);
|
||||
}
|
||||
|
||||
public static SplitId CreateFromString(string stringData)
|
||||
{
|
||||
return new SplitId(stringData);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return this.id.ToString();
|
||||
}
|
||||
|
||||
public byte[]? ToBinary()
|
||||
{
|
||||
if (this.id == Guid.Empty)
|
||||
return null;
|
||||
|
||||
return this.id.ToBytes();
|
||||
}
|
||||
|
||||
public ByteString? GetSplitId()
|
||||
{
|
||||
return this.message ??= ByteString.CopyFrom(ToBinary());
|
||||
}
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
namespace FrostFS.SDK;
|
||||
|
||||
public class FrostFsResponseStatus(FrostFsStatusCode code, string? message = null)
|
||||
{
|
||||
public FrostFsStatusCode Code { get; set; } = code;
|
||||
public string Message { get; set; } = message ?? string.Empty;
|
||||
|
||||
public bool IsSuccess => Code == FrostFsStatusCode.Success;
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"Response status: {Code}. Message: {Message}.";
|
||||
}
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
namespace FrostFS.SDK;
|
||||
|
||||
public class FrostFsSignature()
|
||||
{
|
||||
public byte[]? Key { get; set; }
|
||||
|
||||
public byte[]? Sign { get; set; }
|
||||
|
||||
public SignatureScheme Scheme { get; set; }
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
namespace FrostFS.SDK;
|
||||
|
||||
public class MetaHeader(FrostFsVersion version, int epoch, int ttl)
|
||||
{
|
||||
public FrostFsVersion Version { get; set; } = version;
|
||||
public int Epoch { get; set; } = epoch;
|
||||
public int Ttl { get; set; } = ttl;
|
||||
|
||||
public static MetaHeader Default()
|
||||
{
|
||||
return new MetaHeader(
|
||||
new FrostFsVersion(
|
||||
major: 2,
|
||||
minor: 13
|
||||
),
|
||||
epoch: 0,
|
||||
ttl: 2
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,117 +0,0 @@
|
|||
using System;
|
||||
|
||||
using FrostFS.Refs;
|
||||
|
||||
using FrostFS.SDK.Client;
|
||||
using FrostFS.SDK.Cryptography;
|
||||
using FrostFS.Session;
|
||||
|
||||
using Google.Protobuf;
|
||||
|
||||
namespace FrostFS.SDK;
|
||||
|
||||
public class FrostFsSessionToken
|
||||
{
|
||||
private Guid _id;
|
||||
private ReadOnlyMemory<byte> _sessionKey;
|
||||
private readonly SessionToken.Types.Body _body;
|
||||
|
||||
private FrostFsSessionToken()
|
||||
{
|
||||
ProtoId = ByteString.Empty;
|
||||
ProtoSessionKey = ByteString.Empty;
|
||||
_body = new SessionToken.Types.Body();
|
||||
}
|
||||
|
||||
internal FrostFsSessionToken(SessionToken token)
|
||||
{
|
||||
ProtoId = token.Body.Id;
|
||||
ProtoSessionKey = token.Body.SessionKey;
|
||||
|
||||
_body = token.Body;
|
||||
}
|
||||
|
||||
public Guid Id
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_id == Guid.Empty)
|
||||
_id = ProtoId.ToUuid();
|
||||
|
||||
return _id;
|
||||
}
|
||||
}
|
||||
|
||||
public ReadOnlyMemory<byte> SessionKey
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_sessionKey.IsEmpty)
|
||||
_sessionKey = ProtoSessionKey.Memory;
|
||||
|
||||
return _sessionKey;
|
||||
}
|
||||
}
|
||||
|
||||
internal ByteString ProtoId { get; }
|
||||
|
||||
internal ByteString ProtoSessionKey { get; }
|
||||
|
||||
public SessionToken CreateContainerToken(ContainerID? containerId, ContainerSessionContext.Types.Verb verb, ClientKey key)
|
||||
{
|
||||
if (key is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(key));
|
||||
}
|
||||
|
||||
SessionToken sessionToken = new() { Body = _body.Clone() };
|
||||
|
||||
sessionToken.Body.Container = new() { Verb = verb };
|
||||
|
||||
if (containerId != null)
|
||||
sessionToken.Body.Container.ContainerId = containerId;
|
||||
else
|
||||
sessionToken.Body.Container.Wildcard = true;
|
||||
|
||||
sessionToken.Body.SessionKey = key.PublicKeyProto;
|
||||
|
||||
sessionToken.Signature = key.ECDsaKey.SignMessagePart(sessionToken.Body);
|
||||
|
||||
return sessionToken;
|
||||
}
|
||||
|
||||
public SessionToken CreateObjectTokenContext(Address address, ObjectSessionContext.Types.Verb verb, ClientKey key)
|
||||
{
|
||||
if (address is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(address));
|
||||
}
|
||||
|
||||
if (key is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(key));
|
||||
}
|
||||
|
||||
SessionToken sessionToken = new()
|
||||
{
|
||||
Body = _body.Clone()
|
||||
};
|
||||
|
||||
ObjectSessionContext.Types.Target target = new() { Container = address.ContainerId };
|
||||
|
||||
if (address.ObjectId != null)
|
||||
target.Objects.Add(address.ObjectId);
|
||||
|
||||
sessionToken.Body.Object = new()
|
||||
{
|
||||
Target = target,
|
||||
Verb = verb
|
||||
};
|
||||
|
||||
sessionToken.Body.SessionKey = key.PublicKeyProto;
|
||||
|
||||
sessionToken.Signature = key.ECDsaKey.SignMessagePart(sessionToken.Body);
|
||||
|
||||
return sessionToken;
|
||||
}
|
||||
}
|
|
@ -1,68 +0,0 @@
|
|||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using FrostFS.Object;
|
||||
using FrostFS.SDK.Client.Interfaces;
|
||||
|
||||
using Google.Protobuf;
|
||||
|
||||
namespace FrostFS.SDK.Client
|
||||
{
|
||||
internal sealed class ObjectWriter : IObjectWriter
|
||||
{
|
||||
private readonly ClientContext ctx;
|
||||
private readonly PrmObjectPutBase args;
|
||||
private readonly ObjectStreamer<PutRequest, PutResponse> streamer;
|
||||
private bool disposedValue;
|
||||
|
||||
internal ObjectWriter(ClientContext ctx, PrmObjectPutBase args, ObjectStreamer<PutRequest, PutResponse> streamer)
|
||||
{
|
||||
this.ctx = ctx;
|
||||
this.args = args;
|
||||
this.streamer = streamer;
|
||||
}
|
||||
|
||||
public async Task WriteAsync(ReadOnlyMemory<byte> memory)
|
||||
{
|
||||
var chunkRequest = new PutRequest
|
||||
{
|
||||
Body = new PutRequest.Types.Body
|
||||
{
|
||||
Chunk = UnsafeByteOperations.UnsafeWrap(memory)
|
||||
}
|
||||
};
|
||||
|
||||
chunkRequest.Sign(this.ctx.Key.ECDsaKey);
|
||||
|
||||
await streamer.Write(chunkRequest).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public async Task<FrostFsObjectId> CompleteAsync()
|
||||
{
|
||||
var response = await streamer.Close().ConfigureAwait(false);
|
||||
|
||||
Verifier.CheckResponse(response);
|
||||
|
||||
return FrostFsObjectId.FromHash(response.Body.ObjectId.Value.Span);
|
||||
}
|
||||
|
||||
private void Dispose(bool disposing)
|
||||
{
|
||||
if (!disposedValue)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
streamer.Dispose();
|
||||
}
|
||||
|
||||
disposedValue = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(disposing: true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,44 +0,0 @@
|
|||
using System;
|
||||
using System.Threading;
|
||||
|
||||
namespace FrostFS.SDK.Client;
|
||||
|
||||
public readonly struct CallContext(TimeSpan timeout, CancellationToken cancellationToken = default) : IEquatable<CallContext>
|
||||
{
|
||||
public CancellationToken CancellationToken { get; } = cancellationToken;
|
||||
|
||||
public TimeSpan Timeout { get; } = timeout;
|
||||
|
||||
internal readonly DateTime? GetDeadline()
|
||||
{
|
||||
return Timeout.Ticks > 0 ? DateTime.UtcNow.Add(Timeout) : null;
|
||||
}
|
||||
|
||||
public override readonly bool Equals(object obj)
|
||||
{
|
||||
if (obj == null || obj is not CallContext)
|
||||
return false;
|
||||
|
||||
return Equals((CallContext)obj);
|
||||
}
|
||||
|
||||
public bool Equals(CallContext other)
|
||||
{
|
||||
return Timeout == other.Timeout && CancellationToken.Equals(other.CancellationToken);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return CancellationToken.GetHashCode() ^ Timeout.GetHashCode();
|
||||
}
|
||||
|
||||
public static bool operator ==(CallContext left, CallContext right)
|
||||
{
|
||||
return left.Equals(right);
|
||||
}
|
||||
|
||||
public static bool operator !=(CallContext left, CallContext right)
|
||||
{
|
||||
return !(left == right);
|
||||
}
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
namespace FrostFS.SDK.Client;
|
||||
|
||||
public interface ISessionToken
|
||||
{
|
||||
/// <summary>
|
||||
/// Object represents token of the FrostFS Object session. A session is opened between any two sides of the
|
||||
/// system, and implements a mechanism for transferring the power of attorney of actions to another network
|
||||
/// member. The session has a limited validity period, and applies to a strictly defined set of operations.
|
||||
/// </summary>
|
||||
/// <value>Instance of the session obtained from the server</value>
|
||||
FrostFsSessionToken? SessionToken { get; }
|
||||
}
|
|
@ -1,43 +0,0 @@
|
|||
namespace FrostFS.SDK.Client;
|
||||
|
||||
public readonly struct PrmApeChainAdd(FrostFsChainTarget target, FrostFsChain chain, string[]? xheaders = null) : System.IEquatable<PrmApeChainAdd>
|
||||
{
|
||||
public FrostFsChainTarget Target { get; } = target;
|
||||
|
||||
public FrostFsChain Chain { get; } = chain;
|
||||
|
||||
/// <summary>
|
||||
/// FrostFS request X-Headers
|
||||
/// </summary>
|
||||
public string[] XHeaders { get; } = xheaders ?? [];
|
||||
|
||||
public override readonly bool Equals(object obj)
|
||||
{
|
||||
if (obj == null || obj is not PrmApeChainAdd)
|
||||
return false;
|
||||
|
||||
return Equals((PrmApeChainAdd)obj);
|
||||
}
|
||||
|
||||
public readonly bool Equals(PrmApeChainAdd other)
|
||||
{
|
||||
return Target == other.Target
|
||||
&& Chain == other.Chain
|
||||
&& XHeaders == other.XHeaders;
|
||||
}
|
||||
|
||||
public override readonly int GetHashCode()
|
||||
{
|
||||
return Chain.GetHashCode() ^ Target.GetHashCode() ^ XHeaders.GetHashCode();
|
||||
}
|
||||
|
||||
public static bool operator ==(PrmApeChainAdd left, PrmApeChainAdd right)
|
||||
{
|
||||
return left.Equals(right);
|
||||
}
|
||||
|
||||
public static bool operator !=(PrmApeChainAdd left, PrmApeChainAdd right)
|
||||
{
|
||||
return !(left == right);
|
||||
}
|
||||
}
|
|
@ -1,40 +0,0 @@
|
|||
namespace FrostFS.SDK.Client;
|
||||
|
||||
public readonly struct PrmApeChainList(FrostFsChainTarget target, string[]? xheaders = null) : System.IEquatable<PrmApeChainList>
|
||||
{
|
||||
public FrostFsChainTarget Target { get; } = target;
|
||||
|
||||
/// <summary>
|
||||
/// FrostFS request X-Headers
|
||||
/// </summary>
|
||||
public string[] XHeaders { get; } = xheaders ?? [];
|
||||
|
||||
public override readonly bool Equals(object obj)
|
||||
{
|
||||
if (obj == null || obj is not PrmApeChainList)
|
||||
return false;
|
||||
|
||||
return Equals((PrmApeChainList)obj);
|
||||
}
|
||||
|
||||
public override readonly int GetHashCode()
|
||||
{
|
||||
return Target.GetHashCode() ^ XHeaders.GetHashCode();
|
||||
}
|
||||
|
||||
public readonly bool Equals(PrmApeChainList other)
|
||||
{
|
||||
return Target == other.Target
|
||||
&& XHeaders == other.XHeaders;
|
||||
}
|
||||
|
||||
public static bool operator ==(PrmApeChainList left, PrmApeChainList right)
|
||||
{
|
||||
return left.Equals(right);
|
||||
}
|
||||
|
||||
public static bool operator !=(PrmApeChainList left, PrmApeChainList right)
|
||||
{
|
||||
return !(left == right);
|
||||
}
|
||||
}
|
|
@ -1,46 +0,0 @@
|
|||
namespace FrostFS.SDK.Client;
|
||||
|
||||
public readonly struct PrmApeChainRemove(
|
||||
FrostFsChainTarget target,
|
||||
FrostFsChain chain,
|
||||
string[]? xheaders = null) : System.IEquatable<PrmApeChainRemove>
|
||||
{
|
||||
public FrostFsChainTarget Target { get; } = target;
|
||||
|
||||
public FrostFsChain Chain { get; } = chain;
|
||||
|
||||
/// <summary>
|
||||
/// FrostFS request X-Headers
|
||||
/// </summary>
|
||||
public string[] XHeaders { get; } = xheaders ?? [];
|
||||
|
||||
public override readonly bool Equals(object obj)
|
||||
{
|
||||
if (obj == null || obj is not PrmApeChainRemove)
|
||||
return false;
|
||||
|
||||
return Equals((PrmApeChainRemove)obj);
|
||||
}
|
||||
|
||||
public readonly bool Equals(PrmApeChainRemove other)
|
||||
{
|
||||
return Target == other.Target
|
||||
&& Chain == other.Chain
|
||||
&& XHeaders == other.XHeaders;
|
||||
}
|
||||
|
||||
public override readonly int GetHashCode()
|
||||
{
|
||||
return Chain.GetHashCode() ^ Target.GetHashCode() ^ XHeaders.GetHashCode();
|
||||
}
|
||||
|
||||
public static bool operator ==(PrmApeChainRemove left, PrmApeChainRemove right)
|
||||
{
|
||||
return left.Equals(right);
|
||||
}
|
||||
|
||||
public static bool operator !=(PrmApeChainRemove left, PrmApeChainRemove right)
|
||||
{
|
||||
return !(left == right);
|
||||
}
|
||||
}
|
|
@ -1,61 +0,0 @@
|
|||
namespace FrostFS.SDK.Client;
|
||||
|
||||
public readonly struct PrmContainerCreate(
|
||||
FrostFsContainerInfo container,
|
||||
PrmWait waitParams,
|
||||
FrostFsSessionToken? sessionToken = null,
|
||||
string[]? xheaders = null) : ISessionToken, System.IEquatable<PrmContainerCreate>
|
||||
{
|
||||
public FrostFsContainerInfo Container { get; } = container;
|
||||
|
||||
/// <summary>
|
||||
/// Since the container becomes available with some delay, it needs to poll the container status
|
||||
/// </summary>
|
||||
/// <value>Rules for polling the result</value>
|
||||
public PrmWait WaitParams { get; } = waitParams;
|
||||
|
||||
/// <summary>
|
||||
/// Blank session token
|
||||
/// </summary>
|
||||
public FrostFsSessionToken? SessionToken { get; } = sessionToken;
|
||||
|
||||
/// <summary>
|
||||
/// FrostFS request X-Headers
|
||||
/// </summary>
|
||||
public string[] XHeaders { get; } = xheaders ?? [];
|
||||
|
||||
|
||||
public override readonly bool Equals(object obj)
|
||||
{
|
||||
if (obj == null || obj is not PrmContainerCreate)
|
||||
return false;
|
||||
|
||||
return Equals((PrmContainerCreate)obj);
|
||||
}
|
||||
|
||||
public readonly bool Equals(PrmContainerCreate other)
|
||||
{
|
||||
return Container == other.Container
|
||||
&& WaitParams == other.WaitParams
|
||||
&& SessionToken == other.SessionToken
|
||||
&& XHeaders == other.XHeaders;
|
||||
}
|
||||
|
||||
public override readonly int GetHashCode()
|
||||
{
|
||||
return Container.GetHashCode()
|
||||
^ WaitParams.GetHashCode()
|
||||
^ (SessionToken == null ? 0 : SessionToken.GetHashCode())
|
||||
^ XHeaders.GetHashCode();
|
||||
}
|
||||
|
||||
public static bool operator ==(PrmContainerCreate left, PrmContainerCreate right)
|
||||
{
|
||||
return left.Equals(right);
|
||||
}
|
||||
|
||||
public static bool operator !=(PrmContainerCreate left, PrmContainerCreate right)
|
||||
{
|
||||
return !(left == right);
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue