BugReportApi.cs 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. namespace SRDebugger.Internal
  2. {
  3. using System;
  4. using System.Collections;
  5. using System.Collections.Generic;
  6. using SRF;
  7. using UnityEngine;
  8. using System.Text;
  9. using UnityEngine.Networking;
  10. class BugReportApi : MonoBehaviour
  11. {
  12. private string _apiKey;
  13. private BugReport _bugReport;
  14. private bool _isBusy;
  15. private UnityWebRequest _webRequest;
  16. private Action<BugReportSubmitResult> _onComplete;
  17. private IProgress<float> _progress;
  18. public static void Submit(BugReport report, string apiKey, Action<BugReportSubmitResult> onComplete, IProgress<float> progress)
  19. {
  20. var go = new GameObject("BugReportApi");
  21. go.transform.parent = Hierarchy.Get("SRDebugger");
  22. var bugReportApi = go.AddComponent<BugReportApi>();
  23. bugReportApi.Init(report, apiKey, onComplete, progress);
  24. bugReportApi.StartCoroutine(bugReportApi.Submit());
  25. }
  26. private void Init(BugReport report, string apiKey, Action<BugReportSubmitResult> onComplete, IProgress<float> progress)
  27. {
  28. _bugReport = report;
  29. _apiKey = apiKey;
  30. _onComplete = onComplete;
  31. _progress = progress;
  32. }
  33. void Update()
  34. {
  35. if (_isBusy && _webRequest != null)
  36. {
  37. _progress.Report(_webRequest.uploadProgress);
  38. }
  39. }
  40. IEnumerator Submit()
  41. {
  42. if (_isBusy)
  43. {
  44. throw new InvalidOperationException("BugReportApi is already sending a bug report");
  45. }
  46. // Reset state
  47. _isBusy = true;
  48. _webRequest = null;
  49. string json;
  50. byte[] jsonBytes;
  51. try
  52. {
  53. json = BuildJsonRequest(_bugReport);
  54. jsonBytes = Encoding.UTF8.GetBytes(json);
  55. }
  56. catch (Exception e)
  57. {
  58. Debug.LogError(e);
  59. SetCompletionState(BugReportSubmitResult.Error("Error building bug report."));
  60. yield break;
  61. }
  62. try
  63. {
  64. const string jsonContentType = "application/json";
  65. _webRequest = new UnityWebRequest(SRDebugApi.BugReportEndPoint, UnityWebRequest.kHttpVerbPOST,
  66. new DownloadHandlerBuffer(), new UploadHandlerRaw(jsonBytes)
  67. {
  68. contentType = jsonContentType
  69. });
  70. _webRequest.SetRequestHeader("Accept", jsonContentType);
  71. _webRequest.SetRequestHeader("X-ApiKey", _apiKey);
  72. }
  73. catch (Exception e)
  74. {
  75. Debug.LogError(e);
  76. if (_webRequest != null)
  77. {
  78. _webRequest.Dispose();
  79. _webRequest = null;
  80. }
  81. }
  82. if (_webRequest == null)
  83. {
  84. SetCompletionState(BugReportSubmitResult.Error("Error building bug report request."));
  85. yield break;
  86. }
  87. yield return _webRequest.SendWebRequest();
  88. #if UNITY_2018 || UNITY_2019
  89. bool isError = _webRequest.isNetworkError;
  90. #else
  91. bool isError = _webRequest.result == UnityWebRequest.Result.ConnectionError || _webRequest.result == UnityWebRequest.Result.DataProcessingError;
  92. #endif
  93. if (isError)
  94. {
  95. SetCompletionState(BugReportSubmitResult.Error("Request Error: " + _webRequest.error));
  96. _webRequest.Dispose();
  97. yield break;
  98. }
  99. long responseCode = _webRequest.responseCode;
  100. var responseJson = _webRequest.downloadHandler.text;
  101. _webRequest.Dispose();
  102. if (responseCode != 200)
  103. {
  104. SetCompletionState(BugReportSubmitResult.Error("Server: " + SRDebugApiUtil.ParseErrorResponse(responseJson, "Unknown response from server")));
  105. yield break;
  106. }
  107. SetCompletionState(BugReportSubmitResult.Success);
  108. }
  109. private void SetCompletionState(BugReportSubmitResult result)
  110. {
  111. _bugReport.ScreenshotData = null; // Clear the heaviest data in case something holds onto it
  112. _isBusy = false;
  113. if (!result.IsSuccessful)
  114. {
  115. Debug.LogError("Bug Reporter Error: " + result.ErrorMessage);
  116. }
  117. Destroy(gameObject);
  118. _onComplete(result);
  119. }
  120. private static string BuildJsonRequest(BugReport report)
  121. {
  122. var ht = new Hashtable();
  123. ht.Add("userEmail", report.Email);
  124. ht.Add("userDescription", report.UserDescription);
  125. ht.Add("console", CreateConsoleDump());
  126. ht.Add("systemInformation", report.SystemInformation);
  127. ht.Add("applicationIdentifier", Application.identifier);
  128. if (report.ScreenshotData != null)
  129. {
  130. ht.Add("screenshot", Convert.ToBase64String(report.ScreenshotData));
  131. }
  132. var json = Json.Serialize(ht);
  133. return json;
  134. }
  135. private static List<List<string>> CreateConsoleDump()
  136. {
  137. var consoleLog = Service.Console.AllEntries;
  138. var list = new List<List<string>>(consoleLog.Count);
  139. foreach (var consoleEntry in consoleLog)
  140. {
  141. var entry = new List<string>(5);
  142. entry.Add(consoleEntry.LogType.ToString());
  143. entry.Add(consoleEntry.Message);
  144. entry.Add(consoleEntry.StackTrace);
  145. if (consoleEntry.Count > 1)
  146. {
  147. entry.Add(consoleEntry.Count.ToString());
  148. }
  149. list.Add(entry);
  150. }
  151. return list;
  152. }
  153. }
  154. }