package com.qingjian.module.plat.service; import cn.hutool.core.io.FileUtil; import cn.hutool.core.lang.Assert; import cn.hutool.core.util.RandomUtil; import cn.hutool.core.util.StrUtil; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.qingjian.common.cache.CaseDataCache; import com.qingjian.common.constants.PathConst; import com.qingjian.common.constants.StrConsts; import com.qingjian.common.exception.ServerException; import com.qingjian.common.model.plat.dto.UpdateCasePwdDTO; import com.qingjian.common.model.plat.entity.CaseInfo; import com.qingjian.common.utils.LuceneManager; import com.qingjian.common.utils.StateManager; import com.qingjian.module.plat.mapper.CaseInfoMapper; import lombok.extern.slf4j.Slf4j; import org.noear.solon.Solon; import org.noear.solon.annotation.Inject; import org.noear.solon.annotation.Managed; import org.noear.solon.core.Props; import org.noear.solon.data.datasource.DsUtils; import org.noear.solon.data.dynamicds.DynamicDataSource; import org.noear.solon.data.dynamicds.DynamicDs; import javax.sql.DataSource; import java.nio.file.Files; import java.nio.file.Path; import java.time.LocalDateTime; /** * 案件服务 */ @Slf4j @Managed @DynamicDs(StrConsts.DS_KEY_PLAT) public class CaseInfoService extends ServiceImpl { @Inject("db1") private DynamicDataSource dynamicDataSource; @Inject private SseService sseService; /** * 创建案件 * * @param caseInfo 案件信息 */ public void create(CaseInfo caseInfo) { String caseName = StrUtil.trim(caseInfo.getName()); if (caseInfo.getId() != null) { CaseInfo dbCaseInfo = getById(caseInfo.getId()); if (dbCaseInfo == null) { throw ServerException.spe("案件不存在!"); } if (!StrUtil.equals(dbCaseInfo.getPwd(), caseInfo.getPwd())) { throw ServerException.spe("案件密码错误!"); } long duplicateCount = lambdaQuery() .eq(CaseInfo::getName, caseName) .ne(CaseInfo::getId, caseInfo.getId()) .count(); if (duplicateCount > 0) { throw ServerException.spe("案件名称已存在!"); } caseInfo.setPwd(null); caseInfo.setName(caseName); updateById(caseInfo); return; } long duplicateCount = lambdaQuery() .eq(CaseInfo::getName, caseName) .count(); if (duplicateCount > 0) { throw ServerException.spe("案件名称已存在!"); } caseInfo.setName(caseName); caseInfo.setCreateTime(LocalDateTime.now()); save(caseInfo); String caseDb = RandomUtil.randomString(8) + caseInfo.getId(); Path casePath = PathConst.WORKSPACE.resolve(caseInfo.getId().toString()); FileUtil.mkdir(casePath); Path caseSession = PathConst.AGENT_PATH.resolve("sessions").resolve(caseInfo.getId().toString()); FileUtil.mkdir(caseSession); Path caseDbPath = casePath.resolve(caseDb); if (Files.notExists(caseDbPath)) { if (Files.notExists(PathConst.BASE_CASE_DB_PATH)) { log.error("基础数据库不存在!"); return; } FileUtil.copy(PathConst.BASE_CASE_DB_PATH, caseDbPath); } caseInfo.setDbPath(caseDbPath.toString()); caseInfo.setDb(caseDb); updateById(caseInfo); } /** * 删除案件 * * @param id 案件 ID * @param pwd 案件密码 */ public void delete(Integer id, String pwd) { CaseInfo caseInfo = getById(id); if (caseInfo == null) { throw new ServerException("案件不存在!"); } if (!caseInfo.getPwd().equals(pwd)) { throw new ServerException("案件密码错误!"); } removeById(id); Path casePath = PathConst.WORKSPACE.resolve(caseInfo.getId().toString()); FileUtil.del(casePath); } /** * 更新密码 * * @param updateCasePwdDTO 更新用密码 */ public void updatePwd(UpdateCasePwdDTO updateCasePwdDTO) { CaseInfo caseInfo = getById(updateCasePwdDTO.getId()); if (caseInfo == null) { throw new ServerException("案件不存在!"); } caseInfo.setPwd(updateCasePwdDTO.getNewPwd()); updateById(caseInfo); } /** * 开启案件 * * @param id 案件 ID * @param pwd 案件密码 */ public void open(Integer id, String pwd) { // 根据id和密码查询 sql 语句 CaseInfo ci = getById(id); Assert.notNull(ci, () -> ServerException.spe("案件不存在!")); Assert.isTrue(ci.getPwd().equals(pwd), () -> ServerException.spe("案件密码错误!")); Path caseDbPath = Path.of(ci.getDbPath()); closeOldDb(); openNewDb(caseDbPath.toString()); LuceneManager.createWriter(PathConst.WORKSPACE.resolve(ci.getId().toString()).resolve("lucene")); StateManager.instance().setCaseInfo(ci); CaseDataCache.initCache(); } private void closeOldDb() { try { LuceneManager.close(); dynamicDataSource.removeTargetDataSource(StrConsts.DS_KEY_CASE); CaseDataCache.cleanCache(); sseService.closeSee(); } catch (Exception e) { log.error("关闭数据库连接失败", e); throw ServerException.spe("关闭资源失败!"); } } private void openNewDb(String dbPath) { Props props = Solon.cfg().getProp("qingjian.db1.case"); props.setProperty("url", "jdbc:duckdb:" + dbPath); DataSource dataSource = DsUtils.buildDs(props); dynamicDataSource.setDefaultTargetDataSource(dataSource); dynamicDataSource.addTargetDataSource(StrConsts.DS_KEY_CASE, dataSource); } public void exit() { closeOldDb(); openNewDb(PathConst.TEMP_DB_PATH.toString()); StateManager.instance().cleanCase(); } }