综合平台编程器项目的远程存储
Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.
 
 
 
 

228 строки
6.2 KiB

  1. #include "project_service.h"
  2. #include <algorithm>
  3. #include <chrono>
  4. #include <cctype>
  5. #include <random>
  6. #include <sstream>
  7. #include <utility>
  8. namespace {
  9. // 生成唯一工程 ID:project-时间戳-随机数
  10. std::string generateProjectId()
  11. {
  12. const auto timestamp = static_cast<unsigned long long>(
  13. std::chrono::high_resolution_clock::now().time_since_epoch().count());
  14. std::random_device random_device;
  15. const auto random_value = static_cast<unsigned long long>(random_device());
  16. std::ostringstream stream;
  17. stream << "project-" << std::hex << timestamp << '-' << random_value;
  18. return stream.str();
  19. }
  20. } // namespace
  21. ProjectService::ProjectService(ProjectStorage &storage)
  22. : ProjectService(storage, defaultProjectLimitSettings())
  23. {
  24. }
  25. ProjectService::ProjectService(
  26. ProjectStorage &storage,
  27. const ProjectLimitSettings &project_limits)
  28. : storage_(storage),
  29. project_limits_(project_limits),
  30. project_(makeNewProject("未命名工程"))
  31. {
  32. }
  33. const Project &ProjectService::project() const
  34. {
  35. return project_;
  36. }
  37. Project &ProjectService::editProject()
  38. {
  39. modified_ = true;
  40. return project_;
  41. }
  42. const std::string &ProjectService::currentFilePath() const
  43. {
  44. return current_file_path_;
  45. }
  46. bool ProjectService::hasCurrentFile() const
  47. {
  48. return !current_file_path_.empty();
  49. }
  50. // 查询是否存在未保存修改
  51. bool ProjectService::isModified() const
  52. {
  53. return modified_;
  54. }
  55. const ProjectLimitSettings &ProjectService::projectLimits() const
  56. {
  57. return project_limits_;
  58. }
  59. void ProjectService::restoreModifiedState(bool modified)
  60. {
  61. modified_ = modified;
  62. }
  63. ProjectOperationResult ProjectService::createNewProject(const std::string &name)
  64. {
  65. if (isBlank(name))
  66. {
  67. return {false,
  68. ProjectServiceError::InvalidProjectName,
  69. ProjectStorageError::None,
  70. "工程名称不能为空"};
  71. }
  72. // 新工程创建成功后清除原文件关联,并标记为待保存
  73. project_ = makeNewProject(name);
  74. current_file_path_.clear();
  75. modified_ = true;
  76. return {true, ProjectServiceError::None, ProjectStorageError::None, {}};
  77. }
  78. ProjectOperationResult ProjectService::save()
  79. {
  80. if (!hasCurrentFile())
  81. {
  82. return {false,
  83. ProjectServiceError::FilePathRequired,
  84. ProjectStorageError::None,
  85. "必须指定工程文件路径"};
  86. }
  87. // 复用另存为流程,确保两种保存方式拥有相同的校验和错误处理
  88. return saveAs(current_file_path_);
  89. }
  90. ProjectOperationResult ProjectService::saveAs(const std::string &file_path)
  91. {
  92. if (isBlank(file_path))
  93. {
  94. return {false,
  95. ProjectServiceError::FilePathRequired,
  96. ProjectStorageError::None,
  97. "必须指定工程文件路径"};
  98. }
  99. std::string validation_error;
  100. if (!project_.validate(project_limits_, &validation_error))
  101. {
  102. return {false,
  103. ProjectServiceError::InvalidProject,
  104. ProjectStorageError::InvalidProject,
  105. validation_error};
  106. }
  107. // 先完成领域校验,避免将非法工程交给存储层
  108. const ProjectSaveResult result = storage_.save(project_, file_path);
  109. if (!result.succeeded)
  110. {
  111. return storageFailure(result.error, result.message);
  112. }
  113. // 只有存储成功后才更新文件关联和未保存状态
  114. current_file_path_ = file_path;
  115. modified_ = false;
  116. return {true, ProjectServiceError::None, ProjectStorageError::None, {}};
  117. }
  118. ProjectOperationResult ProjectService::exportAs(const std::string &file_path) const
  119. {
  120. if (isBlank(file_path))
  121. {
  122. return {false,
  123. ProjectServiceError::FilePathRequired,
  124. ProjectStorageError::None,
  125. "必须指定导出文件路径"};
  126. }
  127. std::string validation_error;
  128. if (!project_.validate(project_limits_, &validation_error))
  129. {
  130. return {false,
  131. ProjectServiceError::InvalidProject,
  132. ProjectStorageError::InvalidProject,
  133. validation_error};
  134. }
  135. const ProjectSaveResult result = storage_.save(project_, file_path);
  136. if (!result.succeeded)
  137. {
  138. return storageFailure(result.error, result.message);
  139. }
  140. return {true, ProjectServiceError::None, ProjectStorageError::None, {}};
  141. }
  142. ProjectOperationResult ProjectService::load(const std::string &file_path)
  143. {
  144. if (isBlank(file_path))
  145. {
  146. return {false,
  147. ProjectServiceError::FilePathRequired,
  148. ProjectStorageError::None,
  149. "必须指定工程文件路径"};
  150. }
  151. // 存储层先在临时结果中解析,避免半个工程替换当前工程
  152. ProjectLoadResult result = storage_.load(file_path);
  153. if (!result.succeeded)
  154. {
  155. return storageFailure(result.error, result.message);
  156. }
  157. std::string validation_error;
  158. if (!result.project.validate(project_limits_, &validation_error))
  159. {
  160. return {false,
  161. ProjectServiceError::InvalidProject,
  162. ProjectStorageError::InvalidProject,
  163. validation_error};
  164. }
  165. // 文件读取和领域校验均成功后,才替换当前工程状态
  166. project_ = std::move(result.project);
  167. current_file_path_ = file_path;
  168. modified_ = false;
  169. return {true, ProjectServiceError::None, ProjectStorageError::None, {}};
  170. }
  171. // 创建一个全新空白工程实例
  172. Project ProjectService::makeNewProject(const std::string &name)
  173. {
  174. Project project;
  175. project.metadata.id = generateProjectId();
  176. project.metadata.name = name;
  177. // 新工程固定使用当前存储格式版本
  178. project.metadata.formatVersion = "2.0";
  179. return project;
  180. }
  181. // 判断字符串是不是空白:空字符串 / 全是空格、制表符都算空白
  182. bool ProjectService::isBlank(const std::string &value)
  183. {
  184. return value.empty()
  185. || std::all_of(
  186. value.cbegin(),
  187. value.cend(),
  188. [](unsigned char character)
  189. {
  190. return std::isspace(character) != 0;
  191. });
  192. }
  193. // 包装存储层失败结果
  194. ProjectOperationResult ProjectService::storageFailure(
  195. ProjectStorageError error, const std::string &message)
  196. {
  197. return {false, ProjectServiceError::StorageFailure, error, message};
  198. }