UploadItemController.cs 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  1. #if !BESTHTTP_DISABLE_SIGNALR_CORE
  2. using System;
  3. using BestHTTP;
  4. using BestHTTP.Futures;
  5. using BestHTTP.SignalRCore.Messages;
  6. namespace BestHTTP.SignalRCore
  7. {
  8. public interface IUPloadItemController<TResult> : IDisposable
  9. {
  10. string[] StreamingIDs { get; }
  11. HubConnection Hub { get; }
  12. void UploadParam<T>(string streamId, T item);
  13. void Cancel();
  14. }
  15. public sealed class DownStreamItemController<TResult> : IFuture<TResult>, IDisposable
  16. {
  17. public readonly long invocationId;
  18. public readonly HubConnection hubConnection;
  19. public readonly IFuture<TResult> future;
  20. public FutureState state { get { return this.future.state; } }
  21. public TResult value { get { return this.future.value; } }
  22. public Exception error { get { return this.future.error; } }
  23. public bool IsCanceled { get; private set; }
  24. public DownStreamItemController(HubConnection hub, long iId, IFuture<TResult> future)
  25. {
  26. this.hubConnection = hub;
  27. this.invocationId = iId;
  28. this.future = future;
  29. }
  30. public void Cancel()
  31. {
  32. if (this.IsCanceled)
  33. return;
  34. this.IsCanceled = true;
  35. Message message = new Message
  36. {
  37. type = MessageTypes.CancelInvocation,
  38. invocationId = this.invocationId.ToString()
  39. };
  40. this.hubConnection.SendMessage(message);
  41. }
  42. public void Dispose()
  43. {
  44. GC.SuppressFinalize(this);
  45. Cancel();
  46. }
  47. public IFuture<TResult> OnItem(FutureValueCallback<TResult> callback) { return this.future.OnItem(callback); }
  48. public IFuture<TResult> OnSuccess(FutureValueCallback<TResult> callback) { return this.future.OnSuccess(callback); }
  49. public IFuture<TResult> OnError(FutureErrorCallback callback) { return this.future.OnError(callback); }
  50. public IFuture<TResult> OnComplete(FutureCallback<TResult> callback) { return this.future.OnComplete(callback); }
  51. }
  52. public sealed class UpStreamItemController<TResult> : IUPloadItemController<TResult>, IFuture<TResult>
  53. {
  54. public readonly long invocationId;
  55. public readonly string[] streamingIds;
  56. public readonly HubConnection hubConnection;
  57. public readonly Futures.IFuture<TResult> future;
  58. public string[] StreamingIDs { get { return this.streamingIds; } }
  59. public HubConnection Hub { get { return this.hubConnection; } }
  60. public FutureState state { get { return this.future.state; } }
  61. public TResult value { get { return this.future.value; } }
  62. public Exception error { get { return this.future.error; } }
  63. public bool IsFinished { get; private set; }
  64. public bool IsCanceled { get; private set; }
  65. private object[] streams;
  66. public UpStreamItemController(HubConnection hub, long iId, string[] sIds, IFuture<TResult> future)
  67. {
  68. this.hubConnection = hub;
  69. this.invocationId = iId;
  70. this.streamingIds = sIds;
  71. this.streams = new object[this.streamingIds.Length];
  72. this.future = future;
  73. }
  74. public UploadChannel<TResult, T> GetUploadChannel<T>(int paramIdx)
  75. {
  76. var stream = this.streams[paramIdx] as UploadChannel<TResult, T>;
  77. if (stream == null)
  78. this.streams[paramIdx] = stream = new UploadChannel<TResult, T>(this, paramIdx);
  79. return stream;
  80. }
  81. public void UploadParam<T>(string streamId, T item)
  82. {
  83. if (streamId == null)
  84. return;
  85. var message = new Message
  86. {
  87. type = MessageTypes.StreamItem,
  88. invocationId = streamId.ToString(),
  89. item = item,
  90. };
  91. this.hubConnection.SendMessage(message);
  92. }
  93. public void Finish()
  94. {
  95. if (!this.IsFinished)
  96. {
  97. this.IsFinished = true;
  98. for (int i = 0; i < this.streamingIds.Length; ++i)
  99. if (this.streamingIds[i] != null)
  100. {
  101. var message = new Message
  102. {
  103. type = MessageTypes.Completion,
  104. invocationId = this.streamingIds[i].ToString()
  105. };
  106. this.hubConnection.SendMessage(message);
  107. }
  108. }
  109. }
  110. public void Cancel()
  111. {
  112. if (!this.IsFinished && !this.IsCanceled)
  113. {
  114. this.IsCanceled = true;
  115. var message = new Message
  116. {
  117. type = MessageTypes.CancelInvocation,
  118. invocationId = this.invocationId.ToString(),
  119. };
  120. this.hubConnection.SendMessage(message);
  121. // Zero out the streaming ids, disabling any future message sending
  122. Array.Clear(this.streamingIds, 0, this.streamingIds.Length);
  123. // If it's also a down-stream, set it canceled.
  124. var itemContainer = (this.future.value as StreamItemContainer<TResult>);
  125. if (itemContainer != null)
  126. itemContainer.IsCanceled = true;
  127. }
  128. }
  129. void IDisposable.Dispose()
  130. {
  131. GC.SuppressFinalize(this);
  132. Finish();
  133. }
  134. public IFuture<TResult> OnItem(FutureValueCallback<TResult> callback) { return this.future.OnItem(callback); }
  135. public IFuture<TResult> OnSuccess(FutureValueCallback<TResult> callback) { return this.future.OnSuccess(callback); }
  136. public IFuture<TResult> OnError(FutureErrorCallback callback) { return this.future.OnError(callback); }
  137. public IFuture<TResult> OnComplete(FutureCallback<TResult> callback) { return this.future.OnComplete(callback); }
  138. }
  139. /// <summary>
  140. /// An upload channel that represents one prameter of a client callable function. It implements the IDisposable
  141. /// interface and calls Finish from the Dispose method.
  142. /// </summary>
  143. public sealed class UploadChannel<TResult, T> : IDisposable
  144. {
  145. /// <summary>
  146. /// The associated upload controller
  147. /// </summary>
  148. public IUPloadItemController<TResult> Controller { get; private set; }
  149. /// <summary>
  150. /// What parameter is bound to.
  151. /// </summary>
  152. public int ParamIdx { get; private set; }
  153. /// <summary>
  154. /// Returns true if Finish() or Cancel() is already called.
  155. /// </summary>
  156. public bool IsFinished
  157. {
  158. get { return this.Controller.StreamingIDs[this.ParamIdx] == null; }
  159. private set
  160. {
  161. if (value)
  162. this.Controller.StreamingIDs[this.ParamIdx] = null;
  163. }
  164. }
  165. /// <summary>
  166. /// The unique generated id of this parameter channel.
  167. /// </summary>
  168. public string StreamingId { get { return this.Controller.StreamingIDs[this.ParamIdx]; } }
  169. internal UploadChannel(IUPloadItemController<TResult> ctrl, int paramIdx)
  170. {
  171. this.Controller = ctrl;
  172. this.ParamIdx = paramIdx;
  173. }
  174. /// <summary>
  175. /// Uploads a parameter value to the server.
  176. /// </summary>
  177. public void Upload(T item)
  178. {
  179. string streamId = this.StreamingId;
  180. if (streamId != null)
  181. this.Controller.UploadParam(streamId, item);
  182. }
  183. /// <summary>
  184. /// Calling this function cancels the call itself, not just a parameter upload channel.
  185. /// </summary>
  186. public void Cancel()
  187. {
  188. if (!this.IsFinished)
  189. {
  190. // Cancel all upload stream, cancel will also set streaming ids to 0.
  191. this.Controller.Cancel();
  192. }
  193. }
  194. /// <summary>
  195. /// Finishes the channel by telling the server that no more uplode items will follow.
  196. /// </summary>
  197. public void Finish()
  198. {
  199. if (!this.IsFinished)
  200. {
  201. string streamId = this.StreamingId;
  202. if (streamId != null)
  203. {
  204. // this will set the streaming id to 0
  205. this.IsFinished = true;
  206. var message = new Message
  207. {
  208. type = MessageTypes.Completion,
  209. invocationId = streamId.ToString()
  210. };
  211. this.Controller.Hub.SendMessage(message);
  212. }
  213. }
  214. }
  215. void IDisposable.Dispose()
  216. {
  217. if (!this.IsFinished)
  218. Finish();
  219. GC.SuppressFinalize(this);
  220. }
  221. }
  222. }
  223. #endif