|
- #include "project_service.h"
-
- #include <algorithm>
- #include <chrono>
- #include <cctype>
- #include <random>
- #include <sstream>
- #include <utility>
-
- namespace {
-
- // 生成唯一工程 ID:project-时间戳-随机数
- std::string generateProjectId()
- {
- const auto timestamp = static_cast<unsigned long long>(
- std::chrono::high_resolution_clock::now().time_since_epoch().count());
- std::random_device random_device;
- const auto random_value = static_cast<unsigned long long>(random_device());
-
- std::ostringstream stream;
- stream << "project-" << std::hex << timestamp << '-' << random_value;
- return stream.str();
- }
-
- } // namespace
-
- ProjectService::ProjectService(ProjectStorage &storage)
- : ProjectService(storage, defaultProjectLimitSettings())
- {
- }
-
- ProjectService::ProjectService(
- ProjectStorage &storage,
- const ProjectLimitSettings &project_limits)
- : storage_(storage),
- project_limits_(project_limits),
- project_(makeNewProject("未命名工程"))
- {
- }
-
- const Project &ProjectService::project() const
- {
- return project_;
- }
-
- Project &ProjectService::editProject()
- {
- modified_ = true;
- return project_;
- }
-
- const std::string &ProjectService::currentFilePath() const
- {
- return current_file_path_;
- }
-
- bool ProjectService::hasCurrentFile() const
- {
- return !current_file_path_.empty();
- }
-
- // 查询是否存在未保存修改
- bool ProjectService::isModified() const
- {
- return modified_;
- }
-
- const ProjectLimitSettings &ProjectService::projectLimits() const
- {
- return project_limits_;
- }
-
- void ProjectService::restoreModifiedState(bool modified)
- {
- modified_ = modified;
- }
-
- ProjectOperationResult ProjectService::createNewProject(const std::string &name)
- {
- if (isBlank(name))
- {
- return {false,
- ProjectServiceError::InvalidProjectName,
- ProjectStorageError::None,
- "工程名称不能为空"};
- }
-
- // 新工程创建成功后清除原文件关联,并标记为待保存
- project_ = makeNewProject(name);
- current_file_path_.clear();
- modified_ = true;
- return {true, ProjectServiceError::None, ProjectStorageError::None, {}};
- }
-
- ProjectOperationResult ProjectService::save()
- {
- if (!hasCurrentFile())
- {
- return {false,
- ProjectServiceError::FilePathRequired,
- ProjectStorageError::None,
- "必须指定工程文件路径"};
- }
- // 复用另存为流程,确保两种保存方式拥有相同的校验和错误处理
- return saveAs(current_file_path_);
- }
-
- ProjectOperationResult ProjectService::saveAs(const std::string &file_path)
- {
- if (isBlank(file_path))
- {
- return {false,
- ProjectServiceError::FilePathRequired,
- ProjectStorageError::None,
- "必须指定工程文件路径"};
- }
-
- std::string validation_error;
- if (!project_.validate(project_limits_, &validation_error))
- {
- return {false,
- ProjectServiceError::InvalidProject,
- ProjectStorageError::InvalidProject,
- validation_error};
- }
-
- // 先完成领域校验,避免将非法工程交给存储层
- const ProjectSaveResult result = storage_.save(project_, file_path);
- if (!result.succeeded)
- {
- return storageFailure(result.error, result.message);
- }
-
- // 只有存储成功后才更新文件关联和未保存状态
- current_file_path_ = file_path;
- modified_ = false;
- return {true, ProjectServiceError::None, ProjectStorageError::None, {}};
- }
-
- ProjectOperationResult ProjectService::load(const std::string &file_path)
- {
- if (isBlank(file_path))
- {
- return {false,
- ProjectServiceError::FilePathRequired,
- ProjectStorageError::None,
- "必须指定工程文件路径"};
- }
-
- // 存储层先在临时结果中解析,避免半个工程替换当前工程
- ProjectLoadResult result = storage_.load(file_path);
- if (!result.succeeded)
- {
- return storageFailure(result.error, result.message);
- }
-
- std::string validation_error;
- if (!result.project.validate(project_limits_, &validation_error))
- {
- return {false,
- ProjectServiceError::InvalidProject,
- ProjectStorageError::InvalidProject,
- validation_error};
- }
-
- // 文件读取和领域校验均成功后,才替换当前工程状态
- project_ = std::move(result.project);
- current_file_path_ = file_path;
- modified_ = false;
- return {true, ProjectServiceError::None, ProjectStorageError::None, {}};
- }
-
- // 创建一个全新空白工程实例
- Project ProjectService::makeNewProject(const std::string &name)
- {
- Project project;
- project.metadata.id = generateProjectId();
- project.metadata.name = name;
- // 新工程固定使用当前存储格式版本
- project.metadata.formatVersion = "1.0";
- return project;
- }
-
- // 判断字符串是不是空白:空字符串 / 全是空格、制表符都算空白
- bool ProjectService::isBlank(const std::string &value)
- {
- return value.empty()
- || std::all_of(
- value.cbegin(),
- value.cend(),
- [](unsigned char character)
- {
- return std::isspace(character) != 0;
- });
- }
-
- // 包装存储层失败结果
- ProjectOperationResult ProjectService::storageFailure(
- ProjectStorageError error, const std::string &message)
- {
- return {false, ProjectServiceError::StorageFailure, error, message};
- }
|