PageRenderTime 51ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/Duplicati/GUI/Duplicati.GUI.TrayIcon/HttpServerConnection.cs

http://duplicati.googlecode.com/
C# | 278 lines | 228 code | 46 blank | 4 comment | 21 complexity | 65e5b5db43956963aeffcdcdcdd6ed69 MD5 | raw file
Possible License(s): LGPL-2.1, LGPL-2.0, Apache-2.0, GPL-3.0, CC-BY-SA-3.0
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using Duplicati.Server.Serialization;
  6. namespace Duplicati.GUI.TrayIcon
  7. {
  8. public class HttpServerConnection : IDisposable
  9. {
  10. private const string CONTROL_SCRIPT = "control.cgi";
  11. private const string STATUS_WINDOW = "status-window.html";
  12. private const string EDIT_WINDOW = "edit-window.html";
  13. private Uri m_controlUri;
  14. private string m_baseUri;
  15. private System.Net.NetworkCredential m_credentials;
  16. private static readonly System.Text.Encoding ENCODING = System.Text.Encoding.GetEncoding("utf-8");
  17. public delegate void StatusUpdate(IServerStatus status);
  18. public event StatusUpdate StatusUpdated;
  19. private volatile IServerStatus m_status;
  20. private volatile bool m_shutdown = false;
  21. private volatile System.Threading.Thread m_requestThread;
  22. private volatile System.Threading.Thread m_pollThread;
  23. private System.Threading.AutoResetEvent m_waitLock;
  24. private Serializer m_serializer;
  25. private readonly Dictionary<string, string> m_updateRequest;
  26. public IServerStatus Status { get { return m_status; } }
  27. private object m_lock = new object();
  28. private Queue<Dictionary<string, string>> m_workQueue = new Queue<Dictionary<string,string>>();
  29. public HttpServerConnection(Uri server, System.Net.NetworkCredential credentials)
  30. {
  31. m_baseUri = server.ToString();
  32. if (!m_baseUri.EndsWith("/"))
  33. m_baseUri += "/";
  34. m_controlUri = new Uri(m_baseUri + CONTROL_SCRIPT);
  35. m_serializer = new Serializer();
  36. m_updateRequest = new Dictionary<string, string>();
  37. m_updateRequest["action"] = "get-current-state";
  38. m_updateRequest["longpoll"] = "false";
  39. m_updateRequest["lasteventid"] = "0";
  40. UpdateStatus();
  41. //We do the first request without long poll,
  42. // and all the rest with longpoll
  43. m_updateRequest["longpoll"] = "true";
  44. m_updateRequest["duration"] = "5m";
  45. m_waitLock = new System.Threading.AutoResetEvent(false);
  46. m_requestThread = new System.Threading.Thread(ThreadRunner);
  47. m_pollThread = new System.Threading.Thread(LongPollRunner);
  48. m_requestThread.Name = "TrayIcon Request Thread";
  49. m_pollThread.Name = "TrayIcon Longpoll Thread";
  50. m_requestThread.Start();
  51. m_pollThread.Start();
  52. }
  53. private void UpdateStatus()
  54. {
  55. m_status = PerformRequest<IServerStatus>(m_updateRequest);
  56. m_updateRequest["lasteventid"] = m_status.LastEventID.ToString();
  57. if (StatusUpdated != null)
  58. StatusUpdated(m_status);
  59. }
  60. private void LongPollRunner()
  61. {
  62. while (!m_shutdown)
  63. {
  64. try
  65. {
  66. UpdateStatus();
  67. }
  68. catch (Exception ex)
  69. {
  70. System.Diagnostics.Trace.WriteLine("Request error: " + ex.Message);
  71. Console.WriteLine("Request error: " + ex.Message);
  72. }
  73. }
  74. }
  75. private void ThreadRunner()
  76. {
  77. while (!m_shutdown)
  78. {
  79. try
  80. {
  81. Dictionary<string, string> req;
  82. bool any = false;
  83. do
  84. {
  85. req = null;
  86. lock (m_lock)
  87. if (m_workQueue.Count > 0)
  88. req = m_workQueue.Dequeue();
  89. if (m_shutdown)
  90. break;
  91. if (req != null)
  92. {
  93. any = true;
  94. PerformRequest<string>(req);
  95. }
  96. } while (req != null);
  97. if (!(any || m_shutdown))
  98. m_waitLock.WaitOne(TimeSpan.FromMinutes(1), true);
  99. }
  100. catch (Exception ex)
  101. {
  102. System.Diagnostics.Trace.WriteLine("Request error: " + ex.Message);
  103. Console.WriteLine("Request error: " + ex.Message);
  104. }
  105. }
  106. }
  107. public void Close()
  108. {
  109. m_shutdown = true;
  110. m_waitLock.Set();
  111. m_pollThread.Abort();
  112. m_pollThread.Join(TimeSpan.FromSeconds(10));
  113. if (!m_requestThread.Join(TimeSpan.FromSeconds(10)))
  114. {
  115. m_requestThread.Abort();
  116. m_requestThread.Join(TimeSpan.FromSeconds(10));
  117. }
  118. }
  119. private static string EncodeQueryString(Dictionary<string, string> dict)
  120. {
  121. return string.Join("&", Array.ConvertAll(dict.Keys.ToArray(), key => string.Format("{0}={1}", Uri.EscapeUriString(key), Uri.EscapeUriString(dict[key]))));
  122. }
  123. private T PerformRequest<T>(Dictionary<string, string> queryparams)
  124. {
  125. queryparams["format"] = "json";
  126. string query = EncodeQueryString(queryparams);
  127. byte[] data = ENCODING.GetBytes(query);
  128. System.Net.HttpWebRequest req = (System.Net.HttpWebRequest)System.Net.WebRequest.Create(m_controlUri);
  129. req.Method = "POST";
  130. req.ContentLength = data.Length;
  131. req.ContentType = "application/x-www-form-urlencoded ; charset=" + ENCODING.BodyName;
  132. req.Headers.Add("Accept-Charset", ENCODING.BodyName);
  133. req.UserAgent = "Duplicati TrayIcon Monitor, v" + System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString();
  134. //Wrap it all in async stuff
  135. Duplicati.Library.Utility.AsyncHttpRequest areq = new Library.Utility.AsyncHttpRequest(req);
  136. using (System.IO.Stream s = areq.GetRequestStream())
  137. s.Write(data, 0, data.Length);
  138. //Assign the timeout, and add a little processing time as well
  139. if (queryparams["action"] == "get-current-state" && queryparams.ContainsKey("duration"))
  140. areq.Timeout = (int)(Duplicati.Library.Utility.Timeparser.ParseTimeSpan(queryparams["duration"]) + TimeSpan.FromSeconds(5)).TotalMilliseconds;
  141. using(System.Net.HttpWebResponse r = (System.Net.HttpWebResponse)areq.GetResponse())
  142. using (System.IO.Stream s = r.GetResponseStream())
  143. if (typeof(T) == typeof(string))
  144. {
  145. using (System.IO.MemoryStream ms = new System.IO.MemoryStream())
  146. {
  147. s.CopyTo(ms);
  148. return (T)(object)ENCODING.GetString(ms.ToArray());
  149. }
  150. }
  151. else
  152. {
  153. using (var sr = new System.IO.StreamReader(s, ENCODING, true))
  154. return m_serializer.Deserialize<T>(sr);
  155. }
  156. }
  157. private void ExecuteAndNotify(Dictionary<string, string> req)
  158. {
  159. lock (m_lock)
  160. {
  161. m_workQueue.Enqueue(req);
  162. m_waitLock.Set();
  163. }
  164. }
  165. public void Pause(string duration = null)
  166. {
  167. Dictionary<string, string> req = new Dictionary<string, string>();
  168. req.Add("action", "send-command");
  169. req.Add("command", "pause");
  170. if (!string.IsNullOrWhiteSpace(duration))
  171. req.Add("duration", duration);
  172. ExecuteAndNotify(req);
  173. }
  174. public void Resume()
  175. {
  176. Dictionary<string, string> req = new Dictionary<string, string>();
  177. req.Add("action", "send-command");
  178. req.Add("command", "resume");
  179. ExecuteAndNotify(req);
  180. }
  181. public void StopBackup()
  182. {
  183. Dictionary<string, string> req = new Dictionary<string, string>();
  184. req.Add("action", "send-command");
  185. req.Add("command", "stop");
  186. ExecuteAndNotify(req);
  187. }
  188. public void AbortBackup()
  189. {
  190. Dictionary<string, string> req = new Dictionary<string, string>();
  191. req.Add("action", "send-command");
  192. req.Add("command", "abort");
  193. ExecuteAndNotify(req);
  194. }
  195. public void RunBackup(long id, bool forcefull = false)
  196. {
  197. Dictionary<string, string> req = new Dictionary<string, string>();
  198. req.Add("action", "send-command");
  199. req.Add("command", "run-backup");
  200. req.Add("id", id.ToString());
  201. if (forcefull)
  202. req.Add("full", "true");
  203. ExecuteAndNotify(req);
  204. }
  205. public void ClearWarning()
  206. {
  207. Dictionary<string, string> req = new Dictionary<string, string>();
  208. req.Add("action", "send-command");
  209. req.Add("command", "clear-warning");
  210. ExecuteAndNotify(req);
  211. }
  212. public void ClearError()
  213. {
  214. Dictionary<string, string> req = new Dictionary<string, string>();
  215. req.Add("action", "send-command");
  216. req.Add("command", "clear-error");
  217. ExecuteAndNotify(req);
  218. }
  219. public void Dispose()
  220. {
  221. Close();
  222. }
  223. public string StatusWindowURL
  224. {
  225. get { return m_baseUri + STATUS_WINDOW; }
  226. }
  227. public string EditWindowURL
  228. {
  229. get { return m_baseUri + EDIT_WINDOW; }
  230. }
  231. }
  232. }