// Safely handles private bool ProcessStringResponse(string stringResponse) { // Decode full response responseData = WitResponseJson.Parse(stringResponse); // Handle responses bool isFinal = responseData.HandleResponse((transcription, final) => { // Call partial transcription if (!final) { MainThreadCallback(() => onPartialTranscription?.Invoke(transcription)); } // Call full transcription else { MainThreadCallback(() => onFullTranscription?.Invoke(transcription)); } }, (response, final) => { // Call partial response SafeInvoke(onPartialResponse); // Call final response if (final) { SafeInvoke(onResponse); } }); // Return final return(isFinal); }
private void HandleResponse(IAsyncResult ar) { bool sentResponse = false; string stringResponse = ""; responseStarted = true; try { response = (HttpWebResponse)_request.EndGetResponse(ar); statusCode = (int)response.StatusCode; statusDescription = response.StatusDescription; try { var responseStream = response.GetResponseStream(); if (response.Headers["Transfer-Encoding"] == "chunked") { byte[] buffer = new byte[10240]; int bytes = 0; int offset = 0; int totalRead = 0; while ((bytes = responseStream.Read(buffer, offset, buffer.Length - offset)) > 0) { totalRead += bytes; stringResponse = Encoding.UTF8.GetString(buffer, 0, totalRead); if (stringResponse.EndsWith("\r\n")) { try { offset = 0; totalRead = 0; sentResponse |= ProcessStringResponse(stringResponse); } catch (JSONParseException e) { offset = bytes; Debug.LogWarning("Received what appears to be a partial response or invalid json. Attempting to continue reading. Parsing error: " + e.Message + "\n" + stringResponse); } } else { offset = totalRead; } } // If the final transmission didn't end with \r\n process it as the final // result if (!stringResponse.EndsWith("\r\n") && !string.IsNullOrEmpty(stringResponse)) { sentResponse |= ProcessStringResponse(stringResponse); } if (stringResponse.Length > 0 && null != responseData) { MainThreadCallback(() => onRawResponse?.Invoke(stringResponse)); } } else { using (StreamReader reader = new StreamReader(responseStream)) { stringResponse = reader.ReadToEnd(); MainThreadCallback(() => onRawResponse?.Invoke(stringResponse)); responseData = WitResponseJson.Parse(stringResponse); } } responseStream.Close(); } catch (JSONParseException e) { Debug.LogError("Server returned invalid data: " + e.Message + "\n" + stringResponse); statusCode = ERROR_CODE_INVALID_DATA_FROM_SERVER; statusDescription = "Server returned invalid data."; } catch (Exception e) { Debug.LogError( $"{e.Message}\nRequest Stack Trace:\n{callingStackTrace}\nResponse Stack Trace:\n{e.StackTrace}"); statusCode = ERROR_CODE_GENERAL; statusDescription = e.Message; } response.Close(); } catch (WebException e) { statusCode = (int)e.Status; if (e.Response is HttpWebResponse errorResponse) { statusCode = (int)errorResponse.StatusCode; try { var stream = errorResponse.GetResponseStream(); if (null != stream) { using (StreamReader reader = new StreamReader(stream)) { stringResponse = reader.ReadToEnd(); MainThreadCallback(() => onRawResponse?.Invoke(stringResponse)); responseData = WitResponseJson.Parse(stringResponse); } } } catch (JSONParseException) { // Response wasn't encoded error, ignore it. } catch (Exception errorResponseError) { // We've already caught that there is an error, we'll ignore any errors // reading error response data and use the status/original error for validation Debug.LogWarning(errorResponseError); } } statusDescription = e.Message; if (e.Status != WebExceptionStatus.RequestCanceled) { Debug.LogError( $"Http Request Failed [{statusCode}]: {e.Message}\nRequest Stack Trace:\n{callingStackTrace}\nResponse Stack Trace:\n{e.StackTrace}"); } } finally { isActive = false; } CloseRequestStream(); if (null != responseData) { var error = responseData["error"]; if (!string.IsNullOrEmpty(error)) { statusDescription = $"Error: {responseData["code"]}. {error}"; statusCode = statusCode == 200 ? ERROR_CODE_GENERAL : statusCode; } } else if (statusCode == 200) { statusCode = ERROR_CODE_NO_DATA_FROM_SERVER; statusDescription = "Server did not return a valid json response."; Debug.LogWarning( "No valid data was received from the server even though the request was successful. Actual potential response data: \n" + stringResponse); } // Send final response if have not yet if (!sentResponse) { // Final transcription string transcription = responseData.GetTranscription(); if (!string.IsNullOrEmpty(transcription)) { MainThreadCallback(() => onFullTranscription?.Invoke(transcription)); } // Final response SafeInvoke(onResponse); } // Complete responseStarted = false; }
private void HandleResponse(IAsyncResult ar) { string stringResponse = ""; responseStarted = true; try { response = (HttpWebResponse)request.EndGetResponse(ar); statusCode = (int)response.StatusCode; statusDescription = response.StatusDescription; try { var responseStream = response.GetResponseStream(); if (response.Headers["Transfer-Encoding"] == "chunked") { byte[] buffer = new byte[10240]; int bytes = 0; int offset = 0; int totalRead = 0; while ((bytes = responseStream.Read(buffer, offset, buffer.Length - offset)) > 0) { totalRead += bytes; stringResponse = Encoding.UTF8.GetString(buffer, 0, totalRead); if (stringResponse.Length > 0) { try { responseData = WitResponseJson.Parse(stringResponse); offset = 0; totalRead = 0; if (null != responseData) { var transcription = responseData["text"]; if (!string.IsNullOrEmpty(transcription)) { onPartialTranscription?.Invoke(transcription); } } } catch (JSONParseException e) { // TODO: t105419819 Update the protocol to better handle this issue. // This is a bit of a hack to get around an issue with a full // socket buffer or partial server response. We will need to // address this server side to make sure we're reading all data // rather than relying on a json parse exception to catch this. // Test case: Utterance with multiple entity responses pushing // final data > 1024 bytes. offset = bytes; Debug.LogWarning("Received what appears to be a partial response or invalid json. Attempting to continue reading. Parsing error: " + e.Message); } } } if (stringResponse.Length > 0 && null != responseData) { onFullTranscription?.Invoke(responseData["text"]); onRawResponse?.Invoke(stringResponse); } } else { using (StreamReader reader = new StreamReader(responseStream)) { stringResponse = reader.ReadToEnd(); onRawResponse?.Invoke(stringResponse); responseData = WitResponseJson.Parse(stringResponse); } } responseStream.Close(); } catch (JSONParseException e) { Debug.LogError("Server returned invalid data: " + e.Message + "\n" + stringResponse); statusCode = ERROR_CODE_INVALID_DATA_FROM_SERVER; statusDescription = "Server returned invalid data."; } catch (Exception e) { Debug.LogError( $"{e.Message}\nRequest Stack Trace:\n{callingStackTrace}\nResponse Stack Trace:\n{e.StackTrace}"); statusCode = ERROR_CODE_GENERAL; statusDescription = e.Message; } response.Close(); } catch (WebException e) { statusCode = (int)e.Status; if (e.Response is HttpWebResponse errorResponse) { statusCode = (int)errorResponse.StatusCode; try { var stream = errorResponse.GetResponseStream(); if (null != stream) { using (StreamReader reader = new StreamReader(stream)) { stringResponse = reader.ReadToEnd(); onRawResponse?.Invoke(stringResponse); responseData = WitResponseJson.Parse(stringResponse); } } } catch (JSONParseException) { // Response wasn't encoded error, ignore it. } catch (Exception errorResponseError) { // We've already caught that there is an error, we'll ignore any errors // reading error response data and use the status/original error for validation Debug.LogWarning(errorResponseError); } } statusDescription = e.Message; if (e.Status != WebExceptionStatus.RequestCanceled) { Debug.LogError( $"Http Request Failed [{statusCode}]: {e.Message}\nRequest Stack Trace:\n{callingStackTrace}\nResponse Stack Trace:\n{e.StackTrace}"); } } finally { isActive = false; } CloseRequestStream(); if (null != responseData) { var error = responseData["error"]; if (!string.IsNullOrEmpty(error)) { statusDescription = $"Error: {responseData["code"]}. {error}"; statusCode = statusCode == 200 ? ERROR_CODE_GENERAL : statusCode; } } else if (statusCode == 200) { statusCode = ERROR_CODE_NO_DATA_FROM_SERVER; statusDescription = "Server did not return a valid json response."; Debug.LogWarning( "No valid data was received from the server even though the request was successful. Actual potential response data: \n" + stringResponse); } SafeInvoke(onResponse); }