LocationComponent.cs 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Threading.Tasks;
  4. namespace Model
  5. {
  6. public abstract class LocationTask : SceneEntity
  7. {
  8. protected LocationTask()
  9. {
  10. }
  11. protected LocationTask(long id) : base(id)
  12. {
  13. }
  14. public abstract void Run();
  15. }
  16. public sealed class LocationLockTask : LocationTask
  17. {
  18. private readonly long key;
  19. private readonly int time;
  20. private readonly TaskCompletionSource<bool> tcs;
  21. public LocationLockTask(long key, int time)
  22. {
  23. this.key = key;
  24. this.time = time;
  25. this.tcs = new TaskCompletionSource<bool>();
  26. }
  27. public Task<bool> Task
  28. {
  29. get
  30. {
  31. return this.tcs.Task;
  32. }
  33. }
  34. public override void Run()
  35. {
  36. try
  37. {
  38. Scene.GetComponent<LocationComponent>().Lock(this.key, this.time);
  39. this.tcs.SetResult(true);
  40. }
  41. catch (Exception e)
  42. {
  43. this.tcs.SetException(e);
  44. }
  45. }
  46. }
  47. public sealed class LocationQueryTask : LocationTask
  48. {
  49. private readonly long key;
  50. private readonly TaskCompletionSource<string> tcs;
  51. public LocationQueryTask(long key)
  52. {
  53. this.key = key;
  54. this.tcs = new TaskCompletionSource<string>();
  55. }
  56. public Task<string> Task
  57. {
  58. get
  59. {
  60. return this.tcs.Task;
  61. }
  62. }
  63. public override void Run()
  64. {
  65. try
  66. {
  67. string location = Scene.GetComponent<LocationComponent>().Get(key);
  68. this.tcs.SetResult(location);
  69. }
  70. catch (Exception e)
  71. {
  72. this.tcs.SetException(e);
  73. }
  74. }
  75. }
  76. public class LocationComponent : Component
  77. {
  78. private readonly Dictionary<long, string> locations = new Dictionary<long, string>();
  79. private readonly Dictionary<long, int> lockDict = new Dictionary<long, int>();
  80. private readonly Dictionary<long, Queue<LocationTask>> taskQueues = new Dictionary<long, Queue<LocationTask>>();
  81. public async void Add(long key, string address)
  82. {
  83. this.locations[key] = address;
  84. // 更新db
  85. await Game.Scene.GetComponent<DBProxyComponent>().Save(new Location(key, address));
  86. }
  87. public void Remove(long key)
  88. {
  89. this.locations.Remove(key);
  90. }
  91. public string Get(long key)
  92. {
  93. this.locations.TryGetValue(key, out string location);
  94. return location;
  95. }
  96. public async void Lock(long key, int appId, int time = 0)
  97. {
  98. if (this.lockDict.ContainsKey(key))
  99. {
  100. return;
  101. }
  102. this.lockDict.Add(key, appId);
  103. // 超时则解锁
  104. if (time > 0)
  105. {
  106. await Game.Scene.GetComponent<TimerComponent>().WaitAsync(time);
  107. int saveAppId = 0;
  108. this.lockDict.TryGetValue(key, out saveAppId);
  109. if (saveAppId != appId)
  110. {
  111. Log.Warning($"unlock appid is different {saveAppId} {appId}");
  112. return;
  113. }
  114. this.UnLock(key);
  115. }
  116. }
  117. public void UpdateAndUnLock(long key, int appId, string value)
  118. {
  119. int saveAppId = 0;
  120. this.lockDict.TryGetValue(key, out saveAppId);
  121. if (saveAppId != appId)
  122. {
  123. Log.Warning($"unlock appid is different {saveAppId} {appId}" );
  124. return;
  125. }
  126. this.Add(key, value);
  127. this.UnLock(key);
  128. }
  129. private void UnLock(long key)
  130. {
  131. this.lockDict.Remove(key);
  132. if (!this.taskQueues.TryGetValue(key, out Queue<LocationTask> tasks))
  133. {
  134. return;
  135. }
  136. while (true)
  137. {
  138. if (tasks.Count <= 0)
  139. {
  140. this.taskQueues.Remove(key);
  141. return;
  142. }
  143. if (this.lockDict.ContainsKey(key))
  144. {
  145. return;
  146. }
  147. LocationTask task = tasks.Dequeue();
  148. task.Run();
  149. }
  150. }
  151. public Task<bool> LockAsync(long key, int time)
  152. {
  153. if (!this.lockDict.ContainsKey(key))
  154. {
  155. this.Lock(key, time);
  156. return Task.FromResult(true);
  157. }
  158. LocationLockTask task = new LocationLockTask(key, time);
  159. this.AddTask(key, task);
  160. return task.Task;
  161. }
  162. public Task<string> GetAsync(long key)
  163. {
  164. if (!this.lockDict.ContainsKey(key))
  165. {
  166. this.locations.TryGetValue(key, out string location);
  167. return Task.FromResult(location);
  168. }
  169. LocationQueryTask task = new LocationQueryTask(key);
  170. this.AddTask(key, task);
  171. return task.Task;
  172. }
  173. public void AddTask(long key, LocationTask task)
  174. {
  175. if (!this.taskQueues.TryGetValue(key, out Queue<LocationTask> tasks))
  176. {
  177. tasks = new Queue<LocationTask>();
  178. this.taskQueues[key] = tasks;
  179. }
  180. task.Scene = this.GetOwner<Scene>();
  181. tasks.Enqueue(task);
  182. }
  183. public override void Dispose()
  184. {
  185. if (this.Id == 0)
  186. {
  187. return;
  188. }
  189. base.Dispose();
  190. }
  191. }
  192. }