综合平台编程器项目的远程存储
Non puoi selezionare più di 25 argomenti Gli argomenti devono iniziare con una lettera o un numero, possono includere trattini ('-') e possono essere lunghi fino a 35 caratteri.
 
 
 
 

203 righe
5.4 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::load(const std::string &file_path)
  119. {
  120. if (isBlank(file_path))
  121. {
  122. return {false,
  123. ProjectServiceError::FilePathRequired,
  124. ProjectStorageError::None,
  125. "必须指定工程文件路径"};
  126. }
  127. // 存储层先在临时结果中解析,避免半个工程替换当前工程
  128. ProjectLoadResult result = storage_.load(file_path);
  129. if (!result.succeeded)
  130. {
  131. return storageFailure(result.error, result.message);
  132. }
  133. std::string validation_error;
  134. if (!result.project.validate(project_limits_, &validation_error))
  135. {
  136. return {false,
  137. ProjectServiceError::InvalidProject,
  138. ProjectStorageError::InvalidProject,
  139. validation_error};
  140. }
  141. // 文件读取和领域校验均成功后,才替换当前工程状态
  142. project_ = std::move(result.project);
  143. current_file_path_ = file_path;
  144. modified_ = false;
  145. return {true, ProjectServiceError::None, ProjectStorageError::None, {}};
  146. }
  147. // 创建一个全新空白工程实例
  148. Project ProjectService::makeNewProject(const std::string &name)
  149. {
  150. Project project;
  151. project.metadata.id = generateProjectId();
  152. project.metadata.name = name;
  153. // 新工程固定使用当前存储格式版本
  154. project.metadata.formatVersion = "1.0";
  155. return project;
  156. }
  157. // 判断字符串是不是空白:空字符串 / 全是空格、制表符都算空白
  158. bool ProjectService::isBlank(const std::string &value)
  159. {
  160. return value.empty()
  161. || std::all_of(
  162. value.cbegin(),
  163. value.cend(),
  164. [](unsigned char character)
  165. {
  166. return std::isspace(character) != 0;
  167. });
  168. }
  169. // 包装存储层失败结果
  170. ProjectOperationResult ProjectService::storageFailure(
  171. ProjectStorageError error, const std::string &message)
  172. {
  173. return {false, ProjectServiceError::StorageFailure, error, message};
  174. }