private void ClearGeneratedApiObjects() { lock (GeneratedApiObjects) { foreach (var item in GeneratedApiObjects.Keys) { try { if (GeneratedApiObjects.TryRemove(item, out var value)) { GeneratedAPI target = null; if (value?.TryGetTarget(out target) ?? false) { _ = Task.Run(() => { try { target?.OnClosed(); } catch { } }); } } } catch (Exception ex) { logger.Error(ex); } } } }
#pragma warning disable 1591 // no XML Comment Warning for override public override bool TryConvert(ConvertBinder binder, out object result) { Type gArgs = binder.ReturnType.GetGenericArguments().FirstOrDefault(); bool tryDynamicResult = false; if (gArgs == typeof(object)) { gArgs = typeof(JObject); tryDynamicResult = true; } gArgs = gArgs ?? typeof(object); if (!gArgs.IsAssignableFrom(typeof(JToken))) { var tcs = new TaskCompletionSource(gArgs); input.ContinueWith((message) => { if (message.IsCanceled) { tcs.SetCanceled(); return; } if (message.IsFaulted) { tcs.SetException(message.Exception); return; } var qReturn = message?.Result?.SelectToken("qReturn"); if (qReturn != null && qReturn.Type == JTokenType.Object && qReturn["qHandle"] != null) { if (qReturn["qHandle"].Type == JTokenType.Null) { tcs.SetResult(null); } else { try { var objectResult = qReturn.ToObject <ObjectResult>(); var newObj = new GeneratedAPI(objectResult, session, gArgs); session.GeneratedApiObjects.TryAdd(objectResult.QHandle, new WeakReference <GeneratedAPI>(newObj)); tcs.SetResult(newObj.ProxyClass); } catch (Exception ex) { tcs.SetException(ex); } } } else { try { object newRes = null; JToken resultToken = null; var results = message.Result.Children().ToList(); if (results.Count == 1) { resultToken = results.FirstOrDefault().First(); } else { resultToken = message.Result; } if (gArgs.IsAssignableFrom(typeof(JObject)) && resultToken as JObject != null) { if (tryDynamicResult) { dynamic dt = resultToken as JObject; var tcs2 = new TaskCompletionSource <dynamic>(); tcs2.SetResult(resultToken); } else { tcs.SetResult(resultToken); } return; } if (gArgs != typeof(object)) { newRes = resultToken.ToObject(gArgs); } else { newRes = resultToken; } tcs.SetResult(newRes); } catch (Exception ex) { tcs.SetException(ex); } } } ); result = tcs.Task; return(true); } result = input; return(true); }
private void StartReceiveLoop(CancellationToken cancellationToken) { _ = Task.Run(async() => { byte[] buffer = new byte[4096 * 8]; #region Helper to Notify API Objects void notifyGeneratedAPI(WeakReference <GeneratedAPI> wrGeneratedAPI, bool close) { Console.WriteLine("notifyGeneratedAPI"); GeneratedAPI generatedAPI = null; wrGeneratedAPI?.TryGetTarget(out generatedAPI); if (generatedAPI != null) { Console.WriteLine("notifyGeneratedAPI - genAPI"); _ = Task.Run(() => { try { Console.WriteLine("notifyGeneratedAPI - RUN"); if (close) { generatedAPI?.OnClosed(); } else { generatedAPI?.OnChanged(); } } catch (Exception ex) { logger.Error(ex); } }).ConfigureAwait(false); } } #endregion try { while (!cancellationToken.IsCancellationRequested && socket != null && socket.State == WebSocketState.Open) { var writeSegment = new ArraySegment <byte>(buffer); WebSocketReceiveResult result; do { result = await socket.ReceiveAsync(writeSegment, cancellationToken).ConfigureAwait(false); writeSegment = new ArraySegment <byte>(buffer, writeSegment.Offset + result.Count, writeSegment.Count - result.Count); // check buffer overflow if (!result.EndOfMessage && writeSegment.Count == 0) { // autoIncreaseRecieveBuffer) Array.Resize(ref buffer, buffer.Length * 2); writeSegment = new ArraySegment <byte>(buffer, writeSegment.Offset, buffer.Length - writeSegment.Offset); } } while (!result.EndOfMessage); var message = Encoding.UTF8.GetString(buffer, 0, writeSegment.Offset); logger.Trace("Response" + message); try { var responseMessage = JsonConvert.DeserializeObject <JsonRpcGeneratedAPIResponseMessage>(message); try { var list = Messages.GetBuffer(); if (responseMessage != null) { foreach (var item in list) { if (item != null && item.ID == responseMessage.Id) { var ts = DateTime.Now - item.StartTime; item.Duration = ts.TotalMilliseconds; item.Error = responseMessage.Error?.ToString() ?? ""; } } } } catch (Exception ex) { logger.Error(ex); } if (responseMessage != null && (responseMessage.Result != null || responseMessage.Error != null || responseMessage.Change?.Count > 0 || responseMessage.Closed?.Count > 0 )) { if (responseMessage.Id != null) { OpenRequests.TryRemove(responseMessage.Id.Value, out var tcs); if (responseMessage.Error != null) { tcs?.SetException(new Exception(responseMessage.Error?.ToString())); } else { tcs?.SetResult(responseMessage.Result); } } #region Notify Changed or Closed API Objects if (responseMessage.Change != null) { foreach (var item in responseMessage.Change) { logger.Trace($"Object Id: {item} changed."); GeneratedApiObjects.TryGetValue(item, out var wkValues); notifyGeneratedAPI(wkValues, false); } } if (responseMessage.Closed != null) { foreach (var item in responseMessage.Closed) { logger.Trace($"Object Id: {item} closed."); GeneratedApiObjects.TryRemove(item, out var wkValues); notifyGeneratedAPI(wkValues, true); } } #endregion } else { var requestMessage = JsonConvert.DeserializeObject <JsonRpcRequestMessage>(message); if (requestMessage != null) { _ = Task.Run(() => { try { this.RPCMethodCalled?.Invoke(this, requestMessage); } catch (Exception ex) { logger.Error(ex); } }); } } } catch (Exception ex) { logger.Error(ex); } } ClearGeneratedApiObjects(); } catch (Exception ex) { logger.Error(ex); } }); }
/// <summary> /// Establishes the websocket against the configured URL. /// Try to get the QIX global interface when the connection has been established. /// </summary> /// <returns></returns> public async Task <dynamic> OpenAsync(CancellationToken?ctn = null) { if (socket != null) { await CloseAsync(ctn); } LastOpenError = null; CancellationToken ct = ctn ?? CancellationToken.None; socket = await config.CreateSocketCall(ct).ConfigureAwait(false); // Todo add here the global Cancelation Token that is // triggered from the CloseAsync bool?connected = null; void RPCMethodCall(object sender, JsonRpcRequestMessage e) { logger.Trace($"RPCMethodCall - {e.Method}:{e.Parameters}"); if (e.Method == "OnAuthenticationInformation" && (bool?)e.Parameters["mustAuthenticate"] == true) { connected = false; LastOpenError = "Connection established but authentication failed"; } if (e.Method == "OnConnected") { LastOpenError = ""; connected = true; } if (!connected.HasValue) { string message = ""; try { message = (string)e.Parameters["message"]; } catch (Exception ex) { logger.Error(ex); } string severity = ""; try { severity = (string)e.Parameters["severity"]; } catch (Exception ex) { logger.Error(ex); } if (!string.IsNullOrEmpty(severity) && severity == "fatal") { try { LastOpenError = e.Method + "\n" + message; } catch (Exception ex) { logger.Error(ex); LastOpenError = "Communication Error"; } connected = false; } } } RPCMethodCalled += RPCMethodCall; StartReceiveLoop(ct); while (connected == null && !ct.IsCancellationRequested) { Thread.Sleep(10); } RPCMethodCalled -= RPCMethodCall; if (connected == false) { socket?.CloseAsync(WebSocketCloseStatus.InternalServerError, "", ct); throw new Exception("Connection Error"); } // start SendLoop only if connection is opened StartSendLoop(ct); var global = new GeneratedAPI(new ObjectResult() { QHandle = -1, QType = "Global" }, this); GeneratedApiObjects.TryAdd(-1, new WeakReference <GeneratedAPI>(global)); return(global); }