KernelOutputKeywordSet.cs 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. using LiteDB;
  2. using NTMiner.Core;
  3. using System;
  4. using System.Collections;
  5. using System.Collections.Generic;
  6. using System.IO;
  7. using System.Linq;
  8. using System.Text;
  9. namespace NTMiner.KernelOutputKeyword {
  10. public class KernelOutputKeywordSet : IKernelOutputKeywordSet {
  11. private readonly Dictionary<Guid, KernelOutputKeywordData> _dicById = new Dictionary<Guid, KernelOutputKeywordData>();
  12. private readonly string _connectionString;
  13. public KernelOutputKeywordSet(string dbFileFullName, bool isServer) {
  14. if (string.IsNullOrEmpty(dbFileFullName)) {
  15. throw new ArgumentNullException(nameof(dbFileFullName));
  16. }
  17. _connectionString = $"filename={dbFileFullName};journal=false";
  18. if (!isServer) {
  19. VirtualRoot.BuildCmdPath<LoadKernelOutputKeywordCommand>(action: message => {
  20. DateTime localTimestamp = VirtualRoot.LocalKernelOutputKeywordSetTimestamp;
  21. // 如果已知服务器端最新内核输出关键字时间戳不比本地已加载的最新内核输出关键字时间戳新就不用加载了
  22. if (message.KnowKernelOutputKeywordTimestamp <= Timestamp.GetTimestamp(localTimestamp)) {
  23. return;
  24. }
  25. OfficialServer.KernelOutputKeywordService.GetKernelOutputKeywords((response, e) => {
  26. if (response.IsSuccess()) {
  27. Guid[] toRemoves = _dicById.Where(a => a.Value.DataLevel == DataLevel.Global).Select(a => a.Key).ToArray();
  28. foreach (var id in toRemoves) {
  29. _dicById.Remove(id);
  30. }
  31. if (response.Data.Count != 0) {
  32. foreach (var item in response.Data) {
  33. item.SetDataLevel(DataLevel.Global);
  34. _dicById.Add(item.Id, item);
  35. }
  36. if (response.Timestamp != Timestamp.GetTimestamp(localTimestamp)) {
  37. VirtualRoot.LocalKernelOutputKeywordSetTimestamp = Timestamp.FromTimestamp(response.Timestamp);
  38. }
  39. CacheServerKernelOutputKeywords(response.Data);
  40. VirtualRoot.RaiseEvent(new KernelOutputKeywordLoadedEvent(response.Data));
  41. }
  42. }
  43. });
  44. });
  45. }
  46. VirtualRoot.BuildCmdPath<AddOrUpdateKernelOutputKeywordCommand>(action: (message) => {
  47. InitOnece();
  48. if (isServer || !DevMode.IsDevMode) {
  49. DataLevel dataLevel = isServer ? DataLevel.Global : DataLevel.Profile;
  50. if (_dicById.TryGetValue(message.Input.GetId(), out KernelOutputKeywordData exist)) {
  51. exist.Update(message.Input);
  52. exist.SetDataLevel(dataLevel);
  53. using (LiteDatabase db = new LiteDatabase(_connectionString)) {
  54. var col = db.GetCollection<KernelOutputKeywordData>();
  55. col.Update(exist);
  56. }
  57. if (!isServer) {
  58. VirtualRoot.RaiseEvent(new UserKernelOutputKeywordUpdatedEvent(exist));
  59. }
  60. }
  61. else {
  62. KernelOutputKeywordData entity = new KernelOutputKeywordData().Update(message.Input);
  63. entity.SetDataLevel(dataLevel);
  64. _dicById.Add(entity.Id, entity);
  65. using (LiteDatabase db = new LiteDatabase(_connectionString)) {
  66. var col = db.GetCollection<KernelOutputKeywordData>();
  67. col.Insert(entity);
  68. }
  69. if (!isServer) {
  70. VirtualRoot.RaiseEvent(new UserKernelOutputKeywordAddedEvent(exist));
  71. }
  72. }
  73. }
  74. else if (DevMode.IsDevMode) {
  75. OfficialServer.KernelOutputKeywordService.AddOrUpdateKernelOutputKeywordAsync(KernelOutputKeywordData.Create(message.Input), (response, e) => {
  76. if (response.IsSuccess()) {
  77. VirtualRoot.Execute(new LoadKernelOutputKeywordCommand());
  78. }
  79. });
  80. }
  81. });
  82. VirtualRoot.BuildCmdPath<RemoveKernelOutputKeywordCommand>(action: (message) => {
  83. InitOnece();
  84. if (isServer || !DevMode.IsDevMode) {
  85. if (message == null || message.EntityId == Guid.Empty) {
  86. return;
  87. }
  88. if (!_dicById.ContainsKey(message.EntityId)) {
  89. return;
  90. }
  91. KernelOutputKeywordData entity = _dicById[message.EntityId];
  92. _dicById.Remove(entity.GetId());
  93. using (LiteDatabase db = new LiteDatabase(_connectionString)) {
  94. var col = db.GetCollection<KernelOutputKeywordData>();
  95. col.Delete(message.EntityId);
  96. }
  97. if (!isServer) {
  98. VirtualRoot.RaiseEvent(new UserKernelOutputKeywordRemovedEvent(entity));
  99. }
  100. }
  101. else if (DevMode.IsDevMode) {
  102. OfficialServer.KernelOutputKeywordService.RemoveKernelOutputKeyword(message.EntityId, (response, e) => {
  103. if (response.IsSuccess()) {
  104. VirtualRoot.Execute(new LoadKernelOutputKeywordCommand());
  105. }
  106. });
  107. }
  108. });
  109. }
  110. private const string fileName = "ServerKernelOutputKeywords.json";
  111. private void CacheServerKernelOutputKeywords(List<KernelOutputKeywordData> data) {
  112. string json = VirtualRoot.JsonSerializer.Serialize(data);
  113. string fileId = $"$/cache/{fileName}";
  114. using (MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(json))) {
  115. using (LiteDatabase db = new LiteDatabase(_connectionString)) {
  116. db.FileStorage.Upload(fileId, fileName, ms);
  117. }
  118. }
  119. }
  120. private List<KernelOutputKeywordData> GetServerKernelOutputKeywordsFromCache() {
  121. try {
  122. using (LiteDatabase db = new LiteDatabase(_connectionString))
  123. using (MemoryStream ms = new MemoryStream()) {
  124. string fileId = $"$/cache/{fileName}";
  125. db.FileStorage.Download(fileId, ms);
  126. var json = Encoding.UTF8.GetString(ms.ToArray());
  127. return VirtualRoot.JsonSerializer.Deserialize<List<KernelOutputKeywordData>>(json);
  128. }
  129. }
  130. catch (Exception e) {
  131. Logger.ErrorDebugLine(e);
  132. return new List<KernelOutputKeywordData>();
  133. }
  134. }
  135. private bool _isInited = false;
  136. private readonly object _locker = new object();
  137. private void InitOnece() {
  138. if (_isInited) {
  139. return;
  140. }
  141. Init();
  142. }
  143. private void Init() {
  144. lock (_locker) {
  145. if (!_isInited) {
  146. foreach (var item in GetServerKernelOutputKeywordsFromCache()) {
  147. if (!_dicById.ContainsKey(item.GetId())) {
  148. item.SetDataLevel(DataLevel.Global);
  149. _dicById.Add(item.GetId(), item);
  150. }
  151. }
  152. using (LiteDatabase db = new LiteDatabase(_connectionString)) {
  153. var col = db.GetCollection<KernelOutputKeywordData>();
  154. foreach (var item in col.FindAll()) {
  155. if (!_dicById.ContainsKey(item.GetId())) {
  156. item.SetDataLevel(DataLevel.Profile);
  157. _dicById.Add(item.GetId(), item);
  158. }
  159. }
  160. }
  161. _isInited = true;
  162. }
  163. }
  164. }
  165. public IEnumerable<IKernelOutputKeyword> GetKeywords(Guid kernelOutputId) {
  166. InitOnece();
  167. return _dicById.Values.Where(a => a.KernelOutputId == kernelOutputId);
  168. }
  169. public bool Contains(Guid kernelOutputId, string keyword) {
  170. InitOnece();
  171. return _dicById.Values.Any(a => a.KernelOutputId == kernelOutputId && a.Keyword == keyword);
  172. }
  173. public bool TryGetKernelOutputKeyword(Guid id, out IKernelOutputKeyword keyword) {
  174. InitOnece();
  175. var result = _dicById.TryGetValue(id, out KernelOutputKeywordData data);
  176. keyword = data;
  177. return result;
  178. }
  179. public IEnumerator<IKernelOutputKeyword> GetEnumerator() {
  180. InitOnece();
  181. return _dicById.Values.GetEnumerator();
  182. }
  183. IEnumerator IEnumerable.GetEnumerator() {
  184. InitOnece();
  185. return _dicById.Values.GetEnumerator();
  186. }
  187. }
  188. }