StoreServiceProvider.java 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  1. package org.ssssssss.magicapi.provider;
  2. import org.slf4j.Logger;
  3. import org.slf4j.LoggerFactory;
  4. import org.ssssssss.magicapi.adapter.Resource;
  5. import org.ssssssss.magicapi.model.Constants;
  6. import org.ssssssss.magicapi.model.MagicEntity;
  7. import org.ssssssss.magicapi.utils.JsonUtils;
  8. import java.nio.charset.StandardCharsets;
  9. import java.util.*;
  10. import java.util.stream.Collectors;
  11. public abstract class StoreServiceProvider<T extends MagicEntity> {
  12. private static Logger logger = LoggerFactory.getLogger(StoreServiceProvider.class);
  13. protected Resource workspace;
  14. protected Resource backupResource;
  15. protected Map<String, Resource> mappings = new HashMap<>();
  16. protected Map<String, T> infos = new HashMap<>();
  17. protected GroupServiceProvider groupServiceProvider;
  18. protected Class<T> clazz;
  19. String separatorWithCRLF = "\r\n================================\r\n";
  20. String separatorWithLF = "\n================================\n";
  21. public StoreServiceProvider(Class<T> clazz, Resource workspace, GroupServiceProvider groupServiceProvider) {
  22. this.clazz = clazz;
  23. this.workspace = workspace;
  24. this.groupServiceProvider = groupServiceProvider;
  25. if (!this.workspace.exists()) {
  26. this.workspace.mkdir();
  27. }
  28. this.backupResource = this.workspace.parent().getDirectory(Constants.PATH_BACKUPS);
  29. if (!this.backupResource.exists()) {
  30. this.backupResource.mkdir();
  31. }
  32. }
  33. /**
  34. * 添加
  35. */
  36. public boolean insert(T info) {
  37. info.setId(UUID.randomUUID().toString().replace("-", ""));
  38. info.setUpdateTime(System.currentTimeMillis());
  39. info.setCreateTime(info.getUpdateTime());
  40. Resource dest = groupServiceProvider.getGroupResource(info.getGroupId()).getResource(info.getName() + ".ms");
  41. if (!dest.exists() && dest.write(serialize(info))) {
  42. mappings.put(info.getId(), dest);
  43. infos.put(info.getId(), info);
  44. return true;
  45. }
  46. return false;
  47. }
  48. /**
  49. * 备份历史记录
  50. */
  51. public boolean backup(T info) {
  52. Resource directory = this.backupResource.getDirectory(info.getId());
  53. if (!directory.readonly() && (directory.exists() || directory.mkdir())) {
  54. Resource resource = directory.getResource(String.format("%s.ms", System.currentTimeMillis()));
  55. try {
  56. return resource.write(serialize(info));
  57. } catch (Exception e) {
  58. logger.warn("保存历史记录失败,{}", e.getMessage());
  59. }
  60. }
  61. return false;
  62. }
  63. /**
  64. * 查询历史记录
  65. *
  66. * @return 时间戳列表
  67. */
  68. public List<Long> backupList(String id) {
  69. Resource directory = this.backupResource.getDirectory(id);
  70. List<Resource> resources = directory.files(".ms");
  71. return resources.stream()
  72. .map(it -> Long.valueOf(it.name().replace(".ms", "")))
  73. .sorted(Comparator.reverseOrder())
  74. .collect(Collectors.toList());
  75. }
  76. /**
  77. * 查询历史记录详情
  78. *
  79. * @param id ID
  80. * @param timestamp 时间戳
  81. */
  82. public T backupInfo(String id, Long timestamp) {
  83. Resource directory = this.backupResource.getDirectory(id);
  84. if (directory.exists()) {
  85. Resource resource = directory.getResource(String.format("%s.ms", timestamp));
  86. if (resource.exists()) {
  87. return deserialize(resource.read());
  88. }
  89. }
  90. return null;
  91. }
  92. /**
  93. * 修改
  94. */
  95. public boolean update(T info) {
  96. Resource dest = groupServiceProvider.getGroupResource(info.getGroupId()).getResource(info.getName() + ".ms");
  97. Resource src = mappings.get(info.getId());
  98. if (!src.name().equals(dest.name())) {
  99. if (dest.exists()) {
  100. return false;
  101. }
  102. src.renameTo(dest);
  103. }
  104. if (dest.write(serialize(info))) {
  105. mappings.put(info.getId(), dest);
  106. infos.put(info.getId(), info);
  107. return true;
  108. }
  109. return false;
  110. }
  111. /**
  112. * 删除
  113. */
  114. public boolean delete(String id) {
  115. Resource resource = mappings.get(id);
  116. if (resource != null && resource.delete()) {
  117. mappings.remove(id);
  118. infos.remove(id);
  119. return true;
  120. }
  121. return false;
  122. }
  123. /**
  124. * 查询所有(提供给页面,无需带script)
  125. */
  126. public List<T> list() {
  127. List<T> infos = listWithScript();
  128. infos.forEach(info -> info.setScript(null));
  129. return infos;
  130. }
  131. /**
  132. * 重新加载分组
  133. */
  134. public void reload(String groupId) {
  135. Resource dest = groupServiceProvider.getGroupResource(groupId);
  136. dest.files(".ms").forEach(r -> {
  137. T info = deserialize(r.read());
  138. infos.put(info.getId(), info);
  139. mappings.put(info.getId(), r);
  140. });
  141. }
  142. /**
  143. * 查询所有(内部使用,需要带Script)
  144. */
  145. public List<T> listWithScript() {
  146. workspace.readAll();
  147. List<Resource> resources = workspace.files(".ms");
  148. Map<String, Resource> mappings = new HashMap<>();
  149. Map<String, T> infos = new HashMap<>();
  150. List<T> result = resources.stream().map(r -> {
  151. T info = deserialize(r.read());
  152. infos.put(info.getId(), info);
  153. mappings.put(info.getId(), r);
  154. return (T) info.clone();
  155. }).collect(Collectors.toList());
  156. this.mappings = mappings;
  157. this.infos = infos;
  158. return result;
  159. }
  160. /**
  161. * 查询详情(主要给页面使用)
  162. *
  163. * @param id ID
  164. */
  165. public T get(String id) {
  166. return infos.get(id);
  167. }
  168. /**
  169. * 判断是否允许移动
  170. */
  171. public boolean allowMove(String id, String groupId) {
  172. Resource resource = mappings.get(id);
  173. if (resource == null) {
  174. return false;
  175. }
  176. return !resource.readonly() && !groupServiceProvider.getGroupResource(groupId).getResource(resource.name()).exists();
  177. }
  178. /**
  179. * 移动
  180. *
  181. * @param id 接口ID
  182. * @param groupId 分组ID
  183. */
  184. public boolean move(String id, String groupId) {
  185. Resource dest = groupServiceProvider.getGroupResource(groupId);
  186. Resource src = mappings.get(id);
  187. dest = dest.getResource(src.name());
  188. if (dest.exists()) {
  189. return false;
  190. }
  191. T info = infos.get(id);
  192. src.renameTo(dest);
  193. info.setGroupId(groupId);
  194. mappings.put(id, dest);
  195. return dest.write(serialize(info));
  196. }
  197. /**
  198. * 根据组ID删除
  199. */
  200. public boolean deleteGroup(String rootId, List<String> groupIds) {
  201. if (!groupServiceProvider.getGroupResource(rootId).delete()) {
  202. return false;
  203. }
  204. for (String groupId : groupIds) {
  205. List<String> infoIds = infos.values().stream().filter(info -> groupId.equals(info.getGroupId()))
  206. .map(T::getId)
  207. .collect(Collectors.toList());
  208. infoIds.forEach(infos::remove);
  209. infoIds.forEach(mappings::remove);
  210. }
  211. return true;
  212. }
  213. /**
  214. * 包装信息(可用于加密)
  215. */
  216. public void wrap(T info) {
  217. }
  218. /**
  219. * 解除包装信息(可用于解密)
  220. */
  221. public void unwrap(T info) {
  222. }
  223. public byte[] serialize(T info) {
  224. wrap(info);
  225. String script = info.getScript();
  226. info.setScript(null);
  227. String content = JsonUtils.toJsonString(info) + separatorWithCRLF + script;
  228. info.setScript(script);
  229. unwrap(info);
  230. return content.getBytes(StandardCharsets.UTF_8);
  231. }
  232. public T deserialize(byte[] data) {
  233. String content = new String(data, StandardCharsets.UTF_8);
  234. String separator = separatorWithCRLF;
  235. int index = content.indexOf(separator);
  236. if (index == -1) {
  237. separator = separatorWithLF;
  238. index = content.indexOf(separatorWithLF);
  239. }
  240. if (index > -1) {
  241. T info = JsonUtils.readValue(content.substring(0, index), clazz);
  242. info.setScript(content.substring(index + separator.length()));
  243. unwrap(info);
  244. return info;
  245. }
  246. logger.warn("文件内容格式错误,请检查。");
  247. return null;
  248. }
  249. }