Decompiled source of CultOfTheButtplug v0.2.0
plugins/CultOfTheButtplug/Buttplug.Client.Connectors.WebsocketConnector.dll
Decompiled 9 months agousing System; using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using System.Threading; using System.Threading.Channels; using System.Threading.Tasks; using Buttplug.Core; using Buttplug.Core.Messages; using vtortola.WebSockets; using vtortola.WebSockets.Rfc6455; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName = ".NET Standard 2.0")] [assembly: AssemblyCompany("Nonpolynomial Labs, LLC")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyCopyright("Copyright Nonpolynomial Labs, LLC")] [assembly: AssemblyDescription("Websocket Connection Capabilities for Buttplug Clients. (.Net Standard 2.0+)")] [assembly: AssemblyFileVersion("3.0.1.0")] [assembly: AssemblyInformationalVersion("3.0.1")] [assembly: AssemblyProduct("Buttplug.Client.Connectors.WebsocketConnector")] [assembly: AssemblyTitle("Buttplug.Client.Connectors.WebsocketConnector")] [assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/buttplugio/buttplug-csharp")] [assembly: AssemblyVersion("3.0.1.0")] namespace Buttplug.Client.Connectors.WebsocketConnector; public class ButtplugWebsocketConnector : ButtplugRemoteJSONConnector, IButtplugClientConnector { private WebSocketClient _wsClient; private WebSocket _ws; private readonly SynchronizationContext _owningDispatcher = SynchronizationContext.Current ?? new SynchronizationContext(); private readonly Uri _uri; private Channel<string> _channel = Channel.CreateBounded<string>(256); private Task _readTask; public bool Connected { get { WebSocket ws = _ws; if (ws == null) { return false; } return ws.IsConnected; } } public event EventHandler Disconnected; public ButtplugWebsocketConnector(Uri uri) { _uri = uri; } public async Task ConnectAsync(CancellationToken token = default(CancellationToken)) { if (_ws != null) { throw new ButtplugHandshakeException("Websocket connector is already connected.", 0u, (Exception)null); } WebSocketListenerOptions val = new WebSocketListenerOptions { SendBufferSize = 8192, BufferManager = BufferManager.CreateBufferManager(819200L, 8192), PingTimeout = Timeout.InfiniteTimeSpan, PingMode = (PingMode)0 }; WebSocketFactoryCollectionExtensions.RegisterRfc6455(val.Standards, (Action<WebSocketFactoryRfc6455>)null); _wsClient = new WebSocketClient(val); try { _ws = await _wsClient.ConnectAsync(_uri, token).ConfigureAwait(continueOnCapturedContext: false); } catch (Exception ex) { throw new ButtplugClientConnectorException("Websocket Connection Exception! See Inner Exception", ex); } _readTask = Task.Run(async delegate { await RunClientLoop(token).ConfigureAwait(continueOnCapturedContext: false); }, token); } public async Task DisconnectAsync(CancellationToken token = default(CancellationToken)) { try { WebSocket ws = _ws; if (ws != null && ws.IsConnected) { await _ws.CloseAsync().ConfigureAwait(continueOnCapturedContext: false); } } catch { } await _readTask.ConfigureAwait(continueOnCapturedContext: false); } public async Task<ButtplugMessage> SendAsync(ButtplugMessage msg, CancellationToken token) { var (item, msgPromise) = ((ButtplugRemoteJSONConnector)this).PrepareMessage(msg); await _channel.Writer.WriteAsync(item); return await msgPromise.ConfigureAwait(continueOnCapturedContext: false); } private async Task RunClientLoop(CancellationToken token) { _ = 4; try { UTF8Encoding utf8NoBom = new UTF8Encoding(encoderShouldEmitUTF8Identifier: false, throwOnInvalidBytes: false); Task<WebSocketMessageReadStream> readTask = _ws.ReadMessageAsync(token); Task<string> writeTask = _channel.Reader.ReadAsync(token).AsTask(); while (_ws.IsConnected && !token.IsCancellationRequested) { await Task.WhenAny(new Task[2] { readTask, writeTask }); if (readTask.IsCompleted) { WebSocketMessageReadStream val = await readTask.ConfigureAwait(continueOnCapturedContext: false); if (val == null) { break; } if ((int)val.MessageType == 1) { string text = string.Empty; using (StreamReader reader = new StreamReader((Stream)(object)val, utf8NoBom)) { text = await reader.ReadToEndAsync(); } ((ButtplugRemoteJSONConnector)this).ReceiveMessages(text); } readTask = _ws.ReadMessageAsync(token); continue; } if (readTask.IsCanceled) { break; } if (writeTask.IsCompleted) { try { string text2 = await writeTask.ConfigureAwait(continueOnCapturedContext: false); if (text2 != null) { WebSocket ws = _ws; if (ws != null && ws.IsConnected) { await WebSocketStringExtensions.WriteStringAsync(_ws, text2, token).ConfigureAwait(continueOnCapturedContext: false); writeTask = _channel.Reader.ReadAsync(token).AsTask(); continue; } } } catch (WebSocketException val2) { WebSocketException val3 = val2; throw new ButtplugClientConnectorException("Websocket Client Read Error", (Exception)(object)val3); } break; } if (writeTask.IsCanceled) { Console.WriteLine("Write cancelled"); } } } catch (Exception) { } finally { _ws.CloseAsync().Dispose(); _ws = null; _owningDispatcher.Send(delegate { ((ButtplugRemoteJSONConnector)this).Dispose(); }, null); _owningDispatcher.Send(delegate { this.Disconnected?.Invoke(this, EventArgs.Empty); }, null); } } void IButtplugClientConnector.add_MessageReceived(EventHandler<MessageReceivedEventArgs> value) { ((ButtplugRemoteJSONConnector)this).MessageReceived += value; } void IButtplugClientConnector.remove_MessageReceived(EventHandler<MessageReceivedEventArgs> value) { ((ButtplugRemoteJSONConnector)this).MessageReceived -= value; } void IButtplugClientConnector.add_InvalidMessageReceived(EventHandler<ButtplugExceptionEventArgs> value) { ((ButtplugRemoteJSONConnector)this).InvalidMessageReceived += value; } void IButtplugClientConnector.remove_InvalidMessageReceived(EventHandler<ButtplugExceptionEventArgs> value) { ((ButtplugRemoteJSONConnector)this).InvalidMessageReceived -= value; } }
plugins/CultOfTheButtplug/Buttplug.dll
Decompiled 9 months agousing System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Serialization; using System.Runtime.Versioning; using System.Threading; using System.Threading.Tasks; using Buttplug.Core; using Buttplug.Core.Messages; using Newtonsoft.Json; using Newtonsoft.Json.Converters; using Newtonsoft.Json.Linq; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: InternalsVisibleTo("Buttplug.Test")] [assembly: InternalsVisibleTo("Buttplug.Client.Test")] [assembly: TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName = ".NET Standard 2.0")] [assembly: AssemblyCompany("Nonpolynomial Labs, LLC")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyCopyright("Copyright Nonpolynomial Labs, LLC")] [assembly: AssemblyDescription("Buttplug Sex Toy Control Library. Contains Core (messages, errors, etc), and Client components. Server can be found in Buttplug.FFI.Server (.Net Standard 2.0+)")] [assembly: AssemblyFileVersion("3.0.1.0")] [assembly: AssemblyInformationalVersion("3.0.1")] [assembly: AssemblyProduct("Buttplug")] [assembly: AssemblyTitle("Buttplug")] [assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/buttplugio/buttplug-csharp")] [assembly: AssemblyVersion("3.0.1.0")] namespace Buttplug.Core { public static class ButtplugConsts { public const uint SystemMsgId = 0u; public const uint DefaultMsgId = 1u; public const uint CurrentSpecVersion = 3u; } public class ButtplugDeviceException : ButtplugException { public ButtplugDeviceException(string message, uint id = 0u, Exception inner = null) : base(message, Error.ErrorClass.ERROR_DEVICE, id, inner) { } } public class ButtplugException : Exception { public Error ButtplugErrorMessage { get; } public static ButtplugException FromError(Error msg) { return msg.ErrorCode switch { Error.ErrorClass.ERROR_DEVICE => new ButtplugDeviceException(msg.ErrorMessage, msg.Id), Error.ErrorClass.ERROR_INIT => new ButtplugHandshakeException(msg.ErrorMessage, msg.Id), Error.ErrorClass.ERROR_MSG => new ButtplugMessageException(msg.ErrorMessage, msg.Id), Error.ErrorClass.ERROR_PING => new ButtplugPingException(msg.ErrorMessage, msg.Id), Error.ErrorClass.ERROR_UNKNOWN => new ButtplugException(msg.ErrorMessage, msg.Id), _ => new ButtplugException(msg.ErrorMessage, msg.Id), }; } public ButtplugException(string message, uint id = 0u, Exception inner = null) : this(message, Error.ErrorClass.ERROR_UNKNOWN, id, inner) { } public ButtplugException(string message, Error.ErrorClass err = Error.ErrorClass.ERROR_UNKNOWN, uint id = 0u, Exception inner = null) : base(message, inner) { ButtplugErrorMessage = new Error(message, err, id); } } public class ButtplugExceptionEventArgs : EventArgs { public ButtplugException Exception { get; } public ButtplugExceptionEventArgs(ButtplugException ex) { Exception = ex; } } public class ButtplugHandshakeException : ButtplugException { public ButtplugHandshakeException(string message, uint id = 0u, Exception inner = null) : base(message, Error.ErrorClass.ERROR_INIT, id, inner) { } } public class ButtplugJsonMessageParser { private readonly Dictionary<string, Type> _messageTypes; private readonly JsonSerializer _serializer; public ButtplugJsonMessageParser() { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Expected O, but got Unknown _serializer = new JsonSerializer { MissingMemberHandling = (MissingMemberHandling)1 }; _messageTypes = new Dictionary<string, Type>(); foreach (Type allMessageType in ButtplugUtils.GetAllMessageTypes()) { _messageTypes.Add(allMessageType.Name, allMessageType); } if (!_messageTypes.Any()) { throw new ButtplugMessageException("No message types available."); } } public IEnumerable<ButtplugMessage> Deserialize(string jsonMsg) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Expected O, but got Unknown //IL_0031: Expected O, but got Unknown //IL_005b: Expected O, but got Unknown //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) JsonTextReader val = new JsonTextReader((TextReader)new StringReader(jsonMsg)) { CloseInput = false, SupportMultipleContent = true }; List<ButtplugMessage> list = new List<ButtplugMessage>(); while (true) { try { if (!((JsonReader)val).Read()) { return list; } } catch (JsonReaderException val2) { JsonReaderException val3 = val2; throw new ButtplugMessageException("Not valid JSON: " + jsonMsg + " - " + ((Exception)(object)val3).Message); } JArray val4; try { val4 = JArray.Load((JsonReader)(object)val); } catch (JsonReaderException val5) { JsonReaderException val6 = val5; throw new ButtplugMessageException("Not valid JSON: " + jsonMsg + " - " + ((Exception)(object)val6).Message); } foreach (JObject item in ((JToken)val4).Children<JObject>()) { string name = item.Properties().First().Name; if (!_messageTypes.ContainsKey(name)) { throw new ButtplugMessageException(name + " is not a valid message class"); } list.Add(DeserializeAs(item, _messageTypes[name])); } } } private ButtplugMessage DeserializeAs(JObject obj, Type msgType) { //IL_00c0: Expected O, but got Unknown if (!msgType.IsSubclassOf(typeof(ButtplugMessage))) { throw new ButtplugMessageException("Type " + msgType.Name + " is not a subclass of ButtplugMessage"); } if (msgType.Namespace != "Buttplug.Core.Messages") { throw new ButtplugMessageException("Type " + msgType.Name + " (" + msgType.Namespace + ") is not in the namespace of Buttplug.Core.Messages"); } string name = ButtplugMessage.GetName(msgType); try { return (ButtplugMessage)((JToken)Extensions.Value<JObject>((IEnumerable<JToken>)obj[name])).ToObject(msgType, _serializer); } catch (InvalidCastException ex) { throw new ButtplugMessageException($"Could not create message for JSON {obj}: {ex.Message}"); } catch (JsonSerializationException val) { JsonSerializationException val2 = val; throw new ButtplugMessageException($"Could not create message for JSON {obj}: {((Exception)(object)val2).Message}"); } } public string Serialize(ButtplugMessage msg) { //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) if (msg.GetType().Namespace != "Buttplug.Core.Messages") { throw new ButtplugMessageException("Type " + msg.GetType().Name + " (" + msg.GetType().Namespace + ") is not in the namespace of Buttplug.Core.Messages"); } JObject val = ButtplugMessageToJObject(msg); if (val == null) { throw new ButtplugMessageException("Message cannot be converted to JSON.", msg.Id); } JArray val2 = new JArray(); val2.Add((JToken)(object)val); return ((JToken)val2).ToString((Formatting)0, Array.Empty<JsonConverter>()); } public string Serialize(IEnumerable<ButtplugMessage> msgs) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Expected O, but got Unknown JArray val = new JArray(); foreach (ButtplugMessage msg in msgs) { JObject val2 = ButtplugMessageToJObject(msg); if (val2 != null) { val.Add((JToken)(object)val2); } } if (!((IEnumerable<JToken>)val).Any()) { throw new ButtplugMessageException("No messages serialized."); } return ((JToken)val).ToString((Formatting)0, Array.Empty<JsonConverter>()); } private JObject ButtplugMessageToJObject(ButtplugMessage msg) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Expected O, but got Unknown //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Expected O, but got Unknown return new JObject((object)new JProperty(msg.Name, (object)JObject.FromObject((object)msg))); } } public class ButtplugMessageException : ButtplugException { public ButtplugMessageException(string message, uint id = 0u, Exception inner = null) : base(message, Error.ErrorClass.ERROR_MSG, id, inner) { } } public class ButtplugPingException : ButtplugException { public ButtplugPingException(string message, uint id = 0u, Exception inner = null) : base(message, Error.ErrorClass.ERROR_PING, id, inner) { } } public static class ButtplugUtils { public static IEnumerable<Type> GetAllMessageTypes() { IEnumerable<Type> enumerable; try { enumerable = Assembly.GetAssembly(typeof(ButtplugMessage))?.GetTypes(); } catch (ReflectionTypeLoadException ex) { enumerable = ex.Types; } return (enumerable ?? throw new InvalidOperationException()).Where((Type type) => type != null && type.IsClass && type.IsSubclassOf(typeof(ButtplugMessage)) && type != typeof(ButtplugDeviceMessage)); } [DebuggerStepThrough] public static void ArgumentNotNull(object argument, string argumentName) { if (argument == null) { throw new ArgumentNullException(argumentName); } } public static Type GetMessageType(string messageName) { return Type.GetType("Buttplug.Core.Messages." + messageName); } } } namespace Buttplug.Core.Messages { public class ButtplugDeviceMessage : ButtplugMessage { [JsonProperty(/*Could not decode attribute arguments.*/)] public uint DeviceIndex { get; set; } public ButtplugDeviceMessage(uint id = 1u, uint deviceIndex = uint.MaxValue) : base(id) { DeviceIndex = deviceIndex; } } public abstract class ButtplugMessage { private static readonly Dictionary<Type, ButtplugMessageMetadata> _metadataCache = new Dictionary<Type, ButtplugMessageMetadata>(); [JsonProperty(/*Could not decode attribute arguments.*/)] public uint Id { get; set; } [JsonIgnore] public string Name => GetName(GetType()); protected ButtplugMessage(uint id) { Id = id; } private static T GetMessageAttribute<T>(Type msgType, Func<ButtplugMessageMetadata, T> func) { ButtplugUtils.ArgumentNotNull(msgType, "msgType"); ButtplugUtils.ArgumentNotNull(func, "func"); if (!msgType.IsSubclassOf(typeof(ButtplugMessage))) { throw new ArgumentException("Argument " + msgType.Name + " must be a subclass of ButtplugMessage"); } if (_metadataCache.ContainsKey(msgType)) { return func(_metadataCache[msgType]); } Attribute[] customAttributes = Attribute.GetCustomAttributes(msgType); for (int i = 0; i < customAttributes.Length; i++) { if (customAttributes[i] is ButtplugMessageMetadata buttplugMessageMetadata) { _metadataCache[msgType] = buttplugMessageMetadata; return func(buttplugMessageMetadata); } } throw new ArgumentException($"Type {msgType} does not have ButtplugMessageMetadata Attributes"); } public static string GetName(Type msgType) { return GetMessageAttribute(msgType, (ButtplugMessageMetadata md) => md.Name); } } public interface IButtplugMessageOutgoingOnly { } public interface IButtplugDeviceInfoMessage { string DeviceName { get; } uint DeviceIndex { get; } DeviceMessageAttributes DeviceMessages { get; } string DeviceDisplayName { get; } uint DeviceMessageTimingGap { get; } } [AttributeUsage(AttributeTargets.Class)] public class ButtplugMessageMetadata : Attribute { public string Name { get; } public ButtplugMessageMetadata(string name) { Name = name; } } [JsonConverter(typeof(StringEnumConverter))] public enum ActuatorType { [EnumMember(Value = "Unknown")] Unknown, [EnumMember(Value = "Vibrate")] Vibrate, [EnumMember(Value = "Rotate")] Rotate, [EnumMember(Value = "Oscillate")] Oscillate, [EnumMember(Value = "Constrict")] Constrict, [EnumMember(Value = "Inflate")] Inflate, [EnumMember(Value = "Position")] Position } [JsonConverter(typeof(StringEnumConverter))] public enum SensorType { [EnumMember(Value = "Unknown")] Unknown, [EnumMember(Value = "Battery")] Battery, [EnumMember(Value = "RSSI")] RSSI, [EnumMember(Value = "Button")] Button, [EnumMember(Value = "Pressure")] Pressure } public class GenericDeviceMessageAttributes { [JsonIgnore] internal uint _index; [JsonProperty(/*Could not decode attribute arguments.*/)] public readonly string FeatureDescriptor; [JsonProperty(/*Could not decode attribute arguments.*/)] [JsonConverter(typeof(StringEnumConverter))] public readonly ActuatorType ActuatorType; [JsonProperty(/*Could not decode attribute arguments.*/)] public readonly uint StepCount; [JsonIgnore] public uint Index => _index; } public class SensorDeviceMessageAttributes { [JsonIgnore] internal uint _index; [JsonProperty(/*Could not decode attribute arguments.*/)] public readonly string FeatureDescriptor; [JsonProperty(/*Could not decode attribute arguments.*/)] [JsonConverter(typeof(StringEnumConverter))] public readonly SensorType SensorType; [JsonProperty(/*Could not decode attribute arguments.*/)] public readonly uint[][] SensorRange; [JsonIgnore] public uint Index => _index; } public class RawDeviceMessageAttributes { public readonly string[] Endpoints; } public class NullDeviceMessageAttributes { } public class DeviceMessageAttributes { public GenericDeviceMessageAttributes[] ScalarCmd; public GenericDeviceMessageAttributes[] RotateCmd; public GenericDeviceMessageAttributes[] LinearCmd; public SensorDeviceMessageAttributes[] SensorReadCmd; public SensorDeviceMessageAttributes[] SensorSubscribeCmd; public readonly RawDeviceMessageAttributes[] RawReadCmd; public readonly RawDeviceMessageAttributes[] RawWriteCmd; public readonly RawDeviceMessageAttributes[] RawSubscribeCmd; public readonly NullDeviceMessageAttributes StopDeviceCmd; [OnDeserialized] internal void OnDeserializedMethod(StreamingContext context) { ScalarCmd?.Select((GenericDeviceMessageAttributes x, int i) => (x, i)).ToList().ForEach(delegate((GenericDeviceMessageAttributes x, int i) x) { x.x._index = (uint)x.i; }); RotateCmd?.Select((GenericDeviceMessageAttributes x, int i) => (x, i)).ToList().ForEach(delegate((GenericDeviceMessageAttributes x, int i) x) { x.x._index = (uint)x.i; }); LinearCmd?.Select((GenericDeviceMessageAttributes x, int i) => (x, i)).ToList().ForEach(delegate((GenericDeviceMessageAttributes x, int i) x) { x.x._index = (uint)x.i; }); SensorReadCmd?.Select((SensorDeviceMessageAttributes x, int i) => (x, i)).ToList().ForEach(delegate((SensorDeviceMessageAttributes x, int i) x) { x.x._index = (uint)x.i; }); SensorSubscribeCmd?.Select((SensorDeviceMessageAttributes x, int i) => (x, i)).ToList().ForEach(delegate((SensorDeviceMessageAttributes x, int i) x) { x.x._index = (uint)x.i; }); } } public class MessageReceivedEventArgs : EventArgs { public ButtplugMessage Message { get; } public MessageReceivedEventArgs(ButtplugMessage message) { Message = message; } } [ButtplugMessageMetadata("Ok")] public class Ok : ButtplugMessage, IButtplugMessageOutgoingOnly { public Ok(uint id) : base(id) { } } [ButtplugMessageMetadata("Test")] public class Test : ButtplugMessage { private string _testStringImpl; [JsonProperty(/*Could not decode attribute arguments.*/)] public string TestString { get { return _testStringImpl; } set { if (value == "Error") { throw new ArgumentException("Got an Error Message"); } _testStringImpl = value; } } public Test(string str, uint id = 1u) : base(id) { TestString = str; } } [ButtplugMessageMetadata("Error")] public class Error : ButtplugMessage, IButtplugMessageOutgoingOnly { public enum ErrorClass { ERROR_UNKNOWN, ERROR_INIT, ERROR_PING, ERROR_MSG, ERROR_DEVICE } [JsonProperty(/*Could not decode attribute arguments.*/)] public ErrorClass ErrorCode; [JsonProperty(/*Could not decode attribute arguments.*/)] public string ErrorMessage; public Error(string errorMessage, ErrorClass errorCode, uint id) : base(id) { ErrorMessage = errorMessage; ErrorCode = errorCode; } } public class MessageAttributes : IEquatable<MessageAttributes> { [JsonProperty(/*Could not decode attribute arguments.*/)] public uint? FeatureCount; public MessageAttributes() { } public MessageAttributes(uint featureCount) { FeatureCount = featureCount; } public bool Equals(MessageAttributes attrs) { return FeatureCount == attrs.FeatureCount; } } public class DeviceMessageInfo : IButtplugDeviceInfoMessage { [JsonProperty(/*Could not decode attribute arguments.*/)] public readonly string DeviceName; [JsonProperty(/*Could not decode attribute arguments.*/)] public readonly uint DeviceIndex; public readonly string DeviceDisplayName; [JsonProperty(/*Could not decode attribute arguments.*/)] public readonly uint DeviceMessageTimingGap; [JsonProperty(/*Could not decode attribute arguments.*/)] public readonly DeviceMessageAttributes DeviceMessages; string IButtplugDeviceInfoMessage.DeviceName => DeviceName; uint IButtplugDeviceInfoMessage.DeviceIndex => DeviceIndex; DeviceMessageAttributes IButtplugDeviceInfoMessage.DeviceMessages => DeviceMessages; string IButtplugDeviceInfoMessage.DeviceDisplayName => DeviceDisplayName; uint IButtplugDeviceInfoMessage.DeviceMessageTimingGap => DeviceMessageTimingGap; public DeviceMessageInfo(uint index, string name, DeviceMessageAttributes messages) { DeviceName = name; DeviceIndex = index; DeviceMessages = messages; } } [ButtplugMessageMetadata("DeviceList")] public class DeviceList : ButtplugMessage, IButtplugMessageOutgoingOnly { [JsonProperty(/*Could not decode attribute arguments.*/)] public readonly DeviceMessageInfo[] Devices = new DeviceMessageInfo[0]; public DeviceList(DeviceMessageInfo[] deviceList, uint id) : base(id) { Devices = deviceList; } internal DeviceList() : base(0u) { } } [ButtplugMessageMetadata("DeviceAdded")] public class DeviceAdded : ButtplugDeviceMessage, IButtplugMessageOutgoingOnly, IButtplugDeviceInfoMessage { [JsonProperty(/*Could not decode attribute arguments.*/)] public string DeviceName; public readonly string DeviceDisplayName; [JsonProperty(/*Could not decode attribute arguments.*/)] public readonly uint DeviceMessageTimingGap; [JsonProperty(/*Could not decode attribute arguments.*/)] public readonly DeviceMessageAttributes DeviceMessages; string IButtplugDeviceInfoMessage.DeviceName => DeviceName; uint IButtplugDeviceInfoMessage.DeviceIndex => base.DeviceIndex; DeviceMessageAttributes IButtplugDeviceInfoMessage.DeviceMessages => DeviceMessages; string IButtplugDeviceInfoMessage.DeviceDisplayName => DeviceDisplayName; uint IButtplugDeviceInfoMessage.DeviceMessageTimingGap => DeviceMessageTimingGap; public DeviceAdded(uint index, string name, DeviceMessageAttributes messages) : base(0u, index) { DeviceName = name; DeviceMessages = messages; } internal DeviceAdded() : base(0u) { } } [ButtplugMessageMetadata("DeviceRemoved")] public class DeviceRemoved : ButtplugMessage, IButtplugMessageOutgoingOnly { [JsonProperty(/*Could not decode attribute arguments.*/)] public readonly uint DeviceIndex; public DeviceRemoved(uint index) : base(0u) { DeviceIndex = index; } } [ButtplugMessageMetadata("RequestDeviceList")] public class RequestDeviceList : ButtplugMessage { public RequestDeviceList(uint id = 1u) : base(id) { } } [ButtplugMessageMetadata("StartScanning")] public class StartScanning : ButtplugMessage { public StartScanning(uint id = 1u) : base(id) { } } [ButtplugMessageMetadata("StopScanning")] public class StopScanning : ButtplugMessage { public StopScanning(uint id = 1u) : base(id) { } } [ButtplugMessageMetadata("ScanningFinished")] public class ScanningFinished : ButtplugMessage, IButtplugMessageOutgoingOnly { public ScanningFinished() : base(0u) { } } [ButtplugMessageMetadata("RequestServerInfo")] public class RequestServerInfo : ButtplugMessage { [JsonProperty(/*Could not decode attribute arguments.*/)] public string ClientName; [JsonProperty(/*Could not decode attribute arguments.*/)] public uint MessageVersion; public RequestServerInfo(string clientName, uint id = 1u, uint schemversion = 3u) : base(id) { ClientName = clientName; MessageVersion = schemversion; } } [ButtplugMessageMetadata("ServerInfo")] public class ServerInfo : ButtplugMessage, IButtplugMessageOutgoingOnly { [JsonProperty(/*Could not decode attribute arguments.*/)] public uint MessageVersion; [JsonProperty(/*Could not decode attribute arguments.*/)] public uint MaxPingTime; [JsonProperty(/*Could not decode attribute arguments.*/)] public string ServerName; public ServerInfo(string serverName, uint messageVersion, uint maxPingTime, uint id = 1u) : base(id) { ServerName = serverName; MessageVersion = messageVersion; MaxPingTime = maxPingTime; } } [ButtplugMessageMetadata("Ping")] public class Ping : ButtplugMessage { public Ping(uint id = 1u) : base(id) { } } public class GenericMessageSubcommand { [JsonProperty(/*Could not decode attribute arguments.*/)] public uint Index; protected GenericMessageSubcommand(uint index) { Index = index; } } [ButtplugMessageMetadata("ScalarCmd")] public class ScalarCmd : ButtplugDeviceMessage { public class ScalarSubcommand : GenericMessageSubcommand { private double _scalarImpl; public readonly ActuatorType ActuatorType; [JsonProperty(/*Could not decode attribute arguments.*/)] public double Scalar { get { return _scalarImpl; } set { if (value < 0.0) { throw new ArgumentException("ScalarCmd value cannot be less than 0!"); } if (value > 1.0) { throw new ArgumentException("ScalarCmd value cannot be greater than 1!"); } _scalarImpl = value; } } public ScalarSubcommand(uint index, double scalar, ActuatorType actuatorType) : base(index) { Scalar = scalar; ActuatorType = actuatorType; } } [JsonProperty(/*Could not decode attribute arguments.*/)] public List<ScalarSubcommand> Scalars; [JsonConstructor] public ScalarCmd(uint deviceIndex, List<ScalarSubcommand> scalars, uint id = 1u) : base(id, deviceIndex) { Scalars = scalars; } public ScalarCmd(List<ScalarSubcommand> scalars) : this(uint.MaxValue, scalars) { } } [ButtplugMessageMetadata("RotateCmd")] public class RotateCmd : ButtplugDeviceMessage { public class RotateSubcommand : GenericMessageSubcommand { private double _speedImpl; [JsonProperty(/*Could not decode attribute arguments.*/)] public bool Clockwise; [JsonProperty(/*Could not decode attribute arguments.*/)] public double Speed { get { return _speedImpl; } set { if (value < 0.0) { throw new ArgumentException("RotateCmd Speed cannot be less than 0!"); } if (value > 1.0) { throw new ArgumentException("RotateCmd Speed cannot be greater than 1!"); } _speedImpl = value; } } public RotateSubcommand(uint index, double speed, bool clockwise) : base(index) { Speed = speed; Clockwise = clockwise; } } [JsonProperty(/*Could not decode attribute arguments.*/)] public List<RotateSubcommand> Rotations; public static RotateCmd Create(double speed, bool clockwise, uint cmdCount) { return Create(uint.MaxValue, 1u, Enumerable.Repeat((speed, clockwise), (int)cmdCount)); } public static RotateCmd Create(IEnumerable<(double speed, bool clockwise)> cmds) { return Create(uint.MaxValue, 1u, cmds); } public static RotateCmd Create(uint deviceIndex, uint msgId, double speed, bool clockwise, uint cmdCount) { return Create(deviceIndex, msgId, Enumerable.Repeat((speed, clockwise), (int)cmdCount)); } public static RotateCmd Create(uint deviceIndex, uint msgId, IEnumerable<(double speed, bool clockwise)> cmds) { List<RotateSubcommand> list = new List<RotateSubcommand>(cmds.Count()); uint num = 0u; foreach (var (speed, clockwise) in cmds) { list.Add(new RotateSubcommand(num, speed, clockwise)); num++; } return new RotateCmd(deviceIndex, list, msgId); } [JsonConstructor] public RotateCmd(uint deviceIndex, List<RotateSubcommand> rotations, uint id = 1u) : base(id, deviceIndex) { Rotations = rotations; } public RotateCmd(List<RotateSubcommand> rotations) : this(uint.MaxValue, rotations) { } } [ButtplugMessageMetadata("LinearCmd")] public class LinearCmd : ButtplugDeviceMessage { public class VectorSubcommand : GenericMessageSubcommand { private double _positionImpl; [JsonProperty(/*Could not decode attribute arguments.*/)] public uint Duration; [JsonProperty(/*Could not decode attribute arguments.*/)] public double Position { get { return _positionImpl; } set { if (value < 0.0) { throw new ArgumentException("LinearCmd Speed cannot be less than 0!"); } if (value > 1.0) { throw new ArgumentException("LinearCmd Speed cannot be greater than 1!"); } _positionImpl = value; } } public VectorSubcommand(uint index, uint duration, double position) : base(index) { Duration = duration; Position = position; } } [JsonProperty(/*Could not decode attribute arguments.*/)] public List<VectorSubcommand> Vectors; public static LinearCmd Create(uint duration, double position, uint cmdCount) { return Create(uint.MaxValue, 1u, Enumerable.Repeat((duration, position), (int)cmdCount)); } public static LinearCmd Create(uint deviceIndex, uint msgId, uint duration, double position, uint cmdCount) { return Create(deviceIndex, msgId, Enumerable.Repeat((duration, position), (int)cmdCount)); } public static LinearCmd Create(IEnumerable<(uint duration, double position)> cmds) { return Create(uint.MaxValue, 1u, cmds); } public static LinearCmd Create(uint deviceIndex, uint msgId, IEnumerable<(uint duration, double position)> cmds) { List<VectorSubcommand> list = new List<VectorSubcommand>(cmds.Count()); uint num = 0u; foreach (var (duration, position) in cmds) { list.Add(new VectorSubcommand(num, duration, position)); num++; } return new LinearCmd(deviceIndex, list, msgId); } [JsonConstructor] public LinearCmd(uint deviceIndex, List<VectorSubcommand> vectors, uint id = 1u) : base(id, deviceIndex) { Vectors = vectors; } public LinearCmd(List<VectorSubcommand> vectors) : this(uint.MaxValue, vectors) { } } [ButtplugMessageMetadata("StopDeviceCmd")] public class StopDeviceCmd : ButtplugDeviceMessage { public StopDeviceCmd(uint deviceIndex = uint.MaxValue, uint id = 1u) : base(id, deviceIndex) { } } [ButtplugMessageMetadata("StopAllDevices")] public class StopAllDevices : ButtplugMessage { public StopAllDevices(uint id = 1u) : base(id) { } } [ButtplugMessageMetadata("SensorReadCmd")] public class SensorReadCmd : ButtplugDeviceMessage { [JsonProperty(/*Could not decode attribute arguments.*/)] public uint SensorIndex; [JsonProperty(/*Could not decode attribute arguments.*/)] public SensorType SensorType; [JsonConstructor] public SensorReadCmd(uint deviceIndex, uint sensorIndex, SensorType sensorType, uint id = 1u) : base(id, deviceIndex) { SensorIndex = sensorIndex; SensorType = sensorType; } public SensorReadCmd(uint sensorIndex, SensorType sensorType) : this(uint.MaxValue, sensorIndex, sensorType) { } } [ButtplugMessageMetadata("SensorReading")] public class SensorReading : ButtplugDeviceMessage { [JsonProperty(/*Could not decode attribute arguments.*/)] public readonly uint SensorIndex; [JsonProperty(/*Could not decode attribute arguments.*/)] public readonly SensorType SensorType; [JsonProperty(/*Could not decode attribute arguments.*/)] public readonly List<int> data; } } namespace Buttplug.Client { public class ButtplugClient : IDisposable { protected Timer _pingTimer; internal ButtplugClientMessageHandler _handler; private readonly ConcurrentDictionary<uint, ButtplugClientDevice> _devices = new ConcurrentDictionary<uint, ButtplugClientDevice>(); private IButtplugClientConnector _connector; public string Name { get; } public ButtplugClientDevice[] Devices => _devices.Values.ToArray(); public bool Connected => _connector?.Connected ?? false; public event EventHandler<DeviceAddedEventArgs> DeviceAdded; public event EventHandler<DeviceRemovedEventArgs> DeviceRemoved; public event EventHandler<ButtplugExceptionEventArgs> ErrorReceived; public event EventHandler ScanningFinished; public event EventHandler PingTimeout; public event EventHandler ServerDisconnect; public ButtplugClient(string clientName) { Name = clientName; } public async Task ConnectAsync(IButtplugClientConnector connector, CancellationToken token = default(CancellationToken)) { if (Connected) { throw new ButtplugHandshakeException("Client already connected to a server."); } ButtplugUtils.ArgumentNotNull(connector, "connector"); _connector = connector; _connector.Disconnected += delegate(object obj, EventArgs eventArgs) { this.ServerDisconnect?.Invoke(obj, eventArgs); }; _connector.InvalidMessageReceived += ConnectorErrorHandler; _connector.MessageReceived += MessageReceivedHandler; _devices.Clear(); _handler = new ButtplugClientMessageHandler(connector); await _connector.ConnectAsync(token).ConfigureAwait(continueOnCapturedContext: false); ButtplugMessage res = await _handler.SendMessageAsync(new RequestServerInfo(Name), token).ConfigureAwait(continueOnCapturedContext: false); if (!(res is ServerInfo si)) { if (res is Error e) { await DisconnectAsync().ConfigureAwait(continueOnCapturedContext: false); throw ButtplugException.FromError(e); } await DisconnectAsync().ConfigureAwait(continueOnCapturedContext: false); throw new ButtplugHandshakeException("Unrecognized message " + res.Name + " during handshake", res.Id); } if (si.MaxPingTime != 0) { _pingTimer?.Dispose(); _pingTimer = new Timer(OnPingTimer, null, 0, Convert.ToInt32(Math.Round((double)si.MaxPingTime / 2.0, 0))); } if (si.MessageVersion < 3) { await DisconnectAsync().ConfigureAwait(continueOnCapturedContext: false); throw new ButtplugHandshakeException($"Buttplug Server's schema version ({si.MessageVersion}) is less than the client's ({3u}). A newer server is required.", res.Id); } ButtplugMessage resp = await _handler.SendMessageAsync(new RequestDeviceList()).ConfigureAwait(continueOnCapturedContext: false); if (resp is DeviceList deviceList) { DeviceMessageInfo[] devices = deviceList.Devices; foreach (DeviceMessageInfo deviceMessageInfo in devices) { if (!_devices.ContainsKey(deviceMessageInfo.DeviceIndex)) { ButtplugClientDevice buttplugClientDevice = new ButtplugClientDevice(_handler, deviceMessageInfo); _devices[deviceMessageInfo.DeviceIndex] = buttplugClientDevice; this.DeviceAdded?.Invoke(this, new DeviceAddedEventArgs(buttplugClientDevice)); } } return; } await DisconnectAsync().ConfigureAwait(continueOnCapturedContext: false); if (resp is Error msg) { throw ButtplugException.FromError(msg); } throw new ButtplugHandshakeException("Received unknown response to DeviceList handshake query"); } public async Task DisconnectAsync() { if (Connected) { _connector.MessageReceived -= MessageReceivedHandler; await _connector.DisconnectAsync().ConfigureAwait(continueOnCapturedContext: false); this.ServerDisconnect?.Invoke(this, EventArgs.Empty); } } public async Task StartScanningAsync(CancellationToken token = default(CancellationToken)) { await _handler.SendMessageExpectOk(new StartScanning(), token).ConfigureAwait(continueOnCapturedContext: false); } public async Task StopScanningAsync(CancellationToken token = default(CancellationToken)) { await _handler.SendMessageExpectOk(new StopScanning(), token).ConfigureAwait(continueOnCapturedContext: false); } public async Task StopAllDevicesAsync(CancellationToken token = default(CancellationToken)) { await _handler.SendMessageExpectOk(new StopAllDevices(), token).ConfigureAwait(continueOnCapturedContext: false); } private void ConnectorErrorHandler(object sender, ButtplugExceptionEventArgs exception) { this.ErrorReceived?.Invoke(this, exception); } private async void MessageReceivedHandler(object sender, MessageReceivedEventArgs args) { ButtplugMessage message = args.Message; if (!(message is DeviceAdded deviceAdded)) { ButtplugClientDevice value; if (!(message is DeviceRemoved deviceRemoved)) { if (!(message is ScanningFinished)) { if (message is Error error) { this.ErrorReceived?.Invoke(this, new ButtplugExceptionEventArgs(ButtplugException.FromError(error))); if (error.ErrorCode == Error.ErrorClass.ERROR_PING) { this.PingTimeout?.Invoke(this, EventArgs.Empty); await DisconnectAsync().ConfigureAwait(continueOnCapturedContext: false); } } else { this.ErrorReceived?.Invoke(this, new ButtplugExceptionEventArgs(new ButtplugMessageException($"Got unhandled message: {message}", message.Id))); } } else { this.ScanningFinished?.Invoke(this, EventArgs.Empty); } } else if (!_devices.ContainsKey(deviceRemoved.DeviceIndex)) { this.ErrorReceived?.Invoke(this, new ButtplugExceptionEventArgs(new ButtplugDeviceException("Got device removed message for unknown device.", message.Id))); } else if (_devices.TryRemove(deviceRemoved.DeviceIndex, out value)) { this.DeviceRemoved?.Invoke(this, new DeviceRemovedEventArgs(value)); } } else { ButtplugClientDevice dev = new ButtplugClientDevice(_handler, deviceAdded); _devices.AddOrUpdate(deviceAdded.DeviceIndex, dev, (uint u, ButtplugClientDevice device) => dev); this.DeviceAdded?.Invoke(this, new DeviceAddedEventArgs(dev)); } } private async void OnPingTimer(object state) { try { await _handler.SendMessageExpectOk(new Ping()).ConfigureAwait(continueOnCapturedContext: false); } catch (Exception inner) { this.ErrorReceived?.Invoke(this, new ButtplugExceptionEventArgs(new ButtplugPingException("Exception thrown during ping update", 0u, inner))); await DisconnectAsync().ConfigureAwait(continueOnCapturedContext: false); } } protected virtual void Dispose(bool disposing) { DisconnectAsync().GetAwaiter().GetResult(); } public void Dispose() { Dispose(disposing: true); GC.SuppressFinalize(this); } } public class ButtplugClientConnectorException : ButtplugException { public ButtplugClientConnectorException(string message, Exception inner = null) : base(message, Error.ErrorClass.ERROR_UNKNOWN, 0u, inner) { } } public class ButtplugClientDevice { private readonly ButtplugClientMessageHandler _handler; public uint Index { get; } public string Name { get; } public string DisplayName { get; } public uint MessageTimingGap { get; } public DeviceMessageAttributes MessageAttributes { get; } public List<GenericDeviceMessageAttributes> VibrateAttributes => GenericAcutatorAttributes(ActuatorType.Vibrate); public List<GenericDeviceMessageAttributes> OscillateAttributes => GenericAcutatorAttributes(ActuatorType.Oscillate); public List<GenericDeviceMessageAttributes> RotateAttributes { get { if (MessageAttributes.RotateCmd != null) { return MessageAttributes.RotateCmd.ToList(); } return Enumerable.Empty<GenericDeviceMessageAttributes>().ToList(); } } public List<GenericDeviceMessageAttributes> LinearAttributes { get { if (MessageAttributes.LinearCmd != null) { return MessageAttributes.LinearCmd.ToList(); } return Enumerable.Empty<GenericDeviceMessageAttributes>().ToList(); } } public bool HasBattery => SensorReadAttributes(SensorType.Battery).Any(); internal ButtplugClientDevice(ButtplugClientMessageHandler handler, IButtplugDeviceInfoMessage devInfo) : this(handler, devInfo.DeviceIndex, devInfo.DeviceName, devInfo.DeviceMessages, devInfo.DeviceDisplayName, devInfo.DeviceMessageTimingGap) { ButtplugUtils.ArgumentNotNull(devInfo, "devInfo"); } internal ButtplugClientDevice(ButtplugClientMessageHandler handler, uint index, string name, DeviceMessageAttributes messages, string displayName, uint messageTimingGap) { ButtplugUtils.ArgumentNotNull(handler, "handler"); _handler = handler; Index = index; Name = name; MessageAttributes = messages; DisplayName = displayName; MessageTimingGap = messageTimingGap; } public List<GenericDeviceMessageAttributes> GenericAcutatorAttributes(ActuatorType actuator) { if (MessageAttributes.ScalarCmd != null) { return MessageAttributes.ScalarCmd.Where((GenericDeviceMessageAttributes x) => x.ActuatorType == actuator).ToList(); } return Enumerable.Empty<GenericDeviceMessageAttributes>().ToList(); } public async Task ScalarAsync(ScalarCmd.ScalarSubcommand command) { List<ScalarCmd.ScalarSubcommand> scalars = new List<ScalarCmd.ScalarSubcommand>(); GenericAcutatorAttributes(command.ActuatorType).ForEach(delegate(GenericDeviceMessageAttributes x) { scalars.Add(new ScalarCmd.ScalarSubcommand(x.Index, command.Scalar, command.ActuatorType)); }); if (!scalars.Any()) { throw new ButtplugDeviceException("Scalar command for device " + Name + " did not generate any commands. Are you sure the device supports the ActuatorType sent?"); } await _handler.SendMessageExpectOk(new ScalarCmd(Index, scalars)).ConfigureAwait(continueOnCapturedContext: false); } public async Task ScalarAsync(List<ScalarCmd.ScalarSubcommand> command) { if (!command.Any()) { throw new ArgumentException("Command List for ScalarAsync must have at least 1 command."); } await _handler.SendMessageExpectOk(new ScalarCmd(Index, command)).ConfigureAwait(continueOnCapturedContext: false); } public async Task VibrateAsync(double speed) { await ScalarAsync(new ScalarCmd.ScalarSubcommand(uint.MaxValue, speed, ActuatorType.Vibrate)); } public async Task VibrateAsync(IEnumerable<double> cmds) { List<GenericDeviceMessageAttributes> vibrateAttributes = VibrateAttributes; if (cmds.Count() > vibrateAttributes.Count()) { throw new ButtplugDeviceException($"Device {Name} only has {vibrateAttributes.Count()} vibrators, but {cmds.Count()} commands given."); } await ScalarAsync(vibrateAttributes.Select((GenericDeviceMessageAttributes x, int i) => new ScalarCmd.ScalarSubcommand(x.Index, cmds.ElementAt(i), ActuatorType.Vibrate)).ToList()).ConfigureAwait(continueOnCapturedContext: false); } public async Task VibrateAsync(IEnumerable<(uint, double)> cmds) { await ScalarAsync(cmds.Select(((uint, double) x) => new ScalarCmd.ScalarSubcommand(x.Item1, x.Item2, ActuatorType.Vibrate)).ToList()).ConfigureAwait(continueOnCapturedContext: false); } public async Task OscillateAsync(double speed) { await ScalarAsync(new ScalarCmd.ScalarSubcommand(uint.MaxValue, speed, ActuatorType.Oscillate)); } public async Task OscillateAsync(IEnumerable<double> cmds) { List<GenericDeviceMessageAttributes> oscillateAttributes = OscillateAttributes; if (cmds.Count() > oscillateAttributes.Count()) { throw new ButtplugDeviceException($"Device {Name} only has {oscillateAttributes.Count()} vibrators, but {cmds.Count()} commands given."); } await ScalarAsync(oscillateAttributes.Select((GenericDeviceMessageAttributes x, int i) => new ScalarCmd.ScalarSubcommand(x.Index, cmds.ElementAt(i), ActuatorType.Oscillate)).ToList()).ConfigureAwait(continueOnCapturedContext: false); } public async Task OscillateAsync(IEnumerable<(uint, double)> cmds) { await ScalarAsync(cmds.Select(((uint, double) x) => new ScalarCmd.ScalarSubcommand(x.Item1, x.Item2, ActuatorType.Oscillate)).ToList()).ConfigureAwait(continueOnCapturedContext: false); } public async Task RotateAsync(double speed, bool clockwise) { if (!RotateAttributes.Any()) { throw new ButtplugDeviceException("Device " + Name + " does not support rotation"); } RotateCmd rotateCmd = RotateCmd.Create(speed, clockwise, (uint)RotateAttributes.Count); rotateCmd.DeviceIndex = Index; await _handler.SendMessageExpectOk(rotateCmd).ConfigureAwait(continueOnCapturedContext: false); } public async Task RotateAsync(IEnumerable<(double, bool)> cmds) { if (!RotateAttributes.Any()) { throw new ButtplugDeviceException("Device " + Name + " does not support rotation"); } RotateCmd rotateCmd = RotateCmd.Create(cmds); rotateCmd.DeviceIndex = Index; await _handler.SendMessageExpectOk(rotateCmd).ConfigureAwait(continueOnCapturedContext: false); } public async Task LinearAsync(uint duration, double position) { if (!LinearAttributes.Any()) { throw new ButtplugDeviceException("Device " + Name + " does not support linear position"); } LinearCmd linearCmd = LinearCmd.Create(duration, position, (uint)LinearAttributes.Count); linearCmd.DeviceIndex = Index; await _handler.SendMessageExpectOk(linearCmd).ConfigureAwait(continueOnCapturedContext: false); } public async Task LinearAsync(IEnumerable<(uint, double)> cmds) { if (!LinearAttributes.Any()) { throw new ButtplugDeviceException("Device " + Name + " does not support linear position"); } LinearCmd linearCmd = LinearCmd.Create(cmds); linearCmd.DeviceIndex = Index; await _handler.SendMessageExpectOk(linearCmd).ConfigureAwait(continueOnCapturedContext: false); } public List<SensorDeviceMessageAttributes> SensorReadAttributes(SensorType sensor) { if (MessageAttributes.SensorReadCmd != null) { return MessageAttributes.SensorReadCmd.Where((SensorDeviceMessageAttributes x) => x.SensorType == sensor).ToList(); } return Enumerable.Empty<SensorDeviceMessageAttributes>().ToList(); } public async Task<double> BatteryAsync() { if (!HasBattery) { throw new ButtplugDeviceException("Device " + Name + " does not have battery capabilities."); } ButtplugMessage buttplugMessage = await _handler.SendMessageAsync(new SensorReadCmd(Index, SensorReadAttributes(SensorType.Battery).ElementAt(0).Index, SensorType.Battery)).ConfigureAwait(continueOnCapturedContext: false); if (!(buttplugMessage is SensorReading sensorReading)) { if (buttplugMessage is Error msg) { throw ButtplugException.FromError(msg); } throw new ButtplugMessageException("Message type " + buttplugMessage.Name + " not handled by BatteryAsync", buttplugMessage.Id); } return (double)sensorReading.data[0] / 100.0; } public async Task Stop() { await _handler.SendMessageExpectOk(new StopDeviceCmd(Index)).ConfigureAwait(continueOnCapturedContext: false); } } internal class ButtplugClientMessageHandler { private IButtplugClientConnector _connector; internal ButtplugClientMessageHandler(IButtplugClientConnector connector) { _connector = connector; } public async Task<ButtplugMessage> SendMessageAsync(ButtplugMessage msg, CancellationToken token = default(CancellationToken)) { if (!_connector.Connected) { throw new ButtplugClientConnectorException("Client not connected."); } return await _connector.SendAsync(msg, token).ConfigureAwait(continueOnCapturedContext: false); } public async Task SendMessageExpectOk(ButtplugMessage msg, CancellationToken token = default(CancellationToken)) { ButtplugMessage buttplugMessage = await SendMessageAsync(msg, token).ConfigureAwait(continueOnCapturedContext: false); if (!(buttplugMessage is Ok)) { if (buttplugMessage is Error msg2) { throw ButtplugException.FromError(msg2); } throw new ButtplugMessageException("Message type " + msg.Name + " not handled by SendMessageExpectOk", msg.Id); } } } public class ButtplugConnectorJSONParser { private readonly ButtplugJsonMessageParser _parser = new ButtplugJsonMessageParser(); public string Serialize(ButtplugMessage msg) { return _parser.Serialize(msg); } public string Serialize(ButtplugMessage[] msgs) { return _parser.Serialize(msgs); } public IEnumerable<ButtplugMessage> Deserialize(string msg) { return _parser.Deserialize(msg); } } public class ButtplugConnectorMessageSorter : IDisposable { private int _counter; private readonly ConcurrentDictionary<uint, TaskCompletionSource<ButtplugMessage>> _waitingMsgs = new ConcurrentDictionary<uint, TaskCompletionSource<ButtplugMessage>>(); public uint NextMsgId => Convert.ToUInt32(Interlocked.Increment(ref _counter)); public Task<ButtplugMessage> PrepareMessage(ButtplugMessage msg) { msg.Id = NextMsgId; TaskCompletionSource<ButtplugMessage> taskCompletionSource = new TaskCompletionSource<ButtplugMessage>(); _waitingMsgs.TryAdd(msg.Id, taskCompletionSource); return taskCompletionSource.Task; } public void CheckMessage(ButtplugMessage msg) { if (msg.Id == 0) { throw new ButtplugMessageException("Cannot sort message with System ID", msg.Id); } if (!_waitingMsgs.TryRemove(msg.Id, out var value)) { throw new ButtplugMessageException("Message with non-matching ID received.", msg.Id); } if (msg is Error msg2) { value.SetException(ButtplugException.FromError(msg2)); } else { value.SetResult(msg); } } protected virtual void Dispose(bool disposing) { foreach (TaskCompletionSource<ButtplugMessage> value in _waitingMsgs.Values) { value.TrySetException(new Exception("Sorter has been destroyed with live tasks still in queue.")); } } public void Dispose() { Dispose(disposing: true); GC.SuppressFinalize(this); } } public class ButtplugRemoteJSONConnector : IDisposable { private readonly ButtplugConnectorJSONParser _jsonSerializer = new ButtplugConnectorJSONParser(); private readonly ButtplugConnectorMessageSorter _msgSorter = new ButtplugConnectorMessageSorter(); public event EventHandler<MessageReceivedEventArgs> MessageReceived; public event EventHandler<ButtplugExceptionEventArgs> InvalidMessageReceived; protected Tuple<string, Task<ButtplugMessage>> PrepareMessage(ButtplugMessage msg) { Task<ButtplugMessage> item = _msgSorter.PrepareMessage(msg); return new Tuple<string, Task<ButtplugMessage>>(_jsonSerializer.Serialize(msg), item); } protected void ReceiveMessages(string jSONMsg) { IEnumerable<ButtplugMessage> enumerable; try { enumerable = _jsonSerializer.Deserialize(jSONMsg); } catch (ButtplugMessageException ex) { this.InvalidMessageReceived?.Invoke(this, new ButtplugExceptionEventArgs(ex)); return; } foreach (ButtplugMessage item in enumerable) { if (item.Id == 0) { this.MessageReceived?.Invoke(this, new MessageReceivedEventArgs(item)); continue; } try { _msgSorter.CheckMessage(item); } catch (ButtplugMessageException ex2) { this.InvalidMessageReceived?.Invoke(this, new ButtplugExceptionEventArgs(ex2)); } } } protected virtual void Dispose(bool disposing) { _msgSorter.Dispose(); } public void Dispose() { Dispose(disposing: true); GC.SuppressFinalize(this); } } public class DeviceAddedEventArgs { public readonly ButtplugClientDevice Device; public DeviceAddedEventArgs(ButtplugClientDevice device) { Device = device; } } public class DeviceRemovedEventArgs { public readonly ButtplugClientDevice Device; public DeviceRemovedEventArgs(ButtplugClientDevice device) { Device = device; } } public interface IButtplugClientConnector { bool Connected { get; } event EventHandler<MessageReceivedEventArgs> MessageReceived; event EventHandler<ButtplugExceptionEventArgs> InvalidMessageReceived; event EventHandler Disconnected; Task ConnectAsync(CancellationToken token = default(CancellationToken)); Task DisconnectAsync(CancellationToken token = default(CancellationToken)); Task<ButtplugMessage> SendAsync(ButtplugMessage msg, CancellationToken token = default(CancellationToken)); } }
plugins/CultOfTheButtplug/CultOfButtplug.dll
Decompiled 9 months agousing System; using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Threading; using System.Threading.Tasks; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using Buttplug.Client; using Buttplug.Client.Connectors.WebsocketConnector; using COTL_API.CustomFollowerCommand; using COTL_API.CustomSettings; using COTL_API.Helpers; using HarmonyLib; using Microsoft.CodeAnalysis; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("p1xel8ted")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyDescription("CultOfButtplug")] [assembly: AssemblyFileVersion("2.1.0")] [assembly: AssemblyInformationalVersion("2.1.0")] [assembly: AssemblyProduct("CultOfButtplug")] [assembly: AssemblyTitle("CultOfButtplug")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("2.1.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace CultOfButtplug { internal class ButtplugFollowerCommand : CustomFollowerCommand { public override string InternalName => "Buttplug_Follower_Command"; public override Sprite CommandIcon => TextureHelper.CreateSpriteFromPath(Path.Combine(Plugin.PluginPath, "Assets", "buttplug.png")); public override string GetTitle(Follower follower) { return "Fornicate With Follower"; } public override string GetDescription(Follower follower) { return "Bring follower Closer To God. Biblically. With Haptics."; } public override void Execute(interaction_FollowerInteraction interaction, FollowerCommands finalCommand) { interaction_FollowerInteraction interaction2 = interaction; Task.Run(async delegate { ButtplugClientDevice[] devices = Plugin.client.Devices; foreach (ButtplugClientDevice device in devices) { if (device.VibrateAttributes.Count > 0) { await Task.Delay(500); await device.VibrateAsync(1.0); await Task.Delay(500); await device.Stop(); } } }); ((MonoBehaviour)interaction2).StartCoroutine(interaction2.FrameDelayCallback((Action)delegate { //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Expected O, but got Unknown interaction2.eventListener.PlayFollowerVO(interaction2.generalAcknowledgeVO); interaction2.follower.Brain.HardSwapToTask((FollowerTask)new FollowerTask_Vomit()); })); interaction2.Close(true, true, false); } } internal class ButtplugInteraction { } [BepInPlugin("bsf.cutofbuttplug", "Cult of the Buttplug", "0.2.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] [HarmonyPatch] public class Plugin : BaseUnityPlugin { private const string PluginGuid = "bsf.cutofbuttplug"; private const string PluginName = "Cult of the Buttplug"; private const string PluginVer = "0.2.0"; public static ButtplugClient client = new ButtplugClient("Cult of the Buttplug"); internal static string PluginPath; internal static FollowerCommands? FollowerCommand; internal static ManualLogSource Log = null; internal static readonly Harmony Harmony = new Harmony("bsf.cutofbuttplug"); private CancellationTokenSource _connectionTokenSource = new CancellationTokenSource(); private static ConfigEntry<bool>? _allowIntifaceConnection { get; set; } public static bool AllowIntifaceConnection => _allowIntifaceConnection?.Value ?? true; private static ConfigEntry<bool>? _vibrateOnAttack { get; set; } public static bool VibrateOnAttack => _vibrateOnAttack?.Value ?? false; private static ConfigEntry<bool>? _vibrateOnPlayerDamage { get; set; } public static bool VibrateOnPlayerDamage => _vibrateOnPlayerDamage?.Value ?? true; private ConfigEntry<bool>? _allowButtplugInteraction { get; set; } public bool AllowButtplugInteraction => _allowButtplugInteraction?.Value ?? true; private void Awake() { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Expected O, but got Unknown PluginPath = Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location); Log = new ManualLogSource("Cult-of-the-Buttplug"); Logger.Sources.Add((ILogSource)(object)Log); Harmony.PatchAll(); _allowIntifaceConnection = ((BaseUnityPlugin)this).Config.Bind<bool>("Cult of the Buttplug", "Connect to Intiface Central", true, "Allow connection to Intiface Central for controlling sex toys."); _vibrateOnAttack = ((BaseUnityPlugin)this).Config.Bind<bool>("Cult of the Buttplug", "Vibrate on Attack", true, "Vibrate whenever enemy is damaged from player attack."); _vibrateOnPlayerDamage = ((BaseUnityPlugin)this).Config.Bind<bool>("Cult of the Buttplug", "Vibrate on Player Damage", true, "Vibrate whenever player takes damage."); _allowButtplugInteraction = ((BaseUnityPlugin)this).Config.Bind<bool>("Cult of the Buttplug", "Allow Fornication Follower Interaction", true, "Turn on follower interaction that will increase adoration/loyalty and control toys."); CustomSettingsManager.AddBepInExConfig("Cult of the Buttplug", "Allow Initface Central Connection", _allowIntifaceConnection, (Action<bool>)handleAllowIntifaceConnectionUpdate); CustomSettingsManager.AddBepInExConfig("Cult of the Buttplug", "Vibrate On Attack", _vibrateOnAttack, (Action<bool>)null); CustomSettingsManager.AddBepInExConfig("Cult of the Buttplug", "Vibrate On Player Damage", _vibrateOnPlayerDamage, (Action<bool>)null); CustomSettingsManager.AddBepInExConfig("Cult of the Buttplug", "Allow Follower Fornication interaction", _allowButtplugInteraction, (Action<bool>)handleAllowFollowerFornicationUpdate); handleAllowFollowerFornicationUpdate(AllowButtplugInteraction); handleAllowIntifaceConnectionUpdate(AllowIntifaceConnection); } private void handleAllowIntifaceConnectionUpdate(bool value) { if (value) { _connectionTokenSource = new CancellationTokenSource(); CancellationToken cancellationToken = _connectionTokenSource.Token; Task.Run(async delegate { L("Starting Intiface Central Connection Loop"); while (!cancellationToken.IsCancellationRequested) { if (!client.Connected) { try { await client.ConnectAsync((IButtplugClientConnector)new ButtplugWebsocketConnector(new Uri("ws://127.0.0.1:12345")), cancellationToken); } catch { await Task.Delay(2000); } } else { TaskCompletionSource<bool> disconnectWaiter = new TaskCompletionSource<bool>(); client.ServerDisconnect += delegate { disconnectWaiter.SetResult(result: true); }; await disconnectWaiter.Task; L("Intiface Central disconnected."); } } L("Stopping Intiface Central Connection Loop"); }); return; } if (client.Connected) { Task.Run(async delegate { await client.DisconnectAsync(); }); } _connectionTokenSource.Cancel(); _connectionTokenSource.Dispose(); } private void handleAllowFollowerFornicationUpdate(bool value) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) if (value) { L("Adding Buttplug Interaction Command."); FollowerCommand = CustomFollowerCommandManager.Add((CustomFollowerCommand)(object)new ButtplugFollowerCommand()); return; } FollowerCommands? followerCommand = FollowerCommand; if (followerCommand.HasValue) { L("Removing Buttplug Interacton Command."); CustomFollowerCommandManager.CustomFollowerCommandList.Remove(FollowerCommand.Value); } } public static void L(string message) { Log.LogWarning((object)message); } } } namespace CultOfButtplug.Patches { [HarmonyPatch] public static class Patches { [HarmonyPrefix] [HarmonyPatch(typeof(Health), "DealDamage")] public static void Health_DealDamage(ref Health? __instance, ref float Damage, ref GameObject Attacker) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Invalid comparison between Unknown and I4 //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Invalid comparison between Unknown and I4 if (__instance == null || (((int)__instance.team != 1 || !Plugin.VibrateOnPlayerDamage) && ((int)__instance.team != 2 || !Plugin.VibrateOnAttack))) { return; } ButtplugClientDevice[] devices = Plugin.client.Devices; foreach (ButtplugClientDevice device in devices) { if (device.VibrateAttributes.Count > 0) { float DamageClone = Damage; Task.Run(async delegate { await device.VibrateAsync((double)DamageClone / 5.0); await Task.Delay(100); await device.Stop(); }); } } Plugin.L($"Deal {Damage} damage!"); } } }
plugins/CultOfTheButtplug/deniszykov.WebSocketListener.dll
Decompiled 9 months ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Concurrent; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Collections.Specialized; using System.Diagnostics; using System.Globalization; using System.IO; using System.IO.Compression; using System.IO.Pipes; using System.Linq; using System.Linq.Expressions; using System.Net; using System.Net.Security; using System.Net.Sockets; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.ExceptionServices; using System.Security; using System.Security.Authentication; using System.Security.Cryptography; using System.Security.Cryptography.X509Certificates; using System.Text; using System.Threading; using System.Threading.Tasks; using JetBrains.Annotations; using vtortola.WebSockets.Async; using vtortola.WebSockets.Extensibility; using vtortola.WebSockets.Http; using vtortola.WebSockets.Rfc6455.Header; using vtortola.WebSockets.Tools; using vtortola.WebSockets.Transports; using vtortola.WebSockets.Transports.NamedPipes; using vtortola.WebSockets.Transports.Sockets; using vtortola.WebSockets.Transports.Tcp; using vtortola.WebSockets.Transports.UnixSockets; [assembly: AssemblyCompany("deniszykov")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyDescription("A lightweight and highly scalable asynchronous WebSocket listener for .NET Core, .NET and Mono.\r\nhttps://github.com/deniszykov/WebSocketListener")] [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/deniszykov/WebSocketListener")] [assembly: AssemblyTitle("deniszykov.WebSocketListener")] [assembly: AssemblyInformationalVersion("4.2.16")] [assembly: AssemblyProduct("deniszykov.WebSocketListener")] [assembly: AssemblyFileVersion("4.2.16.0")] [assembly: AssemblyVersion("4.2.16.0")] namespace vtortola.WebSockets.Deflate { public sealed class WebSocketDeflateContext : IWebSocketMessageExtensionContext { public WebSocketMessageReadStream ExtendReader(WebSocketMessageReadStream message) { if (message == null) { throw new ArgumentNullException("message"); } if (message.Flags.Rsv1) { return new WebSocketDeflateReadStream(message); } return message; } public WebSocketMessageWriteStream ExtendWriter(WebSocketMessageWriteStream message) { if (message == null) { throw new ArgumentNullException("message"); } message.ExtensionFlags.Rsv1 = true; return new WebSocketDeflateWriteStream(message); } } public sealed class WebSocketDeflateExtension : IWebSocketMessageExtension { public const string EXTENSION_NAME = "permessage-deflate"; private static readonly ReadOnlyCollection<WebSocketExtensionOption> DefaultOptions = new ReadOnlyCollection<WebSocketExtensionOption>(new WebSocketExtensionOption[1] { new WebSocketExtensionOption("client_no_context_takeover") }); private static readonly WebSocketExtension DefaultResponse = new WebSocketExtension("permessage-deflate", DefaultOptions); public string Name => "permessage-deflate"; public bool TryNegotiate(WebSocketHttpRequest request, out WebSocketExtension extensionResponse, out IWebSocketMessageExtensionContext context) { if (request == null) { throw new ArgumentNullException("request"); } extensionResponse = DefaultResponse; context = new WebSocketDeflateContext(); return true; } public IWebSocketMessageExtension Clone() { return (WebSocketDeflateExtension)MemberwiseClone(); } public override string ToString() { return DefaultResponse.ToString(); } } public sealed class WebSocketDeflateReadStream : WebSocketMessageReadStream { private const int STATE_OPEN = 0; private const int STATE_CLOSED = 1; private const int STATE_DISPOSED = 2; private readonly WebSocketMessageReadStream innerStream; private readonly DeflateStream deflateStream; private volatile int state; public override WebSocketMessageType MessageType => innerStream.MessageType; public override WebSocketExtensionFlags Flags => innerStream.Flags; internal override WebSocketListenerOptions Options => innerStream.Options; public WebSocketDeflateReadStream([NotNull] WebSocketMessageReadStream innerStream) { if (innerStream == null) { throw new ArgumentNullException("innerStream"); } this.innerStream = innerStream; deflateStream = new DeflateStream(innerStream, CompressionMode.Decompress, leaveOpen: true); } public override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) { return deflateStream.ReadAsync(buffer, offset, count, cancellationToken); } public override Task CloseAsync() { if (Interlocked.CompareExchange(ref state, 1, 0) != 0) { return TaskHelper.CompletedTask; } return innerStream.CloseAsync(); } protected override void Dispose(bool disposing) { if (Interlocked.Exchange(ref state, 2) != 2) { SafeEnd.Dispose(deflateStream); SafeEnd.Dispose(innerStream); } } } public sealed class WebSocketDeflateWriteStream : WebSocketMessageWriteStream { private static readonly byte[] FINAL_BYTE = new byte[1]; private const int STATE_OPEN = 0; private const int STATE_CLOSED = 1; private const int STATE_DISPOSED = 2; private readonly WebSocketMessageWriteStream innerStream; private readonly DeflateStream deflateStream; private volatile int state; internal override WebSocketListenerOptions Options => innerStream.Options; public WebSocketDeflateWriteStream([NotNull] WebSocketMessageWriteStream innerStream) { if (innerStream == null) { throw new ArgumentNullException("innerStream"); } this.innerStream = innerStream; deflateStream = new DeflateStream(innerStream, CompressionLevel.Optimal, leaveOpen: true); } public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) { if (buffer == null) { throw new ArgumentNullException("buffer"); } if (offset < 0 || offset > buffer.Length) { throw new ArgumentOutOfRangeException("offset"); } if (count < 0 || offset + count > buffer.Length) { throw new ArgumentOutOfRangeException("count"); } if (count == 0) { return Task.FromResult(0); } return deflateStream.WriteAsync(buffer, offset, count, cancellationToken); } public override async Task WriteAndCloseAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) { if (buffer == null) { throw new ArgumentNullException("buffer"); } if (offset < 0 || offset > buffer.Length) { throw new ArgumentOutOfRangeException("offset"); } if (count < 0 || offset + count > buffer.Length) { throw new ArgumentOutOfRangeException("count"); } if (count > 0) { await deflateStream.WriteAsync(buffer, offset, count, cancellationToken); } await CloseAsync().ConfigureAwait(continueOnCapturedContext: false); } public override async Task CloseAsync() { if (Interlocked.CompareExchange(ref state, 1, 0) == 0) { await deflateStream.FlushAsync(CancellationToken.None); deflateStream.Dispose(); await innerStream.WriteAndCloseAsync(FINAL_BYTE, 0, 1, CancellationToken.None).ConfigureAwait(continueOnCapturedContext: false); } } protected override void Dispose(bool disposing) { if (Interlocked.Exchange(ref state, 2) != 2) { SafeEnd.Dispose(deflateStream); SafeEnd.Dispose(innerStream); base.Dispose(disposing); } } } public static class WebSocketMessageExtensionCollectionExtensions { public static WebSocketMessageExtensionCollection RegisterDeflateCompression(this WebSocketMessageExtensionCollection collection) { if (collection == null) { throw new ArgumentNullException("collection"); } collection.Add(new WebSocketDeflateExtension()); return collection; } } } namespace JetBrains.Annotations { [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Interface | AttributeTargets.Parameter | AttributeTargets.Delegate | AttributeTargets.GenericParameter)] internal sealed class CanBeNullAttribute : Attribute { } [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Interface | AttributeTargets.Parameter | AttributeTargets.Delegate | AttributeTargets.GenericParameter)] internal sealed class NotNullAttribute : Attribute { } [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Delegate)] internal sealed class ItemNotNullAttribute : Attribute { } [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Delegate)] internal sealed class ItemCanBeNullAttribute : Attribute { } [AttributeUsage(AttributeTargets.Constructor | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Delegate)] internal sealed class StringFormatMethodAttribute : Attribute { [NotNull] public string FormatParameterName { get; private set; } public StringFormatMethodAttribute([NotNull] string formatParameterName) { FormatParameterName = formatParameterName; } } [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = true)] internal sealed class ValueProviderAttribute : Attribute { [NotNull] public string Name { get; private set; } public ValueProviderAttribute([NotNull] string name) { Name = name; } } [AttributeUsage(AttributeTargets.Parameter)] internal sealed class InvokerParameterNameAttribute : Attribute { } [AttributeUsage(AttributeTargets.Method)] internal sealed class NotifyPropertyChangedInvocatorAttribute : Attribute { [CanBeNull] public string ParameterName { get; private set; } public NotifyPropertyChangedInvocatorAttribute() { } public NotifyPropertyChangedInvocatorAttribute([NotNull] string parameterName) { ParameterName = parameterName; } } [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] internal sealed class ContractAnnotationAttribute : Attribute { [NotNull] public string Contract { get; private set; } public bool ForceFullStates { get; private set; } public ContractAnnotationAttribute([NotNull] string contract) : this(contract, forceFullStates: false) { } public ContractAnnotationAttribute([NotNull] string contract, bool forceFullStates) { Contract = contract; ForceFullStates = forceFullStates; } } [AttributeUsage(AttributeTargets.All)] internal sealed class LocalizationRequiredAttribute : Attribute { public bool Required { get; private set; } public LocalizationRequiredAttribute() : this(required: true) { } public LocalizationRequiredAttribute(bool required) { Required = required; } } [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Interface)] internal sealed class CannotApplyEqualityOperatorAttribute : Attribute { } [BaseTypeRequired(typeof(Attribute))] [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] internal sealed class BaseTypeRequiredAttribute : Attribute { [NotNull] public Type BaseType { get; private set; } public BaseTypeRequiredAttribute([NotNull] Type baseType) { BaseType = baseType; } } [AttributeUsage(AttributeTargets.All)] internal sealed class UsedImplicitlyAttribute : Attribute { public ImplicitUseKindFlags UseKindFlags { get; private set; } public ImplicitUseTargetFlags TargetFlags { get; private set; } public UsedImplicitlyAttribute() : this(ImplicitUseKindFlags.Default, ImplicitUseTargetFlags.Default) { } public UsedImplicitlyAttribute(ImplicitUseKindFlags useKindFlags) : this(useKindFlags, ImplicitUseTargetFlags.Default) { } public UsedImplicitlyAttribute(ImplicitUseTargetFlags targetFlags) : this(ImplicitUseKindFlags.Default, targetFlags) { } public UsedImplicitlyAttribute(ImplicitUseKindFlags useKindFlags, ImplicitUseTargetFlags targetFlags) { UseKindFlags = useKindFlags; TargetFlags = targetFlags; } } [AttributeUsage(AttributeTargets.Class | AttributeTargets.GenericParameter)] internal sealed class MeansImplicitUseAttribute : Attribute { [UsedImplicitly] public ImplicitUseKindFlags UseKindFlags { get; private set; } [UsedImplicitly] public ImplicitUseTargetFlags TargetFlags { get; private set; } public MeansImplicitUseAttribute() : this(ImplicitUseKindFlags.Default, ImplicitUseTargetFlags.Default) { } public MeansImplicitUseAttribute(ImplicitUseKindFlags useKindFlags) : this(useKindFlags, ImplicitUseTargetFlags.Default) { } public MeansImplicitUseAttribute(ImplicitUseTargetFlags targetFlags) : this(ImplicitUseKindFlags.Default, targetFlags) { } public MeansImplicitUseAttribute(ImplicitUseKindFlags useKindFlags, ImplicitUseTargetFlags targetFlags) { UseKindFlags = useKindFlags; TargetFlags = targetFlags; } } [Flags] internal enum ImplicitUseKindFlags { Default = 7, Access = 1, Assign = 2, InstantiatedWithFixedConstructorSignature = 4, InstantiatedNoFixedConstructorSignature = 8 } [Flags] internal enum ImplicitUseTargetFlags { Default = 1, Itself = 1, Members = 2, WithMembers = 3 } [MeansImplicitUse(ImplicitUseTargetFlags.WithMembers)] internal sealed class PublicAPIAttribute : Attribute { [CanBeNull] public string Comment { get; private set; } public PublicAPIAttribute() { } public PublicAPIAttribute([NotNull] string comment) { Comment = comment; } } [AttributeUsage(AttributeTargets.Parameter)] internal sealed class InstantHandleAttribute : Attribute { } [AttributeUsage(AttributeTargets.Method)] internal sealed class PureAttribute : Attribute { } [AttributeUsage(AttributeTargets.Method)] internal sealed class MustUseReturnValueAttribute : Attribute { [CanBeNull] public string Justification { get; private set; } public MustUseReturnValueAttribute() { } public MustUseReturnValueAttribute([NotNull] string justification) { Justification = justification; } } [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Interface | AttributeTargets.Parameter | AttributeTargets.GenericParameter)] internal sealed class ProvidesContextAttribute : Attribute { } [AttributeUsage(AttributeTargets.Parameter)] internal sealed class PathReferenceAttribute : Attribute { [CanBeNull] public string BasePath { get; private set; } public PathReferenceAttribute() { } public PathReferenceAttribute([NotNull][PathReference] string basePath) { BasePath = basePath; } } [AttributeUsage(AttributeTargets.Method)] internal sealed class SourceTemplateAttribute : Attribute { } [AttributeUsage(AttributeTargets.Method | AttributeTargets.Parameter, AllowMultiple = true)] internal sealed class MacroAttribute : Attribute { [CanBeNull] public string Expression { get; set; } public int Editable { get; set; } [CanBeNull] public string Target { get; set; } } [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = true)] internal sealed class AspMvcAreaMasterLocationFormatAttribute : Attribute { [NotNull] public string Format { get; private set; } public AspMvcAreaMasterLocationFormatAttribute([NotNull] string format) { Format = format; } } [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = true)] internal sealed class AspMvcAreaPartialViewLocationFormatAttribute : Attribute { [NotNull] public string Format { get; private set; } public AspMvcAreaPartialViewLocationFormatAttribute([NotNull] string format) { Format = format; } } [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = true)] internal sealed class AspMvcAreaViewLocationFormatAttribute : Attribute { [NotNull] public string Format { get; private set; } public AspMvcAreaViewLocationFormatAttribute([NotNull] string format) { Format = format; } } [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = true)] internal sealed class AspMvcMasterLocationFormatAttribute : Attribute { [NotNull] public string Format { get; private set; } public AspMvcMasterLocationFormatAttribute([NotNull] string format) { Format = format; } } [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = true)] internal sealed class AspMvcPartialViewLocationFormatAttribute : Attribute { [NotNull] public string Format { get; private set; } public AspMvcPartialViewLocationFormatAttribute([NotNull] string format) { Format = format; } } [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = true)] internal sealed class AspMvcViewLocationFormatAttribute : Attribute { [NotNull] public string Format { get; private set; } public AspMvcViewLocationFormatAttribute([NotNull] string format) { Format = format; } } [AttributeUsage(AttributeTargets.Method | AttributeTargets.Parameter)] internal sealed class AspMvcActionAttribute : Attribute { [CanBeNull] public string AnonymousProperty { get; private set; } public AspMvcActionAttribute() { } public AspMvcActionAttribute([NotNull] string anonymousProperty) { AnonymousProperty = anonymousProperty; } } [AttributeUsage(AttributeTargets.Parameter)] internal sealed class AspMvcAreaAttribute : Attribute { [CanBeNull] public string AnonymousProperty { get; private set; } public AspMvcAreaAttribute() { } public AspMvcAreaAttribute([NotNull] string anonymousProperty) { AnonymousProperty = anonymousProperty; } } [AttributeUsage(AttributeTargets.Method | AttributeTargets.Parameter)] internal sealed class AspMvcControllerAttribute : Attribute { [CanBeNull] public string AnonymousProperty { get; private set; } public AspMvcControllerAttribute() { } public AspMvcControllerAttribute([NotNull] string anonymousProperty) { AnonymousProperty = anonymousProperty; } } [AttributeUsage(AttributeTargets.Parameter)] internal sealed class AspMvcMasterAttribute : Attribute { } [AttributeUsage(AttributeTargets.Parameter)] internal sealed class AspMvcModelTypeAttribute : Attribute { } [AttributeUsage(AttributeTargets.Method | AttributeTargets.Parameter)] internal sealed class AspMvcPartialViewAttribute : Attribute { } [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)] internal sealed class AspMvcSuppressViewErrorAttribute : Attribute { } [AttributeUsage(AttributeTargets.Parameter)] internal sealed class AspMvcDisplayTemplateAttribute : Attribute { } [AttributeUsage(AttributeTargets.Parameter)] internal sealed class AspMvcEditorTemplateAttribute : Attribute { } [AttributeUsage(AttributeTargets.Parameter)] internal sealed class AspMvcTemplateAttribute : Attribute { } [AttributeUsage(AttributeTargets.Method | AttributeTargets.Parameter)] internal sealed class AspMvcViewAttribute : Attribute { } [AttributeUsage(AttributeTargets.Parameter)] internal sealed class AspMvcViewComponentAttribute : Attribute { } [AttributeUsage(AttributeTargets.Method | AttributeTargets.Parameter)] internal sealed class AspMvcViewComponentViewAttribute : Attribute { } [AttributeUsage(AttributeTargets.Property | AttributeTargets.Parameter)] internal sealed class AspMvcActionSelectorAttribute : Attribute { } [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter)] internal sealed class HtmlElementAttributesAttribute : Attribute { [CanBeNull] public string Name { get; private set; } public HtmlElementAttributesAttribute() { } public HtmlElementAttributesAttribute([NotNull] string name) { Name = name; } } [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter)] internal sealed class HtmlAttributeValueAttribute : Attribute { [NotNull] public string Name { get; private set; } public HtmlAttributeValueAttribute([NotNull] string name) { Name = name; } } [AttributeUsage(AttributeTargets.Method | AttributeTargets.Parameter)] internal sealed class RazorSectionAttribute : Attribute { } [AttributeUsage(AttributeTargets.Constructor | AttributeTargets.Method | AttributeTargets.Property)] internal sealed class CollectionAccessAttribute : Attribute { public CollectionAccessType CollectionAccessType { get; private set; } public CollectionAccessAttribute(CollectionAccessType collectionAccessType) { CollectionAccessType = collectionAccessType; } } [Flags] internal enum CollectionAccessType { None = 0, Read = 1, ModifyExistingContent = 2, UpdatedContent = 6 } [AttributeUsage(AttributeTargets.Method)] internal sealed class AssertionMethodAttribute : Attribute { } [AttributeUsage(AttributeTargets.Parameter)] internal sealed class AssertionConditionAttribute : Attribute { public AssertionConditionType ConditionType { get; private set; } public AssertionConditionAttribute(AssertionConditionType conditionType) { ConditionType = conditionType; } } internal enum AssertionConditionType { IS_TRUE, IS_FALSE, IS_NULL, IS_NOT_NULL } [Obsolete("Use [ContractAnnotation('=> halt')] instead")] [AttributeUsage(AttributeTargets.Method)] internal sealed class TerminatesProgramAttribute : Attribute { } [AttributeUsage(AttributeTargets.Method)] internal sealed class LinqTunnelAttribute : Attribute { } [AttributeUsage(AttributeTargets.Parameter)] internal sealed class NoEnumerationAttribute : Attribute { } [AttributeUsage(AttributeTargets.Parameter)] internal sealed class RegexPatternAttribute : Attribute { } [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum | AttributeTargets.Interface)] internal sealed class NoReorderAttribute : Attribute { } [AttributeUsage(AttributeTargets.Class)] internal sealed class XamlItemsControlAttribute : Attribute { } [AttributeUsage(AttributeTargets.Property)] internal sealed class XamlItemBindingOfItemsControlAttribute : Attribute { } [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] internal sealed class AspChildControlTypeAttribute : Attribute { [NotNull] public string TagName { get; private set; } [NotNull] public Type ControlType { get; private set; } public AspChildControlTypeAttribute([NotNull] string tagName, [NotNull] Type controlType) { TagName = tagName; ControlType = controlType; } } [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property)] internal sealed class AspDataFieldAttribute : Attribute { } [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property)] internal sealed class AspDataFieldsAttribute : Attribute { } [AttributeUsage(AttributeTargets.Property)] internal sealed class AspMethodPropertyAttribute : Attribute { } [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] internal sealed class AspRequiredAttributeAttribute : Attribute { [NotNull] public string Attribute { get; private set; } public AspRequiredAttributeAttribute([NotNull] string attribute) { Attribute = attribute; } } [AttributeUsage(AttributeTargets.Property)] internal sealed class AspTypePropertyAttribute : Attribute { public bool CreateConstructorReferences { get; private set; } public AspTypePropertyAttribute(bool createConstructorReferences) { CreateConstructorReferences = createConstructorReferences; } } [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] internal sealed class RazorImportNamespaceAttribute : Attribute { [NotNull] public string Name { get; private set; } public RazorImportNamespaceAttribute([NotNull] string name) { Name = name; } } [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] internal sealed class RazorInjectionAttribute : Attribute { [NotNull] public string Type { get; private set; } [NotNull] public string FieldName { get; private set; } public RazorInjectionAttribute([NotNull] string type, [NotNull] string fieldName) { Type = type; FieldName = fieldName; } } [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] internal sealed class RazorDirectiveAttribute : Attribute { [NotNull] public string Directive { get; private set; } public RazorDirectiveAttribute([NotNull] string directive) { Directive = directive; } } [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] internal sealed class RazorPageBaseTypeAttribute : Attribute { [NotNull] public string BaseType { get; private set; } [CanBeNull] public string PageName { get; private set; } public RazorPageBaseTypeAttribute([NotNull] string baseType) { BaseType = baseType; } public RazorPageBaseTypeAttribute([NotNull] string baseType, string pageName) { BaseType = baseType; PageName = pageName; } } [AttributeUsage(AttributeTargets.Method)] internal sealed class RazorHelperCommonAttribute : Attribute { } [AttributeUsage(AttributeTargets.Property)] internal sealed class RazorLayoutAttribute : Attribute { } [AttributeUsage(AttributeTargets.Method)] internal sealed class RazorWriteLiteralMethodAttribute : Attribute { } [AttributeUsage(AttributeTargets.Method)] internal sealed class RazorWriteMethodAttribute : Attribute { } [AttributeUsage(AttributeTargets.Parameter)] internal sealed class RazorWriteMethodParameterAttribute : Attribute { } } namespace vtortola.WebSockets { public abstract class BufferManager { [Obsolete("Is not used")] public abstract int SmallBufferSize { get; } public abstract int LargeBufferSize { get; } public static BufferManager CreateBufferManager(long maxBufferPoolSize, int maxBufferSize) { if (maxBufferPoolSize < 0) { throw new ArgumentOutOfRangeException("maxBufferPoolSize"); } if (maxBufferSize < 0) { throw new ArgumentOutOfRangeException("maxBufferSize"); } if (maxBufferSize < 256) { maxBufferSize = 256; } if (maxBufferPoolSize < maxBufferSize) { maxBufferPoolSize = maxBufferSize * 10; } int num = (int)Math.Pow(2.0, Math.Ceiling(Math.Log(maxBufferSize) / Math.Log(2.0))); int num2 = (int)Math.Max(2.0, Math.Ceiling((float)maxBufferPoolSize / 2f / (float)num)); int num3 = Math.Max(32, num / 256); int smallPoolSizeLimit = (int)Math.Max(2L, (maxBufferPoolSize - num2 * num) / num3); return new DefaultBufferManager(num3, smallPoolSizeLimit, num, num2); } [NotNull] public static BufferManager CreateBufferManager(int smallBufferSize, int smallBufferPoolSize, int largeBufferSize, int largeBufferPoolSize) { if (smallBufferSize < 0) { throw new ArgumentOutOfRangeException("smallBufferSize"); } if (largeBufferSize < 0) { throw new ArgumentOutOfRangeException("largeBufferSize"); } if (smallBufferPoolSize < 0) { throw new ArgumentOutOfRangeException("smallBufferPoolSize"); } if (largeBufferPoolSize < 0) { throw new ArgumentOutOfRangeException("largeBufferPoolSize"); } return new DefaultBufferManager(smallBufferSize, smallBufferPoolSize, largeBufferSize, largeBufferPoolSize); } [Obsolete("Is not used")] public abstract void Clear(); public abstract void ReturnBuffer(byte[] buffer); public abstract byte[] TakeBuffer(int bufferSize); } public sealed class ConsoleLogger : ILogger { public static ConsoleLogger Instance = new ConsoleLogger(); public bool IsDebugEnabled { get; set; } public bool IsWarningEnabled { get; set; } public bool IsErrorEnabled { get; set; } public ConsoleLogger() { IsDebugEnabled = true; IsWarningEnabled = true; IsErrorEnabled = true; } public void Debug(string message, Exception error = null) { if (IsDebugEnabled) { if (!string.IsNullOrEmpty(message)) { Console.WriteLine(message); } if (error != null) { Console.WriteLine(error); } } } public void Warning(string message, Exception error = null) { if (IsWarningEnabled) { string.IsNullOrEmpty(message); if (error != null) { Console.WriteLine(error); } } } public void Error(string message, Exception error = null) { if (IsErrorEnabled) { string.IsNullOrEmpty(message); if (error != null) { Console.WriteLine(error); } } } } public sealed class DebugLogger : ILogger { public static DebugLogger Instance = new DebugLogger(); public bool IsDebugEnabled { get; set; } public bool IsWarningEnabled { get; set; } public bool IsErrorEnabled { get; set; } public DebugLogger() { IsDebugEnabled = true; IsWarningEnabled = true; IsErrorEnabled = true; } public void Debug(string message, Exception error = null) { if (IsDebugEnabled) { string.IsNullOrEmpty(message); } } public void Warning(string message, Exception error = null) { if (IsWarningEnabled) { string.IsNullOrEmpty(message); } } public void Error(string message, Exception error = null) { if (IsErrorEnabled) { string.IsNullOrEmpty(message); } } } internal sealed class DefaultBufferManager : BufferManager { private readonly ObjectPool<byte[]> smallPool; private readonly ObjectPool<byte[]> largePool; public override int SmallBufferSize { get; } public override int LargeBufferSize { get; } public DefaultBufferManager(int smallBufferSize, int smallPoolSizeLimit, int largeBufferSize, int largePoolSizeLimit) { SmallBufferSize = smallBufferSize; LargeBufferSize = largeBufferSize; smallPool = new ObjectPool<byte[]>(() => new byte[smallBufferSize], smallPoolSizeLimit); largePool = new ObjectPool<byte[]>(() => new byte[largeBufferSize], largePoolSizeLimit); } public override void Clear() { smallPool.Clear(); largePool.Clear(); } public override void ReturnBuffer(byte[] buffer) { if (buffer == null) { throw new ArgumentNullException("buffer"); } if (buffer.Length >= LargeBufferSize) { largePool.Return(buffer); return; } if (buffer.Length >= SmallBufferSize) { smallPool.Return(buffer); return; } throw new ArgumentException("Length of buffer does not match the pool's buffer length property.", "buffer"); } public override byte[] TakeBuffer(int bufferSize) { if (bufferSize < 0 || bufferSize > LargeBufferSize) { throw new ArgumentOutOfRangeException("bufferSize"); } if (bufferSize >= SmallBufferSize) { return largePool.Take(); } return smallPool.Take(); } } [PublicAPI] public interface IHttpFallback { void Post([NotNull] IHttpRequest request, [NotNull] NetworkConnection networkConnection); } [PublicAPI] public interface IHttpRequest { EndPoint LocalEndPoint { get; } EndPoint RemoteEndPoint { get; } Uri RequestUri { get; } Version HttpVersion { get; } bool IsSecure { get; } CookieCollection Cookies { get; } Headers<RequestHeader> Headers { get; } IDictionary<string, object> Items { get; } } public interface IWebSocketConnectionExtension { [ItemNotNull] [NotNull] Task<NetworkConnection> ExtendConnectionAsync([NotNull] NetworkConnection networkConnection); [NotNull] IWebSocketConnectionExtension Clone(); } public interface IWebSocketMessageExtension { string Name { get; } bool TryNegotiate(WebSocketHttpRequest request, out WebSocketExtension extensionResponse, out IWebSocketMessageExtensionContext context); IWebSocketMessageExtension Clone(); new string ToString(); } public interface IWebSocketMessageExtensionContext { [NotNull] WebSocketMessageReadStream ExtendReader([NotNull] WebSocketMessageReadStream message); [NotNull] WebSocketMessageWriteStream ExtendWriter([NotNull] WebSocketMessageWriteStream message); } [PublicAPI] public sealed class WebSocketConnectionExtensionCollection : IReadOnlyCollection<IWebSocketConnectionExtension>, IEnumerable<IWebSocketConnectionExtension>, IEnumerable { private readonly List<IWebSocketConnectionExtension> extensions; private volatile int useCounter; public int Count => extensions.Count; public bool IsReadOnly => useCounter > 0; public WebSocketConnectionExtensionCollection() { extensions = new List<IWebSocketConnectionExtension>(); } public void Add(IWebSocketConnectionExtension extension) { if (extension == null) { throw new ArgumentNullException("extension"); } if (IsReadOnly) { throw new WebSocketException("New entries cannot be added because this collection is used in running WebSocketClient or WebSocketListener."); } if (extensions.Any((IWebSocketConnectionExtension ext) => ext.GetType() == extension.GetType())) { throw new WebSocketException($"Can't add extension '{extension}' because another extension of type '{extension.GetType().Name}' is already exists in collection."); } extensions.Add(extension); } public WebSocketConnectionExtensionCollection RegisterSecureConnection(X509Certificate2 certificate, RemoteCertificateValidationCallback validation = null, SslProtocols supportedSslProtocols = SslProtocols.Tls12) { if (certificate == null) { throw new ArgumentNullException("certificate"); } WebSocketSecureConnectionExtension extension = new WebSocketSecureConnectionExtension(certificate, validation, supportedSslProtocols); Add(extension); return this; } IEnumerator<IWebSocketConnectionExtension> IEnumerable<IWebSocketConnectionExtension>.GetEnumerator() { return extensions.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return extensions.GetEnumerator(); } public List<IWebSocketConnectionExtension>.Enumerator GetEnumerator() { return extensions.GetEnumerator(); } internal WebSocketConnectionExtensionCollection Clone() { WebSocketConnectionExtensionCollection webSocketConnectionExtensionCollection = new WebSocketConnectionExtensionCollection(); foreach (IWebSocketConnectionExtension extension in extensions) { webSocketConnectionExtensionCollection.extensions.Add(extension.Clone()); } return webSocketConnectionExtensionCollection; } internal void SetUsed(bool isUsed) { int num = 0; num = ((!isUsed) ? Interlocked.Decrement(ref useCounter) : Interlocked.Increment(ref useCounter)); if (num < 0) { throw new InvalidOperationException("The collection is released more than once."); } } public override string ToString() { return string.Join(", ", extensions); } } public sealed class WebSocketFactoryCollection : IReadOnlyCollection<WebSocketFactory>, IEnumerable<WebSocketFactory>, IEnumerable { private readonly Dictionary<short, WebSocketFactory> factoryByVersion; private volatile int useCounter; public IEnumerable<short> SupportedVersions => factoryByVersion.Keys; public int Count => factoryByVersion.Count; public bool IsReadOnly => useCounter > 0; public WebSocketFactoryCollection() { factoryByVersion = new Dictionary<short, WebSocketFactory>(); } public void Add(WebSocketFactory factory) { if (factory == null) { throw new ArgumentNullException("factory"); } if (IsReadOnly) { throw new WebSocketException("New entries cannot be added because this collection is used in running WebSocketClient or WebSocketListener."); } if (factoryByVersion.ContainsKey(factory.Version)) { throw new WebSocketException(string.Format("Can't add {0} '{1}' because another {2} with ", "WebSocketFactory", factory, "WebSocketFactory") + $"version '{factory.Version}' is already exists in collection."); } factoryByVersion.Add(factory.Version, factory); } IEnumerator IEnumerable.GetEnumerator() { return factoryByVersion.Values.GetEnumerator(); } IEnumerator<WebSocketFactory> IEnumerable<WebSocketFactory>.GetEnumerator() { return factoryByVersion.Values.GetEnumerator(); } public Dictionary<short, WebSocketFactory>.ValueCollection.Enumerator GetEnumerator() { return factoryByVersion.Values.GetEnumerator(); } internal WebSocketFactoryCollection Clone() { WebSocketFactoryCollection webSocketFactoryCollection = new WebSocketFactoryCollection(); foreach (KeyValuePair<short, WebSocketFactory> item in factoryByVersion) { webSocketFactoryCollection.factoryByVersion[item.Key] = item.Value.Clone(); } return webSocketFactoryCollection; } internal void SetUsed(bool isUsed) { int num = 0; num = ((!isUsed) ? Interlocked.Decrement(ref useCounter) : Interlocked.Increment(ref useCounter)); if (num < 0) { throw new InvalidOperationException("The collection is released more than once."); } } internal WebSocketFactory GetLast() { return factoryByVersion[factoryByVersion.Keys.Max()]; } public bool TryGetWebSocketFactory(WebSocketHttpRequest request, out WebSocketFactory factory) { if (request == null) { throw new ArgumentNullException("request"); } factory = null; short result = 0; if (short.TryParse(request.Headers[RequestHeader.WebSocketVersion], out result) && factoryByVersion.TryGetValue(result, out factory)) { return true; } return false; } } public sealed class WebSocketMessageExtensionCollection : IReadOnlyCollection<IWebSocketMessageExtension>, IEnumerable<IWebSocketMessageExtension>, IEnumerable { private readonly List<IWebSocketMessageExtension> extensions; private volatile int useCounter; public int Count => extensions.Count; public bool IsReadOnly => useCounter > 0; public WebSocketMessageExtensionCollection() { extensions = new List<IWebSocketMessageExtension>(); } public void Add(IWebSocketMessageExtension extension) { if (extension == null) { throw new ArgumentNullException("extension"); } if (IsReadOnly) { throw new WebSocketException("New entries cannot be added because this collection is used in running WebSocketClient or WebSocketListener."); } if (extensions.Any((IWebSocketMessageExtension ext) => ext.GetType() == extension.GetType())) { throw new WebSocketException($"Can't add extension '{extension}' because another extension of type '{extension.GetType().Name}' is already exists in collection."); } extensions.Add(extension); } IEnumerator<IWebSocketMessageExtension> IEnumerable<IWebSocketMessageExtension>.GetEnumerator() { return extensions.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return extensions.GetEnumerator(); } public List<IWebSocketMessageExtension>.Enumerator GetEnumerator() { return extensions.GetEnumerator(); } internal WebSocketMessageExtensionCollection Clone() { WebSocketMessageExtensionCollection webSocketMessageExtensionCollection = new WebSocketMessageExtensionCollection(); foreach (IWebSocketMessageExtension extension in extensions) { webSocketMessageExtensionCollection.extensions.Add(extension.Clone()); } return webSocketMessageExtensionCollection; } internal void SetUsed(bool isUsed) { int num = 0; num = ((!isUsed) ? Interlocked.Decrement(ref useCounter) : Interlocked.Increment(ref useCounter)); if (num < 0) { throw new InvalidOperationException("The collection is released more than once."); } } public override string ToString() { return string.Join(", ", extensions); } } public sealed class WebSocketSecureConnectionExtension : IWebSocketConnectionExtension { private readonly X509Certificate2 _certificate; private readonly RemoteCertificateValidationCallback _validation; private readonly SslProtocols _protocols; public WebSocketSecureConnectionExtension(X509Certificate2 certificate) { if (certificate == null) { throw new ArgumentNullException("certificate"); } _certificate = certificate; _protocols = SslProtocols.Tls12; } public WebSocketSecureConnectionExtension(X509Certificate2 certificate, RemoteCertificateValidationCallback validation) { if (certificate == null) { throw new ArgumentNullException("certificate"); } _certificate = certificate; _validation = validation; _protocols = SslProtocols.Tls12; } public WebSocketSecureConnectionExtension(X509Certificate2 certificate, RemoteCertificateValidationCallback validation, SslProtocols supportedSslProtocols) { if (certificate == null) { throw new ArgumentNullException("certificate"); } _certificate = certificate; _validation = validation; _protocols = supportedSslProtocols; } public async Task<NetworkConnection> ExtendConnectionAsync(NetworkConnection networkConnection) { if (networkConnection == null) { throw new ArgumentNullException("networkConnection"); } SslStream ssl = new SslStream(networkConnection.AsStream(), leaveInnerStreamOpen: false, _validation); try { await ssl.AuthenticateAsServerAsync(_certificate, _validation != null, _protocols, checkCertificateRevocation: false).ConfigureAwait(continueOnCapturedContext: false); return new SslNetworkConnection(ssl, networkConnection); } catch { SafeEnd.Dispose(ssl); throw; } } public IWebSocketConnectionExtension Clone() { return (IWebSocketConnectionExtension)MemberwiseClone(); } public override string ToString() { return $"Secure Connection: protocols: {_protocols}, certificate: {_certificate.SubjectName}"; } } public sealed class WebSocketExtensionFlags { private bool _rsv1; private bool _rsv2; private bool _rsv3; private readonly bool _none; public static readonly WebSocketExtensionFlags None = new WebSocketExtensionFlags(none: true); public bool Rsv1 { get { return _rsv1; } set { _rsv1 = value && !_none; } } public bool Rsv2 { get { return _rsv2; } set { _rsv2 = value && !_none; } } public bool Rsv3 { get { return _rsv3; } set { _rsv3 = value && !_none; } } public WebSocketExtensionFlags() { _none = false; } private WebSocketExtensionFlags(bool none) { _none = true; } } public enum WebSocketMessageType { Text = 1, Binary } public delegate Task<bool> HttpAuthenticationCallback(WebSocketHttpRequest request, WebSocketHttpResponse response); public static class CookieParser { public static IEnumerable<Cookie> Parse([CanBeNull] string cookieString) { if (string.IsNullOrWhiteSpace(cookieString)) { yield break; } string text = string.Empty; string text2 = string.Empty; for (int i = 0; i < cookieString.Length; i++) { char c = cookieString[i]; if (c == '=' && string.IsNullOrWhiteSpace(text2)) { text2 = text; text = string.Empty; } else if (c == ';') { if (!string.IsNullOrWhiteSpace(text2)) { yield return CreateCookie(text2, text); } else { yield return CreateCookie(text, string.Empty); } text2 = string.Empty; text = string.Empty; } else { text += c; } } if (!string.IsNullOrWhiteSpace(text2) && !string.IsNullOrWhiteSpace(text)) { yield return CreateCookie(text2, text); } } private static Cookie CreateCookie(string key, string value) { return new Cookie(key.Trim(), WebUtility.UrlDecode(value.Trim())); } } public sealed class WebSocketExtension { public static readonly ReadOnlyCollection<WebSocketExtensionOption> Empty = new ReadOnlyCollection<WebSocketExtensionOption>(new List<WebSocketExtensionOption>()); private readonly string extensionString; public readonly string Name; public readonly ReadOnlyCollection<WebSocketExtensionOption> Options; public WebSocketExtension(string name, IList<WebSocketExtensionOption> options) { if (name == null) { throw new ArgumentNullException("name"); } if (options == null) { throw new ArgumentNullException("options"); } Name = name; Options = (options as ReadOnlyCollection<WebSocketExtensionOption>) ?? new ReadOnlyCollection<WebSocketExtensionOption>(options); extensionString = ((Options.Count > 0) ? (Name + ";" + string.Join(";", Options)) : Name); } public WebSocketExtension(string name) { Name = name; Options = Empty; } public override string ToString() { return extensionString; } } public class WebSocketExtensionOption { public readonly string Name; public readonly string Value; public readonly bool ClientAvailableOption; public WebSocketExtensionOption(string name) { if (name == null) { throw new ArgumentNullException("name"); } Name = name; } public WebSocketExtensionOption(string name, bool clientAvailableOption) { if (name == null) { throw new ArgumentNullException("name"); } Name = name; ClientAvailableOption = clientAvailableOption; } public WebSocketExtensionOption(string name, string value) { if (name == null) { throw new ArgumentNullException("name"); } Name = name; Value = value; } public override string ToString() { if (string.IsNullOrEmpty(Value)) { return Name; } return Name + "=" + Value; } } internal class WebSocketHandshake : IComparable<WebSocketHandshake>, IEquatable<WebSocketHandshake> { private static long LastId = 1L; private bool _invalidated; public readonly long Id; [NotNull] public readonly WebSocketHttpRequest Request; public readonly WebSocketHttpResponse Response; public readonly List<IWebSocketMessageExtensionContext> NegotiatedMessageExtensions; public bool IsWebSocketRequest { get; internal set; } public bool IsVersionSupported { get; internal set; } public bool IsResponseSent { get; internal set; } public WebSocketFactory Factory { get; internal set; } public ExceptionDispatchInfo Error { get; internal set; } public bool IsValidWebSocketRequest { get { if (!_invalidated && Error == null && IsWebSocketRequest && IsVersionSupported) { return Response.Status == HttpStatusCode.SwitchingProtocols; } return false; } set { _invalidated = !value; } } public bool IsValidHttpRequest { get { if (!_invalidated) { return Error == null; } return false; } set { _invalidated = !value; } } public WebSocketHandshake([NotNull] WebSocketHttpRequest request) { if (request == null) { throw new ArgumentNullException("request"); } Id = Interlocked.Increment(ref LastId); Request = request; Response = new WebSocketHttpResponse(); NegotiatedMessageExtensions = new List<IWebSocketMessageExtensionContext>(); } public string ComputeHandshake() { string text = Request.Headers[RequestHeader.WebSocketKey]; if (string.IsNullOrEmpty(text)) { throw new InvalidOperationException("Missing or wrong " + Headers<RequestHeader>.GetHeaderName(RequestHeader.WebSocketKey) + " header in request."); } using SHA1 sHA = SHA1.Create(); return Convert.ToBase64String(sHA.ComputeHash(Encoding.UTF8.GetBytes(text + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"))); } public string GenerateClientNonce() { return Convert.ToBase64String(Guid.NewGuid().ToByteArray()); } public int CompareTo(WebSocketHandshake other) { if (other == null) { return 1; } long id = Id; return id.CompareTo(other.Id); } public bool Equals(WebSocketHandshake other) { if (other == null) { return false; } if (this == other) { return true; } return Id == other.Id; } public override bool Equals(object obj) { return Equals(obj as WebSocketHandshake); } public override int GetHashCode() { long id = Id; return id.GetHashCode(); } public override string ToString() { return $"Handshake, id: {Id}, request: {Request}, response: {Response}"; } } internal class WebSocketHandshaker { private static readonly Version HttpVersion11 = new Version(1, 1); private static readonly Version HttpVersion10 = new Version(1, 0); private readonly ILogger log; private readonly WebSocketListenerOptions options; private readonly WebSocketFactoryCollection factories; public WebSocketHandshaker(WebSocketFactoryCollection factories, WebSocketListenerOptions options) { if (factories == null) { throw new ArgumentNullException("factories"); } if (options == null) { throw new ArgumentNullException("options"); } log = options.Logger; this.factories = factories; this.options = options; } public async Task<WebSocketHandshake> HandshakeAsync(NetworkConnection networkConnection) { if (networkConnection == null) { throw new ArgumentNullException("networkConnection"); } WebSocketHttpRequest request = new WebSocketHttpRequest(HttpRequestDirection.Incoming) { LocalEndPoint = (networkConnection.LocalEndPoint ?? WebSocketHttpRequest.NoAddress), RemoteEndPoint = (networkConnection.RemoteEndPoint ?? WebSocketHttpRequest.NoAddress), IsSecure = (networkConnection is SslNetworkConnection) }; WebSocketHandshake handshake = new WebSocketHandshake(request); try { await ReadHttpRequestAsync(networkConnection, handshake).ConfigureAwait(continueOnCapturedContext: false); if (!IsWebSocketRequestValid(handshake)) { await WriteHttpResponseAsync(handshake, networkConnection).ConfigureAwait(continueOnCapturedContext: false); return handshake; } handshake.IsWebSocketRequest = true; WebSocketFactory factory = null; if (!factories.TryGetWebSocketFactory(handshake.Request, out factory)) { await WriteHttpResponseAsync(handshake, networkConnection).ConfigureAwait(continueOnCapturedContext: false); return handshake; } handshake.Factory = factory; handshake.IsVersionSupported = true; ConsolidateObjectModel(handshake); SelectExtensions(handshake); if (!(await RunHttpNegotiationHandlerAsync(handshake).ConfigureAwait(continueOnCapturedContext: false))) { throw new WebSocketException("HTTP authentication failed."); } await WriteHttpResponseAsync(handshake, networkConnection).ConfigureAwait(continueOnCapturedContext: false); } catch (Exception ex) { if (log.IsDebugEnabled) { log.Debug("Failed to handshake request.", ex); } handshake.Error = ExceptionDispatchInfo.Capture(ex); if (!handshake.IsResponseSent) { try { await WriteHttpResponseAsync(handshake, networkConnection).ConfigureAwait(continueOnCapturedContext: false); } catch (Exception error) { if (log.IsDebugEnabled) { log.Debug("Failed to write error response.", error); } } } } return handshake; } private static bool IsWebSocketRequestValid(WebSocketHandshake handShake) { if (handShake == null) { throw new ArgumentNullException("handShake"); } Headers<RequestHeader> headers = handShake.Request.Headers; if (headers.Contains(RequestHeader.Host) && headers.Contains(RequestHeader.Upgrade) && headers.GetValues(RequestHeader.Upgrade).Contains("websocket", StringComparison.OrdinalIgnoreCase) && headers.Contains(RequestHeader.Connection) && !string.IsNullOrWhiteSpace(headers.Get(RequestHeader.WebSocketKey))) { return headers.Contains(RequestHeader.WebSocketVersion); } return false; } private async Task<bool> RunHttpNegotiationHandlerAsync(WebSocketHandshake handshake) { if (handshake == null) { throw new ArgumentNullException("handshake"); } if (options.HttpAuthenticationHandler != null) { try { return await options.HttpAuthenticationHandler(handshake.Request, handshake.Response).ConfigureAwait(continueOnCapturedContext: false); } catch (Exception source) { handshake.Response.Status = HttpStatusCode.InternalServerError; handshake.Error = ExceptionDispatchInfo.Capture(source); return false; } } return true; } private void SelectExtensions(WebSocketHandshake handshake) { if (handshake == null) { throw new ArgumentNullException("handshake"); } foreach (WebSocketExtension extRequest in handshake.Request.WebSocketExtensions) { IWebSocketMessageExtension webSocketMessageExtension = handshake.Factory.MessageExtensions.SingleOrDefault((IWebSocketMessageExtension x) => x.Name.Equals(extRequest.Name, StringComparison.OrdinalIgnoreCase)); if (webSocketMessageExtension != null && webSocketMessageExtension.TryNegotiate(handshake.Request, out var extensionResponse, out var context)) { handshake.NegotiatedMessageExtensions.Add(context); handshake.Response.WebSocketExtensions.Add(extensionResponse); } } } private async Task WriteHttpResponseAsync(WebSocketHandshake handshake, NetworkConnection networkConnection) { if (handshake == null) { throw new ArgumentNullException("handshake"); } if (networkConnection == null) { throw new ArgumentNullException("networkConnection"); } if (handshake.IsWebSocketRequest || !handshake.IsValidHttpRequest || options.HttpFallback == null) { handshake.IsResponseSent = true; using StreamWriter writer = new StreamWriter(networkConnection.AsStream(), Encoding.ASCII, 1024, leaveOpen: true); await WriteResponseInternal(handshake, writer).ConfigureAwait(continueOnCapturedContext: false); await writer.FlushAsync().ConfigureAwait(continueOnCapturedContext: false); } } private async Task WriteResponseInternal(WebSocketHandshake handshake, StreamWriter writer) { if (handshake == null) { throw new ArgumentNullException("handshake"); } if (writer == null) { throw new ArgumentNullException("writer"); } if (!handshake.IsWebSocketRequest) { handshake.Response.Status = HttpStatusCode.BadRequest; await SendNegotiationErrorResponseAsync(writer, handshake.Response.Status); } else if (!handshake.IsVersionSupported) { handshake.Response.Status = HttpStatusCode.UpgradeRequired; await SendVersionNegotiationErrorResponse(writer); } else if (handshake.IsValidWebSocketRequest) { await SendNegotiationResponse(handshake, writer); } else { handshake.Response.Status = ((handshake.Response.Status != HttpStatusCode.SwitchingProtocols) ? handshake.Response.Status : HttpStatusCode.BadRequest); await SendNegotiationErrorResponseAsync(writer, handshake.Response.Status); } } private async Task ReadHttpRequestAsync(NetworkConnection clientStream, WebSocketHandshake handshake) { if (clientStream == null) { throw new ArgumentNullException("clientStream"); } if (handshake == null) { throw new ArgumentNullException("handshake"); } using StreamReader sr = new StreamReader(clientStream.AsStream(), Encoding.ASCII, detectEncodingFromByteOrderMarks: false, 1024, leaveOpen: true); ParseGET(await sr.ReadLineAsync(), handshake); string header; while (!string.IsNullOrWhiteSpace(header = await sr.ReadLineAsync())) { handshake.Request.Headers.TryParseAndAdd(header); } ParseCookies(handshake); } private void ParseGET(string line, WebSocketHandshake handshake) { if (handshake == null) { throw new ArgumentNullException("handshake"); } if (string.IsNullOrWhiteSpace(line)) { throw new WebSocketException("Empty request line is received. Probably connection is closed."); } string[] array = line.Split(new char[1] { ' ' }); if (!line.StartsWith("GET", StringComparison.Ordinal)) { throw new WebSocketException($"Invalid request method '{array.FirstOrDefault() ?? line}' while 'GET' is expected."); } handshake.Request.RequestUri = new Uri(array[1], UriKind.Relative); string text = array[2]; handshake.Request.HttpVersion = (text.EndsWith("1.1") ? HttpVersion11 : HttpVersion10); } private async Task SendNegotiationResponse(WebSocketHandshake handshake, StreamWriter writer) { await writer.WriteAsync("HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\n"); if (handshake.Response.Cookies.Count > 0) { foreach (object cookie in handshake.Response.Cookies) { await writer.WriteAsync("Set-Cookie: "); await writer.WriteAsync(cookie.ToString()); await writer.WriteAsync("\r\n"); } } await writer.WriteAsync("Sec-WebSocket-Accept: "); await writer.WriteAsync(handshake.ComputeHandshake()); if (handshake.Response.Headers.Contains(ResponseHeader.WebSocketProtocol)) { await writer.WriteAsync("\r\nSec-WebSocket-Protocol: "); await writer.WriteAsync(handshake.Response.Headers[ResponseHeader.WebSocketProtocol]); } WriteHandshakeCookies(handshake, writer); await writer.WriteAsync("\r\n\r\n"); } private static void WriteHandshakeCookies(WebSocketHandshake handshake, StreamWriter writer) { if (handshake == null) { throw new ArgumentNullException("handshake"); } if (writer == null) { throw new ArgumentNullException("writer"); } if (!handshake.Response.WebSocketExtensions.Any()) { return; } bool flag = true; bool flag2 = true; writer.Write("\r\nSec-WebSocket-Extensions: "); foreach (WebSocketExtension webSocketExtension in handshake.Response.WebSocketExtensions) { if (!flag) { writer.Write(","); } writer.Write(webSocketExtension.Name); IEnumerable<WebSocketExtensionOption> enumerable = webSocketExtension.Options.Where((WebSocketExtensionOption x) => !x.ClientAvailableOption); if (!webSocketExtension.Options.Any()) { continue; } writer.Write(";"); foreach (WebSocketExtensionOption item in enumerable) { if (!flag2) { writer.Write(";"); } writer.Write(item.Name); if (item.Value != null) { writer.Write("="); writer.Write(item.Value); } flag2 = false; } flag = false; } } private async Task SendNegotiationErrorResponseAsync(StreamWriter writer, HttpStatusCode code) { if (writer == null) { throw new ArgumentNullException("writer"); } await writer.WriteAsync($"HTTP/1.1 {(int)code} {HttpStatusDescription.Get(code)}\r\nConnection: close\r\n\r\n"); } private async Task SendVersionNegotiationErrorResponse(StreamWriter writer) { await writer.WriteAsync("HTTP/1.1 426 Upgrade Required\r\nSec-WebSocket-Version: "); bool first = true; foreach (WebSocketFactory standard in factories) { if (!first) { await writer.WriteAsync(","); } first = false; await writer.WriteAsync(standard.Version.ToString()); } await writer.WriteAsync("\r\n\r\n"); } private void ConsolidateObjectModel(WebSocketHandshake handshake) { if (handshake == null) { throw new ArgumentNullException("handshake"); } ParseWebSocketProtocol(handshake); ParseWebSocketExtensions(handshake); } private void ParseWebSocketProtocol(WebSocketHandshake handshake) { if (handshake == null) { throw new ArgumentNullException("handshake"); } if (!options.SubProtocols.Any() || !handshake.Request.Headers.Contains(RequestHeader.WebSocketProtocol)) { return; } foreach (string value in handshake.Request.Headers.GetValues(RequestHeader.WebSocketProtocol)) { if (options.SubProtocols.Contains<string>(value, StringComparer.OrdinalIgnoreCase)) { handshake.Response.Headers[ResponseHeader.WebSocketProtocol] = value; break; } } } private void ParseWebSocketExtensions(WebSocketHandshake handshake) { if (handshake == null) { throw new ArgumentNullException("handshake"); } List<WebSocketExtension> list = new List<WebSocketExtension>(); Headers<RequestHeader> headers = handshake.Request.Headers; if (headers.Contains(RequestHeader.WebSocketExtensions)) { foreach (string value in headers.GetValues(RequestHeader.WebSocketExtensions)) { List<WebSocketExtensionOption> list2 = new List<WebSocketExtensionOption>(); string text = null; foreach (KeyValuePair<string, string> item in HeadersHelper.SplitAndTrimKeyValue(value, ';', '=', StringSplitOptions.RemoveEmptyEntries)) { if (text == null) { text = item.Value; } else if (string.IsNullOrEmpty(item.Key)) { list2.Add(new WebSocketExtensionOption(item.Value, clientAvailableOption: true)); } else { list2.Add(new WebSocketExtensionOption(item.Key, item.Value)); } } if (string.IsNullOrEmpty(text)) { throw new WebSocketException("Wrong value '" + headers[RequestHeader.WebSocketExtensions] + "' of " + Headers<ResponseHeader>.GetHeaderName(ResponseHeader.WebSocketExtensions) + " header in request."); } list.Add(new WebSocketExtension(text, list2)); } } handshake.Request.SetExtensions(list); } private void ParseCookies(WebSocketHandshake handshake) { if (handshake == null) { throw new ArgumentNullException("handshake"); } string domain = handshake.Request.Headers[RequestHeader.Host]; foreach (string value in handshake.Request.Headers.GetValues(RequestHeader.Cookie)) { try { foreach (Cookie item in CookieParser.Parse(value)) { item.Domain = domain; item.Path = string.Empty; handshake.Request.Cookies.Add(item); } } catch (Exception ex) { throw new WebSocketException("Cannot parse cookie string: '" + value + "' because: " + ex.Message); } } } } public sealed class WebSocketHttpRequest : IHttpRequest { public static readonly IPEndPoint NoAddress = new IPEndPoint(IPAddress.None, 0); public EndPoint LocalEndPoint { get; internal set; } public EndPoint RemoteEndPoint { get; internal set; } public Uri RequestUri { get; internal set; } public Version HttpVersion { get; internal set; } public bool IsSecure { get; internal set; } public CookieCollection Cookies { get; } public Headers<RequestHeader> Headers { get; } public IDictionary<string, object> Items { get; } public HttpRequestDirection Direction { get; } public IReadOnlyList<WebSocketExtension> WebSocketExtensions { get; private set; } public WebSocketHttpRequest(HttpRequestDirection direction) { Headers = new Headers<RequestHeader>(); Cookies = new CookieCollection(); Items = new Dictionary<string, object>(); LocalEndPoint = NoAddress; RemoteEndPoint = NoAddress; Direction = direction; } internal void SetExtensions(List<WebSocketExtension> extensions) { if (extensions == null) { throw new ArgumentNullException("extensions"); } WebSocketExtensions = new ReadOnlyCollection<WebSocketExtension>(extensions); } public override string ToString() { if (RequestUri != null) { return RequestUri.ToString(); } return $"{LocalEndPoint}->{RemoteEndPoint}"; } } public sealed class WebSocketHttpResponse { public readonly CookieCollection Cookies; public readonly Headers<ResponseHeader> Headers; public HttpStatusCode Status; public string StatusDescription; public readonly List<WebSocketExtension> WebSocketExtensions; public WebSocketHttpResponse() { Headers = new Headers<ResponseHeader>(); Cookies = new CookieCollection(); WebSocketExtensions = new List<WebSocketExtension>(); Status = HttpStatusCode.SwitchingProtocols; StatusDescription = "Web Socket Protocol Handshake"; } public void ThrowIfInvalid(string computedHandshake) { if (computedHandshake == null) { throw new ArgumentNullException("computedHandshake"); } string b = Headers[ResponseHeader.Upgrade]; if (!string.Equals("websocket", b, StringComparison.OrdinalIgnoreCase)) { throw new WebSocketException("Missing or wrong " + Headers<ResponseHeader>.GetHeaderName(ResponseHeader.Upgrade) + " header in response."); } if (!Headers.GetValues(ResponseHeader.Connection).Contains("Upgrade", StringComparison.OrdinalIgnoreCase)) { throw new WebSocketException("Missing or wrong " + Headers<ResponseHeader>.GetHeaderName(ResponseHeader.Connection) + " header in response."); } string b2 = Headers[ResponseHeader.WebSocketAccept]; if (!string.Equals(computedHandshake, b2, StringComparison.OrdinalIgnoreCase)) { throw new WebSocketException("Missing or wrong " + Headers<ResponseHeader>.GetHeaderName(ResponseHeader.WebSocketAccept) + " header in response."); } } public override string ToString() { return $"{Status} {StatusDescription}"; } } public interface ILogger { bool IsDebugEnabled { get; } bool IsWarningEnabled { get; } bool IsErrorEnabled { get; } void Debug(string message, Exception error = null); void Warning(string message, Exception error = null); void Error(string message, Exception error = null); } public sealed class NullLogger : ILogger { public static readonly NullLogger Instance = new NullLogger(); public bool IsDebugEnabled => false; public bool IsWarningEnabled => false; public bool IsErrorEnabled => false; public void Debug(string message, Exception error = null) { } public void Warning(string message, Exception error = null) { } public void Error(string message, Exception error = null) { } } public enum PingMode { Manual, LatencyControl, BandwidthSaving } public abstract class WebSocketMessageReadStream : WebSocketMessageStream { public abstract WebSocketMessageType MessageType { get; } public abstract WebSocketExtensionFlags Flags { get; } public sealed override bool CanRead => true; [Obsolete("Writing to the read stream is not allowed", true)] public sealed override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) { throw new NotSupportedException(); } } public abstract class WebSocketMessageStream : Stream { public override bool CanRead => false; public sealed override bool CanSeek => false; public override bool CanWrite => false; public sealed override long Length { get { throw new NotSupportedException(); } } public sealed override long Position { get { throw new NotSupportedException(); } set { throw new NotSupportedException(); } } internal abstract WebSocketListenerOptions Options { get; } public override Task FlushAsync(CancellationToken cancellationToken) { return TaskHelper.CompletedTask; } public abstract Task CloseAsync(); public abstract override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken); public abstract override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken); public sealed override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state) { if (buffer == null) { throw new ArgumentNullException("buffer"); } if (offset < 0 || offset > buffer.Length) { throw new ArgumentOutOfRangeException("offset"); } if (count < 0 || offset + count > buffer.Length) { throw new ArgumentOutOfRangeException("count"); } if (callback != null || state != null) { TaskCompletionSource<int> taskCompletionSource = new TaskCompletionSource<int>(state); ReadAsync(buffer, offset, count, CancellationToken.None).PropagateResultTo(taskCompletionSource); if (callback != null) { taskCompletionSource.Task.ContinueWith(delegate(Task<int> t, object s) { ((AsyncCallback)s)(t); }, callback, CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default); } return taskCompletionSource.Task; } return ReadAsync(buffer, offset, count, CancellationToken.None); } public sealed override int EndRead(IAsyncResult asyncResult) { return ((Task<int>)asyncResult).Result; } public sealed override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state) { if (buffer == null) { throw new ArgumentNullException("buffer"); } if (offset < 0 || offset > buffer.Length) { throw new ArgumentOutOfRangeException("offset"); } if (count < 0 || offset + count > buffer.Length) { throw new ArgumentOutOfRangeException("count"); } if (callback != null || state != null) { TaskCompletionSource<bool> taskCompletionSource = new TaskCompletionSource<bool>(state); WriteAsync(buffer, offset, count, CancellationToken.None).PropagateResultTo(taskCompletionSource); if (callback != null) { taskCompletionSource.Task.ContinueWith(delegate(Task<bool> t, object s) { ((AsyncCallback)s)(t); }, callback, CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default); } return taskCompletionSource.Task; } return WriteAsync(buffer, offset, count, CancellationToken.None); } public sealed override void EndWrite(IAsyncResult asyncResult) { ((Task)asyncResult).Wait(); } public sealed override long Seek(long offset, SeekOrigin origin) { throw new NotSupportedException(); } public sealed override void SetLength(long value) { throw new NotSupportedException(); } [Obsolete("Do not use synchronous IO operation on network streams. Use ReadAsync() instead.")] public sealed override int ReadByte() { throw new NotSupportedException(); } [Obsolete("Do not use synchronous IO operation on network streams. Use ReadAsync() instead.")] public override int Read(byte[] buffer, int offset, int count) { return ReadAsync(buffer, offset, count, CancellationToken.None).Result; } [Obsolete("Do not use synchronous IO operation on network streams. Use WriteAsync() instead.")] public sealed override void WriteByte(byte value) { throw new NotSupportedException(); } [Obsolete("Do not use synchronous IO operation on network streams. Use WriteAsync() instead.")] public override void Write(byte[] buffer, int offset, int count) { WriteAsync(buffer, offset, count).Wait(); } [Obsolete("Do not use synchronous IO operation on network streams. Use FlushAsync() instead.")] public override void Flush() { } [Obsolete("Do not use synchronous IO operation on network streams. Use CloseAsync() instead.")] public override void Close() { base.Close(); } } public abstract class WebSocketMessageWriteStream : WebSocketMessageStream { public sealed override bool CanWrite => true; [NotNull] public WebSocketExtensionFlags ExtensionFlags { get; } protected WebSocketMessageWriteStream() { ExtensionFlags = new WebSocketExtensionFlags(); } [Obsolete("Reading from the write stream is not allowed", true)] public override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) { throw new NotSupportedException(); } public abstract Task WriteAndCloseAsync([NotNull] byte[] buffer, int offset, int count, CancellationToken cancellationToken); } internal static class SafeEnd { public static void Dispose<T>([CanBeNull] T disposable, ILogger log = null) where T : class, IDisposable { if (log == null) { log = NullLogger.Instance; } try { disposable?.Dispose(); } catch (Exception error) { if (log.IsDebugEnabled) { log.Debug($"{typeof(T)} dispose cause error.", error); } } } public static void ReleaseSemaphore(SemaphoreSlim semaphore, ILogger log = null) { try { semaphore.Release(); } catch (ObjectDisposedException) { } catch (Exception error) { if (log != null && log.IsDebugEnabled) { log.Debug("Semaphore release cause error.", error); } } } } [PublicAPI] public abstract class WebSocket : IDisposable { [NotNull] public WebSocketHttpRequest HttpRequest { get; } [NotNull] public WebSocketHttpResponse HttpResponse { get; } public abstract bool IsConnected { get; } public abstract EndPoint RemoteEndpoint { get; } public abstract EndPoint LocalEndpoint { get; } public abstract TimeSpan Latency { get; } public abstract string SubProtocol { get; } public abstract WebSocketCloseReason? CloseReason { get; } protected WebSocket([NotNull] WebSocketHttpRequest request, [NotNull] WebSocketHttpResponse response) { if (request == null) { throw new ArgumentNullException("request"); } if (response == null) { throw new ArgumentNullException("response"); } HttpRequest = request; HttpResponse = response; } [NotNull] [ItemCanBeNull] public abstract Task<WebSocketMessageReadStream> ReadMessageAsync(CancellationToken token); [NotNull] public abstract WebSocketMessageWriteStream CreateMessageWriter(WebSocketMessageType messageType); public Task SendPingAsync() { return SendPingAsync(null, 0, 0); } public abstract Task SendPingAsync(byte[] data, int offset, int count); public abstract Task CloseAsync(); public abstract Task CloseAsync(WebSocketCloseReason closeCode); public abstract void Dispose(); public override string ToString() { return $"{GetType().Name}, remote: {RemoteEndpoint}, connected: {IsConnected}"; } } [PublicAPI] public sealed class WebSocketClient { private const string WEB_SOCKET_HTTP_VERSION = "HTTP/1.1"; private readonly ILogger log; private readonly AsyncConditionSource closeEvent; private readonly CancellationTokenSource workCancellationSource; private readonly WebSocketListenerOptions options; private readonly ConcurrentDictionary<WebSocketHandshake, Task<WebSocket>> pendingRequests; private readonly CancellationQueue negotiationsTimeoutQueue; private readonly PingQueue pingQueue; public bool HasPendingRequests => !pendingRequests.IsEmpty; public WebSocketClient([NotNull] WebSocketListenerOptions options) { if (options == null) { throw new ArgumentNullException("options"); } if (options.Standards.Count == 0) { throw new ArgumentException("Empty list of WebSocket standards.", "options"); } options.CheckCoherence(); this.options = options.Clone(); this.options.SetUsed(isUsed: true); if (this.options.NegotiationTimeout > TimeSpan.Zero) { negotiationsTimeoutQueue = new CancellationQueue(this.options.NegotiationTimeout); } if (this.options.PingMode != 0) { pingQueue = new PingQueue(options.PingInterval); } log = this.options.Logger; closeEvent = new AsyncConditionSource(isSet: true) { ContinueOnCapturedContext = false }; workCancellationSource = new CancellationTokenSource(); pendingRequests = new ConcurrentDictionary<WebSocketHandshake, Task<WebSocket>>(); if (this.options.BufferManager == null) { this.options.BufferManager = BufferManager.CreateBufferManager(this.options.SendBufferSize * 2 * 100, this.options.SendBufferSize * 2); } if (this.options.CertificateValidationHandler == null) { this.options.CertificateValidationHandler = ValidateRemoteCertificate; } } private bool ValidateRemoteCertificate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { if (sslPolicyErrors == SslPolicyErrors.None) { return true; } if (log.IsWarningEnabled) { log.Warning($"Certificate validation error: {sslPolicyErrors}."); } return false; } public Task<WebSocket> ConnectAsync([NotNull] Uri address, CancellationToken cancellation = default(CancellationToken)) { return ConnectAsync(address, null, cancellation); } public async Task<WebSocket> ConnectAsync([NotNull] Uri address, Headers<RequestHeader> requestHeaders = null, CancellationToken cancellation = default(CancellationToken)) { _ = 1; try { cancellation.ThrowIfCancellationRequested(); if (workCancellationSource.IsCancellationRequested) { throw new WebSocketException("Client is currently closing or closed."); } CancellationToken workCancellation = workCancellationSource.Token; CancellationToken negotiationCancellation = negotiationsTimeoutQueue?.GetSubscriptionList().Token ?? CancellationToken.None; if (cancellation.CanBeCanceled || workCancellation.CanBeCanceled || negotiationCancellation.CanBeCanceled) { cancellation = CancellationTokenSource.CreateLinkedTokenSource(cancellation, workCancellation, negotiationCancellation).Token; } WebSocketHttpRequest webSocketHttpRequest = new WebSocketHttpRequest(HttpRequestDirection.Outgoing) { RequestUri = address }; if (requestHeaders != null) { webSocketHttpRequest.Headers.AddMany(requestHeaders); } WebSocketHandshake handshake = new WebSocketHandshake(webSocketHttpRequest); Task<WebSocket> value = OpenConnectionAsync(handshake, cancellation); pendingRequests.TryAdd(handshake, value); WebSocket disposable = await value.IgnoreFaultOrCancellation().ConfigureAwait(continueOnCapturedContext: false); if (!workCancellation.IsCancellationRequested && negotiationCancellation.IsCancellationRequested) { SafeEnd.Dispose(disposable, log); throw new WebSocketException("Negotiation timeout."); } if (pendingRequests.TryRemove(handshake, out value) && workCancellationSource.IsCancellationRequested && pendingRequests.IsEmpty) { closeEvent.Set(); } disposable = await value.ConfigureAwait(continueOnCapturedContext: false); pingQueue?.GetSubscriptionList().Add(disposable); return disposable; } catch (Exception exception) when (!(exception.Unwrap() is ThreadAbortException) && !(exception.Unwrap() is OperationCanceledException) && !(exception.Unwrap() is WebSocketException)) { throw new WebSocketException($"An unknown error occurred while connection to '{address}'. More detailed information in inner exception.", exception.Unwrap()); } } public async Task CloseAsync() { workCancellationSource.Cancel(throwOnFirstException: false); await closeEvent; SafeEnd.Dispose(pingQueue, log); SafeEnd.Dispose(negotiationsTimeoutQueue, log); SafeEnd.Dispose(workCancellationSource, log); options.SetUsed(isUsed: false); } private async Task<WebSocket> OpenConnectionAsync(WebSocketHandshake handshake, CancellationToken cancellation) { if (handshake == null) { throw new ArgumentNullException("handshake"); } NetworkConnection connection = null; WebSocket webSocket = null; try { cancellation.ThrowIfCancellationRequested(); Uri requestUri = handshake.Request.RequestUri; WebSocketTransport transport = null; if (!options.Transports.TryGetWebSocketTransport(requestUri, out transport)) { throw new WebSocketException($"Unable to find transport for '{requestUri}'. " + "Available transports are: " + string.Join(", ", options.Transports.SelectMany((WebSocketTransport t) => t.Schemes).Distinct()) + "."); } connection = await transport.ConnectAsync(requestUri, options, cancellation).ConfigureAwait(continueOnCapturedContext: false); handshake.Request.IsSecure = transport.ShouldUseSsl(requestUri); handshake.Request.LocalEndPoint = connection.LocalEndPoint ?? WebSocketHttpRequest.NoAddress; handshake.Request.RemoteEndPoint = connection.RemoteEndPoint ?? WebSocketHttpRequest.NoAddress; webSocket = await NegotiateRequestAsync(handshake, connection, cancellation).ConfigureAwait(continueOnCapturedContext: false); return webSocket; } finally { if (webSocket == null) { SafeEnd.Dispose(connection, log); } } } private async Task<WebSocket> NegotiateRequestAsync(WebSocketHandshake handshake, NetworkConnection connection, CancellationToken cancellation) { if (handshake == null) { throw new ArgumentNullException("handshake"); } if (connection == null) { throw new ArgumentNullException("connection"); } cancellation.ThrowIfCancellationRequested(); Stream stream = connection.AsStream(); if (handshake.Request.IsSecure) { SslProtocols supportedSslProtocols = options.SupportedSslProtocols; string dnsSafeHost = handshake.Request.RequestUri.DnsSafeHost; SslStream secureStream = new SslStream(stream, leaveInnerStreamOpen: false, options.CertificateValidationHandler); await secureStream.AuthenticateAsClientAsync(dnsSafeHost, null, supportedSslProtocols, checkCertificateRevocation: false).ConfigureAwait(continueOnCapturedContext: false); connection = new SslNetworkConnection(secureStream, connection); stream = secureStream; } handshake.Factory = options.Standards.GetLast(); await WriteRequestAsync(handshake, stream).ConfigureAwait(continueOnCapturedContext: false); cancellation.ThrowIfCancellationRequested(); await ReadResponseAsync(handshake, stream).ConfigureAwait(continueOnCapturedContext: false); cancellation.ThrowIfCancellationRequested(); if (await (options.HttpAuthenticationHandler?.Invoke(handshake.Request, handshake.Response) ?? Task.FromResult(result: false)).ConfigureAwait(continueOnCapturedContext: false)) { throw new WebSocketException("HTTP authentication failed."); } return handshake.Factory.CreateWebSocket(connection, options, handshake.Request, handshake.Response, handshake.NegotiatedMessageExtensions); } private async Task WriteRequestAsync(WebSocketHandshake handshake, Stream stream) { Uri url = handshake.Request.RequestUri; string value2 = handshake.GenerateClientNonce(); int largeBufferSize = options.BufferManager.LargeBufferSize; using StreamWriter writer = new StreamWriter(stream, Encoding.ASCII, largeBufferSize, leaveOpen: true); Headers<RequestHeader> requestHeaders = handshake.Request.Headers; requestHeaders[RequestHeader.Host] = url.DnsSafeHost; requestHeaders[RequestHeader.Upgrade] = "websocket"; requestHeaders[RequestHeader.Connection] = "keep-alive, Upgrade"; requestHeaders[RequestHeader.WebSocketKey] = value2; requestHeaders[RequestHeader.WebSocketVersion] = handshake.Factory.Version.ToString(); requestHeaders[RequestHeader.CacheControl] = "no-cache"; requestHeaders[RequestHeader.Pragma] = "no-cache"; foreach (IWebSocketMessageExtension messageExtension in handshake.Factory.MessageExtensions) { requestHeaders.Add(RequestHeader.WebSocketExtensions, messageExtension.ToString()); } string[] subProtocols = options.SubProtocols; foreach (string value3 in subProtocols) { requestHeaders.Add(RequestHeader.WebSocketProtocol, value3); } writer.NewLine = "\r\n"; await writer.WriteAsync("GET ").ConfigureAwait(continueOnCapturedContext: false); await writer.WriteAsync(url.PathAndQuery).ConfigureAwait(continueOnCapturedContext: false); await writer.WriteLineAsync(" HTTP/1.1").ConfigureAwait(continueOnCapturedContext: false); foreach (KeyValuePair<string, Headers<RequestHeader>.ValueCollection> item in requestHeaders) { string headerName = item.Key; foreach (string value in item.Value) { await writer.WriteAsync(headerName).ConfigureAwait(continueOnCapturedContext: false); await writer.WriteAsync(": ").ConfigureAwait(continueOnCapturedContext: false); await writer.WriteLineAsync(value).ConfigureAwait(continueOnCapturedContext: false); } } await writer.WriteLineAsync().ConfigureAwait(continueOnCapturedContext: false); await writer.FlushAsync().ConfigureAwait(continueOnCapturedContext: false); } private async Task ReadResponseAsync(WebSocketHandshake handshake, Stream stream) { int largeBufferSize = options.BufferManager.LargeBufferSize; using (StreamReader reader = new StreamReader(stream, Encoding.ASCII, detectEncodingFromByteOrderMarks: false, largeBufferSize, leaveOpen: true)) { Headers<ResponseHeader> responseHeaders = handshake.Response.Headers; string text = (await reader.ReadLineAsync().ConfigureAwait(continueOnCapturedContext: false)) ?? string.Empty; if (!HttpHelper.TryParseHttpResponse(text, out handshake.Response.Status, out handshake.Response.StatusDescription)) { if (string.IsNullOrEmpty(text)) { throw new WebSocketException("Empty response. Probably connection is closed by remote party."); } throw new WebSocketException("Invalid handshake response: " + text + "."); } if (handshake.Response.Status != HttpStatusCode.SwitchingProtocols) { throw new WebSocketException("Invalid handshake response: " + text + "."); } string text2 = await reader.ReadLineAsync().ConfigureAwait(continueOnCapturedContext: false); while (!string.IsNullOrEmpty(text2)) { responseHeaders.TryParseAndAdd(text2); text2 = await reader.ReadLineAsync().ConfigureAwait(continueOnCapturedContext: false); } handshake.Response.ThrowIfInvalid(handshake.ComputeHandshake()); } ParseWebSocketExtensions(handshake); SelectExtensions(handshake); } private void SelectExtensions(WebSocketHandshake handshake) { if (handshake == null) { throw new ArgumentNullException("handshake"); } foreach (WebSocketExtension responseExtension in handshake.Response.WebSocketExtensions) { IWebSocketMessageExtension webSocketMessageExtension = handshake.Factory.MessageExtensions.SingleOrDefault((IWebSocketMessageExtension x) => x.Name.Equals(responseExtension.Name, StringComparison.OrdinalIgnoreCase)); if (webSocketMessageExtension != null && webSocketMessageExtension.TryNegotiate(handshake.Request, out var _, out var context)) { handshake.NegotiatedMessageExtensions.Add(context); } } } private void ParseWebSocketExtensions(WebSocketHandshake handshake) { if (handshake == null) { throw new ArgumentNullException("handshake"); } Headers<ResponseHeader> headers = handshake.Response.Headers; if (!headers.Contains(ResponseHeader.WebSocketExtensions)) { return; } foreach (string value in headers.GetValues(ResponseHeader.WebSocketExtensions)) { List<WebSocketExtensionOption> list = new List<WebSocketExtensionOption>(); string text = null; foreach (KeyValuePair<string, string> item in HeadersHelper.SplitAndTrimKeyValue(value, ';', '=', StringSplitOptions.RemoveEmptyEntries)) { if (text == null) { text = item.Value; } else if (string.IsNullOrEmpty(item.Key)) { list.Add(new WebSocketExtensionOption(item.Value, clientAvailableOption: true)); } else { list.Add(new WebSocketExtensionOption(item.Key, item.Value)); } } if (string.IsNullOrEmpty(text)) { throw new WebSocketException("Wrong value '" + headers[ResponseHeader.WebSocketExtensions] + "' of " + Headers<ResponseHeader>.GetHeaderName(ResponseHeader.WebSocketExtensions) + " header in request."); } handshake.Response.WebSocketExtensions.Add(new WebSocketExtension(text, list)); } } } public enum WebSocketCloseReason : short { NormalClose = 1000, GoingAway = 1001, ProtocolError = 1002, UnacceptableDataType = 1003, InvalidData = 1007, MessageViolatesPolicy = 1008, MessageToLarge = 1009, ExtensionRequired = 1010, UnexpectedCondition = 1011, TLSFailure = 105 } public class WebSocketException : Exception { public WebSocketException(string message) : base(message) { } public WebSocketException(string message, Exception inner) : base(message, inner) { } } [PublicAPI] public abstract class WebSocketFactory { public abstract short Version { get; } public WebSocketMessageExtensionCollection MessageExtensions { get; private set; } protected WebSocketFactory() { MessageExtensions = new WebSocketMessageExtensionCollection(); } public abstract WebSocket CreateWebSocket(NetworkConnection networkConnection, WebSocketListenerOptions options, WebSocketHttpRequest httpRequest, WebSocketHttpResponse httpResponse, List<IWebSocketMessageExtensionContext> negotiatedExtensions); public virtual WebSocketFactory Clone() { WebSocketFactory webSocketFactory = (WebSocketFactory)MemberwiseClone(); webSocketFactory.MessageExtensions = new WebSocketMessageExtensionCollection(); foreach (IWebSocketMessageExtension messageExtension in MessageExtensions) { webSocketFactory.MessageExtensions.Add(messageExtension.Clone()); } return webSocketFactory; } } public sealed class WebSocketListener : IDisposable { private const int STATE_STOPPED = 0; private const int STATE_STARTING = 1; private const int STATE_STARTED = 2; private const int STATE_STOPPING = 3; private const int STATE_DISPOSED = 5; private static readonly Listener[] EmptyListeners = new Listener[0]; private static readonly EndPoint[] EmptyEndPoints = new EndPoint[0]; private readonly ILogger log; private readonly HttpNegotiationQueue negotiationQueue; private readonly WebSocketListenerOptions options; private readonly Uri[] listenEndPoints; private volatile AsyncConditionSource stopConditionSource; private volatile Listener[] listeners; private volatile EndPoint[] localEndPoints; private volatile int state; public bool IsStarted => state == 2; public IReadOnlyCollection<EndPoint> LocalEndpoints => (IReadOnlyCollection<EndPoint>)(object)localEndPoints; public WebSocketListener(IPEndPoint endpoint) : this(endpoint, new WebSocketListenerOptions()) { } public WebSocketListener(IPEndPoint endpoint, WebSocketListenerOptions options) : this(new Uri[1] { new Uri("tcp://" + endpoint) }, options) { } public WebSocketListener(Uri[] listenEndPoints, WebSocketListenerOptions options) { if (listenEndPoints == null) { throw new ArgumentNullException("listenEndPoints"); } if (listenEndPoints.Length == 0) { throw new ArgumentException("At least one prefix should be specified.", "listenEndPoints"); } if (listenEndPoints.Any((Uri p) => p == null)) { throw new ArgumentException("Null objects passed in array.", "listenEndPoints"); } if (options == null) { throw new ArgumentNullException("options"); } options.CheckCoherence(); this.options = options.Clone(); if (this.options.BufferManager == null) { this.options.BufferManager = BufferManager.CreateBufferManager(this.options.SendBufferSize * 100, this.options.SendBufferSize); } if (this.options.Logger == null) { this.options.Logger = NullLogger.Instance; } log = this.options.Logger; listeners = EmptyListeners; localEndPoints = EmptyEndPoints; this.listenEndPoints = listenEndPoints; negotiationQueue = new HttpNegotiationQueue(options.Standards, options.ConnectionExtensions, this.options); } public async Task StartAsync() { if (options.Standards.Count <= 0) { throw new WebSocketException("There are no WebSocket standards. Please, register standards using WebSocketListenerOptions.Standards."); } if (options.Transports.Count <= 0) { throw new WebSocketException("There are no WebSocket transports. Please, register transports using WebSocketListenerOptions.Transports."); } if (Interlocked.CompareExchange(ref state, 1, 0) != 0) { throw new WebSocketException("Failed to start listener from current state. Maybe it is disposed or already started."); } options.SetUsed(isUsed: true); Listener[] listeners = null; try { if (log.IsDebugEnabled) { log.Debug("WebSocketListener is starting."); } Tuple<Uri, WebSocketTransport>[] endPoints = new Tuple<Uri, WebSocketTransport>[listenEndPoints.Length]; for (int j = 0; j < listenEndPoints.Length; j++) { Uri uri = listenEndPoints[j]; WebSocketTransport transport = null; if (!options.Transports.TryGetWebSocketTransport(uri, out transport)) { string arg = string.Join(", ", options.Transports.SelectMany((WebSocketTransport t) => t.Schemes).Distinct()); throw new WebSocketException($"Unable to find transport for '{uri}'. Available transports are: {arg}."); } endPoints[j] = Tuple.Create(uri, transport); } listeners = new Listener[endPoints.Length]; for (int i = 0; i < endPoints.Length; i++) { Listener[] array = listeners; int num = i; array[num] = await endPoints[i].Item2.ListenAsync(endPoints[i].Item1, options).ConfigureAwait(continueOnCapturedContext: false); } this.listeners = listeners; localEndPoints = this.listeners.SelectMany((Listener l) => l.LocalEndpoints).ToArray(); stopConditionSource = new AsyncConditionSource(isSet: true) { ContinueOnCapturedContext = false }; if (Interlocked.CompareExchange(ref state, 2, 1) != 1) { throw new WebSocketException("Failed to start listener from current state. Maybe it is disposed."); } AcceptConnectionsAsync().LogFault(log, null, "StartAsync", "D:\\dev\\projects\\vtortola.WebSocketListener\\vtortola.WebSockets\\WebSocketListener.cs", 117); if (log.IsDebugEnabled) { log.Debug("WebSocketListener is started."); } listeners = null; } catch { options.SetUsed(isUsed: false); throw; } finally { Interlocked.CompareExchange(ref state, 0, 1); if (listeners != null) { Listener[] array2 = listeners; for (int k = 0; k < array2.Length; k++) { SafeEnd.Dispose(array2[k]); } this.listeners = EmptyListeners; localEndPoints = EmptyEndPoints; stopConditionSource = null; } } } public async Task StopAsync() { if (Interlocked.CompareExchange(ref state, 3, 2) != 2) { throw new WebSocketException("Failed to stop listener from current state. Maybe it is disposed or not started."); } options.SetUsed(isUsed: false); AsyncConditionSource asyncConditionSource = stopConditionSource; if (log.IsDebugEnabled) { log.Debug("WebSocketListener is stopping."); } localEndPoints = EmptyEndPoints; Listener[] array = Interlocked.Exchange(ref listeners, EmptyListeners); for (int i = 0; i < array.Length; i++) { SafeEnd.Dispose(array[i], log); } if (asyncConditionSource != null) { await asyncConditionSource; } if (Interlocked.CompareExchange(ref state, 0, 3) != 3) { throw new WebSocketException("Failed to stop listener from current state. Maybe it is disposed."); } if (log.IsDebugEnabled) { log.Debug("WebSocketListener is stopped."); } } private async Task AcceptConnectionsAsync() { await Task.Yield(); Listener[] listeners = this.listeners; Task<NetworkConnection>[] acceptTasks = new Task<NetworkConnection>[listeners.Length]; int acceptOffset = 0; try { while (IsStarted) { for (int i = 0; i < acceptTasks.Length; i++) { if (acceptTasks[i] == null) { try { acceptTasks[i] = listeners[i].AcceptConnectionAsync(); } catch (Exception ex) when (!(ex is ThreadAbortException)) { acceptTasks[i] = TaskHelper.FailedTask<NetworkConnection>(ex); } } } await Task.WhenAny(acceptTasks).ConfigureAwait(continueOnCapturedContext: false); if (acceptOffset == 65535) { acceptOffset = 0; } acceptOffset++; for (int j = 0; j < acceptTasks.Length; j++) { int num = (acceptOffset + j) % acceptTasks.Length; Task<NetworkConnection> task = acceptTasks[num]; if (task != null && task.IsCompleted) { acceptTasks[num] = null; AcceptNewConnection(task, listeners[num]); } } } } finally { CleanupPendingConnections(acceptTasks); } } private void CleanupPendingConnections(Task<NetworkConnection>[] acceptTasks) { if (acceptTasks == null) { throw new ArgumentNullException("acceptTasks"); } for (int i = 0; i < acceptTasks.Length; i++) { acceptTasks[i]?.ContinueWith(delegate(Task<NetworkConnection> t) { SafeEnd.Dispose(t.Result, log); }, CancellationToken.None, TaskContinuationOptions.OnlyOnRanToCompletion | TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Current).LogFault(log, null, "CleanupPendingConnections", "D:\\dev\\projects\\vtortola.WebSocketListener\\vtortola.WebSockets\\WebSocketListener.cs", 234); } Array.Clear(acceptTasks, 0, acceptTasks.Length); } private void AcceptNewConnection(Task<NetworkConnection> acceptTask, Listener listener) { if (acceptTask == null) { throw new ArgumentNullException("acceptTask"); } if (listener == null) { throw new ArgumentNullException("listener"); } Exception ex = acceptTask.Exception.Unwrap(); if (acceptTask.Status != TaskStatus.RanToCompletion) { if (log.IsDebugEnabled && ex != null && !(ex is OperationCanceledException)) { log.Debug($"Accept from '{listener}' has failed.", ex); } return; } NetworkConnection result = acceptTask.Result; if (log.IsDebugEnabled) { log.Debug($"New client from '{result}' is connected."); } negotiationQueue.Queue(result); } public async Task<WebSocket> AcceptWebSocketAsync(CancellationToken token) { try { WebSocketNegotiationResult webSocketNegotiationResult = await negotiationQueue.DequeueAsync(token).ConfigureAwait(continueOnCapturedContext: false); if (webSocketNegotiationResult.Error != null) { if (log.IsDebugEnabled && !(webSocketNegotiationResult.Error.SourceException.Unwrap() is OperationCanceledException)) { log.Debug("AcceptWebSocketAsync is complete with error.", webSocketNegotiationResult.Error.SourceException); } webSocketNegotiationResult.Error.Throw(); return null; } return webSocketNegotiationResult.Result; } catch (OperationCanceledException) { return null; } } public void Dispose() { if (Interlocked.Exchange(ref state, 5) != 5) { stopConditionSource?.Set(); localEndPoints = EmptyEndPoints; Listener[] array = Interlocked.Exchange(ref listeners, EmptyListeners); for (int i = 0; i < array.Length; i++) { SafeEnd.Dispose(array[i], log); } SafeEnd.Dispose(negotiationQueue, log); } } } [PublicAPI] public sealed class WebSocketListenerOptions { public const int DEFAULT_SEND_BUFFER_SIZE = 8192; public static readonly string[] NoSubProtocols = new string[0]; [NotNull] public WebSocketTransportCollection Transports { get; private set; } [NotNull] public WebSocketFactoryCollection Standards { get; private set; } [NotNull] public WebSocketConnectionExtensionCollection ConnectionExtensions { get; private set; } public TimeSpan PingTimeout { get; set; } public TimeSpan PingInterval { get { if (!(PingTimeout > TimeSpan.Zero)) { return TimeSpan.FromSeconds(5.0); } return TimeSpan.FromTicks(PingTimeout.Ticks / 3); } } public int NegotiationQueueCapacity { get; set; } public int ParallelNegotiations { get; set; } public TimeSpan NegotiationTimeout { get; set; } public int SendBufferSize { get; set; } public string[] SubProtocols { get; set; } public BufferManager BufferManager { get; set; } public HttpAuthenticationCallback HttpAuthenticationHandler { get; set; } public RemoteCertificateValidationCallback CertificateValidationHandler { get; set; } public SslProtocols SupportedSslProtocols { get; set; } public PingMode PingMode { get; set; } public IHttpFallback HttpFallback { get; set; } public ILogger Logger { get; set; } public WebSocketListenerOptions() { PingTimeout = TimeSpan.FromSeconds(5.0); Transports = new WebSocketTransportCollection(); Standards = new WebSocketFactoryCollection(); ConnectionExtensions = new WebSocketConnectionExtensionCollection(); NegotiationQueueCapacity = Environment.ProcessorCount * 10; ParallelNegotiations = Environment.ProcessorCount * 2; NegotiationTimeout = TimeSpan.FromSeconds(5.0); SendBufferSize = 8192; SubProtocols = NoSubProtocols; HttpAuthenticationHandler = null; CertificateValidationHandler = null; PingMode = PingMode.LatencyControl; SupportedSslProtocols = SslProtocols.Tls | SslProtocols.Tls11 | SslProtocols.Tls12; Logger = NullLogger.Instance; } public void CheckCoherence() { if (PingTimeout <= TimeSpan.Zero) { PingTimeout = Timeout.InfiniteTimeSpan; } if (PingTimeout <= TimeSpan.FromSeconds(1.0)) { PingTimeout = TimeSpan.FromSeconds(1.0); } if (NegotiationQueueCapacity < 0) { throw new WebSocketException(string.Format("{0} must be 0 or more. Actual value: {1}", "NegotiationQueueCapacity", NegotiationQueueCapacity)); } if (ParallelNegotiations < 1) { throw new WebSocketException(string.Format("{0} cannot be less than 1. Actual value: {1}", "ParallelNegotiations", ParallelNegotiations)); } if (NegotiationTimeout == TimeSpan.Zero) { NegotiationTimeout = Timeout.InfiniteTimeSpan; } if (SendBufferSize < 1024) { t
plugins/CultOfTheButtplug/Newtonsoft.Json.dll
Decompiled 9 months ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Concurrent; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Collections.Specialized; using System.ComponentModel; using System.Data; using System.Data.SqlTypes; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Dynamic; using System.Globalization; using System.IO; using System.Linq; using System.Linq.Expressions; using System.Numerics; using System.Reflection; using System.Reflection.Emit; using System.Resources; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Serialization; using System.Runtime.Serialization.Formatters; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; using System.Xml; using System.Xml.Linq; using Microsoft.CodeAnalysis; using Newtonsoft.Json.Bson; using Newtonsoft.Json.Converters; using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq.JsonPath; using Newtonsoft.Json.Schema; using Newtonsoft.Json.Serialization; using Newtonsoft.Json.Utilities; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AllowPartiallyTrustedCallers] [assembly: InternalsVisibleTo("Newtonsoft.Json.Schema, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f561df277c6c0b497d629032b410cdcf286e537c054724f7ffa0164345f62b3e642029d7a80cc351918955328c4adc8a048823ef90b0cf38ea7db0d729caf2b633c3babe08b0310198c1081995c19029bc675193744eab9d7345b8a67258ec17d112cebdbbb2a281487dceeafb9d83aa930f32103fbe1d2911425bc5744002c7")] [assembly: InternalsVisibleTo("Newtonsoft.Json.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f561df277c6c0b497d629032b410cdcf286e537c054724f7ffa0164345f62b3e642029d7a80cc351918955328c4adc8a048823ef90b0cf38ea7db0d729caf2b633c3babe08b0310198c1081995c19029bc675193744eab9d7345b8a67258ec17d112cebdbbb2a281487dceeafb9d83aa930f32103fbe1d2911425bc5744002c7")] [assembly: InternalsVisibleTo("Newtonsoft.Json.Dynamic, PublicKey=0024000004800000940000000602000000240000525341310004000001000100cbd8d53b9d7de30f1f1278f636ec462cf9c254991291e66ebb157a885638a517887633b898ccbcf0d5c5ff7be85a6abe9e765d0ac7cd33c68dac67e7e64530e8222101109f154ab14a941c490ac155cd1d4fcba0fabb49016b4ef28593b015cab5937da31172f03f67d09edda404b88a60023f062ae71d0b2e4438b74cc11dc9")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("9ca358aa-317b-4925-8ada-4a29e943a363")] [assembly: CLSCompliant(true)] [assembly: TargetFramework(".NETFramework,Version=v4.5", FrameworkDisplayName = ".NET Framework 4.5")] [assembly: AssemblyCompany("Newtonsoft")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyCopyright("Copyright © James Newton-King 2008")] [assembly: AssemblyDescription("Json.NET is a popular high-performance JSON framework for .NET")] [assembly: AssemblyFileVersion("13.0.2.27524")] [assembly: AssemblyInformationalVersion("13.0.2+4fba53a324c445f06ee08e45a015c346000a7ef2")] [assembly: AssemblyProduct("Json.NET")] [assembly: AssemblyTitle("Json.NET .NET 4.5")] [assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/JamesNK/Newtonsoft.Json")] [assembly: NeutralResourcesLanguage("en-US")] [assembly: AssemblyVersion("13.0.0.0")] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class IsReadOnlyAttribute : Attribute { } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } } namespace System.Diagnostics.CodeAnalysis { [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.ReturnValue, AllowMultiple = true)] internal sealed class NotNullAttribute : Attribute { } [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false)] internal sealed class NotNullWhenAttribute : Attribute { public bool ReturnValue { get; } public NotNullWhenAttribute(bool returnValue) { ReturnValue = returnValue; } } [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.ReturnValue, Inherited = false)] internal sealed class MaybeNullAttribute : Attribute { } [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, Inherited = false)] internal sealed class AllowNullAttribute : Attribute { } [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] internal class DoesNotReturnIfAttribute : Attribute { public bool ParameterValue { get; } public DoesNotReturnIfAttribute(bool parameterValue) { ParameterValue = parameterValue; } } } namespace Newtonsoft.Json { public enum ConstructorHandling { Default, AllowNonPublicDefaultConstructor } public enum DateFormatHandling { IsoDateFormat, MicrosoftDateFormat } public enum DateParseHandling { None, DateTime, DateTimeOffset } public enum DateTimeZoneHandling { Local, Utc, Unspecified, RoundtripKind } public class DefaultJsonNameTable : JsonNameTable { private class Entry { internal readonly string Value; internal readonly int HashCode; internal Entry Next; internal Entry(string value, int hashCode, Entry next) { Value = value; HashCode = hashCode; Next = next; } } private static readonly int HashCodeRandomizer; private int _count; private Entry[] _entries; private int _mask = 31; static DefaultJsonNameTable() { HashCodeRandomizer = Environment.TickCount; } public DefaultJsonNameTable() { _entries = new Entry[_mask + 1]; } public override string? Get(char[] key, int start, int length) { if (length == 0) { return string.Empty; } int num = length + HashCodeRandomizer; num += (num << 7) ^ key[start]; int num2 = start + length; for (int i = start + 1; i < num2; i++) { num += (num << 7) ^ key[i]; } num -= num >> 17; num -= num >> 11; num -= num >> 5; int num3 = Volatile.Read(ref _mask); int num4 = num & num3; for (Entry entry = _entries[num4]; entry != null; entry = entry.Next) { if (entry.HashCode == num && TextEquals(entry.Value, key, start, length)) { return entry.Value; } } return null; } public string Add(string key) { if (key == null) { throw new ArgumentNullException("key"); } int length = key.Length; if (length == 0) { return string.Empty; } int num = length + HashCodeRandomizer; for (int i = 0; i < key.Length; i++) { num += (num << 7) ^ key[i]; } num -= num >> 17; num -= num >> 11; num -= num >> 5; for (Entry entry = _entries[num & _mask]; entry != null; entry = entry.Next) { if (entry.HashCode == num && entry.Value.Equals(key, StringComparison.Ordinal)) { return entry.Value; } } return AddEntry(key, num); } private string AddEntry(string str, int hashCode) { int num = hashCode & _mask; Entry entry = new Entry(str, hashCode, _entries[num]); _entries[num] = entry; if (_count++ == _mask) { Grow(); } return entry.Value; } private void Grow() { Entry[] entries = _entries; int num = _mask * 2 + 1; Entry[] array = new Entry[num + 1]; for (int i = 0; i < entries.Length; i++) { Entry entry = entries[i]; while (entry != null) { int num2 = entry.HashCode & num; Entry next = entry.Next; entry.Next = array[num2]; array[num2] = entry; entry = next; } } _entries = array; Volatile.Write(ref _mask, num); } private static bool TextEquals(string str1, char[] str2, int str2Start, int str2Length) { if (str1.Length != str2Length) { return false; } for (int i = 0; i < str1.Length; i++) { if (str1[i] != str2[str2Start + i]) { return false; } } return true; } } [Flags] public enum DefaultValueHandling { Include = 0, Ignore = 1, Populate = 2, IgnoreAndPopulate = 3 } public enum FloatFormatHandling { String, Symbol, DefaultValue } public enum FloatParseHandling { Double, Decimal } public enum Formatting { None, Indented } public interface IArrayPool<T> { T[] Rent(int minimumLength); void Return(T[]? array); } public interface IJsonLineInfo { int LineNumber { get; } int LinePosition { get; } bool HasLineInfo(); } [AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface, AllowMultiple = false)] public sealed class JsonArrayAttribute : JsonContainerAttribute { private bool _allowNullItems; public bool AllowNullItems { get { return _allowNullItems; } set { _allowNullItems = value; } } public JsonArrayAttribute() { } public JsonArrayAttribute(bool allowNullItems) { _allowNullItems = allowNullItems; } public JsonArrayAttribute(string id) : base(id) { } } [AttributeUsage(AttributeTargets.Constructor, AllowMultiple = false)] public sealed class JsonConstructorAttribute : Attribute { } [AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface, AllowMultiple = false)] public abstract class JsonContainerAttribute : Attribute { internal bool? _isReference; internal bool? _itemIsReference; internal ReferenceLoopHandling? _itemReferenceLoopHandling; internal TypeNameHandling? _itemTypeNameHandling; private Type? _namingStrategyType; private object[]? _namingStrategyParameters; public string? Id { get; set; } public string? Title { get; set; } public string? Description { get; set; } public Type? ItemConverterType { get; set; } public object[]? ItemConverterParameters { get; set; } public Type? NamingStrategyType { get { return _namingStrategyType; } set { _namingStrategyType = value; NamingStrategyInstance = null; } } public object[]? NamingStrategyParameters { get { return _namingStrategyParameters; } set { _namingStrategyParameters = value; NamingStrategyInstance = null; } } internal NamingStrategy? NamingStrategyInstance { get; set; } public bool IsReference { get { return _isReference.GetValueOrDefault(); } set { _isReference = value; } } public bool ItemIsReference { get { return _itemIsReference.GetValueOrDefault(); } set { _itemIsReference = value; } } public ReferenceLoopHandling ItemReferenceLoopHandling { get { return _itemReferenceLoopHandling.GetValueOrDefault(); } set { _itemReferenceLoopHandling = value; } } public TypeNameHandling ItemTypeNameHandling { get { return _itemTypeNameHandling.GetValueOrDefault(); } set { _itemTypeNameHandling = value; } } protected JsonContainerAttribute() { } protected JsonContainerAttribute(string id) { Id = id; } } public static class JsonConvert { public static readonly string True = "true"; public static readonly string False = "false"; public static readonly string Null = "null"; public static readonly string Undefined = "undefined"; public static readonly string PositiveInfinity = "Infinity"; public static readonly string NegativeInfinity = "-Infinity"; public static readonly string NaN = "NaN"; public static Func<JsonSerializerSettings>? DefaultSettings { get; set; } public static string ToString(DateTime value) { return ToString(value, DateFormatHandling.IsoDateFormat, DateTimeZoneHandling.RoundtripKind); } public static string ToString(DateTime value, DateFormatHandling format, DateTimeZoneHandling timeZoneHandling) { DateTime value2 = DateTimeUtils.EnsureDateTime(value, timeZoneHandling); using StringWriter stringWriter = StringUtils.CreateStringWriter(64); stringWriter.Write('"'); DateTimeUtils.WriteDateTimeString(stringWriter, value2, format, null, CultureInfo.InvariantCulture); stringWriter.Write('"'); return stringWriter.ToString(); } public static string ToString(DateTimeOffset value) { return ToString(value, DateFormatHandling.IsoDateFormat); } public static string ToString(DateTimeOffset value, DateFormatHandling format) { using StringWriter stringWriter = StringUtils.CreateStringWriter(64); stringWriter.Write('"'); DateTimeUtils.WriteDateTimeOffsetString(stringWriter, value, format, null, CultureInfo.InvariantCulture); stringWriter.Write('"'); return stringWriter.ToString(); } public static string ToString(bool value) { if (!value) { return False; } return True; } public static string ToString(char value) { return ToString(char.ToString(value)); } public static string ToString(Enum value) { return value.ToString("D"); } public static string ToString(int value) { return value.ToString(null, CultureInfo.InvariantCulture); } public static string ToString(short value) { return value.ToString(null, CultureInfo.InvariantCulture); } [CLSCompliant(false)] public static string ToString(ushort value) { return value.ToString(null, CultureInfo.InvariantCulture); } [CLSCompliant(false)] public static string ToString(uint value) { return value.ToString(null, CultureInfo.InvariantCulture); } public static string ToString(long value) { return value.ToString(null, CultureInfo.InvariantCulture); } private static string ToStringInternal(BigInteger value) { return value.ToString(null, CultureInfo.InvariantCulture); } [CLSCompliant(false)] public static string ToString(ulong value) { return value.ToString(null, CultureInfo.InvariantCulture); } public static string ToString(float value) { return EnsureDecimalPlace(value, value.ToString("R", CultureInfo.InvariantCulture)); } internal static string ToString(float value, FloatFormatHandling floatFormatHandling, char quoteChar, bool nullable) { return EnsureFloatFormat(value, EnsureDecimalPlace(value, value.ToString("R", CultureInfo.InvariantCulture)), floatFormatHandling, quoteChar, nullable); } private static string EnsureFloatFormat(double value, string text, FloatFormatHandling floatFormatHandling, char quoteChar, bool nullable) { if (floatFormatHandling == FloatFormatHandling.Symbol || (!double.IsInfinity(value) && !double.IsNaN(value))) { return text; } if (floatFormatHandling == FloatFormatHandling.DefaultValue) { if (nullable) { return Null; } return "0.0"; } return quoteChar + text + quoteChar; } public static string ToString(double value) { return EnsureDecimalPlace(value, value.ToString("R", CultureInfo.InvariantCulture)); } internal static string ToString(double value, FloatFormatHandling floatFormatHandling, char quoteChar, bool nullable) { return EnsureFloatFormat(value, EnsureDecimalPlace(value, value.ToString("R", CultureInfo.InvariantCulture)), floatFormatHandling, quoteChar, nullable); } private static string EnsureDecimalPlace(double value, string text) { if (double.IsNaN(value) || double.IsInfinity(value) || StringUtils.IndexOf(text, '.') != -1 || StringUtils.IndexOf(text, 'E') != -1 || StringUtils.IndexOf(text, 'e') != -1) { return text; } return text + ".0"; } private static string EnsureDecimalPlace(string text) { if (StringUtils.IndexOf(text, '.') != -1) { return text; } return text + ".0"; } public static string ToString(byte value) { return value.ToString(null, CultureInfo.InvariantCulture); } [CLSCompliant(false)] public static string ToString(sbyte value) { return value.ToString(null, CultureInfo.InvariantCulture); } public static string ToString(decimal value) { return EnsureDecimalPlace(value.ToString(null, CultureInfo.InvariantCulture)); } public static string ToString(Guid value) { return ToString(value, '"'); } internal static string ToString(Guid value, char quoteChar) { string text = value.ToString("D", CultureInfo.InvariantCulture); string text2 = quoteChar.ToString(CultureInfo.InvariantCulture); return text2 + text + text2; } public static string ToString(TimeSpan value) { return ToString(value, '"'); } internal static string ToString(TimeSpan value, char quoteChar) { return ToString(value.ToString(), quoteChar); } public static string ToString(Uri? value) { if (value == null) { return Null; } return ToString(value, '"'); } internal static string ToString(Uri value, char quoteChar) { return ToString(value.OriginalString, quoteChar); } public static string ToString(string? value) { return ToString(value, '"'); } public static string ToString(string? value, char delimiter) { return ToString(value, delimiter, StringEscapeHandling.Default); } public static string ToString(string? value, char delimiter, StringEscapeHandling stringEscapeHandling) { if (delimiter != '"' && delimiter != '\'') { throw new ArgumentException("Delimiter must be a single or double quote.", "delimiter"); } return JavaScriptUtils.ToEscapedJavaScriptString(value, delimiter, appendDelimiters: true, stringEscapeHandling); } public static string ToString(object? value) { if (value == null) { return Null; } return ConvertUtils.GetTypeCode(value.GetType()) switch { PrimitiveTypeCode.String => ToString((string)value), PrimitiveTypeCode.Char => ToString((char)value), PrimitiveTypeCode.Boolean => ToString((bool)value), PrimitiveTypeCode.SByte => ToString((sbyte)value), PrimitiveTypeCode.Int16 => ToString((short)value), PrimitiveTypeCode.UInt16 => ToString((ushort)value), PrimitiveTypeCode.Int32 => ToString((int)value), PrimitiveTypeCode.Byte => ToString((byte)value), PrimitiveTypeCode.UInt32 => ToString((uint)value), PrimitiveTypeCode.Int64 => ToString((long)value), PrimitiveTypeCode.UInt64 => ToString((ulong)value), PrimitiveTypeCode.Single => ToString((float)value), PrimitiveTypeCode.Double => ToString((double)value), PrimitiveTypeCode.DateTime => ToString((DateTime)value), PrimitiveTypeCode.Decimal => ToString((decimal)value), PrimitiveTypeCode.DBNull => Null, PrimitiveTypeCode.DateTimeOffset => ToString((DateTimeOffset)value), PrimitiveTypeCode.Guid => ToString((Guid)value), PrimitiveTypeCode.Uri => ToString((Uri)value), PrimitiveTypeCode.TimeSpan => ToString((TimeSpan)value), PrimitiveTypeCode.BigInteger => ToStringInternal((BigInteger)value), _ => throw new ArgumentException("Unsupported type: {0}. Use the JsonSerializer class to get the object's JSON representation.".FormatWith(CultureInfo.InvariantCulture, value.GetType())), }; } [DebuggerStepThrough] public static string SerializeObject(object? value) { return SerializeObject(value, (Type?)null, (JsonSerializerSettings?)null); } [DebuggerStepThrough] public static string SerializeObject(object? value, Formatting formatting) { return SerializeObject(value, formatting, (JsonSerializerSettings?)null); } [DebuggerStepThrough] public static string SerializeObject(object? value, params JsonConverter[] converters) { JsonSerializerSettings settings = ((converters != null && converters.Length != 0) ? new JsonSerializerSettings { Converters = converters } : null); return SerializeObject(value, null, settings); } [DebuggerStepThrough] public static string SerializeObject(object? value, Formatting formatting, params JsonConverter[] converters) { JsonSerializerSettings settings = ((converters != null && converters.Length != 0) ? new JsonSerializerSettings { Converters = converters } : null); return SerializeObject(value, null, formatting, settings); } [DebuggerStepThrough] public static string SerializeObject(object? value, JsonSerializerSettings? settings) { return SerializeObject(value, null, settings); } [DebuggerStepThrough] public static string SerializeObject(object? value, Type? type, JsonSerializerSettings? settings) { JsonSerializer jsonSerializer = JsonSerializer.CreateDefault(settings); return SerializeObjectInternal(value, type, jsonSerializer); } [DebuggerStepThrough] public static string SerializeObject(object? value, Formatting formatting, JsonSerializerSettings? settings) { return SerializeObject(value, null, formatting, settings); } [DebuggerStepThrough] public static string SerializeObject(object? value, Type? type, Formatting formatting, JsonSerializerSettings? settings) { JsonSerializer jsonSerializer = JsonSerializer.CreateDefault(settings); jsonSerializer.Formatting = formatting; return SerializeObjectInternal(value, type, jsonSerializer); } private static string SerializeObjectInternal(object? value, Type? type, JsonSerializer jsonSerializer) { StringWriter stringWriter = new StringWriter(new StringBuilder(256), CultureInfo.InvariantCulture); using (JsonTextWriter jsonTextWriter = new JsonTextWriter(stringWriter)) { jsonTextWriter.Formatting = jsonSerializer.Formatting; jsonSerializer.Serialize(jsonTextWriter, value, type); } return stringWriter.ToString(); } [DebuggerStepThrough] public static object? DeserializeObject(string value) { return DeserializeObject(value, (Type?)null, (JsonSerializerSettings?)null); } [DebuggerStepThrough] public static object? DeserializeObject(string value, JsonSerializerSettings settings) { return DeserializeObject(value, null, settings); } [DebuggerStepThrough] public static object? DeserializeObject(string value, Type type) { return DeserializeObject(value, type, (JsonSerializerSettings?)null); } [DebuggerStepThrough] public static T? DeserializeObject<T>(string value) { return JsonConvert.DeserializeObject<T>(value, (JsonSerializerSettings?)null); } [DebuggerStepThrough] public static T? DeserializeAnonymousType<T>(string value, T anonymousTypeObject) { return DeserializeObject<T>(value); } [DebuggerStepThrough] public static T? DeserializeAnonymousType<T>(string value, T anonymousTypeObject, JsonSerializerSettings settings) { return DeserializeObject<T>(value, settings); } [DebuggerStepThrough] public static T? DeserializeObject<T>(string value, params JsonConverter[] converters) { return (T)DeserializeObject(value, typeof(T), converters); } [DebuggerStepThrough] public static T? DeserializeObject<T>(string value, JsonSerializerSettings? settings) { return (T)DeserializeObject(value, typeof(T), settings); } [DebuggerStepThrough] public static object? DeserializeObject(string value, Type type, params JsonConverter[] converters) { JsonSerializerSettings settings = ((converters != null && converters.Length != 0) ? new JsonSerializerSettings { Converters = converters } : null); return DeserializeObject(value, type, settings); } public static object? DeserializeObject(string value, Type? type, JsonSerializerSettings? settings) { ValidationUtils.ArgumentNotNull(value, "value"); JsonSerializer jsonSerializer = JsonSerializer.CreateDefault(settings); if (!jsonSerializer.IsCheckAdditionalContentSet()) { jsonSerializer.CheckAdditionalContent = true; } using JsonTextReader reader = new JsonTextReader(new StringReader(value)); return jsonSerializer.Deserialize(reader, type); } [DebuggerStepThrough] public static void PopulateObject(string value, object target) { PopulateObject(value, target, null); } public static void PopulateObject(string value, object target, JsonSerializerSettings? settings) { JsonSerializer jsonSerializer = JsonSerializer.CreateDefault(settings); using JsonReader jsonReader = new JsonTextReader(new StringReader(value)); jsonSerializer.Populate(jsonReader, target); if (settings == null || !settings.CheckAdditionalContent) { return; } while (jsonReader.Read()) { if (jsonReader.TokenType != JsonToken.Comment) { throw JsonSerializationException.Create(jsonReader, "Additional text found in JSON string after finishing deserializing object."); } } } public static string SerializeXmlNode(XmlNode? node) { return SerializeXmlNode(node, Formatting.None); } public static string SerializeXmlNode(XmlNode? node, Formatting formatting) { XmlNodeConverter xmlNodeConverter = new XmlNodeConverter(); return SerializeObject(node, formatting, xmlNodeConverter); } public static string SerializeXmlNode(XmlNode? node, Formatting formatting, bool omitRootObject) { XmlNodeConverter xmlNodeConverter = new XmlNodeConverter { OmitRootObject = omitRootObject }; return SerializeObject(node, formatting, xmlNodeConverter); } public static XmlDocument? DeserializeXmlNode(string value) { return DeserializeXmlNode(value, null); } public static XmlDocument? DeserializeXmlNode(string value, string? deserializeRootElementName) { return DeserializeXmlNode(value, deserializeRootElementName, writeArrayAttribute: false); } public static XmlDocument? DeserializeXmlNode(string value, string? deserializeRootElementName, bool writeArrayAttribute) { return DeserializeXmlNode(value, deserializeRootElementName, writeArrayAttribute, encodeSpecialCharacters: false); } public static XmlDocument? DeserializeXmlNode(string value, string? deserializeRootElementName, bool writeArrayAttribute, bool encodeSpecialCharacters) { XmlNodeConverter xmlNodeConverter = new XmlNodeConverter(); xmlNodeConverter.DeserializeRootElementName = deserializeRootElementName; xmlNodeConverter.WriteArrayAttribute = writeArrayAttribute; xmlNodeConverter.EncodeSpecialCharacters = encodeSpecialCharacters; return (XmlDocument)DeserializeObject(value, typeof(XmlDocument), xmlNodeConverter); } public static string SerializeXNode(XObject? node) { return SerializeXNode(node, Formatting.None); } public static string SerializeXNode(XObject? node, Formatting formatting) { return SerializeXNode(node, formatting, omitRootObject: false); } public static string SerializeXNode(XObject? node, Formatting formatting, bool omitRootObject) { XmlNodeConverter xmlNodeConverter = new XmlNodeConverter { OmitRootObject = omitRootObject }; return SerializeObject(node, formatting, xmlNodeConverter); } public static XDocument? DeserializeXNode(string value) { return DeserializeXNode(value, null); } public static XDocument? DeserializeXNode(string value, string? deserializeRootElementName) { return DeserializeXNode(value, deserializeRootElementName, writeArrayAttribute: false); } public static XDocument? DeserializeXNode(string value, string? deserializeRootElementName, bool writeArrayAttribute) { return DeserializeXNode(value, deserializeRootElementName, writeArrayAttribute, encodeSpecialCharacters: false); } public static XDocument? DeserializeXNode(string value, string? deserializeRootElementName, bool writeArrayAttribute, bool encodeSpecialCharacters) { //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Expected O, but got Unknown XmlNodeConverter xmlNodeConverter = new XmlNodeConverter(); xmlNodeConverter.DeserializeRootElementName = deserializeRootElementName; xmlNodeConverter.WriteArrayAttribute = writeArrayAttribute; xmlNodeConverter.EncodeSpecialCharacters = encodeSpecialCharacters; return (XDocument)DeserializeObject(value, typeof(XDocument), xmlNodeConverter); } } public abstract class JsonConverter { public virtual bool CanRead => true; public virtual bool CanWrite => true; public abstract void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer); public abstract object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer); public abstract bool CanConvert(Type objectType); } public abstract class JsonConverter<T> : JsonConverter { public sealed override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer) { if (!((value != null) ? (value is T) : ReflectionUtils.IsNullable(typeof(T)))) { throw new JsonSerializationException("Converter cannot write specified value to JSON. {0} is required.".FormatWith(CultureInfo.InvariantCulture, typeof(T))); } WriteJson(writer, (T)value, serializer); } public abstract void WriteJson(JsonWriter writer, T? value, JsonSerializer serializer); public sealed override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer) { bool flag = existingValue == null; if (!flag && !(existingValue is T)) { throw new JsonSerializationException("Converter cannot read JSON with the specified existing value. {0} is required.".FormatWith(CultureInfo.InvariantCulture, typeof(T))); } return ReadJson(reader, objectType, flag ? default(T) : ((T)existingValue), !flag, serializer); } public abstract T? ReadJson(JsonReader reader, Type objectType, T? existingValue, bool hasExistingValue, JsonSerializer serializer); public sealed override bool CanConvert(Type objectType) { return typeof(T).IsAssignableFrom(objectType); } } [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Interface | AttributeTargets.Parameter, AllowMultiple = false)] public sealed class JsonConverterAttribute : Attribute { private readonly Type _converterType; public Type ConverterType => _converterType; public object[]? ConverterParameters { get; } public JsonConverterAttribute(Type converterType) { if (converterType == null) { throw new ArgumentNullException("converterType"); } _converterType = converterType; } public JsonConverterAttribute(Type converterType, params object[] converterParameters) : this(converterType) { ConverterParameters = converterParameters; } } public class JsonConverterCollection : Collection<JsonConverter> { } [AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface, AllowMultiple = false)] public sealed class JsonDictionaryAttribute : JsonContainerAttribute { public JsonDictionaryAttribute() { } public JsonDictionaryAttribute(string id) : base(id) { } } [Serializable] public class JsonException : Exception { public JsonException() { } public JsonException(string message) : base(message) { } public JsonException(string message, Exception? innerException) : base(message, innerException) { } public JsonException(SerializationInfo info, StreamingContext context) : base(info, context) { } internal static JsonException Create(IJsonLineInfo lineInfo, string path, string message) { message = JsonPosition.FormatMessage(lineInfo, path, message); return new JsonException(message); } } [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false)] public class JsonExtensionDataAttribute : Attribute { public bool WriteData { get; set; } public bool ReadData { get; set; } public JsonExtensionDataAttribute() { WriteData = true; ReadData = true; } } [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false)] public sealed class JsonIgnoreAttribute : Attribute { } public abstract class JsonNameTable { public abstract string? Get(char[] key, int start, int length); } [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Interface, AllowMultiple = false)] public sealed class JsonObjectAttribute : JsonContainerAttribute { private MemberSerialization _memberSerialization; internal MissingMemberHandling? _missingMemberHandling; internal Required? _itemRequired; internal NullValueHandling? _itemNullValueHandling; public MemberSerialization MemberSerialization { get { return _memberSerialization; } set { _memberSerialization = value; } } public MissingMemberHandling MissingMemberHandling { get { return _missingMemberHandling.GetValueOrDefault(); } set { _missingMemberHandling = value; } } public NullValueHandling ItemNullValueHandling { get { return _itemNullValueHandling.GetValueOrDefault(); } set { _itemNullValueHandling = value; } } public Required ItemRequired { get { return _itemRequired.GetValueOrDefault(); } set { _itemRequired = value; } } public JsonObjectAttribute() { } public JsonObjectAttribute(MemberSerialization memberSerialization) { MemberSerialization = memberSerialization; } public JsonObjectAttribute(string id) : base(id) { } } internal enum JsonContainerType { None, Object, Array, Constructor } internal struct JsonPosition { private static readonly char[] SpecialCharacters = new char[18] { '.', ' ', '\'', '/', '"', '[', ']', '(', ')', '\t', '\n', '\r', '\f', '\b', '\\', '\u0085', '\u2028', '\u2029' }; internal JsonContainerType Type; internal int Position; internal string? PropertyName; internal bool HasIndex; public JsonPosition(JsonContainerType type) { Type = type; HasIndex = TypeHasIndex(type); Position = -1; PropertyName = null; } internal int CalculateLength() { switch (Type) { case JsonContainerType.Object: return PropertyName.Length + 5; case JsonContainerType.Array: case JsonContainerType.Constructor: return MathUtils.IntLength((ulong)Position) + 2; default: throw new ArgumentOutOfRangeException("Type"); } } internal void WriteTo(StringBuilder sb, ref StringWriter? writer, ref char[]? buffer) { switch (Type) { case JsonContainerType.Object: { string propertyName = PropertyName; if (propertyName.IndexOfAny(SpecialCharacters) != -1) { sb.Append("['"); if (writer == null) { writer = new StringWriter(sb); } JavaScriptUtils.WriteEscapedJavaScriptString(writer, propertyName, '\'', appendDelimiters: false, JavaScriptUtils.SingleQuoteCharEscapeFlags, StringEscapeHandling.Default, null, ref buffer); sb.Append("']"); } else { if (sb.Length > 0) { sb.Append('.'); } sb.Append(propertyName); } break; } case JsonContainerType.Array: case JsonContainerType.Constructor: sb.Append('['); sb.Append(Position); sb.Append(']'); break; } } internal static bool TypeHasIndex(JsonContainerType type) { if (type != JsonContainerType.Array) { return type == JsonContainerType.Constructor; } return true; } internal static string BuildPath(List<JsonPosition> positions, JsonPosition? currentPosition) { int num = 0; if (positions != null) { for (int i = 0; i < positions.Count; i++) { num += positions[i].CalculateLength(); } } if (currentPosition.HasValue) { num += currentPosition.GetValueOrDefault().CalculateLength(); } StringBuilder stringBuilder = new StringBuilder(num); StringWriter writer = null; char[] buffer = null; if (positions != null) { foreach (JsonPosition position in positions) { position.WriteTo(stringBuilder, ref writer, ref buffer); } } currentPosition?.WriteTo(stringBuilder, ref writer, ref buffer); return stringBuilder.ToString(); } internal static string FormatMessage(IJsonLineInfo? lineInfo, string path, string message) { if (!message.EndsWith(Environment.NewLine, StringComparison.Ordinal)) { message = message.Trim(); if (!StringUtils.EndsWith(message, '.')) { message += "."; } message += " "; } message += "Path '{0}'".FormatWith(CultureInfo.InvariantCulture, path); if (lineInfo != null && lineInfo.HasLineInfo()) { message += ", line {0}, position {1}".FormatWith(CultureInfo.InvariantCulture, lineInfo.LineNumber, lineInfo.LinePosition); } message += "."; return message; } } [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = false)] public sealed class JsonPropertyAttribute : Attribute { internal NullValueHandling? _nullValueHandling; internal DefaultValueHandling? _defaultValueHandling; internal ReferenceLoopHandling? _referenceLoopHandling; internal ObjectCreationHandling? _objectCreationHandling; internal TypeNameHandling? _typeNameHandling; internal bool? _isReference; internal int? _order; internal Required? _required; internal bool? _itemIsReference; internal ReferenceLoopHandling? _itemReferenceLoopHandling; internal TypeNameHandling? _itemTypeNameHandling; public Type? ItemConverterType { get; set; } public object[]? ItemConverterParameters { get; set; } public Type? NamingStrategyType { get; set; } public object[]? NamingStrategyParameters { get; set; } public NullValueHandling NullValueHandling { get { return _nullValueHandling.GetValueOrDefault(); } set { _nullValueHandling = value; } } public DefaultValueHandling DefaultValueHandling { get { return _defaultValueHandling.GetValueOrDefault(); } set { _defaultValueHandling = value; } } public ReferenceLoopHandling ReferenceLoopHandling { get { return _referenceLoopHandling.GetValueOrDefault(); } set { _referenceLoopHandling = value; } } public ObjectCreationHandling ObjectCreationHandling { get { return _objectCreationHandling.GetValueOrDefault(); } set { _objectCreationHandling = value; } } public TypeNameHandling TypeNameHandling { get { return _typeNameHandling.GetValueOrDefault(); } set { _typeNameHandling = value; } } public bool IsReference { get { return _isReference.GetValueOrDefault(); } set { _isReference = value; } } public int Order { get { return _order.GetValueOrDefault(); } set { _order = value; } } public Required Required { get { return _required.GetValueOrDefault(); } set { _required = value; } } public string? PropertyName { get; set; } public ReferenceLoopHandling ItemReferenceLoopHandling { get { return _itemReferenceLoopHandling.GetValueOrDefault(); } set { _itemReferenceLoopHandling = value; } } public TypeNameHandling ItemTypeNameHandling { get { return _itemTypeNameHandling.GetValueOrDefault(); } set { _itemTypeNameHandling = value; } } public bool ItemIsReference { get { return _itemIsReference.GetValueOrDefault(); } set { _itemIsReference = value; } } public JsonPropertyAttribute() { } public JsonPropertyAttribute(string propertyName) { PropertyName = propertyName; } } public abstract class JsonReader : IDisposable { protected internal enum State { Start, Complete, Property, ObjectStart, Object, ArrayStart, Array, Closed, PostValue, ConstructorStart, Constructor, Error, Finished } private JsonToken _tokenType; private object? _value; internal char _quoteChar; internal State _currentState; private JsonPosition _currentPosition; private CultureInfo? _culture; private DateTimeZoneHandling _dateTimeZoneHandling; private int? _maxDepth; private bool _hasExceededMaxDepth; internal DateParseHandling _dateParseHandling; internal FloatParseHandling _floatParseHandling; private string? _dateFormatString; private List<JsonPosition>? _stack; protected State CurrentState => _currentState; public bool CloseInput { get; set; } public bool SupportMultipleContent { get; set; } public virtual char QuoteChar { get { return _quoteChar; } protected internal set { _quoteChar = value; } } public DateTimeZoneHandling DateTimeZoneHandling { get { return _dateTimeZoneHandling; } set { if (value < DateTimeZoneHandling.Local || value > DateTimeZoneHandling.RoundtripKind) { throw new ArgumentOutOfRangeException("value"); } _dateTimeZoneHandling = value; } } public DateParseHandling DateParseHandling { get { return _dateParseHandling; } set { if (value < DateParseHandling.None || value > DateParseHandling.DateTimeOffset) { throw new ArgumentOutOfRangeException("value"); } _dateParseHandling = value; } } public FloatParseHandling FloatParseHandling { get { return _floatParseHandling; } set { if (value < FloatParseHandling.Double || value > FloatParseHandling.Decimal) { throw new ArgumentOutOfRangeException("value"); } _floatParseHandling = value; } } public string? DateFormatString { get { return _dateFormatString; } set { _dateFormatString = value; } } public int? MaxDepth { get { return _maxDepth; } set { if (value <= 0) { throw new ArgumentException("Value must be positive.", "value"); } _maxDepth = value; } } public virtual JsonToken TokenType => _tokenType; public virtual object? Value => _value; public virtual Type? ValueType => _value?.GetType(); public virtual int Depth { get { int num = _stack?.Count ?? 0; if (JsonTokenUtils.IsStartToken(TokenType) || _currentPosition.Type == JsonContainerType.None) { return num; } return num + 1; } } public virtual string Path { get { if (_currentPosition.Type == JsonContainerType.None) { return string.Empty; } JsonPosition? currentPosition = ((_currentState != State.ArrayStart && _currentState != State.ConstructorStart && _currentState != State.ObjectStart) ? new JsonPosition?(_currentPosition) : null); return JsonPosition.BuildPath(_stack, currentPosition); } } public CultureInfo Culture { get { return _culture ?? CultureInfo.InvariantCulture; } set { _culture = value; } } public virtual Task<bool> ReadAsync(CancellationToken cancellationToken = default(CancellationToken)) { return cancellationToken.CancelIfRequestedAsync<bool>() ?? Read().ToAsync(); } public async Task SkipAsync(CancellationToken cancellationToken = default(CancellationToken)) { if (TokenType == JsonToken.PropertyName) { await ReadAsync(cancellationToken).ConfigureAwait(continueOnCapturedContext: false); } if (JsonTokenUtils.IsStartToken(TokenType)) { int depth = Depth; while (await ReadAsync(cancellationToken).ConfigureAwait(continueOnCapturedContext: false) && depth < Depth) { } } } internal async Task ReaderReadAndAssertAsync(CancellationToken cancellationToken) { if (!(await ReadAsync(cancellationToken).ConfigureAwait(continueOnCapturedContext: false))) { throw CreateUnexpectedEndException(); } } public virtual Task<bool?> ReadAsBooleanAsync(CancellationToken cancellationToken = default(CancellationToken)) { return cancellationToken.CancelIfRequestedAsync<bool?>() ?? Task.FromResult(ReadAsBoolean()); } public virtual Task<byte[]?> ReadAsBytesAsync(CancellationToken cancellationToken = default(CancellationToken)) { return cancellationToken.CancelIfRequestedAsync<byte[]>() ?? Task.FromResult(ReadAsBytes()); } internal async Task<byte[]?> ReadArrayIntoByteArrayAsync(CancellationToken cancellationToken) { List<byte> buffer = new List<byte>(); do { if (!(await ReadAsync(cancellationToken).ConfigureAwait(continueOnCapturedContext: false))) { SetToken(JsonToken.None); } } while (!ReadArrayElementIntoByteArrayReportDone(buffer)); byte[] array = buffer.ToArray(); SetToken(JsonToken.Bytes, array, updateIndex: false); return array; } public virtual Task<DateTime?> ReadAsDateTimeAsync(CancellationToken cancellationToken = default(CancellationToken)) { return cancellationToken.CancelIfRequestedAsync<DateTime?>() ?? Task.FromResult(ReadAsDateTime()); } public virtual Task<DateTimeOffset?> ReadAsDateTimeOffsetAsync(CancellationToken cancellationToken = default(CancellationToken)) { return cancellationToken.CancelIfRequestedAsync<DateTimeOffset?>() ?? Task.FromResult(ReadAsDateTimeOffset()); } public virtual Task<decimal?> ReadAsDecimalAsync(CancellationToken cancellationToken = default(CancellationToken)) { return cancellationToken.CancelIfRequestedAsync<decimal?>() ?? Task.FromResult(ReadAsDecimal()); } public virtual Task<double?> ReadAsDoubleAsync(CancellationToken cancellationToken = default(CancellationToken)) { return Task.FromResult(ReadAsDouble()); } public virtual Task<int?> ReadAsInt32Async(CancellationToken cancellationToken = default(CancellationToken)) { return cancellationToken.CancelIfRequestedAsync<int?>() ?? Task.FromResult(ReadAsInt32()); } public virtual Task<string?> ReadAsStringAsync(CancellationToken cancellationToken = default(CancellationToken)) { return cancellationToken.CancelIfRequestedAsync<string>() ?? Task.FromResult(ReadAsString()); } internal async Task<bool> ReadAndMoveToContentAsync(CancellationToken cancellationToken) { bool flag = await ReadAsync(cancellationToken).ConfigureAwait(continueOnCapturedContext: false); if (flag) { flag = await MoveToContentAsync(cancellationToken).ConfigureAwait(continueOnCapturedContext: false); } return flag; } internal Task<bool> MoveToContentAsync(CancellationToken cancellationToken) { JsonToken tokenType = TokenType; if (tokenType == JsonToken.None || tokenType == JsonToken.Comment) { return MoveToContentFromNonContentAsync(cancellationToken); } return AsyncUtils.True; } private async Task<bool> MoveToContentFromNonContentAsync(CancellationToken cancellationToken) { JsonToken tokenType; do { if (!(await ReadAsync(cancellationToken).ConfigureAwait(continueOnCapturedContext: false))) { return false; } tokenType = TokenType; } while (tokenType == JsonToken.None || tokenType == JsonToken.Comment); return true; } internal JsonPosition GetPosition(int depth) { if (_stack != null && depth < _stack.Count) { return _stack[depth]; } return _currentPosition; } protected JsonReader() { _currentState = State.Start; _dateTimeZoneHandling = DateTimeZoneHandling.RoundtripKind; _dateParseHandling = DateParseHandling.DateTime; _floatParseHandling = FloatParseHandling.Double; _maxDepth = 64; CloseInput = true; } private void Push(JsonContainerType value) { UpdateScopeWithFinishedValue(); if (_currentPosition.Type == JsonContainerType.None) { _currentPosition = new JsonPosition(value); return; } if (_stack == null) { _stack = new List<JsonPosition>(); } _stack.Add(_currentPosition); _currentPosition = new JsonPosition(value); if (!_maxDepth.HasValue || !(Depth + 1 > _maxDepth) || _hasExceededMaxDepth) { return; } _hasExceededMaxDepth = true; throw JsonReaderException.Create(this, "The reader's MaxDepth of {0} has been exceeded.".FormatWith(CultureInfo.InvariantCulture, _maxDepth)); } private JsonContainerType Pop() { JsonPosition currentPosition; if (_stack != null && _stack.Count > 0) { currentPosition = _currentPosition; _currentPosition = _stack[_stack.Count - 1]; _stack.RemoveAt(_stack.Count - 1); } else { currentPosition = _currentPosition; _currentPosition = default(JsonPosition); } if (_maxDepth.HasValue && Depth <= _maxDepth) { _hasExceededMaxDepth = false; } return currentPosition.Type; } private JsonContainerType Peek() { return _currentPosition.Type; } public abstract bool Read(); public virtual int? ReadAsInt32() { JsonToken contentToken = GetContentToken(); switch (contentToken) { case JsonToken.None: case JsonToken.Null: case JsonToken.EndArray: return null; case JsonToken.Integer: case JsonToken.Float: { object value = Value; if (value is int) { return (int)value; } int num; if (value is BigInteger bigInteger) { num = (int)bigInteger; } else { try { num = Convert.ToInt32(value, CultureInfo.InvariantCulture); } catch (Exception ex) { throw JsonReaderException.Create(this, "Could not convert to integer: {0}.".FormatWith(CultureInfo.InvariantCulture, value), ex); } } SetToken(JsonToken.Integer, num, updateIndex: false); return num; } case JsonToken.String: { string s = (string)Value; return ReadInt32String(s); } default: throw JsonReaderException.Create(this, "Error reading integer. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, contentToken)); } } internal int? ReadInt32String(string? s) { if (StringUtils.IsNullOrEmpty(s)) { SetToken(JsonToken.Null, null, updateIndex: false); return null; } if (int.TryParse(s, NumberStyles.Integer, Culture, out var result)) { SetToken(JsonToken.Integer, result, updateIndex: false); return result; } SetToken(JsonToken.String, s, updateIndex: false); throw JsonReaderException.Create(this, "Could not convert string to integer: {0}.".FormatWith(CultureInfo.InvariantCulture, s)); } public virtual string? ReadAsString() { JsonToken contentToken = GetContentToken(); switch (contentToken) { case JsonToken.None: case JsonToken.Null: case JsonToken.EndArray: return null; case JsonToken.String: return (string)Value; default: if (JsonTokenUtils.IsPrimitiveToken(contentToken)) { object value = Value; if (value != null) { string text = ((!(value is IFormattable formattable)) ? ((value is Uri uri) ? uri.OriginalString : value.ToString()) : formattable.ToString(null, Culture)); SetToken(JsonToken.String, text, updateIndex: false); return text; } } throw JsonReaderException.Create(this, "Error reading string. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, contentToken)); } } public virtual byte[]? ReadAsBytes() { JsonToken contentToken = GetContentToken(); switch (contentToken) { case JsonToken.StartObject: { ReadIntoWrappedTypeObject(); byte[] array2 = ReadAsBytes(); ReaderReadAndAssert(); if (TokenType != JsonToken.EndObject) { throw JsonReaderException.Create(this, "Error reading bytes. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, TokenType)); } SetToken(JsonToken.Bytes, array2, updateIndex: false); return array2; } case JsonToken.String: { string text = (string)Value; Guid g; byte[] array3 = ((text.Length == 0) ? CollectionUtils.ArrayEmpty<byte>() : ((!ConvertUtils.TryConvertGuid(text, out g)) ? Convert.FromBase64String(text) : g.ToByteArray())); SetToken(JsonToken.Bytes, array3, updateIndex: false); return array3; } case JsonToken.None: case JsonToken.Null: case JsonToken.EndArray: return null; case JsonToken.Bytes: if (Value is Guid guid) { byte[] array = guid.ToByteArray(); SetToken(JsonToken.Bytes, array, updateIndex: false); return array; } return (byte[])Value; case JsonToken.StartArray: return ReadArrayIntoByteArray(); default: throw JsonReaderException.Create(this, "Error reading bytes. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, contentToken)); } } internal byte[] ReadArrayIntoByteArray() { List<byte> list = new List<byte>(); do { if (!Read()) { SetToken(JsonToken.None); } } while (!ReadArrayElementIntoByteArrayReportDone(list)); byte[] array = list.ToArray(); SetToken(JsonToken.Bytes, array, updateIndex: false); return array; } private bool ReadArrayElementIntoByteArrayReportDone(List<byte> buffer) { switch (TokenType) { case JsonToken.None: throw JsonReaderException.Create(this, "Unexpected end when reading bytes."); case JsonToken.Integer: buffer.Add(Convert.ToByte(Value, CultureInfo.InvariantCulture)); return false; case JsonToken.EndArray: return true; case JsonToken.Comment: return false; default: throw JsonReaderException.Create(this, "Unexpected token when reading bytes: {0}.".FormatWith(CultureInfo.InvariantCulture, TokenType)); } } public virtual double? ReadAsDouble() { JsonToken contentToken = GetContentToken(); switch (contentToken) { case JsonToken.None: case JsonToken.Null: case JsonToken.EndArray: return null; case JsonToken.Integer: case JsonToken.Float: { object value = Value; if (value is double) { return (double)value; } double num = ((!(value is BigInteger bigInteger)) ? Convert.ToDouble(value, CultureInfo.InvariantCulture) : ((double)bigInteger)); SetToken(JsonToken.Float, num, updateIndex: false); return num; } case JsonToken.String: return ReadDoubleString((string)Value); default: throw JsonReaderException.Create(this, "Error reading double. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, contentToken)); } } internal double? ReadDoubleString(string? s) { if (StringUtils.IsNullOrEmpty(s)) { SetToken(JsonToken.Null, null, updateIndex: false); return null; } if (double.TryParse(s, NumberStyles.Float | NumberStyles.AllowThousands, Culture, out var result)) { SetToken(JsonToken.Float, result, updateIndex: false); return result; } SetToken(JsonToken.String, s, updateIndex: false); throw JsonReaderException.Create(this, "Could not convert string to double: {0}.".FormatWith(CultureInfo.InvariantCulture, s)); } public virtual bool? ReadAsBoolean() { JsonToken contentToken = GetContentToken(); switch (contentToken) { case JsonToken.None: case JsonToken.Null: case JsonToken.EndArray: return null; case JsonToken.Integer: case JsonToken.Float: { bool flag = ((!(Value is BigInteger bigInteger)) ? Convert.ToBoolean(Value, CultureInfo.InvariantCulture) : (bigInteger != 0L)); SetToken(JsonToken.Boolean, flag, updateIndex: false); return flag; } case JsonToken.String: return ReadBooleanString((string)Value); case JsonToken.Boolean: return (bool)Value; default: throw JsonReaderException.Create(this, "Error reading boolean. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, contentToken)); } } internal bool? ReadBooleanString(string? s) { if (StringUtils.IsNullOrEmpty(s)) { SetToken(JsonToken.Null, null, updateIndex: false); return null; } if (bool.TryParse(s, out var result)) { SetToken(JsonToken.Boolean, result, updateIndex: false); return result; } SetToken(JsonToken.String, s, updateIndex: false); throw JsonReaderException.Create(this, "Could not convert string to boolean: {0}.".FormatWith(CultureInfo.InvariantCulture, s)); } public virtual decimal? ReadAsDecimal() { JsonToken contentToken = GetContentToken(); switch (contentToken) { case JsonToken.None: case JsonToken.Null: case JsonToken.EndArray: return null; case JsonToken.Integer: case JsonToken.Float: { object value = Value; if (value is decimal) { return (decimal)value; } decimal num; if (value is BigInteger bigInteger) { num = (decimal)bigInteger; } else { try { num = Convert.ToDecimal(value, CultureInfo.InvariantCulture); } catch (Exception ex) { throw JsonReaderException.Create(this, "Could not convert to decimal: {0}.".FormatWith(CultureInfo.InvariantCulture, value), ex); } } SetToken(JsonToken.Float, num, updateIndex: false); return num; } case JsonToken.String: return ReadDecimalString((string)Value); default: throw JsonReaderException.Create(this, "Error reading decimal. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, contentToken)); } } internal decimal? ReadDecimalString(string? s) { if (StringUtils.IsNullOrEmpty(s)) { SetToken(JsonToken.Null, null, updateIndex: false); return null; } if (decimal.TryParse(s, NumberStyles.Number, Culture, out var result)) { SetToken(JsonToken.Float, result, updateIndex: false); return result; } if (ConvertUtils.DecimalTryParse(s.ToCharArray(), 0, s.Length, out result) == ParseResult.Success) { SetToken(JsonToken.Float, result, updateIndex: false); return result; } SetToken(JsonToken.String, s, updateIndex: false); throw JsonReaderException.Create(this, "Could not convert string to decimal: {0}.".FormatWith(CultureInfo.InvariantCulture, s)); } public virtual DateTime? ReadAsDateTime() { switch (GetContentToken()) { case JsonToken.None: case JsonToken.Null: case JsonToken.EndArray: return null; case JsonToken.Date: if (Value is DateTimeOffset dateTimeOffset) { SetToken(JsonToken.Date, dateTimeOffset.DateTime, updateIndex: false); } return (DateTime)Value; case JsonToken.String: return ReadDateTimeString((string)Value); default: throw JsonReaderException.Create(this, "Error reading date. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, TokenType)); } } internal DateTime? ReadDateTimeString(string? s) { if (StringUtils.IsNullOrEmpty(s)) { SetToken(JsonToken.Null, null, updateIndex: false); return null; } if (DateTimeUtils.TryParseDateTime(s, DateTimeZoneHandling, _dateFormatString, Culture, out var dt)) { dt = DateTimeUtils.EnsureDateTime(dt, DateTimeZoneHandling); SetToken(JsonToken.Date, dt, updateIndex: false); return dt; } if (DateTime.TryParse(s, Culture, DateTimeStyles.RoundtripKind, out dt)) { dt = DateTimeUtils.EnsureDateTime(dt, DateTimeZoneHandling); SetToken(JsonToken.Date, dt, updateIndex: false); return dt; } throw JsonReaderException.Create(this, "Could not convert string to DateTime: {0}.".FormatWith(CultureInfo.InvariantCulture, s)); } public virtual DateTimeOffset? ReadAsDateTimeOffset() { JsonToken contentToken = GetContentToken(); switch (contentToken) { case JsonToken.None: case JsonToken.Null: case JsonToken.EndArray: return null; case JsonToken.Date: if (Value is DateTime dateTime) { SetToken(JsonToken.Date, new DateTimeOffset(dateTime), updateIndex: false); } return (DateTimeOffset)Value; case JsonToken.String: { string s = (string)Value; return ReadDateTimeOffsetString(s); } default: throw JsonReaderException.Create(this, "Error reading date. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, contentToken)); } } internal DateTimeOffset? ReadDateTimeOffsetString(string? s) { if (StringUtils.IsNullOrEmpty(s)) { SetToken(JsonToken.Null, null, updateIndex: false); return null; } if (DateTimeUtils.TryParseDateTimeOffset(s, _dateFormatString, Culture, out var dt)) { SetToken(JsonToken.Date, dt, updateIndex: false); return dt; } if (DateTimeOffset.TryParse(s, Culture, DateTimeStyles.RoundtripKind, out dt)) { SetToken(JsonToken.Date, dt, updateIndex: false); return dt; } SetToken(JsonToken.String, s, updateIndex: false); throw JsonReaderException.Create(this, "Could not convert string to DateTimeOffset: {0}.".FormatWith(CultureInfo.InvariantCulture, s)); } internal void ReaderReadAndAssert() { if (!Read()) { throw CreateUnexpectedEndException(); } } internal JsonReaderException CreateUnexpectedEndException() { return JsonReaderException.Create(this, "Unexpected end when reading JSON."); } internal void ReadIntoWrappedTypeObject() { ReaderReadAndAssert(); if (Value != null && Value.ToString() == "$type") { ReaderReadAndAssert(); if (Value != null && Value.ToString().StartsWith("System.Byte[]", StringComparison.Ordinal)) { ReaderReadAndAssert(); if (Value.ToString() == "$value") { return; } } } throw JsonReaderException.Create(this, "Error reading bytes. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, JsonToken.StartObject)); } public void Skip() { if (TokenType == JsonToken.PropertyName) { Read(); } if (JsonTokenUtils.IsStartToken(TokenType)) { int depth = Depth; while (Read() && depth < Depth) { } } } protected void SetToken(JsonToken newToken) { SetToken(newToken, null, updateIndex: true); } protected void SetToken(JsonToken newToken, object? value) { SetToken(newToken, value, updateIndex: true); } protected void SetToken(JsonToken newToken, object? value, bool updateIndex) { _tokenType = newToken; _value = value; switch (newToken) { case JsonToken.StartObject: _currentState = State.ObjectStart; Push(JsonContainerType.Object); break; case JsonToken.StartArray: _currentState = State.ArrayStart; Push(JsonContainerType.Array); break; case JsonToken.StartConstructor: _currentState = State.ConstructorStart; Push(JsonContainerType.Constructor); break; case JsonToken.EndObject: ValidateEnd(JsonToken.EndObject); break; case JsonToken.EndArray: ValidateEnd(JsonToken.EndArray); break; case JsonToken.EndConstructor: ValidateEnd(JsonToken.EndConstructor); break; case JsonToken.PropertyName: _currentState = State.Property; _currentPosition.PropertyName = (string)value; break; case JsonToken.Raw: case JsonToken.Integer: case JsonToken.Float: case JsonToken.String: case JsonToken.Boolean: case JsonToken.Null: case JsonToken.Undefined: case JsonToken.Date: case JsonToken.Bytes: SetPostValueState(updateIndex); break; case JsonToken.Comment: break; } } internal void SetPostValueState(bool updateIndex) { if (Peek() != 0 || SupportMultipleContent) { _currentState = State.PostValue; } else { SetFinished(); } if (updateIndex) { UpdateScopeWithFinishedValue(); } } private void UpdateScopeWithFinishedValue() { if (_currentPosition.HasIndex) { _currentPosition.Position++; } } private void ValidateEnd(JsonToken endToken) { JsonContainerType jsonContainerType = Pop(); if (GetTypeForCloseToken(endToken) != jsonContainerType) { throw JsonReaderException.Create(this, "JsonToken {0} is not valid for closing JsonType {1}.".FormatWith(CultureInfo.InvariantCulture, endToken, jsonContainerType)); } if (Peek() != 0 || SupportMultipleContent) { _currentState = State.PostValue; } else { SetFinished(); } } protected void SetStateBasedOnCurrent() { JsonContainerType jsonContainerType = Peek(); switch (jsonContainerType) { case JsonContainerType.Object: _currentState = State.Object; break; case JsonContainerType.Array: _currentState = State.Array; break; case JsonContainerType.Constructor: _currentState = State.Constructor; break; case JsonContainerType.None: SetFinished(); break; default: throw JsonReaderException.Create(this, "While setting the reader state back to current object an unexpected JsonType was encountered: {0}".FormatWith(CultureInfo.InvariantCulture, jsonContainerType)); } } private void SetFinished() { _currentState = ((!SupportMultipleContent) ? State.Finished : State.Start); } private JsonContainerType GetTypeForCloseToken(JsonToken token) { return token switch { JsonToken.EndObject => JsonContainerType.Object, JsonToken.EndArray => JsonContainerType.Array, JsonToken.EndConstructor => JsonContainerType.Constructor, _ => throw JsonReaderException.Create(this, "Not a valid close JsonToken: {0}".FormatWith(CultureInfo.InvariantCulture, token)), }; } void IDisposable.Dispose() { Dispose(disposing: true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) { if (_currentState != State.Closed && disposing) { Close(); } } public virtual void Close() { _currentState = State.Closed; _tokenType = JsonToken.None; _value = null; } internal void ReadAndAssert() { if (!Read()) { throw JsonSerializationException.Create(this, "Unexpected end when reading JSON."); } } internal void ReadForTypeAndAssert(JsonContract? contract, bool hasConverter) { if (!ReadForType(contract, hasConverter)) { throw JsonSerializationException.Create(this, "Unexpected end when reading JSON."); } } internal bool ReadForType(JsonContract? contract, bool hasConverter) { if (hasConverter) { return Read(); } switch (contract?.InternalReadType ?? ReadType.Read) { case ReadType.Read: return ReadAndMoveToContent(); case ReadType.ReadAsInt32: ReadAsInt32(); break; case ReadType.ReadAsInt64: { bool result = ReadAndMoveToContent(); if (TokenType == JsonToken.Undefined) { throw JsonReaderException.Create(this, "An undefined token is not a valid {0}.".FormatWith(CultureInfo.InvariantCulture, contract?.UnderlyingType ?? typeof(long))); } return result; } case ReadType.ReadAsDecimal: ReadAsDecimal(); break; case ReadType.ReadAsDouble: ReadAsDouble(); break; case ReadType.ReadAsBytes: ReadAsBytes(); break; case ReadType.ReadAsBoolean: ReadAsBoolean(); break; case ReadType.ReadAsString: ReadAsString(); break; case ReadType.ReadAsDateTime: ReadAsDateTime(); break; case ReadType.ReadAsDateTimeOffset: ReadAsDateTimeOffset(); break; default: throw new ArgumentOutOfRangeException(); } return TokenType != JsonToken.None; } internal bool ReadAndMoveToContent() { if (Read()) { return MoveToContent(); } return false; } internal bool MoveToContent() { JsonToken tokenType = TokenType; while (tokenType == JsonToken.None || tokenType == JsonToken.Comment) { if (!Read()) { return false; } tokenType = TokenType; } return true; } private JsonToken GetContentToken() { JsonToken tokenType; do { if (!Read()) { SetToken(JsonToken.None); return JsonToken.None; } tokenType = TokenType; } while (tokenType == JsonToken.Comment); return tokenType; } } [Serializable] public class JsonReaderException : JsonException { public int LineNumber { get; } public int LinePosition { get; } public string? Path { get; } public JsonReaderException() { } public JsonReaderException(string message) : base(message) { } public JsonReaderException(string message, Exception innerException) : base(message, innerException) { } public JsonReaderException(SerializationInfo info, StreamingContext context) : base(info, context) { } public JsonReaderException(string message, string path, int lineNumber, int linePosition, Exception? innerException) : base(message, innerException) { Path = path; LineNumber = lineNumber; LinePosition = linePosition; } internal static JsonReaderException Create(JsonReader reader, string message) { return Create(reader, message, null); } internal static JsonReaderException Create(JsonReader reader, string message, Exception? ex) { return Create(reader as IJsonLineInfo, reader.Path, message, ex); } internal static JsonReaderException Create(IJsonLineInfo? lineInfo, string path, string message, Exception? ex) { message = JsonPosition.FormatMessage(lineInfo, path, message); int lineNumber; int linePosition; if (lineInfo != null && lineInfo.HasLineInfo()) { lineNumber = lineInfo.LineNumber; linePosition = lineInfo.LinePosition; } else { lineNumber = 0; linePosition = 0; } return new JsonReaderException(message, path, lineNumber, linePosition, ex); } } [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false)] public sealed class JsonRequiredAttribute : Attribute { } [Serializable] public class JsonSerializationException : JsonException { public int LineNumber { get; } public int LinePosition { get; } public string? Path { get; } public JsonSerializationException() { } public JsonSerializationException(string message) : base(message) { } public JsonSerializationException(string message, Exception innerException) : base(message, innerException) { } public JsonSerializationException(SerializationInfo info, StreamingContext context) : base(info, context) { } public JsonSerializationException(string message, string path, int lineNumber, int linePosition, Exception? innerException) : base(message, innerException) { Path = path; LineNumber = lineNumber; LinePosition = linePosition; } internal static JsonSerializationException Create(JsonReader reader, string message) { return Create(reader, message, null); } internal static JsonSerializationException Create(JsonReader reader, string message, Exception? ex) { return Create(reader as IJsonLineInfo, reader.Path, message, ex); } internal static JsonSerializationException Create(IJsonLineInfo? lineInfo, string path, string message, Exception? ex) { message = JsonPosition.FormatMessage(lineInfo, path, message); int lineNumber; int linePosition; if (lineInfo != null && lineInfo.HasLineInfo()) { lineNumber = lineInfo.LineNumber; linePosition = lineInfo.LinePosition; } else { lineNumber = 0; linePosition = 0; } return new JsonSerializationException(message, path, lineNumber, linePosition, ex); } } public class JsonSerializer { internal TypeNameHandling _typeNameHandling; internal TypeNameAssemblyFormatHandling _typeNameAssemblyFormatHandling; internal PreserveReferencesHandling _preserveReferencesHandling; internal ReferenceLoopHandling _referenceLoopHandling; internal MissingMemberHandling _missingMemberHandling; internal ObjectCreationHandling _objectCreationHandling; internal NullValueHandling _nullValueHandling; internal DefaultValueHandling _defaultValueHandling; internal ConstructorHandling _constructorHandling; internal MetadataPropertyHandling _metadataPropertyHandling; internal JsonConverterCollection? _converters; internal IContractResolver _contractResolver; internal ITraceWriter? _traceWriter; internal IEqualityComparer? _equalityComparer; internal ISerializationBinder _serializationBinder; internal StreamingContext _context; private IReferenceResolver? _referenceResolver; private Formatting? _formatting; private DateFormatHandling? _dateFormatHandling; private DateTimeZoneHandling? _dateTimeZoneHandling; private DateParseHandling? _dateParseHandling; private FloatFormatHandling? _floatFormatHandling; private FloatParseHandling? _floatParseHandling; private StringEscapeHandling? _stringEscapeHandling; private CultureInfo _culture; private int? _maxDepth; private bool _maxDepthSet; private bool? _checkAdditionalContent; private string? _dateFormatString; private bool _dateFormatStringSet; public virtual IReferenceResolver? ReferenceResolver { get { return GetReferenceResolver(); } set { if (value == null) { throw new ArgumentNullException("value", "Reference resolver cannot be null."); } _referenceResolver = value; } } [Obsolete("Binder is obsolete. Use SerializationBinder instead.")] public virtual SerializationBinder Binder { get { if (_serializationBinder is SerializationBinder result) { return result; } if (_serializationBinder is SerializationBinderAdapter serializationBinderAdapter) { return serializationBinderAdapter.SerializationBinder; } throw new InvalidOperationException("Cannot get SerializationBinder because an ISerializationBinder was previously set."); } set { if (value == null) { throw new ArgumentNullException("value", "Serialization binder cannot be null."); } _serializationBinder = (value as ISerializationBinder) ?? new SerializationBinderAdapter(value); } } public virtual ISerializationBinder SerializationBinder { get { return _serializationBinder; } set { if (value == null) { throw new ArgumentNullException("value", "Serialization binder cannot be null."); } _serializationBinder = value; } } public virtual ITraceWriter? TraceWriter { get { return _traceWriter; } set { _traceWriter = value; } } public virtual IEqualityComparer? EqualityComparer { get { return _equalityComparer; } set { _equalityComparer = value; } } public virtual TypeNameHandling TypeNameHandling { get { return _typeNameHandling; } set { if (value < TypeNameHandling.None || value > TypeNameHandling.Auto) { throw new ArgumentOutOfRangeException("value"); } _typeNameHandling = value; } } [Obsolete("TypeNameAssemblyFormat is obsolete. Use TypeNameAssemblyFormatHandling instead.")] public virtual FormatterAssemblyStyle TypeNameAssemblyFormat { get { return (FormatterAssemblyStyle)_typeNameAssemblyFormatHandling; } set { if (value < FormatterAssemblyStyle.Simple || value > FormatterAssemblyStyle.Full) { throw new ArgumentOutOfRangeException("value"); } _typeNameAssemblyFormatHandling = (TypeNameAssemblyFormatHandling)value; } } public virtual TypeNameAssemblyFormatHandling TypeNameAssemblyFormatHandling { get { return _typeNameAssemblyFormatHandling; } set { if (value < TypeNameAssemblyFormatHandling.Simple || value > TypeNameAssemblyFormatHandling.Full) { throw new ArgumentOutOfRangeException("value"); } _typeNameAssemblyFormatHandling = value; } } public virtual PreserveReferencesHandling PreserveReferencesHandling { get { return _preserveReferencesHandling; } set { if (value < PreserveReferencesHandling.None || value > PreserveReferencesHandling.All) { throw new ArgumentOutOfRangeException("value"); } _preserveReferencesHandling = value; } } public virtual ReferenceLoopHandling ReferenceLoopHandling { get { return _referenceLoopHandling; } set { if (value < ReferenceLoopHandling.Error || value > ReferenceLoopHandling.Serialize) { throw new ArgumentOutOfRangeException("value"); } _referenceLoopHandling = value; } } public virtual MissingMemberHandling MissingMemberHandling { get { return _missingMemberHandling; } set { if (value < MissingMemberHandling.Ignore || value > MissingMemberHandling.Error) { throw new ArgumentOutOfRangeException("value"); } _missingMemberHandling = value; } } public virtual NullValueHandling NullValueHandling { get { return _nullValueHandling; } set { if (value < NullValueHandling.Include || value > NullValueHandling.Ignore) { throw new ArgumentOutOfRangeException("value"); } _nullValueHandling = value; } } public virtual DefaultValueHandling DefaultValueHandling { get { return _defaultValueHandling; } set { if (value < DefaultValueHandling.Include || value > DefaultValueHandling.IgnoreAndPopulate) { throw new ArgumentOutOfRangeException("value"); } _defaultValueHandling = value; } } public virtual ObjectCreationHandling ObjectCreationHandling { get { return _objectCreationHandling; } set { if (value < ObjectCreationHandling.Auto || value > ObjectCreationHandling.Replace) { throw new ArgumentOutOfRangeException("value"); } _objectCreationHandling = value; } } public virtual ConstructorHandling ConstructorHandling { get { return _constructorHandling; } set { if (value < ConstructorHandling.Default || value > ConstructorHandling.AllowNonPublicDefaultConstructor) { throw new ArgumentOutOfRangeException("value"); } _constructorHandling = value; } } public virtual MetadataPropertyHandling MetadataPropertyHandling { get { return _metadataPropertyHandling; } set { if (value < MetadataPropertyHandling.Default || value > MetadataPropertyHandling.Ignore) { throw new ArgumentOutOfRangeException("value"); } _metadataPropertyHandling = value; } } public virtual JsonConverterCollection Converters { get { if (_converters == null) { _converters = new JsonConverterCollection(); } return _converters; } } public virtual IContractResolver ContractResolver { get { return _contractResolver; } set { _contractResolver = value ?? DefaultContractResolver.Instance; } } public virtual StreamingContext Context { get { return _context; } set { _context = value; } } public virtual Formatting Formatting { get { return _formatting.GetValueOrDefault(); } set { _formatting = value; } } public virtual DateFormatHandling DateFormatHandling { get { return _dateFormatHandling.GetValueOrDefault(); } set { _dateFormatHandling = value; } } public virtual DateTimeZoneHandling DateTimeZoneHandling { get { return _dateTimeZoneHandling ?? DateTimeZoneHandling.RoundtripKind; } set { _dateTimeZoneHandling = value; } } public virtual DateParseHandling DateParseHandling { get { return _dateParseHandling ?? DateParseHandling.DateTime; } set { _dateParseHandling = value; } } public virtual FloatParseHandling FloatParseHandling { get { return _floatParseHandling.GetValueOrDefault(); } set { _floatParseHandling = value; } } public virtual FloatFormatHandling FloatFormatHandling { get { return _floatFormatHandling.GetValueOrDefault(); } set { _floatFormatHandling = value; } } public virtual StringEscapeHandling StringEscapeHandling { get { return _stringEscapeHandling.GetValueOrDefault(); } set { _stringEscapeHandling = value; } } public virtual string DateFormatString { get { return _dateFormatString ?? "yyyy'-'MM'-'dd'T'HH':'mm':'ss.FFFFFFFK"; } set { _dateFormatString = value; _dateFormatStringSet = true; } } public virtual CultureInfo Culture { get { return _culture ?? JsonSerializerSettings.DefaultCulture; } set { _culture = value; } } public virtual int? MaxDepth { get { return _maxDepth; } set { if (value <= 0) { throw new ArgumentException("Value must be positive.", "value"); } _maxDepth = value; _maxDepthSet = true; } } public virtual bool CheckAdditionalContent { get { return _checkAdditionalContent.GetValueOrDefault(); } set { _checkAdditionalContent = value; } } public virtual event EventHandler<Newtonsoft.Json.Serialization.ErrorEventArgs>? Error; internal bool IsCheckAdditionalContentSet() { return _checkAdditionalContent.HasValue; } public JsonSerializer() { _referenceLoopHandling = ReferenceLoopHandling.Error; _missingMemberHandling = MissingMemberHandling.Ignore; _nullValueHandling = NullValueHandling.Include; _defaultValueHandling = DefaultValueHandling.Include; _objectCreationHandling = ObjectCreationHandling.Auto; _preserveReferencesHandling = PreserveReferencesHandling.None; _constructorHandling = ConstructorHandling.Default; _typeNameHandling = TypeNameHandling.None; _metadataPropertyHandling = MetadataPropertyHandling.Default; _context = JsonSerializerSettings.DefaultContext; _serializationBinder = DefaultSerializationBinder.Instance; _culture = JsonSerializerSettings.DefaultCulture; _contractResolver = DefaultContractResolver.Instance; } public static JsonSerializer Create() { return new JsonSerializer(); } public static JsonSerializer Create(JsonSerializerSettings? settings) { JsonSerializer jsonSerializer = Create(); if (settings != null) { ApplySerializerSettings(jsonSerializer, settings); } return jsonSerializer; } public static JsonSerializer CreateDefault() { return Create(JsonConvert.DefaultSettings?.Invoke()); } public static JsonSerializer CreateDefault(JsonSerializerSettings? settings) { JsonSerializer jsonSerializer = CreateDefault(); if (settings != null) { ApplySerializerSettings(jsonSerializer, settings); } return jsonSerializer; } private static void ApplySerializerSettings(JsonSerializer serializer, JsonSerializerSettings settings) { if (!CollectionUtils.IsNullOrEmpty(settings.Converters)) { for (int i = 0; i < settings.Converters.Count; i++) { serializer.Converters.Insert(i, settings.Converters[i]); } } if (settings._typeNameHandling.HasValue) { serializer.TypeNameHandling = settings.TypeNameHandling; } if (settings._metadataPropertyHandling.HasValue) { serializer.MetadataPropertyHandling = settings.MetadataPropertyHandling; } if (settings._typeNameAssemblyFormatHandling.HasValue) { serializer.TypeNameAssemblyFormatHandling = settings.TypeNameAssemblyFormatHandling; } if (settings._preserveReferencesHandling.HasValue) { serializer.PreserveReferencesHandling = settings.PreserveReferencesHandling; } if (settings._referenceLoopHandling.HasValue) { serializer.ReferenceLoopHandling = settings.ReferenceLoopHandling; } if (settings._missingMemberHandling.HasValue) { serializer.MissingMemberHandling = settings.MissingMemberHandling; } if (settings._objectCreationHandling.HasValue) { serializer.ObjectCreationHandling = settings.ObjectCreationHandling; } if (settings._nullValueHandling.HasValue) { serializer.NullValueHandling = settings.NullValueHandling; } if (settings._defaultValueHandling.HasValue) { serializer.DefaultValueHandling = settings.DefaultValueHandling; } if (settings._constructorHandling.HasValue) { serializer.ConstructorHandling = settings.ConstructorHandling; } if (settings._context.HasValue) { serializer.Context = settings.Context; } if (settings._checkAdditionalContent.HasValue) { serializer._checkAdditionalContent = settings._checkAdditionalContent; } if (settings.Error != null) { serializer.Error += settings.Error; } if (settings.ContractResolver != null) { serializer.ContractResolver = settings.ContractResolver; } if (settings.ReferenceResolverProvider != null) { serializer.ReferenceResolver = settings.ReferenceResolverProvider(); } if (settings.TraceWriter != null) { serializer.TraceWriter = settings.TraceWriter; } if (settings.EqualityComparer != null) { serializer.EqualityComparer = settings.EqualityComparer; } if (settings.SerializationBinder != null) { serializer.SerializationBinder = settings.SerializationBinder; } if (settings._formatting.HasValue) { serializer._formatting = settings._formatting; } if (settings._dateFormatHandling.HasValue) { serializer._dateFormatHandling = settings._dateFormatHandling; } if (settings._dateTimeZoneHandling.HasValue) { serializer._dateTimeZoneHandling = settings._dateTimeZoneHandling; } if (settings._dateParseHandling.HasValue) { serializer._dateParseHandling = settings._dateParseHandling; } if (settings._dateFormatStringSet) { serializer._dateFormatString = settings._dateFormatString; serializer._dateFormatStringSet = settings._dateFormatStringSet; } if (settings._floatFormatHandling.HasValue) { serializer._floatFormatHandling = settings._floatFormatHandling; } if (settings._floatParseHandling.HasValue) { serializer._floatParseHandling = settings._floatParseHandling; } if (settings._stringEscapeHandling.HasValue) { serializer._stringEscapeHandling = settings._stringEscapeHandling; } if (settings._culture != null) { serializer._culture = settings._culture; } if (settings._maxDepthSet) { serializer._maxDepth = settings._maxDepth; serializer._maxDepthSet = settings._maxDepthSet; } } [DebuggerStepThrough] public void Populate(TextReader reader, object target) { Populate(new JsonTextReader(reader), target); } [DebuggerStepThrough] public void Populate(JsonReader reader, object target) { PopulateInternal(reader, target); } internal virtual void PopulateInternal(JsonReader reader, object target) { ValidationUtils.ArgumentNotNull(reader, "reader"); ValidationUtils.ArgumentNotNull(target, "target"); SetupReader(reader, out CultureInfo previousCulture, out DateTimeZoneHandling? previousDateTimeZoneHandling, out DateParseHandling? previousDateParseHandling, out FloatParseHandling? previousFloatParseHandling, out int? previousMaxDepth, out string previousDateFormatString); TraceJsonReader traceJsonReader = ((TraceWriter != null && TraceWriter.LevelFilter >= TraceLevel.Verbose) ? CreateTraceJsonReader(reader) : null); new JsonSerializerInternalReader(this).Populate(traceJsonReader ?? reader, target); if (traceJsonReader != null) { TraceWriter.Trace(TraceLevel.Verbose, traceJsonReader.GetDeserializedJsonMessage(), null); } ResetReader(reader, previousCulture, previousDateTimeZoneHandling, previousDateParseHandling, previousFloatParseHandling, previousMaxDepth, previousDateFormatString); } [DebuggerStepThrough] public object? Deserialize(JsonReader reader) { return Deserialize(reader, null); } [DebuggerStepThrough] public object? Deserialize(TextReader reader, Type objectType) { return Deserialize(new JsonTextReader(reader), objectType); } [DebuggerStepThrough] public T? Deserialize<T>(JsonReader reader) { return (T)Deserialize(reader, typeof(T)); } [DebuggerStepThrough] public object? Deserialize(JsonReader reader, Type? objectType) { return DeserializeInternal(reader, objectType); } internal virtual object? DeserializeInternal(JsonReader reader, Type? objectType) { ValidationUtils.ArgumentNotNull(reader, "reader"); SetupReader(reader, out CultureInfo previousCulture, out DateTimeZoneHandling? previousDateTimeZoneHandling, out DateParseHandling? previousDateParseHandling, out FloatParseHandling? previousFloatParseHandling, out int? previousMaxDepth, out string previousDateFormatString); TraceJsonReader traceJsonReader = ((TraceWriter != null && TraceWriter.LevelFilter >= TraceLevel.Verbose) ? CreateTraceJsonReader(reader) : null); object? result = new JsonSerializerInternalReader(this).Deserialize(traceJsonReader ?? reader, objectType, CheckAdditionalContent); if (traceJsonReader != null) { TraceWriter.Trace(TraceLevel.Verbose, traceJsonReader.GetDeserializedJsonMessage(), null); } ResetReader(reader, previousCulture, previousDateTimeZoneHandling, previousDateParseHandling, previousFloatParseHandling, previousMaxDepth, previousDateFormatString); return result; } internal void SetupReader(JsonReader reader, out CultureInfo? previousCulture, out DateTimeZoneHandling? previousDateTimeZoneHandling, out DateParseHandling? previousDateParseHandling, out FloatParseHandling? previousFloatParseHandling, out int? previousMaxDepth, out string? previousDateFormatString) { if (_culture != null && !_culture.Equals(reader.Culture)) { previousCulture = reader.Culture; reader.Culture = _culture; } else { previousCulture = null; } if (_dateTimeZoneHandling.HasValue && reader.DateTimeZoneHandling != _dateTimeZoneHandling) { previousDateTimeZoneHandling = reader.DateTimeZoneHandling; reader.DateTimeZoneHandling = _dateTimeZoneHandling.GetValueOrDefault(); } else { previousDateTimeZoneHandling = null; } if (_dateParseHandling.HasValue && reader.DateParseHandling != _dateParseHandling) { previousDateParseHandling = reader.DateParseHandling; reader.DateParseHandling = _dateParseHandling.GetValueOrDefault(); } else { previousDateParseHandling = null; } if (_floatParseHandling.HasValue && reader.FloatParseHandling != _floatParseHandling) { previousFloatParseHandling = reader.FloatParseHandling; reader.FloatParseHandling = _floatParseHandling.GetValueOrDefault(); } else { previousFloatParseHandling = null; } if (_maxDepthSet && reader.MaxDepth != _maxDepth) { previousMaxDepth = reader.MaxDepth; reader.MaxDepth = _maxDepth; } else { previousMaxDepth = null; } if (_dateFormatStringSet && reader.DateFormatString != _dateFormatString) { previousDateFormatString = reader.DateFormatString; reader.DateFormatString = _dateFormatString; } else { previousDateFormatString = null; } if (reader is JsonTextReader jsonTextReader && jsonTextReader.PropertyNameTable == null && _contractResolver is DefaultContractResolver defaultContractResolver) { jsonTextReader.PropertyNameTable = defaultContractResolver.GetNameTable(); } } private void ResetReader(JsonReader reader, CultureInfo? previousCulture, DateTimeZoneHandling? previousDateTimeZoneHandling, DateParseHandling? previousDateParseHandling, FloatParseHandling? previousFloatParseHandling, int? previousMaxDepth, string? previousDateFormatString) { if (previousCulture != null) { reader.Culture = previousCulture; } if (previousDateTimeZoneHandling.HasValue) { reader.DateTimeZoneHandling = previousDateTimeZoneHandling.GetValueOrDefault(); } if (previousDateParseHandling.HasValue) { reader.DateParseHandling = previousDateParseHandling.GetValueOrDefault(); } if (previousFloatParseHandling.HasValue) { reader.FloatParseHandling = previousFloatParseHandling.GetValueOrDefault(); } if (_maxDepthSet) { reader.MaxDepth = previousMaxDepth; } if (_dateFormatStringSet) { reader.DateFormatString = previousDateFormatString; } if (reader is JsonTextReader jsonTextReader && jsonTextReader.PropertyNameTable != null && _contractResolver is DefaultContractResolver defaultContractResolver && jsonTextReader.PropertyNameTable == defaultContractResolver.GetNameTable()) { jsonTextReader.PropertyNameTable = null; } } public void Serialize(TextWriter textWriter, object? value) { Serialize(new JsonTextWriter(textWriter), value); } public void Serialize(JsonWriter jsonWriter, object? value, Type? objectType) { SerializeInternal(jsonWriter, value, objectType); } public void Serialize(TextWriter textWriter, object? value, Type objectType) { Serialize(new JsonTextWriter(textWriter), value, objectType); } public void Serialize(JsonWriter jsonWriter, object? value) { SerializeInternal(jsonWriter, value, null); } private TraceJsonReader CreateTraceJsonReader(JsonReader reader) { TraceJsonReader traceJsonReader = new TraceJsonReader(reader); if (reader.TokenType != 0) { traceJsonReader.WriteCurrentToken(); } return traceJsonReader; } internal virtual void SerializeInternal(JsonWriter jsonWriter, object? value, Type? objectType) { ValidationUtils.ArgumentNotNull(jsonWriter, "jsonWriter"); Formatting? formatting = null; if (_formatting.HasValue && jsonWriter.Formatting != _formatting) { formatting = jsonWriter.Formatting; jsonWriter.Formatting = _formatting.GetValueOrDefault(); } DateFormatHandling? dateFormatHandling = null; if (_dateFormatHandling.HasValue && jsonWriter.DateFormatHandling != _dateFormatHandling) { dateFormatHandling = jsonWriter.DateFormatHandling; jsonWriter.DateFormatHandling = _dateFormatHandling.GetValueOrDefault(); } DateTimeZoneHandling? dateTimeZoneHandling = null; if (_dateTimeZoneHandling.HasValue && jsonWriter.DateTimeZoneHandling != _dateTimeZoneHandling) { dateTimeZoneHandling = jsonWriter.DateTimeZoneHandling; jsonWriter.DateTimeZoneHandling = _dateTimeZoneHandling.GetValueOrDefault(); } FloatFormatHandling? floatFormatHandling = null; if (_floatFormatHandling.HasValue && jsonWriter.FloatFormatHandling != _floatFormatHandling) { floatFormatHandling = jsonWriter.FloatFormatHandling; jsonWriter.FloatFormatHandling = _floatFormatHandling.GetValueOrDefault(); } StringEscapeHandling? stringEscapeHandling = null; if (_stringEscapeHandling.HasValue && jsonWriter.StringEscapeHandling != _stringEscapeHandling) { stringEscapeHandling = jsonWriter.StringEscapeHandling; jsonWriter.StringEscapeHandling = _stringEscapeHandling.GetValueOrDefault(); } CultureInfo cultureInfo = null; if (_culture != null && !_culture.Equals(jsonWriter.Culture)) { cultureInfo = jsonWriter.Culture; jsonWriter.Culture = _culture; } string dateFormatString = null; if (_dateFormatStringSet && jsonWriter.DateFormatString != _dateFormatString) { dateFormatString = jsonWriter.DateFormatString; jsonWriter.DateFormatString = _dateFormatString; } TraceJsonWriter traceJsonWriter = ((TraceWriter != null && TraceWriter.LevelFilter >= TraceLevel.Verbose) ? new TraceJsonWriter(jsonWriter) : null); new JsonSerializerInternalWriter(this).Serialize(traceJsonWriter ?? jsonWriter, value, objectType); if (traceJsonWriter != null) { TraceWriter.Trace(TraceLevel.Verbose, traceJsonWriter.GetSerializedJsonMessage(), null); } if (formatting.HasValue) { jsonWriter.Formatting = formatting.GetValueOrDefault(); } if (dateFormatHandling.HasValue) { jsonWriter.DateFormatHandling = dateFormatHandling.GetValueOrDefault(); } if (dateTimeZoneHandling.HasValue) { jsonWriter.DateTimeZoneHandling = dateTimeZoneHandling.GetValueOrDefault(); } if (floatFormatHandling.HasValue) { jsonWriter.FloatFormatHandling = floatFormatHandling.GetValueOrDefault(); } if (stringEscapeHandling.HasValue) { jsonWriter.StringEscapeHandling = stringEscapeHandling.GetValueOrDefault(); } if (_dateFormatStringSet) { jsonWriter.DateFormatString = dateFormatString; } if (cultureInfo != null) { jsonWriter.Culture = cultureInfo; } } internal IReferenceResolver GetReferenceResolver() { if (_referenceResolver == null) { _referenceResolver = new DefaultReferenceResolver(); } return _referenceResolver; } internal JsonConverter? GetMatchingConverter(Type type) { return GetMatchingConverter(_converters, type); } internal static JsonConverter? GetMatchingConverter(IList<JsonConverter>? converters, Type objectType) { if (converters != null) { for (int i = 0; i < converters.Count; i++) { JsonConverter jsonConverter = converters[i]; if (jsonConverter.CanConvert(objectType)) { return jsonConverter; } } } return null; } internal void OnError(Newtonsoft.Json.Serialization.ErrorEventArgs e) { this.Error?.Invoke(this, e); } } public class JsonSerializerSettings { internal const ReferenceLoopHandling DefaultReferenceLoopHandling = ReferenceLoopHandling.Error; internal const MissingMemberHandling DefaultMissingMemberHandling = MissingMemberHandling.Ignore; internal const NullValueHandling DefaultNullValueHandling = NullValueHandling.Include; internal const DefaultValueHandling DefaultDefaultValueHandling = DefaultValueHandling.Include; internal const ObjectCreationHandling DefaultObjectCreationHandling = ObjectCreationHandling.Auto; internal const PreserveReferencesHandling DefaultPreserveReferencesHandling = PreserveReferencesHandling.None; internal const ConstructorHandling DefaultConstructorHandling = ConstructorHandling.Default; internal const TypeNameHandling DefaultTypeNameHandling = TypeNameHandling.None; internal const MetadataPropertyHandling DefaultMetadataPropertyHandling = MetadataPropertyHandling.Default; internal static readonly StreamingContext DefaultContext; internal const Formatting DefaultFormatting = Formatting.None; internal const DateFormatHandling DefaultDateFormatHandling = DateFormatHandling.IsoDateFormat; internal const DateTimeZoneHandling DefaultDateTimeZoneHandling = DateTimeZoneHandling.RoundtripKind; internal const DateParseHandling DefaultDateParseHandling = DateParseHandling.DateTime; internal const FloatParseHandling DefaultFloatParseHandling = FloatParseHandling.Double; internal const FloatFormatHandling DefaultFloatFormatHandling = FloatFormatHandling.String; internal const StringEscapeHandling DefaultStringEscapeHandling = StringEscapeHandling.Default; internal const TypeNameAssemblyFormatHandling DefaultTypeNameAssemblyFormatHandling = TypeNameAssemblyFormatHandling.Simple; internal static readonly CultureInfo DefaultCulture; internal const bool DefaultCheckAdditionalContent = false; internal const string DefaultDateFormatString = "yyyy'-'MM'-'dd'T'HH':'mm':'ss.FFFFFFFK"; internal const int DefaultMaxDepth = 64; internal Formatting? _formatting; internal DateFormatHandling? _dateFormatHandling; internal DateTimeZoneHandling? _dateTimeZoneHandling; internal DateParseHandling? _dateParseHandling; internal FloatFormatHandling? _floatFormatHandling; internal FloatParseHandling? _floatParseHandling; internal StringEscapeHandling? _stringEscapeHandling; internal CultureInfo? _culture; internal bool? _checkAdditionalContent; internal int? _maxDepth; internal bool _maxDepthSet; internal string? _dateFormatString; internal bool _dateFormatStringSet; internal TypeNameAssemblyFormatHandling? _typeNameAssemblyFormatHandling; internal DefaultValueHandling? _defaultValueHandling; internal PreserveReferencesHandling? _preserveReferencesHandling; internal NullValueHandling? _nullValueHandling; internal ObjectCreationHandling? _objectCreationHandling; internal MissingMemberHandling? _missingMemberHandling; internal ReferenceLoopHandling? _referenceLoopHandling; internal StreamingContext? _context; internal ConstructorHandling? _constructorHandling; internal TypeNameHandling? _typeNameHandling; internal MetadataPropertyHandling? _metadataPropertyHandling; public ReferenceLoopHandling ReferenceLoopHandling { get { return _referenceLoopHandling.GetValueOrDefault(); } set { _referenceLoopHandling = value; } } public MissingMemberHandling MissingMemberHandling { get { return _missingMemberHandling.GetValueOrDefault(); } set { _missingMemberHandling = value; } } public ObjectCreationHandling ObjectCreationHandling { get { return _objectCreationHandling.GetValueOrDefault(); } set { _objectCreationHandling = value; } } public NullValueHandling NullValueHandling { get { return _nullValueHandling.GetValueOrDefault(); } set { _nullValueHandling = value; } } public DefaultValueHandling DefaultValueHandling { get { return _defaultValueHandling.GetValueOrDefault(); } set { _defaultValueHandling = value; } } public IList<JsonConverter> Converters { get; set; } public PreserveReferencesHandling PreserveReferencesHandling { get { return _preserveReferencesHandling.GetValueOrDef
plugins/CultOfTheButtplug/System.Runtime.CompilerServices.Unsafe.dll
Decompiled 9 months agousing System; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; [assembly: AssemblyCompany("Microsoft Corporation")] [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: AssemblyFileVersion("4.0.0.0")] [assembly: AssemblyInformationalVersion("4.0.0.0")] [assembly: AssemblyTitle("System.Runtime.CompilerServices.Unsafe")] [assembly: AssemblyDescription("System.Runtime.CompilerServices.Unsafe")] [assembly: AssemblyMetadata(".NETFrameworkAssembly", "")] [assembly: AssemblyMetadata("Serviceable", "True")] [assembly: AssemblyCopyright("© Microsoft Corporation. All rights reserved.")] [assembly: AssemblyProduct("Microsoft® .NET Framework")] [assembly: CLSCompliant(false)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyVersion("4.0.4.1")] namespace System.Runtime.CompilerServices { public static class Unsafe { [MethodImpl(MethodImplOptions.AggressiveInlining)] [System.Runtime.Versioning.NonVersionable] public unsafe static T Read<T>(void* source) { return Unsafe.Read<T>(source); } [MethodImpl(MethodImplOptions.AggressiveInlining)] [System.Runtime.Versioning.NonVersionable] public unsafe static T ReadUnaligned<T>(void* source) { return Unsafe.ReadUnaligned<T>(source); } [MethodImpl(MethodImplOptions.AggressiveInlining)] [System.Runtime.Versioning.NonVersionable] public static T ReadUnaligned<T>(ref byte source) { return Unsafe.ReadUnaligned<T>(ref source); } [MethodImpl(MethodImplOptions.AggressiveInlining)] [System.Runtime.Versioning.NonVersionable] public unsafe static void Write<T>(void* destination, T value) { Unsafe.Write(destination, value); } [MethodImpl(MethodImplOptions.AggressiveInlining)] [System.Runtime.Versioning.NonVersionable] public unsafe static void WriteUnaligned<T>(void* destination, T value) { Unsafe.WriteUnaligned(destination, value); } [MethodImpl(MethodImplOptions.AggressiveInlining)] [System.Runtime.Versioning.NonVersionable] public static void WriteUnaligned<T>(ref byte destination, T value) { Unsafe.WriteUnaligned(ref destination, value); } [MethodImpl(MethodImplOptions.AggressiveInlining)] [System.Runtime.Versioning.NonVersionable] public unsafe static void Copy<T>(void* destination, ref T source) { Unsafe.Write(destination, source); } [MethodImpl(MethodImplOptions.AggressiveInlining)] [System.Runtime.Versioning.NonVersionable] public unsafe static void Copy<T>(ref T destination, void* source) { destination = Unsafe.Read<T>(source); } [MethodImpl(MethodImplOptions.AggressiveInlining)] [System.Runtime.Versioning.NonVersionable] public unsafe static void* AsPointer<T>(ref T value) { return Unsafe.AsPointer(ref value); } [MethodImpl(MethodImplOptions.AggressiveInlining)] [System.Runtime.Versioning.NonVersionable] public static int SizeOf<T>() { return Unsafe.SizeOf<T>(); } [MethodImpl(MethodImplOptions.AggressiveInlining)] [System.Runtime.Versioning.NonVersionable] public unsafe static void CopyBlock(void* destination, void* source, uint byteCount) { // IL cpblk instruction Unsafe.CopyBlock(destination, source, byteCount); } [MethodImpl(MethodImplOptions.AggressiveInlining)] [System.Runtime.Versioning.NonVersionable] public static void CopyBlock(ref byte destination, ref byte source, uint byteCount) { // IL cpblk instruction Unsafe.CopyBlock(ref destination, ref source, byteCount); } [MethodImpl(MethodImplOptions.AggressiveInlining)] [System.Runtime.Versioning.NonVersionable] public unsafe static void CopyBlockUnaligned(void* destination, void* source, uint byteCount) { // IL cpblk instruction Unsafe.CopyBlockUnaligned(destination, source, byteCount); } [MethodImpl(MethodImplOptions.AggressiveInlining)] [System.Runtime.Versioning.NonVersionable] public static void CopyBlockUnaligned(ref byte destination, ref byte source, uint byteCount) { // IL cpblk instruction Unsafe.CopyBlockUnaligned(ref destination, ref source, byteCount); } [MethodImpl(MethodImplOptions.AggressiveInlining)] [System.Runtime.Versioning.NonVersionable] public unsafe static void InitBlock(void* startAddress, byte value, uint byteCount) { // IL initblk instruction Unsafe.InitBlock(startAddress, value, byteCount); } [MethodImpl(MethodImplOptions.AggressiveInlining)] [System.Runtime.Versioning.NonVersionable] public static void InitBlock(ref byte startAddress, byte value, uint byteCount) { // IL initblk instruction Unsafe.InitBlock(ref startAddress, value, byteCount); } [MethodImpl(MethodImplOptions.AggressiveInlining)] [System.Runtime.Versioning.NonVersionable] public unsafe static void InitBlockUnaligned(void* startAddress, byte value, uint byteCount) { // IL initblk instruction Unsafe.InitBlockUnaligned(startAddress, value, byteCount); } [MethodImpl(MethodImplOptions.AggressiveInlining)] [System.Runtime.Versioning.NonVersionable] public static void InitBlockUnaligned(ref byte startAddress, byte value, uint byteCount) { // IL initblk instruction Unsafe.InitBlockUnaligned(ref startAddress, value, byteCount); } [MethodImpl(MethodImplOptions.AggressiveInlining)] [System.Runtime.Versioning.NonVersionable] public static T As<T>(object o) where T : class { return (T)o; } [MethodImpl(MethodImplOptions.AggressiveInlining)] [System.Runtime.Versioning.NonVersionable] public unsafe static ref T AsRef<T>(void* source) { return ref *(T*)source; } [MethodImpl(MethodImplOptions.AggressiveInlining)] [System.Runtime.Versioning.NonVersionable] public static ref T AsRef<T>(in T source) { return ref source; } [MethodImpl(MethodImplOptions.AggressiveInlining)] [System.Runtime.Versioning.NonVersionable] public static ref TTo As<TFrom, TTo>(ref TFrom source) { return ref Unsafe.As<TFrom, TTo>(ref source); } [MethodImpl(MethodImplOptions.AggressiveInlining)] [System.Runtime.Versioning.NonVersionable] public static ref T Add<T>(ref T source, int elementOffset) { return ref Unsafe.Add(ref source, elementOffset); } [MethodImpl(MethodImplOptions.AggressiveInlining)] [System.Runtime.Versioning.NonVersionable] public unsafe static void* Add<T>(void* source, int elementOffset) { return (byte*)source + (nint)elementOffset * (nint)Unsafe.SizeOf<T>(); } [MethodImpl(MethodImplOptions.AggressiveInlining)] [System.Runtime.Versioning.NonVersionable] public static ref T Add<T>(ref T source, IntPtr elementOffset) { return ref Unsafe.Add(ref source, elementOffset); } [MethodImpl(MethodImplOptions.AggressiveInlining)] [System.Runtime.Versioning.NonVersionable] public static ref T AddByteOffset<T>(ref T source, IntPtr byteOffset) { return ref Unsafe.AddByteOffset(ref source, byteOffset); } [MethodImpl(MethodImplOptions.AggressiveInlining)] [System.Runtime.Versioning.NonVersionable] public static ref T Subtract<T>(ref T source, int elementOffset) { return ref Unsafe.Subtract(ref source, elementOffset); } [MethodImpl(MethodImplOptions.AggressiveInlining)] [System.Runtime.Versioning.NonVersionable] public unsafe static void* Subtract<T>(void* source, int elementOffset) { return (byte*)source - (nint)elementOffset * (nint)Unsafe.SizeOf<T>(); } [MethodImpl(MethodImplOptions.AggressiveInlining)] [System.Runtime.Versioning.NonVersionable] public static ref T Subtract<T>(ref T source, IntPtr elementOffset) { return ref Unsafe.Subtract(ref source, elementOffset); } [MethodImpl(MethodImplOptions.AggressiveInlining)] [System.Runtime.Versioning.NonVersionable] public static ref T SubtractByteOffset<T>(ref T source, IntPtr byteOffset) { return ref Unsafe.SubtractByteOffset(ref source, byteOffset); } [MethodImpl(MethodImplOptions.AggressiveInlining)] [System.Runtime.Versioning.NonVersionable] public static IntPtr ByteOffset<T>(ref T origin, ref T target) { return Unsafe.ByteOffset(target: ref target, origin: ref origin); } [MethodImpl(MethodImplOptions.AggressiveInlining)] [System.Runtime.Versioning.NonVersionable] public static bool AreSame<T>(ref T left, ref T right) { return Unsafe.AreSame(ref left, ref right); } [MethodImpl(MethodImplOptions.AggressiveInlining)] [System.Runtime.Versioning.NonVersionable] public static bool IsAddressGreaterThan<T>(ref T left, ref T right) { return Unsafe.IsAddressGreaterThan(ref left, ref right); } [MethodImpl(MethodImplOptions.AggressiveInlining)] [System.Runtime.Versioning.NonVersionable] public static bool IsAddressLessThan<T>(ref T left, ref T right) { return Unsafe.IsAddressLessThan(ref left, ref right); } } } namespace System.Runtime.Versioning { [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Constructor | AttributeTargets.Method, AllowMultiple = false, Inherited = false)] internal sealed class NonVersionableAttribute : Attribute { } } namespace System.Runtime.CompilerServices { internal sealed class IsReadOnlyAttribute : Attribute { } }
plugins/CultOfTheButtplug/System.Threading.Channels.dll
Decompiled 9 months agousing System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Reflection; using System.Resources; using System.Runtime.CompilerServices; using System.Runtime.ExceptionServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Threading; using System.Threading.Tasks; using System.Threading.Tasks.Sources; using FxResources.System.Threading.Channels; using Internal; using Microsoft.CodeAnalysis; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.6.2", FrameworkDisplayName = ".NET Framework 4.6.2")] [assembly: AssemblyMetadata(".NETFrameworkAssembly", "")] [assembly: AssemblyMetadata("Serviceable", "True")] [assembly: AssemblyMetadata("PreferInbox", "True")] [assembly: AssemblyDefaultAlias("System.Threading.Channels")] [assembly: NeutralResourcesLanguage("en-US")] [assembly: CLSCompliant(true)] [assembly: AssemblyMetadata("IsTrimmable", "True")] [assembly: DefaultDllImportSearchPaths(DllImportSearchPath.System32 | DllImportSearchPath.AssemblyDirectory)] [assembly: AssemblyCompany("Microsoft Corporation")] [assembly: AssemblyCopyright("© Microsoft Corporation. All rights reserved.")] [assembly: AssemblyDescription("Provides types for passing data between producers and consumers.\r\n\r\nCommonly Used Types:\r\nSystem.Threading.Channel\r\nSystem.Threading.Channel<T>")] [assembly: AssemblyFileVersion("7.0.22.51805")] [assembly: AssemblyInformationalVersion("7.0.0+d099f075e45d2aa6007a22b71b45a08758559f80")] [assembly: AssemblyProduct("Microsoft® .NET")] [assembly: AssemblyTitle("System.Threading.Channels")] [assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/dotnet/runtime")] [assembly: AssemblyVersion("7.0.0.0")] [module: RefSafetyRules(11)] [module: System.Runtime.CompilerServices.NullablePublicOnly(false)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class NullablePublicOnlyAttribute : Attribute { public readonly bool IncludesInternals; public NullablePublicOnlyAttribute(bool P_0) { IncludesInternals = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace FxResources.System.Threading.Channels { internal static class SR { } } namespace Internal { internal static class PaddingHelpers { internal const int CACHE_LINE_SIZE = 128; } [StructLayout(LayoutKind.Explicit, Size = 124)] internal struct PaddingFor32 { } } namespace System { [StructLayout(LayoutKind.Sequential, Size = 1)] internal struct VoidResult { } internal static class SR { private static readonly bool s_usingResourceKeys = AppContext.TryGetSwitch("System.Resources.UseSystemResourceKeys", out var isEnabled) && isEnabled; private static ResourceManager s_resourceManager; internal static ResourceManager ResourceManager => s_resourceManager ?? (s_resourceManager = new ResourceManager(typeof(SR))); internal static string ChannelClosedException_DefaultMessage => GetResourceString("ChannelClosedException_DefaultMessage"); internal static string InvalidOperation_IncompleteAsyncOperation => GetResourceString("InvalidOperation_IncompleteAsyncOperation"); internal static string InvalidOperation_MultipleContinuations => GetResourceString("InvalidOperation_MultipleContinuations"); internal static string InvalidOperation_IncorrectToken => GetResourceString("InvalidOperation_IncorrectToken"); private static bool UsingResourceKeys() { return s_usingResourceKeys; } internal static string GetResourceString(string resourceKey) { if (UsingResourceKeys()) { return resourceKey; } string result = null; try { result = ResourceManager.GetString(resourceKey); } catch (MissingManifestResourceException) { } return result; } internal static string GetResourceString(string resourceKey, string defaultString) { string resourceString = GetResourceString(resourceKey); if (!(resourceKey == resourceString) && resourceString != null) { return resourceString; } return defaultString; } internal static string Format(string resourceFormat, object p1) { if (UsingResourceKeys()) { return string.Join(", ", resourceFormat, p1); } return string.Format(resourceFormat, p1); } internal static string Format(string resourceFormat, object p1, object p2) { if (UsingResourceKeys()) { return string.Join(", ", resourceFormat, p1, p2); } return string.Format(resourceFormat, p1, p2); } internal static string Format(string resourceFormat, object p1, object p2, object p3) { if (UsingResourceKeys()) { return string.Join(", ", resourceFormat, p1, p2, p3); } return string.Format(resourceFormat, p1, p2, p3); } internal static string Format(string resourceFormat, params object[] args) { if (args != null) { if (UsingResourceKeys()) { return resourceFormat + ", " + string.Join(", ", args); } return string.Format(resourceFormat, args); } return resourceFormat; } internal static string Format(IFormatProvider provider, string resourceFormat, object p1) { if (UsingResourceKeys()) { return string.Join(", ", resourceFormat, p1); } return string.Format(provider, resourceFormat, p1); } internal static string Format(IFormatProvider provider, string resourceFormat, object p1, object p2) { if (UsingResourceKeys()) { return string.Join(", ", resourceFormat, p1, p2); } return string.Format(provider, resourceFormat, p1, p2); } internal static string Format(IFormatProvider provider, string resourceFormat, object p1, object p2, object p3) { if (UsingResourceKeys()) { return string.Join(", ", resourceFormat, p1, p2, p3); } return string.Format(provider, resourceFormat, p1, p2, p3); } internal static string Format(IFormatProvider provider, string resourceFormat, params object[] args) { if (args != null) { if (UsingResourceKeys()) { return resourceFormat + ", " + string.Join(", ", args); } return string.Format(provider, resourceFormat, args); } return resourceFormat; } } } namespace System.Diagnostics.CodeAnalysis { [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, Inherited = false)] internal sealed class AllowNullAttribute : Attribute { } [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, Inherited = false)] internal sealed class DisallowNullAttribute : Attribute { } [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.ReturnValue, Inherited = false)] internal sealed class MaybeNullAttribute : Attribute { } [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.ReturnValue, Inherited = false)] internal sealed class NotNullAttribute : Attribute { } [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] internal sealed class MaybeNullWhenAttribute : Attribute { public bool ReturnValue { get; } public MaybeNullWhenAttribute(bool returnValue) { ReturnValue = returnValue; } } [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] internal sealed class NotNullWhenAttribute : Attribute { public bool ReturnValue { get; } public NotNullWhenAttribute(bool returnValue) { ReturnValue = returnValue; } } [AttributeUsage(AttributeTargets.Property | AttributeTargets.Parameter | AttributeTargets.ReturnValue, AllowMultiple = true, Inherited = false)] internal sealed class NotNullIfNotNullAttribute : Attribute { public string ParameterName { get; } public NotNullIfNotNullAttribute(string parameterName) { ParameterName = parameterName; } } [AttributeUsage(AttributeTargets.Method, Inherited = false)] internal sealed class DoesNotReturnAttribute : Attribute { } [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] internal sealed class DoesNotReturnIfAttribute : Attribute { public bool ParameterValue { get; } public DoesNotReturnIfAttribute(bool parameterValue) { ParameterValue = parameterValue; } } [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)] internal sealed class MemberNotNullAttribute : Attribute { public string[] Members { get; } public MemberNotNullAttribute(string member) { Members = new string[1] { member }; } public MemberNotNullAttribute(params string[] members) { Members = members; } } [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)] internal sealed class MemberNotNullWhenAttribute : Attribute { public bool ReturnValue { get; } public string[] Members { get; } public MemberNotNullWhenAttribute(bool returnValue, string member) { ReturnValue = returnValue; Members = new string[1] { member }; } public MemberNotNullWhenAttribute(bool returnValue, params string[] members) { ReturnValue = returnValue; Members = members; } } } namespace System.Runtime.InteropServices { [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)] internal sealed class LibraryImportAttribute : Attribute { public string LibraryName { get; } public string EntryPoint { get; set; } public StringMarshalling StringMarshalling { get; set; } public Type StringMarshallingCustomType { get; set; } public bool SetLastError { get; set; } public LibraryImportAttribute(string libraryName) { LibraryName = libraryName; } } internal enum StringMarshalling { Custom, Utf8, Utf16 } } namespace System.Collections.Generic { [DebuggerDisplay("Count = {_size}")] internal sealed class Deque<T> { private T[] _array = Array.Empty<T>(); private int _head; private int _tail; private int _size; public int Count => _size; public bool IsEmpty => _size == 0; public void EnqueueTail(T item) { if (_size == _array.Length) { Grow(); } _array[_tail] = item; if (++_tail == _array.Length) { _tail = 0; } _size++; } public T DequeueHead() { T result = _array[_head]; _array[_head] = default(T); if (++_head == _array.Length) { _head = 0; } _size--; return result; } public T PeekHead() { return _array[_head]; } public T PeekTail() { int num = _tail - 1; if (num == -1) { num = _array.Length - 1; } return _array[num]; } public T DequeueTail() { if (--_tail == -1) { _tail = _array.Length - 1; } T result = _array[_tail]; _array[_tail] = default(T); _size--; return result; } public IEnumerator<T> GetEnumerator() { int pos = _head; int count = _size; while (count-- > 0) { yield return _array[pos]; pos = (pos + 1) % _array.Length; } } private void Grow() { int num = (int)((long)_array.Length * 2L); if (num < _array.Length + 4) { num = _array.Length + 4; } T[] array = new T[num]; if (_head == 0) { Array.Copy(_array, array, _size); } else { Array.Copy(_array, _head, array, 0, _array.Length - _head); Array.Copy(_array, 0, array, _array.Length - _head, _tail); } _array = array; _head = 0; _tail = _size; } } } namespace System.Collections.Concurrent { [DebuggerDisplay("Count = {Count}")] [DebuggerTypeProxy(typeof(SingleProducerSingleConsumerQueue<>.SingleProducerSingleConsumerQueue_DebugView))] internal sealed class SingleProducerSingleConsumerQueue<T> : IEnumerable<T>, IEnumerable { [StructLayout(LayoutKind.Sequential)] private sealed class Segment { internal Segment _next; internal readonly T[] _array; internal SegmentState _state; internal Segment(int size) { _array = new T[size]; } } private struct SegmentState { internal Internal.PaddingFor32 _pad0; internal volatile int _first; internal int _lastCopy; internal Internal.PaddingFor32 _pad1; internal int _firstCopy; internal volatile int _last; internal Internal.PaddingFor32 _pad2; } private sealed class SingleProducerSingleConsumerQueue_DebugView { private readonly SingleProducerSingleConsumerQueue<T> _queue; [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)] public T[] Items => new List<T>(_queue).ToArray(); public SingleProducerSingleConsumerQueue_DebugView(SingleProducerSingleConsumerQueue<T> queue) { _queue = queue; } } private const int InitialSegmentSize = 32; private const int MaxSegmentSize = 16777216; private volatile Segment _head; private volatile Segment _tail; public bool IsEmpty { get { Segment head = _head; if (head._state._first != head._state._lastCopy) { return false; } if (head._state._first != head._state._last) { return false; } return head._next == null; } } internal int Count { get { int num = 0; for (Segment segment = _head; segment != null; segment = segment._next) { int num2 = segment._array.Length; int first; int last; do { first = segment._state._first; last = segment._state._last; } while (first != segment._state._first); num += (last - first) & (num2 - 1); } return num; } } public SingleProducerSingleConsumerQueue() { _head = (_tail = new Segment(32)); } public void Enqueue(T item) { Segment segment = _tail; T[] array = segment._array; int last = segment._state._last; int num = (last + 1) & (array.Length - 1); if (num != segment._state._firstCopy) { array[last] = item; segment._state._last = num; } else { EnqueueSlow(item, ref segment); } } private void EnqueueSlow(T item, ref Segment segment) { if (segment._state._firstCopy != segment._state._first) { segment._state._firstCopy = segment._state._first; Enqueue(item); return; } int num = _tail._array.Length << 1; if (num > 16777216) { num = 16777216; } Segment segment2 = new Segment(num); segment2._array[0] = item; segment2._state._last = 1; segment2._state._lastCopy = 1; try { } finally { Volatile.Write(ref _tail._next, segment2); _tail = segment2; } } public bool TryDequeue([MaybeNullWhen(false)] out T result) { Segment head = _head; T[] array = head._array; int first = head._state._first; if (first != head._state._lastCopy) { result = array[first]; array[first] = default(T); head._state._first = (first + 1) & (array.Length - 1); return true; } return TryDequeueSlow(head, array, peek: false, out result); } public bool TryPeek([MaybeNullWhen(false)] out T result) { Segment head = _head; T[] array = head._array; int first = head._state._first; if (first != head._state._lastCopy) { result = array[first]; return true; } return TryDequeueSlow(head, array, peek: true, out result); } private bool TryDequeueSlow(Segment segment, T[] array, bool peek, [MaybeNullWhen(false)] out T result) { if (segment._state._last != segment._state._lastCopy) { segment._state._lastCopy = segment._state._last; if (!peek) { return TryDequeue(out result); } return TryPeek(out result); } if (segment._next != null && segment._state._first == segment._state._last) { segment = segment._next; array = segment._array; _head = segment; } int first = segment._state._first; if (first == segment._state._last) { result = default(T); return false; } result = array[first]; if (!peek) { array[first] = default(T); segment._state._first = (first + 1) & (segment._array.Length - 1); segment._state._lastCopy = segment._state._last; } return true; } public IEnumerator<T> GetEnumerator() { for (Segment segment = _head; segment != null; segment = segment._next) { for (int pt = segment._state._first; pt != segment._state._last; pt = (pt + 1) & (segment._array.Length - 1)) { yield return segment._array[pt]; } } } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } } } namespace System.Threading.Channels { internal abstract class AsyncOperation { protected static readonly Action<object> s_availableSentinel = AvailableSentinel; protected static readonly Action<object> s_completedSentinel = CompletedSentinel; private static void AvailableSentinel(object s) { } private static void CompletedSentinel(object s) { } protected static void ThrowIncompleteOperationException() { throw new InvalidOperationException(System.SR.InvalidOperation_IncompleteAsyncOperation); } protected static void ThrowMultipleContinuations() { throw new InvalidOperationException(System.SR.InvalidOperation_MultipleContinuations); } protected static void ThrowIncorrectCurrentIdException() { throw new InvalidOperationException(System.SR.InvalidOperation_IncorrectToken); } } internal class AsyncOperation<TResult> : AsyncOperation, IValueTaskSource, IValueTaskSource<TResult> { private readonly CancellationTokenRegistration _registration; private readonly bool _pooled; private readonly bool _runContinuationsAsynchronously; private volatile int _completionReserved; private TResult _result; private ExceptionDispatchInfo _error; private Action<object> _continuation; private object _continuationState; private object _schedulingContext; private ExecutionContext _executionContext; private short _currentId; public AsyncOperation<TResult> Next { get; set; } public CancellationToken CancellationToken { get; } public ValueTask ValueTask => new ValueTask(this, _currentId); public ValueTask<TResult> ValueTaskOfT => new ValueTask<TResult>(this, _currentId); internal bool IsCompleted => (object)_continuation == AsyncOperation.s_completedSentinel; public AsyncOperation(bool runContinuationsAsynchronously, CancellationToken cancellationToken = default(CancellationToken), bool pooled = false) { _continuation = (pooled ? AsyncOperation.s_availableSentinel : null); _pooled = pooled; _runContinuationsAsynchronously = runContinuationsAsynchronously; if (cancellationToken.CanBeCanceled) { CancellationToken = cancellationToken; _registration = UnsafeRegister(cancellationToken, delegate(object s) { AsyncOperation<TResult> asyncOperation = (AsyncOperation<TResult>)s; asyncOperation.TrySetCanceled(asyncOperation.CancellationToken); }, this); } } public ValueTaskSourceStatus GetStatus(short token) { if (_currentId != token) { AsyncOperation.ThrowIncorrectCurrentIdException(); } if (IsCompleted) { if (_error != null) { if (!(_error.SourceException is OperationCanceledException)) { return ValueTaskSourceStatus.Faulted; } return ValueTaskSourceStatus.Canceled; } return ValueTaskSourceStatus.Succeeded; } return ValueTaskSourceStatus.Pending; } public TResult GetResult(short token) { if (_currentId != token) { AsyncOperation.ThrowIncorrectCurrentIdException(); } if (!IsCompleted) { AsyncOperation.ThrowIncompleteOperationException(); } ExceptionDispatchInfo error = _error; TResult result = _result; _currentId++; if (_pooled) { Volatile.Write(ref _continuation, AsyncOperation.s_availableSentinel); } error?.Throw(); return result; } void IValueTaskSource.GetResult(short token) { if (_currentId != token) { AsyncOperation.ThrowIncorrectCurrentIdException(); } if (!IsCompleted) { AsyncOperation.ThrowIncompleteOperationException(); } ExceptionDispatchInfo error = _error; _currentId++; if (_pooled) { Volatile.Write(ref _continuation, AsyncOperation.s_availableSentinel); } error?.Throw(); } public bool TryOwnAndReset() { if ((object)Interlocked.CompareExchange(ref _continuation, null, AsyncOperation.s_availableSentinel) == AsyncOperation.s_availableSentinel) { _continuationState = null; _result = default(TResult); _error = null; _schedulingContext = null; _executionContext = null; return true; } return false; } public void OnCompleted(Action<object> continuation, object state, short token, ValueTaskSourceOnCompletedFlags flags) { if (_currentId != token) { AsyncOperation.ThrowIncorrectCurrentIdException(); } if (_continuationState != null) { AsyncOperation.ThrowMultipleContinuations(); } _continuationState = state; if ((flags & ValueTaskSourceOnCompletedFlags.FlowExecutionContext) != 0) { _executionContext = ExecutionContext.Capture(); } SynchronizationContext synchronizationContext = null; TaskScheduler taskScheduler = null; if ((flags & ValueTaskSourceOnCompletedFlags.UseSchedulingContext) != 0) { synchronizationContext = SynchronizationContext.Current; if (synchronizationContext != null && synchronizationContext.GetType() != typeof(SynchronizationContext)) { _schedulingContext = synchronizationContext; } else { synchronizationContext = null; taskScheduler = TaskScheduler.Current; if (taskScheduler != TaskScheduler.Default) { _schedulingContext = taskScheduler; } } } Action<object> action = Interlocked.CompareExchange(ref _continuation, continuation, null); if (action == null) { return; } if ((object)action != AsyncOperation.s_completedSentinel) { AsyncOperation.ThrowMultipleContinuations(); } if (_schedulingContext == null) { if (_executionContext == null) { UnsafeQueueUserWorkItem(continuation, state); } else { QueueUserWorkItem(continuation, state); } } else if (synchronizationContext != null) { synchronizationContext.Post(delegate(object s) { KeyValuePair<Action<object>, object> keyValuePair = (KeyValuePair<Action<object>, object>)s; keyValuePair.Key(keyValuePair.Value); }, new KeyValuePair<Action<object>, object>(continuation, state)); } else { Task.Factory.StartNew(continuation, state, CancellationToken.None, TaskCreationOptions.DenyChildAttach, taskScheduler); } } public bool UnregisterCancellation() { if (CancellationToken.CanBeCanceled) { CancellationTokenRegistration registration = _registration; registration.Dispose(); return _completionReserved == 0; } return true; } public bool TrySetResult(TResult item) { UnregisterCancellation(); if (TryReserveCompletionIfCancelable()) { _result = item; SignalCompletion(); return true; } return false; } public bool TrySetException(Exception exception) { UnregisterCancellation(); if (TryReserveCompletionIfCancelable()) { _error = ExceptionDispatchInfo.Capture(exception); SignalCompletion(); return true; } return false; } public bool TrySetCanceled(CancellationToken cancellationToken = default(CancellationToken)) { if (TryReserveCompletionIfCancelable()) { _error = ExceptionDispatchInfo.Capture(new OperationCanceledException(cancellationToken)); SignalCompletion(); return true; } return false; } private bool TryReserveCompletionIfCancelable() { if (CancellationToken.CanBeCanceled) { return Interlocked.CompareExchange(ref _completionReserved, 1, 0) == 0; } return true; } private void SignalCompletion() { if (_continuation == null && Interlocked.CompareExchange(ref _continuation, AsyncOperation.s_completedSentinel, null) == null) { return; } if (_schedulingContext == null) { if (_runContinuationsAsynchronously) { UnsafeQueueSetCompletionAndInvokeContinuation(); return; } } else if (_schedulingContext is SynchronizationContext synchronizationContext) { if (_runContinuationsAsynchronously || synchronizationContext != SynchronizationContext.Current) { synchronizationContext.Post(delegate(object s) { ((AsyncOperation<TResult>)s).SetCompletionAndInvokeContinuation(); }, this); return; } } else { TaskScheduler taskScheduler = (TaskScheduler)_schedulingContext; if (_runContinuationsAsynchronously || taskScheduler != TaskScheduler.Current) { Task.Factory.StartNew(delegate(object s) { ((AsyncOperation<TResult>)s).SetCompletionAndInvokeContinuation(); }, this, CancellationToken.None, TaskCreationOptions.DenyChildAttach, taskScheduler); return; } } SetCompletionAndInvokeContinuation(); } private void SetCompletionAndInvokeContinuation() { if (_executionContext == null) { Action<object> continuation = _continuation; _continuation = AsyncOperation.s_completedSentinel; continuation(_continuationState); return; } ExecutionContext.Run(_executionContext, delegate(object s) { AsyncOperation<TResult> asyncOperation = (AsyncOperation<TResult>)s; Action<object> continuation2 = asyncOperation._continuation; asyncOperation._continuation = AsyncOperation.s_completedSentinel; continuation2(asyncOperation._continuationState); }, this); } private void UnsafeQueueSetCompletionAndInvokeContinuation() { ThreadPool.UnsafeQueueUserWorkItem(delegate(object s) { ((AsyncOperation<TResult>)s).SetCompletionAndInvokeContinuation(); }, this); } private static void UnsafeQueueUserWorkItem(Action<object> action, object state) { QueueUserWorkItem(action, state); } private static void QueueUserWorkItem(Action<object> action, object state) { Task.Factory.StartNew(action, state, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default); } private static CancellationTokenRegistration UnsafeRegister(CancellationToken cancellationToken, Action<object> action, object state) { return cancellationToken.Register(action, state); } } internal sealed class VoidAsyncOperationWithData<TData> : AsyncOperation<VoidResult> { public TData Item { get; set; } public VoidAsyncOperationWithData(bool runContinuationsAsynchronously, CancellationToken cancellationToken = default(CancellationToken), bool pooled = false) : base(runContinuationsAsynchronously, cancellationToken, pooled) { } } [DebuggerDisplay("Items={ItemsCountForDebugger}, Capacity={_bufferedCapacity}, Mode={_mode}, Closed={ChannelIsClosedForDebugger}")] [DebuggerTypeProxy(typeof(DebugEnumeratorDebugView<>))] internal sealed class BoundedChannel<T> : Channel<T>, IDebugEnumerable<T> { [DebuggerDisplay("Items={ItemsCountForDebugger}")] [DebuggerTypeProxy(typeof(DebugEnumeratorDebugView<>))] private sealed class BoundedChannelReader : ChannelReader<T>, IDebugEnumerable<T> { internal readonly BoundedChannel<T> _parent; private readonly AsyncOperation<T> _readerSingleton; private readonly AsyncOperation<bool> _waiterSingleton; public override Task Completion => _parent._completion.Task; public override bool CanCount => true; public override bool CanPeek => true; public override int Count { get { BoundedChannel<T> parent = _parent; lock (parent.SyncObj) { return parent._items.Count; } } } private int ItemsCountForDebugger => _parent._items.Count; internal BoundedChannelReader(BoundedChannel<T> parent) { _parent = parent; _readerSingleton = new AsyncOperation<T>(parent._runContinuationsAsynchronously, default(CancellationToken), pooled: true); _waiterSingleton = new AsyncOperation<bool>(parent._runContinuationsAsynchronously, default(CancellationToken), pooled: true); } public override bool TryRead([MaybeNullWhen(false)] out T item) { BoundedChannel<T> parent = _parent; lock (parent.SyncObj) { if (!parent._items.IsEmpty) { item = DequeueItemAndPostProcess(); return true; } } item = default(T); return false; } public override bool TryPeek([MaybeNullWhen(false)] out T item) { BoundedChannel<T> parent = _parent; lock (parent.SyncObj) { if (!parent._items.IsEmpty) { item = parent._items.PeekHead(); return true; } } item = default(T); return false; } public override ValueTask<T> ReadAsync(CancellationToken cancellationToken) { if (cancellationToken.IsCancellationRequested) { return new ValueTask<T>(Task.FromCanceled<T>(cancellationToken)); } BoundedChannel<T> parent = _parent; lock (parent.SyncObj) { if (!parent._items.IsEmpty) { return new ValueTask<T>(DequeueItemAndPostProcess()); } if (parent._doneWriting != null) { return ChannelUtilities.GetInvalidCompletionValueTask<T>(parent._doneWriting); } if (!cancellationToken.CanBeCanceled) { AsyncOperation<T> readerSingleton = _readerSingleton; if (readerSingleton.TryOwnAndReset()) { parent._blockedReaders.EnqueueTail(readerSingleton); return readerSingleton.ValueTaskOfT; } } AsyncOperation<T> asyncOperation = new AsyncOperation<T>(parent._runContinuationsAsynchronously | cancellationToken.CanBeCanceled, cancellationToken); parent._blockedReaders.EnqueueTail(asyncOperation); return asyncOperation.ValueTaskOfT; } } public override ValueTask<bool> WaitToReadAsync(CancellationToken cancellationToken) { if (cancellationToken.IsCancellationRequested) { return new ValueTask<bool>(Task.FromCanceled<bool>(cancellationToken)); } BoundedChannel<T> parent = _parent; lock (parent.SyncObj) { if (!parent._items.IsEmpty) { return new ValueTask<bool>(result: true); } if (parent._doneWriting != null) { return (parent._doneWriting != ChannelUtilities.s_doneWritingSentinel) ? new ValueTask<bool>(Task.FromException<bool>(parent._doneWriting)) : default(ValueTask<bool>); } if (!cancellationToken.CanBeCanceled) { AsyncOperation<bool> waiterSingleton = _waiterSingleton; if (waiterSingleton.TryOwnAndReset()) { ChannelUtilities.QueueWaiter(ref parent._waitingReadersTail, waiterSingleton); return waiterSingleton.ValueTaskOfT; } } AsyncOperation<bool> asyncOperation = new AsyncOperation<bool>(parent._runContinuationsAsynchronously | cancellationToken.CanBeCanceled, cancellationToken); ChannelUtilities.QueueWaiter(ref _parent._waitingReadersTail, asyncOperation); return asyncOperation.ValueTaskOfT; } } private T DequeueItemAndPostProcess() { BoundedChannel<T> parent = _parent; T result = parent._items.DequeueHead(); if (parent._doneWriting != null) { if (parent._items.IsEmpty) { ChannelUtilities.Complete(parent._completion, parent._doneWriting); } } else { while (!parent._blockedWriters.IsEmpty) { VoidAsyncOperationWithData<T> voidAsyncOperationWithData = parent._blockedWriters.DequeueHead(); if (voidAsyncOperationWithData.TrySetResult(default(VoidResult))) { parent._items.EnqueueTail(voidAsyncOperationWithData.Item); return result; } } ChannelUtilities.WakeUpWaiters(ref parent._waitingWritersTail, result: true); } return result; } IEnumerator<T> IDebugEnumerable<T>.GetEnumerator() { return _parent._items.GetEnumerator(); } } [DebuggerDisplay("Items={ItemsCountForDebugger}, Capacity={CapacityForDebugger}")] [DebuggerTypeProxy(typeof(DebugEnumeratorDebugView<>))] private sealed class BoundedChannelWriter : ChannelWriter<T>, IDebugEnumerable<T> { internal readonly BoundedChannel<T> _parent; private readonly VoidAsyncOperationWithData<T> _writerSingleton; private readonly AsyncOperation<bool> _waiterSingleton; private int ItemsCountForDebugger => _parent._items.Count; private int CapacityForDebugger => _parent._bufferedCapacity; internal BoundedChannelWriter(BoundedChannel<T> parent) { _parent = parent; _writerSingleton = new VoidAsyncOperationWithData<T>(runContinuationsAsynchronously: true, default(CancellationToken), pooled: true); _waiterSingleton = new AsyncOperation<bool>(runContinuationsAsynchronously: true, default(CancellationToken), pooled: true); } public override bool TryComplete(Exception error) { BoundedChannel<T> parent = _parent; bool isEmpty; lock (parent.SyncObj) { if (parent._doneWriting != null) { return false; } parent._doneWriting = error ?? ChannelUtilities.s_doneWritingSentinel; isEmpty = parent._items.IsEmpty; } if (isEmpty) { ChannelUtilities.Complete(parent._completion, error); } ChannelUtilities.FailOperations<AsyncOperation<T>, T>(parent._blockedReaders, ChannelUtilities.CreateInvalidCompletionException(error)); ChannelUtilities.FailOperations<VoidAsyncOperationWithData<T>, VoidResult>(parent._blockedWriters, ChannelUtilities.CreateInvalidCompletionException(error)); ChannelUtilities.WakeUpWaiters(ref parent._waitingReadersTail, result: false, error); ChannelUtilities.WakeUpWaiters(ref parent._waitingWritersTail, result: false, error); return true; } public override bool TryWrite(T item) { AsyncOperation<T> asyncOperation = null; AsyncOperation<bool> listTail = null; BoundedChannel<T> parent = _parent; bool lockTaken = false; try { Monitor.Enter(parent.SyncObj, ref lockTaken); if (parent._doneWriting != null) { return false; } int count = parent._items.Count; if (count != 0) { if (count < parent._bufferedCapacity) { parent._items.EnqueueTail(item); return true; } if (parent._mode == BoundedChannelFullMode.Wait) { return false; } if (parent._mode == BoundedChannelFullMode.DropWrite) { Monitor.Exit(parent.SyncObj); lockTaken = false; parent._itemDropped?.Invoke(item); return true; } T obj = ((parent._mode == BoundedChannelFullMode.DropNewest) ? parent._items.DequeueTail() : parent._items.DequeueHead()); parent._items.EnqueueTail(item); Monitor.Exit(parent.SyncObj); lockTaken = false; parent._itemDropped?.Invoke(obj); return true; } while (!parent._blockedReaders.IsEmpty) { AsyncOperation<T> asyncOperation2 = parent._blockedReaders.DequeueHead(); if (asyncOperation2.UnregisterCancellation()) { asyncOperation = asyncOperation2; break; } } if (asyncOperation == null) { parent._items.EnqueueTail(item); listTail = parent._waitingReadersTail; if (listTail == null) { return true; } parent._waitingReadersTail = null; } } finally { if (lockTaken) { Monitor.Exit(parent.SyncObj); } } if (asyncOperation != null) { bool flag = asyncOperation.TrySetResult(item); } else { ChannelUtilities.WakeUpWaiters(ref listTail, result: true); } return true; } public override ValueTask<bool> WaitToWriteAsync(CancellationToken cancellationToken) { if (cancellationToken.IsCancellationRequested) { return new ValueTask<bool>(Task.FromCanceled<bool>(cancellationToken)); } BoundedChannel<T> parent = _parent; lock (parent.SyncObj) { if (parent._doneWriting != null) { return (parent._doneWriting != ChannelUtilities.s_doneWritingSentinel) ? new ValueTask<bool>(Task.FromException<bool>(parent._doneWriting)) : default(ValueTask<bool>); } if (parent._items.Count < parent._bufferedCapacity || parent._mode != 0) { return new ValueTask<bool>(result: true); } if (!cancellationToken.CanBeCanceled) { AsyncOperation<bool> waiterSingleton = _waiterSingleton; if (waiterSingleton.TryOwnAndReset()) { ChannelUtilities.QueueWaiter(ref parent._waitingWritersTail, waiterSingleton); return waiterSingleton.ValueTaskOfT; } } AsyncOperation<bool> asyncOperation = new AsyncOperation<bool>(runContinuationsAsynchronously: true, cancellationToken); ChannelUtilities.QueueWaiter(ref parent._waitingWritersTail, asyncOperation); return asyncOperation.ValueTaskOfT; } } public override ValueTask WriteAsync(T item, CancellationToken cancellationToken) { if (cancellationToken.IsCancellationRequested) { return new ValueTask(Task.FromCanceled(cancellationToken)); } AsyncOperation<T> asyncOperation = null; AsyncOperation<bool> listTail = null; BoundedChannel<T> parent = _parent; bool lockTaken = false; try { Monitor.Enter(parent.SyncObj, ref lockTaken); if (parent._doneWriting != null) { return new ValueTask(Task.FromException(ChannelUtilities.CreateInvalidCompletionException(parent._doneWriting))); } int count = parent._items.Count; if (count != 0) { if (count < parent._bufferedCapacity) { parent._items.EnqueueTail(item); return default(ValueTask); } if (parent._mode == BoundedChannelFullMode.Wait) { if (!cancellationToken.CanBeCanceled) { VoidAsyncOperationWithData<T> writerSingleton = _writerSingleton; if (writerSingleton.TryOwnAndReset()) { writerSingleton.Item = item; parent._blockedWriters.EnqueueTail(writerSingleton); return writerSingleton.ValueTask; } } VoidAsyncOperationWithData<T> voidAsyncOperationWithData = new VoidAsyncOperationWithData<T>(runContinuationsAsynchronously: true, cancellationToken); voidAsyncOperationWithData.Item = item; parent._blockedWriters.EnqueueTail(voidAsyncOperationWithData); return voidAsyncOperationWithData.ValueTask; } if (parent._mode == BoundedChannelFullMode.DropWrite) { Monitor.Exit(parent.SyncObj); lockTaken = false; parent._itemDropped?.Invoke(item); return default(ValueTask); } T obj = ((parent._mode == BoundedChannelFullMode.DropNewest) ? parent._items.DequeueTail() : parent._items.DequeueHead()); parent._items.EnqueueTail(item); Monitor.Exit(parent.SyncObj); lockTaken = false; parent._itemDropped?.Invoke(obj); return default(ValueTask); } while (!parent._blockedReaders.IsEmpty) { AsyncOperation<T> asyncOperation2 = parent._blockedReaders.DequeueHead(); if (asyncOperation2.UnregisterCancellation()) { asyncOperation = asyncOperation2; break; } } if (asyncOperation == null) { parent._items.EnqueueTail(item); listTail = parent._waitingReadersTail; if (listTail == null) { return default(ValueTask); } parent._waitingReadersTail = null; } } finally { if (lockTaken) { Monitor.Exit(parent.SyncObj); } } if (asyncOperation != null) { bool flag = asyncOperation.TrySetResult(item); } else { ChannelUtilities.WakeUpWaiters(ref listTail, result: true); } return default(ValueTask); } IEnumerator<T> IDebugEnumerable<T>.GetEnumerator() { return _parent._items.GetEnumerator(); } } private readonly BoundedChannelFullMode _mode; private readonly Action<T> _itemDropped; private readonly TaskCompletionSource _completion; private readonly int _bufferedCapacity; private readonly Deque<T> _items = new Deque<T>(); private readonly Deque<AsyncOperation<T>> _blockedReaders = new Deque<AsyncOperation<T>>(); private readonly Deque<VoidAsyncOperationWithData<T>> _blockedWriters = new Deque<VoidAsyncOperationWithData<T>>(); private AsyncOperation<bool> _waitingReadersTail; private AsyncOperation<bool> _waitingWritersTail; private readonly bool _runContinuationsAsynchronously; private Exception _doneWriting; private object SyncObj => _items; private int ItemsCountForDebugger => _items.Count; private bool ChannelIsClosedForDebugger => _doneWriting != null; internal BoundedChannel(int bufferedCapacity, BoundedChannelFullMode mode, bool runContinuationsAsynchronously, Action<T> itemDropped) { _bufferedCapacity = bufferedCapacity; _mode = mode; _runContinuationsAsynchronously = runContinuationsAsynchronously; _itemDropped = itemDropped; _completion = new TaskCompletionSource(runContinuationsAsynchronously ? TaskCreationOptions.RunContinuationsAsynchronously : TaskCreationOptions.None); base.Reader = new BoundedChannelReader(this); base.Writer = new BoundedChannelWriter(this); } [Conditional("DEBUG")] private void AssertInvariants() { _ = _items.IsEmpty; _ = _items.Count; _ = _bufferedCapacity; _ = _blockedReaders.IsEmpty; _ = _blockedWriters.IsEmpty; _ = _completion.Task.IsCompleted; } IEnumerator<T> IDebugEnumerable<T>.GetEnumerator() { return _items.GetEnumerator(); } } public enum BoundedChannelFullMode { Wait, DropNewest, DropOldest, DropWrite } public static class Channel { public static Channel<T> CreateUnbounded<T>() { return new UnboundedChannel<T>(runContinuationsAsynchronously: true); } public static Channel<T> CreateUnbounded<T>(UnboundedChannelOptions options) { if (options == null) { throw new ArgumentNullException("options"); } if (options.SingleReader) { return new SingleConsumerUnboundedChannel<T>(!options.AllowSynchronousContinuations); } return new UnboundedChannel<T>(!options.AllowSynchronousContinuations); } public static Channel<T> CreateBounded<T>(int capacity) { if (capacity < 1) { throw new ArgumentOutOfRangeException("capacity"); } return new BoundedChannel<T>(capacity, BoundedChannelFullMode.Wait, runContinuationsAsynchronously: true, null); } public static Channel<T> CreateBounded<T>(BoundedChannelOptions options) { return CreateBounded<T>(options, null); } public static Channel<T> CreateBounded<T>(BoundedChannelOptions options, Action<T>? itemDropped) { if (options == null) { throw new ArgumentNullException("options"); } return new BoundedChannel<T>(options.Capacity, options.FullMode, !options.AllowSynchronousContinuations, itemDropped); } } public class ChannelClosedException : InvalidOperationException { public ChannelClosedException() : base(System.SR.ChannelClosedException_DefaultMessage) { } public ChannelClosedException(string? message) : base(message) { } public ChannelClosedException(Exception? innerException) : base(System.SR.ChannelClosedException_DefaultMessage, innerException) { } public ChannelClosedException(string? message, Exception? innerException) : base(message, innerException) { } } public abstract class ChannelOptions { public bool SingleWriter { get; set; } public bool SingleReader { get; set; } public bool AllowSynchronousContinuations { get; set; } } public sealed class BoundedChannelOptions : ChannelOptions { private int _capacity; private BoundedChannelFullMode _mode; public int Capacity { get { return _capacity; } set { if (value < 1) { throw new ArgumentOutOfRangeException("value"); } _capacity = value; } } public BoundedChannelFullMode FullMode { get { return _mode; } set { if ((uint)value <= 3u) { _mode = value; return; } throw new ArgumentOutOfRangeException("value"); } } public BoundedChannelOptions(int capacity) { if (capacity < 1) { throw new ArgumentOutOfRangeException("capacity"); } _capacity = capacity; } } public sealed class UnboundedChannelOptions : ChannelOptions { } public abstract class ChannelReader<T> { public virtual Task Completion => ChannelUtilities.s_neverCompletingTask; public virtual bool CanCount => false; public virtual bool CanPeek => false; public virtual int Count { get { throw new NotSupportedException(); } } public abstract bool TryRead([MaybeNullWhen(false)] out T item); public virtual bool TryPeek([MaybeNullWhen(false)] out T item) { item = default(T); return false; } public abstract ValueTask<bool> WaitToReadAsync(CancellationToken cancellationToken = default(CancellationToken)); public virtual ValueTask<T> ReadAsync(CancellationToken cancellationToken = default(CancellationToken)) { if (cancellationToken.IsCancellationRequested) { return new ValueTask<T>(Task.FromCanceled<T>(cancellationToken)); } try { if (TryRead(out var item)) { return new ValueTask<T>(item); } } catch (Exception ex) when (!(ex is ChannelClosedException) && !(ex is OperationCanceledException)) { return new ValueTask<T>(Task.FromException<T>(ex)); } return ReadAsyncCore(cancellationToken); async ValueTask<T> ReadAsyncCore(CancellationToken ct) { T item2; do { if (!(await WaitToReadAsync(ct).ConfigureAwait(continueOnCapturedContext: false))) { throw new ChannelClosedException(); } } while (!TryRead(out item2)); return item2; } } } internal static class ChannelUtilities { internal static readonly Exception s_doneWritingSentinel = new Exception("s_doneWritingSentinel"); internal static readonly Task<bool> s_trueTask = Task.FromResult(result: true); internal static readonly Task<bool> s_falseTask = Task.FromResult(result: false); internal static readonly Task s_neverCompletingTask = new TaskCompletionSource<bool>().Task; internal static void Complete(TaskCompletionSource tcs, Exception error = null) { if (error is OperationCanceledException ex) { tcs.TrySetCanceled(ex.CancellationToken); } else if (error != null && error != s_doneWritingSentinel) { tcs.TrySetException(error); } else { tcs.TrySetResult(); } } internal static ValueTask<T> GetInvalidCompletionValueTask<T>(Exception error) { Task<T> task = ((error == s_doneWritingSentinel) ? Task.FromException<T>(CreateInvalidCompletionException()) : ((error is OperationCanceledException ex) ? Task.FromCanceled<T>(ex.CancellationToken.IsCancellationRequested ? ex.CancellationToken : new CancellationToken(canceled: true)) : Task.FromException<T>(CreateInvalidCompletionException(error)))); return new ValueTask<T>(task); } internal static void QueueWaiter(ref AsyncOperation<bool> tail, AsyncOperation<bool> waiter) { AsyncOperation<bool> asyncOperation = tail; if (asyncOperation == null) { waiter.Next = waiter; } else { waiter.Next = asyncOperation.Next; asyncOperation.Next = waiter; } tail = waiter; } internal static void WakeUpWaiters(ref AsyncOperation<bool> listTail, bool result, Exception error = null) { AsyncOperation<bool> asyncOperation = listTail; if (asyncOperation != null) { listTail = null; AsyncOperation<bool> next = asyncOperation.Next; AsyncOperation<bool> asyncOperation2 = next; do { AsyncOperation<bool> next2 = asyncOperation2.Next; asyncOperation2.Next = null; bool flag = ((error != null) ? asyncOperation2.TrySetException(error) : asyncOperation2.TrySetResult(result)); asyncOperation2 = next2; } while (asyncOperation2 != next); } } internal static void FailOperations<T, TInner>(Deque<T> operations, Exception error) where T : AsyncOperation<TInner> { while (!operations.IsEmpty) { operations.DequeueHead().TrySetException(error); } } internal static Exception CreateInvalidCompletionException(Exception inner = null) { if (!(inner is OperationCanceledException)) { if (inner == null || inner == s_doneWritingSentinel) { return new ChannelClosedException(); } return new ChannelClosedException(inner); } return inner; } } public abstract class ChannelWriter<T> { public virtual bool TryComplete(Exception? error = null) { return false; } public abstract bool TryWrite(T item); public abstract ValueTask<bool> WaitToWriteAsync(CancellationToken cancellationToken = default(CancellationToken)); public virtual ValueTask WriteAsync(T item, CancellationToken cancellationToken = default(CancellationToken)) { try { return cancellationToken.IsCancellationRequested ? new ValueTask(Task.FromCanceled<T>(cancellationToken)) : (TryWrite(item) ? default(ValueTask) : WriteAsyncCore(item, cancellationToken)); } catch (Exception exception) { return new ValueTask(Task.FromException(exception)); } } private async ValueTask WriteAsyncCore(T innerItem, CancellationToken ct) { while (await WaitToWriteAsync(ct).ConfigureAwait(continueOnCapturedContext: false)) { if (TryWrite(innerItem)) { return; } } throw ChannelUtilities.CreateInvalidCompletionException(); } public void Complete(Exception? error = null) { if (!TryComplete(error)) { throw ChannelUtilities.CreateInvalidCompletionException(); } } } public abstract class Channel<T> : Channel<T, T> { } public abstract class Channel<TWrite, TRead> { public ChannelReader<TRead> Reader { get; protected set; } public ChannelWriter<TWrite> Writer { get; protected set; } public static implicit operator ChannelReader<TRead>(Channel<TWrite, TRead> channel) { return channel.Reader; } public static implicit operator ChannelWriter<TWrite>(Channel<TWrite, TRead> channel) { return channel.Writer; } } internal interface IDebugEnumerable<T> { IEnumerator<T> GetEnumerator(); } internal sealed class DebugEnumeratorDebugView<T> { [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)] public T[] Items { get; } public DebugEnumeratorDebugView(IDebugEnumerable<T> enumerable) { List<T> list = new List<T>(); foreach (T item in enumerable) { list.Add(item); } Items = list.ToArray(); } } [DebuggerDisplay("Items={ItemsCountForDebugger}, Closed={ChannelIsClosedForDebugger}")] [DebuggerTypeProxy(typeof(DebugEnumeratorDebugView<>))] internal sealed class SingleConsumerUnboundedChannel<T> : Channel<T>, IDebugEnumerable<T> { [DebuggerDisplay("Items={ItemsCountForDebugger}")] [DebuggerTypeProxy(typeof(DebugEnumeratorDebugView<>))] private sealed class UnboundedChannelReader : ChannelReader<T>, IDebugEnumerable<T> { internal readonly SingleConsumerUnboundedChannel<T> _parent; private readonly AsyncOperation<T> _readerSingleton; private readonly AsyncOperation<bool> _waiterSingleton; public override Task Completion => _parent._completion.Task; public override bool CanPeek => true; private int ItemsCountForDebugger => _parent._items.Count; internal UnboundedChannelReader(SingleConsumerUnboundedChannel<T> parent) { _parent = parent; _readerSingleton = new AsyncOperation<T>(parent._runContinuationsAsynchronously, default(CancellationToken), pooled: true); _waiterSingleton = new AsyncOperation<bool>(parent._runContinuationsAsynchronously, default(CancellationToken), pooled: true); } public override ValueTask<T> ReadAsync(CancellationToken cancellationToken) { if (cancellationToken.IsCancellationRequested) { return new ValueTask<T>(Task.FromCanceled<T>(cancellationToken)); } if (TryRead(out var item)) { return new ValueTask<T>(item); } SingleConsumerUnboundedChannel<T> parent = _parent; AsyncOperation<T> asyncOperation; AsyncOperation<T> asyncOperation2; lock (parent.SyncObj) { if (TryRead(out item)) { return new ValueTask<T>(item); } if (parent._doneWriting != null) { return ChannelUtilities.GetInvalidCompletionValueTask<T>(parent._doneWriting); } asyncOperation = parent._blockedReader; if (!cancellationToken.CanBeCanceled && _readerSingleton.TryOwnAndReset()) { asyncOperation2 = _readerSingleton; if (asyncOperation2 == asyncOperation) { asyncOperation = null; } } else { asyncOperation2 = new AsyncOperation<T>(_parent._runContinuationsAsynchronously, cancellationToken); } parent._blockedReader = asyncOperation2; } asyncOperation?.TrySetCanceled(); return asyncOperation2.ValueTaskOfT; } public override bool TryRead([MaybeNullWhen(false)] out T item) { SingleConsumerUnboundedChannel<T> parent = _parent; if (parent._items.TryDequeue(out item)) { if (parent._doneWriting != null && parent._items.IsEmpty) { ChannelUtilities.Complete(parent._completion, parent._doneWriting); } return true; } return false; } public override bool TryPeek([MaybeNullWhen(false)] out T item) { return _parent._items.TryPeek(out item); } public override ValueTask<bool> WaitToReadAsync(CancellationToken cancellationToken) { if (cancellationToken.IsCancellationRequested) { return new ValueTask<bool>(Task.FromCanceled<bool>(cancellationToken)); } if (!_parent._items.IsEmpty) { return new ValueTask<bool>(result: true); } SingleConsumerUnboundedChannel<T> parent = _parent; AsyncOperation<bool> asyncOperation = null; AsyncOperation<bool> asyncOperation2; lock (parent.SyncObj) { if (!parent._items.IsEmpty) { return new ValueTask<bool>(result: true); } if (parent._doneWriting != null) { return (parent._doneWriting != ChannelUtilities.s_doneWritingSentinel) ? new ValueTask<bool>(Task.FromException<bool>(parent._doneWriting)) : default(ValueTask<bool>); } asyncOperation = parent._waitingReader; if (!cancellationToken.CanBeCanceled && _waiterSingleton.TryOwnAndReset()) { asyncOperation2 = _waiterSingleton; if (asyncOperation2 == asyncOperation) { asyncOperation = null; } } else { asyncOperation2 = new AsyncOperation<bool>(_parent._runContinuationsAsynchronously, cancellationToken); } parent._waitingReader = asyncOperation2; } asyncOperation?.TrySetCanceled(); return asyncOperation2.ValueTaskOfT; } IEnumerator<T> IDebugEnumerable<T>.GetEnumerator() { return _parent._items.GetEnumerator(); } } [DebuggerDisplay("Items={ItemsCountForDebugger}")] [DebuggerTypeProxy(typeof(DebugEnumeratorDebugView<>))] private sealed class UnboundedChannelWriter : ChannelWriter<T>, IDebugEnumerable<T> { internal readonly SingleConsumerUnboundedChannel<T> _parent; private int ItemsCountForDebugger => _parent._items.Count; internal UnboundedChannelWriter(SingleConsumerUnboundedChannel<T> parent) { _parent = parent; } public override bool TryComplete(Exception error) { AsyncOperation<T> asyncOperation = null; AsyncOperation<bool> asyncOperation2 = null; bool flag = false; SingleConsumerUnboundedChannel<T> parent = _parent; lock (parent.SyncObj) { if (parent._doneWriting != null) { return false; } parent._doneWriting = error ?? ChannelUtilities.s_doneWritingSentinel; if (parent._items.IsEmpty) { flag = true; if (parent._blockedReader != null) { asyncOperation = parent._blockedReader; parent._blockedReader = null; } if (parent._waitingReader != null) { asyncOperation2 = parent._waitingReader; parent._waitingReader = null; } } } if (flag) { ChannelUtilities.Complete(parent._completion, error); } if (asyncOperation != null) { error = ChannelUtilities.CreateInvalidCompletionException(error); asyncOperation.TrySetException(error); } if (asyncOperation2 != null) { if (error != null) { asyncOperation2.TrySetException(error); } else { asyncOperation2.TrySetResult(item: false); } } return true; } public override bool TryWrite(T item) { SingleConsumerUnboundedChannel<T> parent = _parent; AsyncOperation<T> asyncOperation; do { asyncOperation = null; AsyncOperation<bool> asyncOperation2 = null; lock (parent.SyncObj) { if (parent._doneWriting != null) { return false; } asyncOperation = parent._blockedReader; if (asyncOperation != null) { parent._blockedReader = null; } else { parent._items.Enqueue(item); asyncOperation2 = parent._waitingReader; if (asyncOperation2 == null) { return true; } parent._waitingReader = null; } } if (asyncOperation2 != null) { asyncOperation2.TrySetResult(item: true); return true; } } while (!asyncOperation.TrySetResult(item)); return true; } public override ValueTask<bool> WaitToWriteAsync(CancellationToken cancellationToken) { Exception doneWriting = _parent._doneWriting; if (!cancellationToken.IsCancellationRequested) { if (doneWriting != null) { if (doneWriting == ChannelUtilities.s_doneWritingSentinel) { return default(ValueTask<bool>); } return new ValueTask<bool>(Task.FromException<bool>(doneWriting)); } return new ValueTask<bool>(result: true); } return new ValueTask<bool>(Task.FromCanceled<bool>(cancellationToken)); } public override ValueTask WriteAsync(T item, CancellationToken cancellationToken) { if (!cancellationToken.IsCancellationRequested) { if (!TryWrite(item)) { return new ValueTask(Task.FromException(ChannelUtilities.CreateInvalidCompletionException(_parent._doneWriting))); } return default(ValueTask); } return new ValueTask(Task.FromCanceled(cancellationToken)); } IEnumerator<T> IDebugEnumerable<T>.GetEnumerator() { return _parent._items.GetEnumerator(); } } private readonly TaskCompletionSource _completion; private readonly SingleProducerSingleConsumerQueue<T> _items = new SingleProducerSingleConsumerQueue<T>(); private readonly bool _runContinuationsAsynchronously; private volatile Exception _doneWriting; private AsyncOperation<T> _blockedReader; private AsyncOperation<bool> _waitingReader; private object SyncObj => _items; private int ItemsCountForDebugger => _items.Count; private bool ChannelIsClosedForDebugger => _doneWriting != null; internal SingleConsumerUnboundedChannel(bool runContinuationsAsynchronously) { _runContinuationsAsynchronously = runContinuationsAsynchronously; _completion = new TaskCompletionSource(runContinuationsAsynchronously ? TaskCreationOptions.RunContinuationsAsynchronously : TaskCreationOptions.None); base.Reader = new UnboundedChannelReader(this); base.Writer = new UnboundedChannelWriter(this); } IEnumerator<T> IDebugEnumerable<T>.GetEnumerator() { return _items.GetEnumerator(); } } internal sealed class TaskCompletionSource : TaskCompletionSource<VoidResult> { public TaskCompletionSource(TaskCreationOptions creationOptions) : base(creationOptions) { } public bool TrySetResult() { return TrySetResult(default(VoidResult)); } } [DebuggerDisplay("Items={ItemsCountForDebugger}, Closed={ChannelIsClosedForDebugger}")] [DebuggerTypeProxy(typeof(DebugEnumeratorDebugView<>))] internal sealed class UnboundedChannel<T> : Channel<T>, IDebugEnumerable<T> { [DebuggerDisplay("Items={Count}")] [DebuggerTypeProxy(typeof(DebugEnumeratorDebugView<>))] private sealed class UnboundedChannelReader : ChannelReader<T>, IDebugEnumerable<T> { internal readonly UnboundedChannel<T> _parent; private readonly AsyncOperation<T> _readerSingleton; private readonly AsyncOperation<bool> _waiterSingleton; public override Task Completion => _parent._completion.Task; public override bool CanCount => true; public override bool CanPeek => true; public override int Count => _parent._items.Count; internal UnboundedChannelReader(UnboundedChannel<T> parent) { _parent = parent; _readerSingleton = new AsyncOperation<T>(parent._runContinuationsAsynchronously, default(CancellationToken), pooled: true); _waiterSingleton = new AsyncOperation<bool>(parent._runContinuationsAsynchronously, default(CancellationToken), pooled: true); } public override ValueTask<T> ReadAsync(CancellationToken cancellationToken) { if (cancellationToken.IsCancellationRequested) { return new ValueTask<T>(Task.FromCanceled<T>(cancellationToken)); } UnboundedChannel<T> parent = _parent; if (parent._items.TryDequeue(out var result)) { CompleteIfDone(parent); return new ValueTask<T>(result); } lock (parent.SyncObj) { if (parent._items.TryDequeue(out result)) { CompleteIfDone(parent); return new ValueTask<T>(result); } if (parent._doneWriting != null) { return ChannelUtilities.GetInvalidCompletionValueTask<T>(parent._doneWriting); } if (!cancellationToken.CanBeCanceled) { AsyncOperation<T> readerSingleton = _readerSingleton; if (readerSingleton.TryOwnAndReset()) { parent._blockedReaders.EnqueueTail(readerSingleton); return readerSingleton.ValueTaskOfT; } } AsyncOperation<T> asyncOperation = new AsyncOperation<T>(parent._runContinuationsAsynchronously, cancellationToken); parent._blockedReaders.EnqueueTail(asyncOperation); return asyncOperation.ValueTaskOfT; } } public override bool TryRead([MaybeNullWhen(false)] out T item) { UnboundedChannel<T> parent = _parent; if (parent._items.TryDequeue(out item)) { CompleteIfDone(parent); return true; } item = default(T); return false; } public override bool TryPeek([MaybeNullWhen(false)] out T item) { return _parent._items.TryPeek(out item); } private static void CompleteIfDone(UnboundedChannel<T> parent) { if (parent._doneWriting != null && parent._items.IsEmpty) { ChannelUtilities.Complete(parent._completion, parent._doneWriting); } } public override ValueTask<bool> WaitToReadAsync(CancellationToken cancellationToken) { if (cancellationToken.IsCancellationRequested) { return new ValueTask<bool>(Task.FromCanceled<bool>(cancellationToken)); } if (!_parent._items.IsEmpty) { return new ValueTask<bool>(result: true); } UnboundedChannel<T> parent = _parent; lock (parent.SyncObj) { if (!parent._items.IsEmpty) { return new ValueTask<bool>(result: true); } if (parent._doneWriting != null) { return (parent._doneWriting != ChannelUtilities.s_doneWritingSentinel) ? new ValueTask<bool>(Task.FromException<bool>(parent._doneWriting)) : default(ValueTask<bool>); } if (!cancellationToken.CanBeCanceled) { AsyncOperation<bool> waiterSingleton = _waiterSingleton; if (waiterSingleton.TryOwnAndReset()) { ChannelUtilities.QueueWaiter(ref parent._waitingReadersTail, waiterSingleton); return waiterSingleton.ValueTaskOfT; } } AsyncOperation<bool> asyncOperation = new AsyncOperation<bool>(parent._runContinuationsAsynchronously, cancellationToken); ChannelUtilities.QueueWaiter(ref parent._waitingReadersTail, asyncOperation); return asyncOperation.ValueTaskOfT; } } IEnumerator<T> IDebugEnumerable<T>.GetEnumerator() { return _parent._items.GetEnumerator(); } } [DebuggerDisplay("Items={ItemsCountForDebugger}")] [DebuggerTypeProxy(typeof(DebugEnumeratorDebugView<>))] private sealed class UnboundedChannelWriter : ChannelWriter<T>, IDebugEnumerable<T> { internal readonly UnboundedChannel<T> _parent; private int ItemsCountForDebugger => _parent._items.Count; internal UnboundedChannelWriter(UnboundedChannel<T> parent) { _parent = parent; } public override bool TryComplete(Exception error) { UnboundedChannel<T> parent = _parent; bool isEmpty; lock (parent.SyncObj) { if (parent._doneWriting != null) { return false; } parent._doneWriting = error ?? ChannelUtilities.s_doneWritingSentinel; isEmpty = parent._items.IsEmpty; } if (isEmpty) { ChannelUtilities.Complete(parent._completion, error); } ChannelUtilities.FailOperations<AsyncOperation<T>, T>(parent._blockedReaders, ChannelUtilities.CreateInvalidCompletionException(error)); ChannelUtilities.WakeUpWaiters(ref parent._waitingReadersTail, result: false, error); return true; } public override bool TryWrite(T item) { UnboundedChannel<T> parent = _parent; AsyncOperation<bool> listTail; while (true) { AsyncOperation<T> asyncOperation = null; listTail = null; lock (parent.SyncObj) { if (parent._doneWriting != null) { return false; } if (parent._blockedReaders.IsEmpty) { parent._items.Enqueue(item); listTail = parent._waitingReadersTail; if (listTail == null) { return true; } parent._waitingReadersTail = null; } else { asyncOperation = parent._blockedReaders.DequeueHead(); } } if (asyncOperation == null) { break; } if (asyncOperation.TrySetResult(item)) { return true; } } ChannelUtilities.WakeUpWaiters(ref listTail, result: true); return true; } public override ValueTask<bool> WaitToWriteAsync(CancellationToken cancellationToken) { Exception doneWriting = _parent._doneWriting; if (!cancellationToken.IsCancellationRequested) { if (doneWriting != null) { if (doneWriting == ChannelUtilities.s_doneWritingSentinel) { return default(ValueTask<bool>); } return new ValueTask<bool>(Task.FromException<bool>(doneWriting)); } return new ValueTask<bool>(result: true); } return new ValueTask<bool>(Task.FromCanceled<bool>(cancellationToken)); } public override ValueTask WriteAsync(T item, CancellationToken cancellationToken) { if (!cancellationToken.IsCancellationRequested) { if (!TryWrite(item)) { return new ValueTask(Task.FromException(ChannelUtilities.CreateInvalidCompletionException(_parent._doneWriting))); } return default(ValueTask); } return new ValueTask(Task.FromCanceled(cancellationToken)); } IEnumerator<T> IDebugEnumerable<T>.GetEnumerator() { return _parent._items.GetEnumerator(); } } private readonly TaskCompletionSource _completion; private readonly ConcurrentQueue<T> _items = new ConcurrentQueue<T>(); private readonly Deque<AsyncOperation<T>> _blockedReaders = new Deque<AsyncOperation<T>>(); private readonly bool _runContinuationsAsynchronously; private AsyncOperation<bool> _waitingReadersTail; private Exception _doneWriting; private object SyncObj => _items; private int ItemsCountForDebugger => _items.Count; private bool ChannelIsClosedForDebugger => _doneWriting != null; internal UnboundedChannel(bool runContinuationsAsynchronously) { _runContinuationsAsynchronously = runContinuationsAsynchronously; _completion = new TaskCompletionSource(runContinuationsAsynchronously ? TaskCreationOptions.RunContinuationsAsynchronously : TaskCreationOptions.None); base.Reader = new UnboundedChannelReader(this); base.Writer = new UnboundedChannelWriter(this); } [Conditional("DEBUG")] private void AssertInvariants() { if (!_items.IsEmpty) { _ = _runContinuationsAsynchronously; } if (!_blockedReaders.IsEmpty || _waitingReadersTail != null) { _ = _runContinuationsAsynchronously; } _ = _completion.Task.IsCompleted; } IEnumerator<T> IDebugEnumerable<T>.GetEnumerator() { return _items.GetEnumerator(); } } }
plugins/CultOfTheButtplug/System.Threading.Tasks.Extensions.dll
Decompiled 9 months agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Security; using System.Threading.Tasks; using System.Threading.Tasks.Sources; using Microsoft.CodeAnalysis; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("System.Threading.Tasks.Extensions")] [assembly: AssemblyDescription("System.Threading.Tasks.Extensions")] [assembly: AssemblyDefaultAlias("System.Threading.Tasks.Extensions")] [assembly: AssemblyCompany("Microsoft Corporation")] [assembly: AssemblyProduct("Microsoft® .NET Framework")] [assembly: AssemblyCopyright("© Microsoft Corporation. All rights reserved.")] [assembly: AssemblyFileVersion("4.6.28619.01")] [assembly: AssemblyInformationalVersion("4.6.28619.01 @BuiltBy: dlab14-DDVSOWINAGE069 @Branch: release/2.1 @SrcCode: https://github.com/dotnet/corefx/tree/7601f4f6225089ffb291dc7d58293c7bbf5c5d4f")] [assembly: CLSCompliant(true)] [assembly: AssemblyMetadata(".NETFrameworkAssembly", "")] [assembly: AssemblyMetadata("Serviceable", "True")] [assembly: AssemblyMetadata("PreferInbox", "True")] [assembly: AssemblyVersion("4.2.0.1")] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class IsReadOnlyAttribute : Attribute { } } namespace System { internal static class ThrowHelper { internal static void ThrowArgumentNullException(System.ExceptionArgument argument) { throw GetArgumentNullException(argument); } internal static void ThrowArgumentOutOfRangeException(System.ExceptionArgument argument) { throw GetArgumentOutOfRangeException(argument); } private static ArgumentNullException GetArgumentNullException(System.ExceptionArgument argument) { return new ArgumentNullException(GetArgumentName(argument)); } private static ArgumentOutOfRangeException GetArgumentOutOfRangeException(System.ExceptionArgument argument) { return new ArgumentOutOfRangeException(GetArgumentName(argument)); } [MethodImpl(MethodImplOptions.NoInlining)] private static string GetArgumentName(System.ExceptionArgument argument) { return argument.ToString(); } } internal enum ExceptionArgument { task, source, state } } namespace System.Threading.Tasks { [StructLayout(LayoutKind.Auto)] [AsyncMethodBuilder(typeof(AsyncValueTaskMethodBuilder))] public readonly struct ValueTask : IEquatable<ValueTask> { private sealed class ValueTaskSourceAsTask : TaskCompletionSource<bool> { private static readonly Action<object> s_completionAction = delegate(object state) { IValueTaskSource source; if (!(state is ValueTaskSourceAsTask valueTaskSourceAsTask) || (source = valueTaskSourceAsTask._source) == null) { System.ThrowHelper.ThrowArgumentOutOfRangeException(System.ExceptionArgument.state); return; } valueTaskSourceAsTask._source = null; ValueTaskSourceStatus status = source.GetStatus(valueTaskSourceAsTask._token); try { source.GetResult(valueTaskSourceAsTask._token); valueTaskSourceAsTask.TrySetResult(result: false); } catch (Exception exception) { if (status == ValueTaskSourceStatus.Canceled) { valueTaskSourceAsTask.TrySetCanceled(); } else { valueTaskSourceAsTask.TrySetException(exception); } } }; private IValueTaskSource _source; private readonly short _token; public ValueTaskSourceAsTask(IValueTaskSource source, short token) { _token = token; _source = source; source.OnCompleted(s_completionAction, this, token, ValueTaskSourceOnCompletedFlags.None); } } private static readonly Task s_canceledTask = Task.Delay(-1, new CancellationToken(canceled: true)); internal readonly object _obj; internal readonly short _token; internal readonly bool _continueOnCapturedContext; internal static Task CompletedTask { get; } = Task.Delay(0); public bool IsCompleted { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { object obj = _obj; if (obj == null) { return true; } if (obj is Task task) { return task.IsCompleted; } return System.Runtime.CompilerServices.Unsafe.As<IValueTaskSource>(obj).GetStatus(_token) != ValueTaskSourceStatus.Pending; } } public bool IsCompletedSuccessfully { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { object obj = _obj; if (obj == null) { return true; } if (obj is Task task) { return task.Status == TaskStatus.RanToCompletion; } return System.Runtime.CompilerServices.Unsafe.As<IValueTaskSource>(obj).GetStatus(_token) == ValueTaskSourceStatus.Succeeded; } } public bool IsFaulted { get { object obj = _obj; if (obj == null) { return false; } if (obj is Task task) { return task.IsFaulted; } return System.Runtime.CompilerServices.Unsafe.As<IValueTaskSource>(obj).GetStatus(_token) == ValueTaskSourceStatus.Faulted; } } public bool IsCanceled { get { object obj = _obj; if (obj == null) { return false; } if (obj is Task task) { return task.IsCanceled; } return System.Runtime.CompilerServices.Unsafe.As<IValueTaskSource>(obj).GetStatus(_token) == ValueTaskSourceStatus.Canceled; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public ValueTask(Task task) { if (task == null) { System.ThrowHelper.ThrowArgumentNullException(System.ExceptionArgument.task); } _obj = task; _continueOnCapturedContext = true; _token = 0; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public ValueTask(IValueTaskSource source, short token) { if (source == null) { System.ThrowHelper.ThrowArgumentNullException(System.ExceptionArgument.source); } _obj = source; _token = token; _continueOnCapturedContext = true; } [MethodImpl(MethodImplOptions.AggressiveInlining)] private ValueTask(object obj, short token, bool continueOnCapturedContext) { _obj = obj; _token = token; _continueOnCapturedContext = continueOnCapturedContext; } public override int GetHashCode() { return _obj?.GetHashCode() ?? 0; } public override bool Equals(object obj) { if (obj is ValueTask) { return Equals((ValueTask)obj); } return false; } public bool Equals(ValueTask other) { if (_obj == other._obj) { return _token == other._token; } return false; } public static bool operator ==(ValueTask left, ValueTask right) { return left.Equals(right); } public static bool operator !=(ValueTask left, ValueTask right) { return !left.Equals(right); } public Task AsTask() { object obj = _obj; object obj2; if (obj != null) { obj2 = obj as Task; if (obj2 == null) { return GetTaskForValueTaskSource(System.Runtime.CompilerServices.Unsafe.As<IValueTaskSource>(obj)); } } else { obj2 = CompletedTask; } return (Task)obj2; } public ValueTask Preserve() { if (_obj != null) { return new ValueTask(AsTask()); } return this; } private Task GetTaskForValueTaskSource(IValueTaskSource t) { ValueTaskSourceStatus status = t.GetStatus(_token); if (status != 0) { try { t.GetResult(_token); return CompletedTask; } catch (Exception exception) { if (status == ValueTaskSourceStatus.Canceled) { return s_canceledTask; } TaskCompletionSource<bool> taskCompletionSource = new TaskCompletionSource<bool>(); taskCompletionSource.TrySetException(exception); return taskCompletionSource.Task; } } ValueTaskSourceAsTask valueTaskSourceAsTask = new ValueTaskSourceAsTask(t, _token); return valueTaskSourceAsTask.Task; } [MethodImpl(MethodImplOptions.AggressiveInlining)] [StackTraceHidden] internal void ThrowIfCompletedUnsuccessfully() { object obj = _obj; if (obj != null) { if (obj is Task task) { task.GetAwaiter().GetResult(); } else { System.Runtime.CompilerServices.Unsafe.As<IValueTaskSource>(obj).GetResult(_token); } } } public ValueTaskAwaiter GetAwaiter() { return new ValueTaskAwaiter(this); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public ConfiguredValueTaskAwaitable ConfigureAwait(bool continueOnCapturedContext) { return new ConfiguredValueTaskAwaitable(new ValueTask(_obj, _token, continueOnCapturedContext)); } } [StructLayout(LayoutKind.Auto)] [AsyncMethodBuilder(typeof(AsyncValueTaskMethodBuilder<>))] public readonly struct ValueTask<TResult> : IEquatable<ValueTask<TResult>> { private sealed class ValueTaskSourceAsTask : TaskCompletionSource<TResult> { private static readonly Action<object> s_completionAction = delegate(object state) { IValueTaskSource<TResult> source; if (!(state is ValueTaskSourceAsTask valueTaskSourceAsTask) || (source = valueTaskSourceAsTask._source) == null) { System.ThrowHelper.ThrowArgumentOutOfRangeException(System.ExceptionArgument.state); return; } valueTaskSourceAsTask._source = null; ValueTaskSourceStatus status = source.GetStatus(valueTaskSourceAsTask._token); try { valueTaskSourceAsTask.TrySetResult(source.GetResult(valueTaskSourceAsTask._token)); } catch (Exception exception) { if (status == ValueTaskSourceStatus.Canceled) { valueTaskSourceAsTask.TrySetCanceled(); } else { valueTaskSourceAsTask.TrySetException(exception); } } }; private IValueTaskSource<TResult> _source; private readonly short _token; public ValueTaskSourceAsTask(IValueTaskSource<TResult> source, short token) { _source = source; _token = token; source.OnCompleted(s_completionAction, this, token, ValueTaskSourceOnCompletedFlags.None); } } private static Task<TResult> s_canceledTask; internal readonly object _obj; internal readonly TResult _result; internal readonly short _token; internal readonly bool _continueOnCapturedContext; public bool IsCompleted { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { object obj = _obj; if (obj == null) { return true; } if (obj is Task<TResult> task) { return task.IsCompleted; } return System.Runtime.CompilerServices.Unsafe.As<IValueTaskSource<TResult>>(obj).GetStatus(_token) != ValueTaskSourceStatus.Pending; } } public bool IsCompletedSuccessfully { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { object obj = _obj; if (obj == null) { return true; } if (obj is Task<TResult> task) { return task.Status == TaskStatus.RanToCompletion; } return System.Runtime.CompilerServices.Unsafe.As<IValueTaskSource<TResult>>(obj).GetStatus(_token) == ValueTaskSourceStatus.Succeeded; } } public bool IsFaulted { get { object obj = _obj; if (obj == null) { return false; } if (obj is Task<TResult> task) { return task.IsFaulted; } return System.Runtime.CompilerServices.Unsafe.As<IValueTaskSource<TResult>>(obj).GetStatus(_token) == ValueTaskSourceStatus.Faulted; } } public bool IsCanceled { get { object obj = _obj; if (obj == null) { return false; } if (obj is Task<TResult> task) { return task.IsCanceled; } return System.Runtime.CompilerServices.Unsafe.As<IValueTaskSource<TResult>>(obj).GetStatus(_token) == ValueTaskSourceStatus.Canceled; } } public TResult Result { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { object obj = _obj; if (obj == null) { return _result; } if (obj is Task<TResult> task) { return task.GetAwaiter().GetResult(); } return System.Runtime.CompilerServices.Unsafe.As<IValueTaskSource<TResult>>(obj).GetResult(_token); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public ValueTask(TResult result) { _result = result; _obj = null; _continueOnCapturedContext = true; _token = 0; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public ValueTask(Task<TResult> task) { if (task == null) { System.ThrowHelper.ThrowArgumentNullException(System.ExceptionArgument.task); } _obj = task; _result = default(TResult); _continueOnCapturedContext = true; _token = 0; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public ValueTask(IValueTaskSource<TResult> source, short token) { if (source == null) { System.ThrowHelper.ThrowArgumentNullException(System.ExceptionArgument.source); } _obj = source; _token = token; _result = default(TResult); _continueOnCapturedContext = true; } [MethodImpl(MethodImplOptions.AggressiveInlining)] private ValueTask(object obj, TResult result, short token, bool continueOnCapturedContext) { _obj = obj; _result = result; _token = token; _continueOnCapturedContext = continueOnCapturedContext; } public override int GetHashCode() { if (_obj == null) { if (_result == null) { return 0; } return _result.GetHashCode(); } return _obj.GetHashCode(); } public override bool Equals(object obj) { if (obj is ValueTask<TResult>) { return Equals((ValueTask<TResult>)obj); } return false; } public bool Equals(ValueTask<TResult> other) { if (_obj == null && other._obj == null) { return EqualityComparer<TResult>.Default.Equals(_result, other._result); } if (_obj == other._obj) { return _token == other._token; } return false; } public static bool operator ==(ValueTask<TResult> left, ValueTask<TResult> right) { return left.Equals(right); } public static bool operator !=(ValueTask<TResult> left, ValueTask<TResult> right) { return !left.Equals(right); } public Task<TResult> AsTask() { object obj = _obj; if (obj == null) { return Task.FromResult(_result); } if (obj is Task<TResult> result) { return result; } return GetTaskForValueTaskSource(System.Runtime.CompilerServices.Unsafe.As<IValueTaskSource<TResult>>(obj)); } public ValueTask<TResult> Preserve() { if (_obj != null) { return new ValueTask<TResult>(AsTask()); } return this; } private Task<TResult> GetTaskForValueTaskSource(IValueTaskSource<TResult> t) { ValueTaskSourceStatus status = t.GetStatus(_token); if (status != 0) { try { return Task.FromResult(t.GetResult(_token)); } catch (Exception exception) { if (status == ValueTaskSourceStatus.Canceled) { Task<TResult> task = s_canceledTask; if (task == null) { TaskCompletionSource<TResult> taskCompletionSource = new TaskCompletionSource<TResult>(); taskCompletionSource.TrySetCanceled(); task = (s_canceledTask = taskCompletionSource.Task); } return task; } TaskCompletionSource<TResult> taskCompletionSource2 = new TaskCompletionSource<TResult>(); taskCompletionSource2.TrySetException(exception); return taskCompletionSource2.Task; } } ValueTaskSourceAsTask valueTaskSourceAsTask = new ValueTaskSourceAsTask(t, _token); return valueTaskSourceAsTask.Task; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public ValueTaskAwaiter<TResult> GetAwaiter() { return new ValueTaskAwaiter<TResult>(this); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public ConfiguredValueTaskAwaitable<TResult> ConfigureAwait(bool continueOnCapturedContext) { return new ConfiguredValueTaskAwaitable<TResult>(new ValueTask<TResult>(_obj, _result, _token, continueOnCapturedContext)); } public override string ToString() { if (IsCompletedSuccessfully) { TResult result = Result; if (result != null) { return result.ToString(); } } return string.Empty; } } } namespace System.Threading.Tasks.Sources { [Flags] public enum ValueTaskSourceOnCompletedFlags { None = 0, UseSchedulingContext = 1, FlowExecutionContext = 2 } public enum ValueTaskSourceStatus { Pending, Succeeded, Faulted, Canceled } public interface IValueTaskSource { ValueTaskSourceStatus GetStatus(short token); void OnCompleted(Action<object> continuation, object state, short token, ValueTaskSourceOnCompletedFlags flags); void GetResult(short token); } public interface IValueTaskSource<out TResult> { ValueTaskSourceStatus GetStatus(short token); void OnCompleted(Action<object> continuation, object state, short token, ValueTaskSourceOnCompletedFlags flags); TResult GetResult(short token); } } namespace System.Runtime.CompilerServices { [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum | AttributeTargets.Interface | AttributeTargets.Delegate, Inherited = false, AllowMultiple = false)] public sealed class AsyncMethodBuilderAttribute : Attribute { public Type BuilderType { get; } public AsyncMethodBuilderAttribute(Type builderType) { BuilderType = builderType; } } [StructLayout(LayoutKind.Auto)] public struct AsyncValueTaskMethodBuilder { private AsyncTaskMethodBuilder _methodBuilder; private bool _haveResult; private bool _useBuilder; public ValueTask Task { get { if (_haveResult) { return default(ValueTask); } _useBuilder = true; return new ValueTask(_methodBuilder.Task); } } public static AsyncValueTaskMethodBuilder Create() { return default(AsyncValueTaskMethodBuilder); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Start<TStateMachine>(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine { _methodBuilder.Start(ref stateMachine); } public void SetStateMachine(IAsyncStateMachine stateMachine) { _methodBuilder.SetStateMachine(stateMachine); } public void SetResult() { if (_useBuilder) { _methodBuilder.SetResult(); } else { _haveResult = true; } } public void SetException(Exception exception) { _methodBuilder.SetException(exception); } public void AwaitOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine) where TAwaiter : INotifyCompletion where TStateMachine : IAsyncStateMachine { _useBuilder = true; _methodBuilder.AwaitOnCompleted(ref awaiter, ref stateMachine); } [SecuritySafeCritical] public void AwaitUnsafeOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine) where TAwaiter : ICriticalNotifyCompletion where TStateMachine : IAsyncStateMachine { _useBuilder = true; _methodBuilder.AwaitUnsafeOnCompleted(ref awaiter, ref stateMachine); } } [StructLayout(LayoutKind.Auto)] public struct AsyncValueTaskMethodBuilder<TResult> { private AsyncTaskMethodBuilder<TResult> _methodBuilder; private TResult _result; private bool _haveResult; private bool _useBuilder; public ValueTask<TResult> Task { get { if (_haveResult) { return new ValueTask<TResult>(_result); } _useBuilder = true; return new ValueTask<TResult>(_methodBuilder.Task); } } public static AsyncValueTaskMethodBuilder<TResult> Create() { return default(AsyncValueTaskMethodBuilder<TResult>); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Start<TStateMachine>(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine { _methodBuilder.Start(ref stateMachine); } public void SetStateMachine(IAsyncStateMachine stateMachine) { _methodBuilder.SetStateMachine(stateMachine); } public void SetResult(TResult result) { if (_useBuilder) { _methodBuilder.SetResult(result); return; } _result = result; _haveResult = true; } public void SetException(Exception exception) { _methodBuilder.SetException(exception); } public void AwaitOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine) where TAwaiter : INotifyCompletion where TStateMachine : IAsyncStateMachine { _useBuilder = true; _methodBuilder.AwaitOnCompleted(ref awaiter, ref stateMachine); } [SecuritySafeCritical] public void AwaitUnsafeOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine) where TAwaiter : ICriticalNotifyCompletion where TStateMachine : IAsyncStateMachine { _useBuilder = true; _methodBuilder.AwaitUnsafeOnCompleted(ref awaiter, ref stateMachine); } } [StructLayout(LayoutKind.Auto)] public readonly struct ConfiguredValueTaskAwaitable { [StructLayout(LayoutKind.Auto)] public readonly struct ConfiguredValueTaskAwaiter : ICriticalNotifyCompletion, INotifyCompletion { private readonly ValueTask _value; public bool IsCompleted { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return _value.IsCompleted; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal ConfiguredValueTaskAwaiter(ValueTask value) { _value = value; } [MethodImpl(MethodImplOptions.AggressiveInlining)] [StackTraceHidden] public void GetResult() { _value.ThrowIfCompletedUnsuccessfully(); } public void OnCompleted(Action continuation) { object obj = _value._obj; if (obj is Task task) { task.ConfigureAwait(_value._continueOnCapturedContext).GetAwaiter().OnCompleted(continuation); } else if (obj != null) { System.Runtime.CompilerServices.Unsafe.As<IValueTaskSource>(obj).OnCompleted(ValueTaskAwaiter.s_invokeActionDelegate, continuation, _value._token, ValueTaskSourceOnCompletedFlags.FlowExecutionContext | (_value._continueOnCapturedContext ? ValueTaskSourceOnCompletedFlags.UseSchedulingContext : ValueTaskSourceOnCompletedFlags.None)); } else { ValueTask.CompletedTask.ConfigureAwait(_value._continueOnCapturedContext).GetAwaiter().OnCompleted(continuation); } } public void UnsafeOnCompleted(Action continuation) { object obj = _value._obj; if (obj is Task task) { task.ConfigureAwait(_value._continueOnCapturedContext).GetAwaiter().UnsafeOnCompleted(continuation); } else if (obj != null) { System.Runtime.CompilerServices.Unsafe.As<IValueTaskSource>(obj).OnCompleted(ValueTaskAwaiter.s_invokeActionDelegate, continuation, _value._token, _value._continueOnCapturedContext ? ValueTaskSourceOnCompletedFlags.UseSchedulingContext : ValueTaskSourceOnCompletedFlags.None); } else { ValueTask.CompletedTask.ConfigureAwait(_value._continueOnCapturedContext).GetAwaiter().UnsafeOnCompleted(continuation); } } } private readonly ValueTask _value; [MethodImpl(MethodImplOptions.AggressiveInlining)] internal ConfiguredValueTaskAwaitable(ValueTask value) { _value = value; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public ConfiguredValueTaskAwaiter GetAwaiter() { return new ConfiguredValueTaskAwaiter(_value); } } [StructLayout(LayoutKind.Auto)] public readonly struct ConfiguredValueTaskAwaitable<TResult> { [StructLayout(LayoutKind.Auto)] public readonly struct ConfiguredValueTaskAwaiter : ICriticalNotifyCompletion, INotifyCompletion { private readonly ValueTask<TResult> _value; public bool IsCompleted { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return _value.IsCompleted; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal ConfiguredValueTaskAwaiter(ValueTask<TResult> value) { _value = value; } [MethodImpl(MethodImplOptions.AggressiveInlining)] [StackTraceHidden] public TResult GetResult() { return _value.Result; } public void OnCompleted(Action continuation) { object obj = _value._obj; if (obj is Task<TResult> task) { task.ConfigureAwait(_value._continueOnCapturedContext).GetAwaiter().OnCompleted(continuation); } else if (obj != null) { System.Runtime.CompilerServices.Unsafe.As<IValueTaskSource<TResult>>(obj).OnCompleted(ValueTaskAwaiter.s_invokeActionDelegate, continuation, _value._token, ValueTaskSourceOnCompletedFlags.FlowExecutionContext | (_value._continueOnCapturedContext ? ValueTaskSourceOnCompletedFlags.UseSchedulingContext : ValueTaskSourceOnCompletedFlags.None)); } else { ValueTask.CompletedTask.ConfigureAwait(_value._continueOnCapturedContext).GetAwaiter().OnCompleted(continuation); } } public void UnsafeOnCompleted(Action continuation) { object obj = _value._obj; if (obj is Task<TResult> task) { task.ConfigureAwait(_value._continueOnCapturedContext).GetAwaiter().UnsafeOnCompleted(continuation); } else if (obj != null) { System.Runtime.CompilerServices.Unsafe.As<IValueTaskSource<TResult>>(obj).OnCompleted(ValueTaskAwaiter.s_invokeActionDelegate, continuation, _value._token, _value._continueOnCapturedContext ? ValueTaskSourceOnCompletedFlags.UseSchedulingContext : ValueTaskSourceOnCompletedFlags.None); } else { ValueTask.CompletedTask.ConfigureAwait(_value._continueOnCapturedContext).GetAwaiter().UnsafeOnCompleted(continuation); } } } private readonly ValueTask<TResult> _value; [MethodImpl(MethodImplOptions.AggressiveInlining)] internal ConfiguredValueTaskAwaitable(ValueTask<TResult> value) { _value = value; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public ConfiguredValueTaskAwaiter GetAwaiter() { return new ConfiguredValueTaskAwaiter(_value); } } public readonly struct ValueTaskAwaiter : ICriticalNotifyCompletion, INotifyCompletion { internal static readonly Action<object> s_invokeActionDelegate = delegate(object state) { if (!(state is Action action)) { System.ThrowHelper.ThrowArgumentOutOfRangeException(System.ExceptionArgument.state); } else { action(); } }; private readonly ValueTask _value; public bool IsCompleted { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return _value.IsCompleted; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal ValueTaskAwaiter(ValueTask value) { _value = value; } [MethodImpl(MethodImplOptions.AggressiveInlining)] [StackTraceHidden] public void GetResult() { _value.ThrowIfCompletedUnsuccessfully(); } public void OnCompleted(Action continuation) { object obj = _value._obj; if (obj is Task task) { task.GetAwaiter().OnCompleted(continuation); } else if (obj != null) { System.Runtime.CompilerServices.Unsafe.As<IValueTaskSource>(obj).OnCompleted(s_invokeActionDelegate, continuation, _value._token, ValueTaskSourceOnCompletedFlags.UseSchedulingContext | ValueTaskSourceOnCompletedFlags.FlowExecutionContext); } else { ValueTask.CompletedTask.GetAwaiter().OnCompleted(continuation); } } public void UnsafeOnCompleted(Action continuation) { object obj = _value._obj; if (obj is Task task) { task.GetAwaiter().UnsafeOnCompleted(continuation); } else if (obj != null) { System.Runtime.CompilerServices.Unsafe.As<IValueTaskSource>(obj).OnCompleted(s_invokeActionDelegate, continuation, _value._token, ValueTaskSourceOnCompletedFlags.UseSchedulingContext); } else { ValueTask.CompletedTask.GetAwaiter().UnsafeOnCompleted(continuation); } } } public readonly struct ValueTaskAwaiter<TResult> : ICriticalNotifyCompletion, INotifyCompletion { private readonly ValueTask<TResult> _value; public bool IsCompleted { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return _value.IsCompleted; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal ValueTaskAwaiter(ValueTask<TResult> value) { _value = value; } [MethodImpl(MethodImplOptions.AggressiveInlining)] [StackTraceHidden] public TResult GetResult() { return _value.Result; } public void OnCompleted(Action continuation) { object obj = _value._obj; if (obj is Task<TResult> task) { task.GetAwaiter().OnCompleted(continuation); } else if (obj != null) { System.Runtime.CompilerServices.Unsafe.As<IValueTaskSource<TResult>>(obj).OnCompleted(ValueTaskAwaiter.s_invokeActionDelegate, continuation, _value._token, ValueTaskSourceOnCompletedFlags.UseSchedulingContext | ValueTaskSourceOnCompletedFlags.FlowExecutionContext); } else { ValueTask.CompletedTask.GetAwaiter().OnCompleted(continuation); } } public void UnsafeOnCompleted(Action continuation) { object obj = _value._obj; if (obj is Task<TResult> task) { task.GetAwaiter().UnsafeOnCompleted(continuation); } else if (obj != null) { System.Runtime.CompilerServices.Unsafe.As<IValueTaskSource<TResult>>(obj).OnCompleted(ValueTaskAwaiter.s_invokeActionDelegate, continuation, _value._token, ValueTaskSourceOnCompletedFlags.UseSchedulingContext); } else { ValueTask.CompletedTask.GetAwaiter().UnsafeOnCompleted(continuation); } } } } namespace System.Diagnostics { [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Constructor | AttributeTargets.Method, Inherited = false)] internal sealed class StackTraceHiddenAttribute : Attribute { } }
plugins/CultOfTheButtplug/System.ValueTuple.dll
Decompiled 9 months agousing System; using System.Diagnostics; using System.Reflection; using System.Resources; using System.Runtime.CompilerServices; using FxResources.System.ValueTuple; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: NeutralResourcesLanguage("en-US")] [assembly: AssemblyTitle("System.ValueTuple")] [assembly: AssemblyDescription("System.ValueTuple")] [assembly: AssemblyDefaultAlias("System.ValueTuple")] [assembly: AssemblyCompany("Microsoft Corporation")] [assembly: AssemblyProduct("Microsoft® .NET Framework")] [assembly: AssemblyCopyright("© Microsoft Corporation. All rights reserved.")] [assembly: AssemblyFileVersion("4.6.26515.06")] [assembly: AssemblyInformationalVersion("4.6.26515.06 @BuiltBy: dlab-DDVSOWINAGE059 @Branch: release/2.1 @SrcCode: https://github.com/dotnet/corefx/tree/30ab651fcb4354552bd4891619a0bdd81e0ebdbf")] [assembly: CLSCompliant(true)] [assembly: AssemblyMetadata(".NETFrameworkAssembly", "")] [assembly: AssemblyMetadata("Serviceable", "True")] [assembly: AssemblyMetadata("PreferInbox", "True")] [assembly: AssemblyVersion("4.0.3.0")] [assembly: TypeForwardedTo(typeof(TupleElementNamesAttribute))] [assembly: TypeForwardedTo(typeof(TupleExtensions))] [assembly: TypeForwardedTo(typeof(ValueTuple))] [assembly: TypeForwardedTo(typeof(ValueTuple<>))] [assembly: TypeForwardedTo(typeof(ValueTuple<, >))] [assembly: TypeForwardedTo(typeof(ValueTuple<, , >))] [assembly: TypeForwardedTo(typeof(ValueTuple<, , , >))] [assembly: TypeForwardedTo(typeof(ValueTuple<, , , , >))] [assembly: TypeForwardedTo(typeof(ValueTuple<, , , , , >))] [assembly: TypeForwardedTo(typeof(ValueTuple<, , , , , , >))] [assembly: TypeForwardedTo(typeof(ValueTuple<, , , , , , , >))] namespace FxResources.System.ValueTuple { internal static class SR { } } namespace System { internal static class SR { private static ResourceManager s_resourceManager; private static ResourceManager ResourceManager => s_resourceManager ?? (s_resourceManager = new ResourceManager(ResourceType)); internal static Type ResourceType { get; } = typeof(SR); internal static string ArgumentException_ValueTupleIncorrectType => GetResourceString("ArgumentException_ValueTupleIncorrectType", null); internal static string ArgumentException_ValueTupleLastArgumentNotAValueTuple => GetResourceString("ArgumentException_ValueTupleLastArgumentNotAValueTuple", null); [MethodImpl(MethodImplOptions.NoInlining)] private static bool UsingResourceKeys() { return false; } internal static string GetResourceString(string resourceKey, string defaultString) { string text = null; try { text = ResourceManager.GetString(resourceKey); } catch (MissingManifestResourceException) { } if (defaultString != null && resourceKey.Equals(text, StringComparison.Ordinal)) { return defaultString; } return text; } internal static string Format(string resourceFormat, params object[] args) { if (args != null) { if (UsingResourceKeys()) { return resourceFormat + string.Join(", ", args); } return string.Format(resourceFormat, args); } return resourceFormat; } internal static string Format(string resourceFormat, object p1) { if (UsingResourceKeys()) { return string.Join(", ", resourceFormat, p1); } return string.Format(resourceFormat, p1); } internal static string Format(string resourceFormat, object p1, object p2) { if (UsingResourceKeys()) { return string.Join(", ", resourceFormat, p1, p2); } return string.Format(resourceFormat, p1, p2); } internal static string Format(string resourceFormat, object p1, object p2, object p3) { if (UsingResourceKeys()) { return string.Join(", ", resourceFormat, p1, p2, p3); } return string.Format(resourceFormat, p1, p2, p3); } } }