package com.ruoyi.cc.controller; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import com.ruoyi.aicall.domain.CcCallPhone; import com.ruoyi.aicall.service.ICcCallPhoneService; import com.ruoyi.aicall.service.ICcInboundLlmAccountService; import com.ruoyi.cc.domain.CcInboundCdr; import com.ruoyi.cc.domain.CcOutboundCdr; import com.ruoyi.cc.domain.CcParams; import com.ruoyi.cc.model.FsConfProfile; import com.ruoyi.cc.model.FsMod; import com.ruoyi.cc.model.ProfileRegExtnumModel; import com.ruoyi.cc.model.ProfileStatusModel; import com.ruoyi.cc.service.*; import com.ruoyi.common.core.controller.BaseController; import com.ruoyi.common.core.domain.AjaxResult; import com.ruoyi.common.core.page.TableDataInfo; import com.ruoyi.common.utils.CommonUtils; import com.ruoyi.common.utils.DateUtils; import com.ruoyi.common.utils.StringUtils; import com.ruoyi.framework.web.domain.server.Sys; import link.thingscloud.freeswitch.esl.EslConnectionUtil; import link.thingscloud.freeswitch.esl.transport.message.EslMessage; import org.apache.shiro.authz.annotation.RequiresPermissions; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.ui.ModelMap; import org.springframework.util.CollectionUtils; import org.springframework.web.bind.annotation.*; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.InputSource; import javax.servlet.http.HttpServletResponse; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import java.io.IOException; import java.io.OutputStream; import java.io.StringReader; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.List; /** * freeswitch配置文件控制层 */ @Controller @RequestMapping("/cc/fsconf") public class FsConfController extends BaseController { @Autowired private IFsConfService fsConfService; @Autowired private IFsVariablesService fsVariablesService; @Autowired private ICcParamsService ccParamsService; @Autowired private ICcGatewaysService ccGatewaysService; @Autowired private ICcCallPhoneService callPhoneService; @Autowired private ICcInboundCdrService inboundCdrService; @Autowired private ICcOutboundCdrService outboundCdrService; /** * 系统全局配置 * @return */ @RequiresPermissions("cc:switchconf:view") @GetMapping(value = "/switchconf") public String switchConf() { return "cc/switchconf/switchconf"; } /** * 保存系统全局配置 * @param params * @return */ @PostMapping(value = "/setSwitchConf") @ResponseBody public AjaxResult setSwitchConf(@RequestBody JSONArray params) { fsConfService.setSwitchConf(params); return AjaxResult.success("设置成功!"); } /** * 重启fs服务 * @return */ @GetMapping(value = "/restartFs") @ResponseBody public AjaxResult restartFs() { fsConfService.restartFs(); return AjaxResult.success("重启成功!"); } /** * 获取系统全局配置 * @return */ @GetMapping(value = "/getSwitchConf") @ResponseBody public AjaxResult getSwitchConf() { // 配置文件所有配置 JSONObject confAllVars = fsConfService.getSwitchConf(); // 可配置的基本配置,其他的为隐藏的高级配置 JSONObject fsVars = fsVariablesService.getFsVariablesByCat(2); // key: 参数名, value:别名 JSONArray baseConfigs = new JSONArray(); JSONArray advancedConfigs = new JSONArray(); for (String name: confAllVars.keySet()) { JSONObject var = new JSONObject(); var.put("name", name); var.put("value", confAllVars.getString(name)); if (fsVars.keySet().contains(name)) { // 基本配置 var.put("aliasName", fsVars.getString(name)); // 别名 baseConfigs.add(var); } else { // 高级配置 var.put("aliasName", name); // 高级配置没有别名 advancedConfigs.add(var); } } JSONObject result = new JSONObject(); result.put("baseConfigs", baseConfigs); result.put("advancedConfigs", advancedConfigs); return AjaxResult.success("success", result); } /** * 全局编码配置 * @return */ @RequiresPermissions("cc:varsconf:view") @GetMapping(value = "/varsconf") public String varsConf() { return "cc/varsconf/varsconf"; } /** * 保存全局编码配置 * @param params * @return */ @PostMapping(value = "/setVarsConf") @ResponseBody public AjaxResult setVarsConf(@RequestBody JSONArray params) { fsConfService.setVarsConf(params); return AjaxResult.success("设置成功!"); } /** * 获取全局编码配置 * @return */ @GetMapping(value = "/getVarsConf") @ResponseBody public AjaxResult getVarsConf() { // 配置文件所有配置 JSONObject confAllVars = fsConfService.getVarsConf(); // 可配置的基本配置,其他的为隐藏的高级配置(1. vars.xml 2. switch.conf.xml 3. profile 4. xunfei_asr 5. aliyun asr) JSONObject fsVars = fsVariablesService.getFsVariablesByCat(1); // key: 参数名, value:别名 JSONArray baseConfigs = new JSONArray(); JSONArray advancedConfigs = new JSONArray(); for (String name: confAllVars.keySet()) { JSONObject var = new JSONObject(); var.put("name", name); var.put("value", confAllVars.getString(name)); if (fsVars.keySet().contains(name)) { // 基本配置 var.put("aliasName", fsVars.getString(name)); // 别名 baseConfigs.add(var); } else { // 高级配置 var.put("aliasName", name); // 高级配置没有别名 advancedConfigs.add(var); } } JSONObject result = new JSONObject(); result.put("baseConfigs", baseConfigs); result.put("advancedConfigs", advancedConfigs); return AjaxResult.success("success", result); } /** * ASR(讯飞)参数配置 * @return */ @RequiresPermissions("cc:xunfeiasrconf:view") @GetMapping(value = "/xunfeiasrconf") public String xunfeiAsrConf() { return "cc/xunfeiasrconf/xunfeiasrconf"; } /** * FunAsr参数配置 * @return */ @RequiresPermissions("cc:funasrconf:view") @GetMapping(value = "/funasrconf") public String funAsrConf() { return "cc/funasrconf/funasrconf"; } /** * TTS(阿里)参数配置 * @return */ @RequiresPermissions("cc:alittsconf:view") @GetMapping(value = "/alittsconf") public String aliTtsConf() { return "cc/alittsconf/alittsconf"; } /** * TTS(科大讯飞)参数配置 * @return */ @RequiresPermissions("cc:xfttsconf:view") @GetMapping(value = "/xfttsconf") public String xfTtsConf() { return "cc/xfttsconf/xfttsconf"; } /** * 获取阿里云tts配置 * @return */ @GetMapping(value = "/getAliTtsConf") @ResponseBody public AjaxResult getAliTtsConf() { String asrFileName = "/autoload_configs/aliyun_tts.conf.xml"; return getConfigFileJsonData(asrFileName, 5); } /** * 获取讯飞tts配置 * @return */ @GetMapping(value = "/getXfTtsConf") @ResponseBody public AjaxResult getXfTtsConf() { String asrFileName = "/autoload_configs/xf_tts.conf.xml"; return getConfigFileJsonData(asrFileName, 5); } /** * 豆包tts 参数配置 * @return */ @RequiresPermissions("cc:doubaottsconf:view") @GetMapping(value = "/doubaottsconf") public String doubaoTtsConf() { return "cc/doubaottsconf/doubaottsconf"; } /** * 获取豆包tts配置 * @return */ @GetMapping(value = "/getDoubaoTtsConf") @ResponseBody public AjaxResult getDoubaoTtsConf() { String fileName = "/autoload_configs/doubao_vcl_tts.conf.xml"; return getConfigFileJsonData(fileName, 5); } /** * 保存Doubao TTS配置 * @param params * @return */ @PostMapping(value = "/setDoubaoTtsConf") @ResponseBody public AjaxResult setDoubaoTtsConf(@RequestBody JSONArray params) { String asrFileName = "/autoload_configs/doubao_vcl_tts.conf.xml"; String moduleName = "mod_doubao_vcl_tts"; AjaxResult result = saveAndReloadTtsModule("doubao-tts-account-json", asrFileName, moduleName, params); return result; } /** * ASR(阿里)参数配置 * @return */ @RequiresPermissions("cc:aliasrconf:view") @GetMapping(value = "/aliasrconf") public String aliAsrConf() { return "cc/aliasrconf/aliasrconf"; } /** * ASR(阿里新模块)参数配置 * @return */ @RequiresPermissions("cc:aliasrbridgeconf:view") @GetMapping(value = "/aliasrbridgeconf") public String aliAsrBridgeConf() { return "cc/aliasrbridgeconf/aliasrbridgeconf"; } /** * ASR(腾讯新模块)参数配置 * @return */ @RequiresPermissions("cc:txasrbridgeconf:view") @GetMapping(value = "/txasrbridgeconf") public String txAsrBridgeConf() { return "cc/txasrbridgeconf/txasrbridgeconf"; } /** * ASR(腾讯MPS字幕模块)参数配置 * @return */ @RequiresPermissions("cc:txasr1bridgeconf:view") @GetMapping(value = "/txasr1bridgeconf") public String txAsr1BridgeConf() { return "cc/txasr1bridgeconf/txasr1bridgeconf"; } /** * 获取ASR配置 * @return */ @GetMapping(value = "/getAliAsrConf") @ResponseBody public AjaxResult getAliAsrConf() { String asrFileName = "/autoload_configs/aliyun_asr.conf.xml"; return getConfigFileJsonData(asrFileName, 5); } /** * 获取新 ASR 模块配置 * @return */ @GetMapping(value = "/getAliBridgeAsrConf") @ResponseBody public AjaxResult getAliBridgeAsrConf() { String asrFileName = "/autoload_configs/ali_asr.conf.xml"; return getConfigFileJsonData(asrFileName, 5); } /** * 获取腾讯 ASR 模块配置 * @return */ @GetMapping(value = "/getTxBridgeAsrConf") @ResponseBody public AjaxResult getTxBridgeAsrConf() { String asrFileName = "/autoload_configs/tx_asr.conf.xml"; return getConfigFileJsonData(asrFileName, 5); } /** * 获取腾讯 ASR1 模块配置 * @return */ @GetMapping(value = "/getTxBridgeAsr1Conf") @ResponseBody public AjaxResult getTxBridgeAsr1Conf() { String asrFileName = "/autoload_configs/tx_asr1.conf.xml"; return getConfigFileJsonData(asrFileName, 5); } /** * 获取FunASR配置 * @return */ @GetMapping(value = "/getFunAsrConf") @ResponseBody public AjaxResult getFunAsrConf() { return getConfigFileJsonData("/autoload_configs/funasr.conf.xml", 4); } @GetMapping(value = "/chinatelecomasrconf") public String chinatelecomAsrConf() { return "cc/chinatelecomasrconf/chinatelecomasrconf"; } @GetMapping(value = "/chinatelecomttsconf") public String chinatelecomTtsConf() { return "cc/chinatelecomttsconf/chinatelecomttsconf"; } @GetMapping(value = "/getChinatelecomAsrConf") @ResponseBody public AjaxResult getChinatelecomAsrConf() { String asrFileName = "/autoload_configs/chinatelecom_asr.conf.xml"; return getConfigFileJsonData(asrFileName, 5); } @GetMapping(value = "/getChinatelecomTtsConf") @ResponseBody public AjaxResult getChinatelecomTtsConf() { String fileName = "/autoload_configs/chinatelecom_tts.conf.xml"; return getConfigFileJsonData(fileName, 5); } /** * 获取ASR配置 * @return */ @GetMapping(value = "/getXunfeiAsrConf") @ResponseBody public AjaxResult getXunfeiAsrConf() { return getConfigFileJsonData("/autoload_configs/xunfei_asr.conf.xml", 4); } private AjaxResult getConfigFileJsonData(String configFile, int cat){ JSONObject confAllVars = fsConfService.getAsrConf(configFile); if(confAllVars.size() != 0) { JSONObject fsVars = fsVariablesService.getFsVariablesByCat(cat); // key: 参数名, value:别名 JSONArray baseConfigs = new JSONArray(); for (String name : confAllVars.keySet()) { JSONObject var = new JSONObject(); var.put("name", name); boolean hidden = fsConfService.checkNeedHidden(name); // server_url_webapi不需要加密 if ("server_url_webapi".equals(name)) { hidden = false; } if(hidden){ var.put("value", CommonUtils.maskStringUtil(confAllVars.getString(name))); }else { var.put("value", confAllVars.getString(name)); } if (fsVars.keySet().contains(name)) { // 基本配置 var.put("aliasName", fsVars.getString(name)); // 别名 baseConfigs.add(var); } else { // 高级配置 var.put("aliasName", name); // 高级配置没有别名 baseConfigs.add(var); } } return AjaxResult.success("success", baseConfigs); }else{ return AjaxResult.error(String.format("config file not found: %s", configFile)); } } private AjaxResult saveAndReloadAsrModule(String asrFileName, String moduleName, JSONArray params, String asrProvider){ String result = fsConfService.setAsrConf(params, asrFileName); if(StringUtils.isEmpty(result)) { // 更新cc_params参数表 ccParamsService.updateParamsValue("sys-asr-provider", asrProvider); String reloadRsp = ccParamsService.reloadParams(); if(!reloadRsp.equalsIgnoreCase("success")){ return error("参数修改成功, 但是刷新失败, 请手动重启 call-center!"); } // reload EslMessage resp = EslConnectionUtil.sendSyncApiCommand("reload", moduleName); String respText = CommonUtils.ListToString(resp.getBodyLines()); if(respText.contains("OK module loaded")) { return AjaxResult.success("配置写入成功!\n 模块已成功加载!"); }else{ return AjaxResult.error("配置写入成功!\n 但是模块加载失败! \n" + respText); } }else{ return AjaxResult.error("配置文件写入失败!\n " + result); } } private AjaxResult saveAndReloadTtsModule(String paramCode, String asrFileName, String moduleName, JSONArray params){ String result = fsConfService.setAsrConf(params, asrFileName); if(StringUtils.isEmpty(result)) { if (StringUtils.isNotEmpty(paramCode)) { String ttsAccountJson = ccParamsService.getParamValueByCode(paramCode, "{}"); logger.info("修改前的tts账号信息"); JSONObject paramValues = JSONObject.parseObject(ttsAccountJson); for (int j = 0; j < params.size(); j++) { JSONObject param = params.getJSONObject(j); String attrName = param.getString("name"); String attValue = param.getString("value"); // 包含星号的参数值不更新 if (!attValue.contains("****")) { paramValues.put(attrName, attValue); } } ccParamsService.updateParamsValue(paramCode, JSONObject.toJSONString(paramValues)); String reloadRsp = ccParamsService.reloadParams(); if(!reloadRsp.equalsIgnoreCase("success")){ return error("参数修改成功, 但是刷新失败, 请手动重启 call-center!"); } } EslMessage resp = EslConnectionUtil.sendSyncApiCommand("reload", moduleName); String respText = CommonUtils.ListToString(resp.getBodyLines()); if(respText.contains("OK module loaded")) { return AjaxResult.success("配置写入成功!\n 模块已成功加载!"); }else{ return AjaxResult.error("配置写入成功!\n 但是模块加载失败! \n" + respText); } }else{ return AjaxResult.error("配置文件写入失败!\n " + result); } } /** * 保存ASR配置 * @param params * @return */ @PostMapping(value = "/setAliAsrConf") @ResponseBody public AjaxResult setAliAsrConf(@RequestBody JSONArray params) { String asrFileName = "/autoload_configs/aliyun_asr.conf.xml"; String moduleName = "mod_aliyun_asr"; return saveAndReloadAsrModule(asrFileName, moduleName, params, "aliyun"); } /** * 保存新 ASR 模块配置 * @param params * @return */ @PostMapping(value = "/setAliBridgeAsrConf") @ResponseBody public AjaxResult setAliBridgeAsrConf(@RequestBody JSONArray params) { String asrFileName = "/autoload_configs/ali_asr.conf.xml"; String moduleName = "mod_ali_asr"; return saveAndReloadAsrModule(asrFileName, moduleName, params, "ali"); } /** * 保存腾讯 ASR 模块配置 * @param params * @return */ @PostMapping(value = "/setTxBridgeAsrConf") @ResponseBody public AjaxResult setTxBridgeAsrConf(@RequestBody JSONArray params) { String asrFileName = "/autoload_configs/tx_asr.conf.xml"; String moduleName = "mod_tx_asr"; return saveAndReloadAsrModule(asrFileName, moduleName, params, "tx"); } /** * 保存腾讯 ASR1 模块配置 * @param params * @return */ @PostMapping(value = "/setTxBridgeAsr1Conf") @ResponseBody public AjaxResult setTxBridgeAsr1Conf(@RequestBody JSONArray params) { String asrFileName = "/autoload_configs/tx_asr1.conf.xml"; String moduleName = "mod_tx_asr1"; return saveAndReloadAsrModule(asrFileName, moduleName, params, "tx1"); } /** * 保存ASR配置 * @param params * @return */ @PostMapping(value = "/setChinatelecomAsrConf") @ResponseBody public AjaxResult setChinatelecomAsrConf(@RequestBody JSONArray params) { String asrFileName = "/autoload_configs/chinatelecom_asr.conf.xml"; String moduleName = "mod_chinatelecom_asr"; return saveAndReloadAsrModule(asrFileName, moduleName, params, "chinatelecom"); } /** * 保存TTS配置 * @param params * @return */ @PostMapping(value = "/setAliTtsConf") @ResponseBody public AjaxResult setAliTtsConf(@RequestBody JSONArray params) { String asrFileName = "/autoload_configs/aliyun_tts.conf.xml"; String moduleName = "mod_aliyun_tts"; AjaxResult result = saveAndReloadTtsModule("aliyun-tts-account-json", asrFileName, moduleName, params); return result; } /** * 保存讯飞TTS配置 * @param params * @return */ @PostMapping(value = "/setXfTtsConf") @ResponseBody public AjaxResult setXfTtsConf(@RequestBody JSONArray params) { String asrFileName = "/autoload_configs/xf_tts.conf.xml"; String moduleName = "mod_xf_tts"; AjaxResult result = saveAndReloadTtsModule("", asrFileName, moduleName, params); return result; } /** * 保存TTS配置 * @param params * @return */ @PostMapping(value = "/setChinatelecomTtsConf") @ResponseBody public AjaxResult setChinatelecomTtsConf(@RequestBody JSONArray params) { String asrFileName = "/autoload_configs/chinatelecom_tts.conf.xml"; String moduleName = "mod_chinatelecom_tts"; AjaxResult result = saveAndReloadTtsModule("", asrFileName, moduleName, params); return result; } /** * 保存ASR配置 * @param params * @return */ @PostMapping(value = "/setXunfeiAsrConf") @ResponseBody public AjaxResult setXunfeiAsrConf(@RequestBody JSONArray params) { String asrFileName = "/autoload_configs/xunfei_asr.conf.xml"; String moduleName = "mod_xunfei_asr"; return saveAndReloadAsrModule(asrFileName, moduleName, params, "xunfeiasr"); } /** * 保存FunASR配置 * @param params * @return */ @PostMapping(value = "/setFunAsrConf") @ResponseBody public AjaxResult setFunAsrConf(@RequestBody JSONArray params) { String asrFileName = "/autoload_configs/funasr.conf.xml"; String moduleName = "mod_funasr"; return saveAndReloadAsrModule(asrFileName, moduleName, params, "funasr"); } /** * ASR引擎设置 * @return */ @RequiresPermissions("cc:asrengine:view") @GetMapping(value = "/asrengine") public String asrengine(ModelMap mmap) { String asrEngine = fsConfService.getAsrengine(); FsMod mod = new FsMod(); mod.setModName("asrEngine"); mod.setModValue(asrEngine); mmap.put("mod", mod); return "cc/asrengine/asrengine"; } /** * 设置ASR引擎(mod_xunfei_asr、mod_aliyun_asr、mod_ali_asr、mod_tx_asr、mod_tx_asr1) * @param asrengine * @return */ @GetMapping(value = "/setAsrengine") @ResponseBody public AjaxResult setAsrengine(@RequestParam String asrengine) { String result = fsConfService.setAsrengine(asrengine); if(StringUtils.isEmpty(result)){ if (StringUtils.isNotEmpty(asrengine)) { EslConnectionUtil.sendSyncApiCommand("unload", "mod_xunfei_asr"); EslConnectionUtil.sendSyncApiCommand("unload", "mod_funasr"); EslConnectionUtil.sendSyncApiCommand("unload", "mod_aliyun_asr"); EslConnectionUtil.sendSyncApiCommand("unload", "mod_ali_asr"); EslConnectionUtil.sendSyncApiCommand("unload", "mod_tx_asr"); EslConnectionUtil.sendSyncApiCommand("unload", "mod_tx_asr1"); EslMessage resp = EslConnectionUtil.sendSyncApiCommand("load", asrengine.trim()); String text = CommonUtils.ListToString(resp.getBodyLines() , '\n'); if(text.contains("+OK")) { return AjaxResult.success("设置成功!"); }else{ return AjaxResult.success("设置失败!\n " + text); } }else{ return AjaxResult.error("参数错误!"); } }else { return AjaxResult.error(result); } } /** * 证书配置 * @return */ @RequiresPermissions("cc:certwsspen:view") @GetMapping(value = "/certwsspen") public String certWssPen() { return "cc/certwsspen/certwsspen"; } /** * 获取证书配置 * @return */ @GetMapping(value = "/getCertWssPen") @ResponseBody public AjaxResult getCertWssPen() { JSONObject result = new JSONObject(); result.put("certValue", fsConfService.getCertWssPen()); return AjaxResult.success("success", result); } /** * 保存证书配置 * @param params * @return */ @PostMapping(value = "/setCertWssPen") @ResponseBody public AjaxResult setCertWssPen(@RequestBody JSONObject params) { fsConfService.setCertWssPen(params.getString("certValue")); return AjaxResult.success("设置成功!"); } /** * 授权配置 * @return */ @RequiresPermissions("cc:licenseconf:view") @GetMapping(value = "/licenseconf") public String licenseconf() { return "cc/licenseconf/licenseconf"; } /** * 获取授权配置 * @return */ @GetMapping(value = "/getLicenseConf") @ResponseBody public AjaxResult getLicenseConf() { JSONObject result = new JSONObject(); result.put("fingerprintValue", fsConfService.getFingerprintValue()); result.put("licenseValue", fsConfService.getLicenseValue()); result.put("licenseInfo", fsConfService.getLicenseInfo()); return AjaxResult.success("success", result); } /** * 保存授权配置 * @param params * @return */ @PostMapping(value = "/setLicenseConf") @ResponseBody public AjaxResult setLicenseConf(@RequestBody JSONObject params) { fsConfService.setLicenseConf(params.getString("licenseValue")); return AjaxResult.success("设置成功!"); } /** * 日志监控 * @return */ @RequiresPermissions("cc:catlogs:view") @GetMapping(value = "/catlogs") public String catLogs(ModelMap mmap) { String ccLogFiles = ccParamsService.getParamValueByCode("cc_log_file_path", ""); String errorLogFiles = ccLogFiles.replace("easycallcenter365.log", "easycallcenter365-ERROR.log"); String errorLogs = fsConfService.getLogs("", errorLogFiles, "error"); mmap.put("errorLogs", errorLogs); return "cc/catlogs/catlogs"; } /** * 获取日志 * @return */ @GetMapping(value = "/getLogs") @ResponseBody public AjaxResult getLogs(@RequestParam String uuid) { if (StringUtils.isBlank(uuid) || uuid.length() <= 10) { return AjaxResult.error("请输入正确的uuid"); } uuid = uuid.trim(); JSONObject result = new JSONObject(); // result.put("fsLogs", "这是freeswitch日志:\r\n19:21:38.255 [schedule-pool-3] INFO c.r.f.s.w.s.OnlineWebSessionManager - [validateSessions,100] - invalidation sessions...\r\n19:21:38.281 [schedule-pool-3] DEBUG c.r.s.m.S.selectOnlineByExpired - [debug,135] - ==> Preparing: select sessionId, login_name, dept_name, ipaddr, login_location, browser, os, status, start_timestamp, last_access_time, expire_time from sys_user_online o WHERE o.last_access_time <= ? ORDER BY o.last_access_time ASC\r\n19:21:38.283 [schedule-pool-3] DEBUG c.r.s.m.S.selectOnlineByExpired - [debug,135] - ==> Parameters: 2024-12-22 18:51:38(String)\r\n19:21:38.312 [schedule-pool-3] DEBUG c.r.s.m.S.selectOnlineByExpired - [debug,135] - <== Total: 0\r\n19:21:38.313 [schedule-pool-3] INFO c.r.f.s.w.s.OnlineWebSessionManager - [validateSessions,165] - Finished invalidation session. No sessions were stopped.\r\n"); // result.put("ccLogs", "这是callcenter日志:\r\n19:21:38.255 [schedule-pool-3] INFO c.r.f.s.w.s.OnlineWebSessionManager - [validateSessions,100] - invalidation sessions...\r\n19:21:38.281 [schedule-pool-3] DEBUG c.r.s.m.S.selectOnlineByExpired - [debug,135] - ==> Preparing: select sessionId, login_name, dept_name, ipaddr, login_location, browser, os, status, start_timestamp, last_access_time, expire_time from sys_user_online o WHERE o.last_access_time <= ? ORDER BY o.last_access_time ASC\r\n19:21:38.283 [schedule-pool-3] DEBUG c.r.s.m.S.selectOnlineByExpired - [debug,135] - ==> Parameters: 2024-12-22 18:51:38(String)\r\n19:21:38.312 [schedule-pool-3] DEBUG c.r.s.m.S.selectOnlineByExpired - [debug,135] - <== Total: 0\r\n19:21:38.313 [schedule-pool-3] INFO c.r.f.s.w.s.OnlineWebSessionManager - [validateSessions,165] - Finished invalidation session. No sessions were stopped.\r\n"); String fsLogFiles = ccParamsService.getParamValueByCode("fs_log_file_path", ""); String fsLogs = fsConfService.getLogs(uuid, fsLogFiles, "cc"); result.put("fsLogs", fsLogs); // freeswitch日志 String ccLogFiles = ccParamsService.getParamValueByCode("cc_log_file_path", ""); String ccLogs = fsConfService.getLogs(uuid, ccLogFiles, "cc"); if (StringUtils.isNotEmpty(fsLogs) && StringUtils.isBlank(ccLogs)) { // String ccHisLogFiles = ccLogFiles.replace(".log", ".*.log"); // logger.info(ccHisLogFiles); // ccLogs = fsConfService.getLogs(uuid, ccHisLogFiles, "cc"); List callPhoneList = callPhoneService.selectCcCallPhoneList(new CcCallPhone().setUuid(uuid)); if (!CollectionUtils.isEmpty(callPhoneList)) { String date = DateUtils.parseDateToStr("yyyy-MM-dd", new Date(callPhoneList.get(0).getCalloutTime())); String ccHisLogFiles = ccLogFiles.replace(".log", "." + date + ".0.log"); logger.info(ccHisLogFiles); ccLogs = fsConfService.getLogs(uuid, ccHisLogFiles, "cc"); } else { List inboundCdrList = inboundCdrService.selectCcInboundCdrList(new CcInboundCdr().setUuid(uuid)); if (!CollectionUtils.isEmpty(inboundCdrList)) { String date = DateUtils.parseDateToStr("yyyy-MM-dd", new Date(inboundCdrList.get(0).getInboundTime())); String ccHisLogFiles = ccLogFiles.replace(".log", "." + date + ".0.log"); logger.info(ccHisLogFiles); ccLogs = fsConfService.getLogs(uuid, ccHisLogFiles, "cc"); } else { List outboundCdrList = outboundCdrService.selectCcOutboundCdrList(new CcOutboundCdr().setUuid(uuid)); if (!CollectionUtils.isEmpty(outboundCdrList)) { String date = DateUtils.parseDateToStr("yyyy-MM-dd", new Date(outboundCdrList.get(0).getStartTime())); String ccHisLogFiles = ccLogFiles.replace(".log", "." + date + ".0.log"); logger.info(ccHisLogFiles); ccLogs = fsConfService.getLogs(uuid, ccHisLogFiles, "cc"); } } } } result.put("ccLogs", ccLogs); // callcenter日志 return AjaxResult.success("success", result); } /** * 获取日志 * @return */ @GetMapping(value = "/downloadLogs") @ResponseBody public void downloadLogs(@RequestParam String uuid, HttpServletResponse response) { if (StringUtils.isBlank(uuid) || uuid.length() <= 10) { try { response.setContentType("application/json;charset=UTF-8"); response.getWriter().write("{\"code\":500,\"msg\":\"请输入正确的uuid\"}"); } catch (IOException e) { logger.error("写入错误响应失败", e); } return; } uuid = uuid.trim(); // 获取日志内容 String fsLogFiles = ccParamsService.getParamValueByCode("fs_log_file_path", ""); String fsLogs = fsConfService.getLogs(uuid, fsLogFiles, "cc"); String ccLogFiles = ccParamsService.getParamValueByCode("cc_log_file_path", ""); String ccLogs = fsConfService.getLogs(uuid, ccLogFiles, "cc"); if (StringUtils.isNotEmpty(fsLogs) && StringUtils.isBlank(ccLogs)) { // String ccHisLogFiles = ccLogFiles.replace(".log", ".*.log"); // logger.info(ccHisLogFiles); // ccLogs = fsConfService.getLogs(uuid, ccHisLogFiles, "cc"); List callPhoneList = callPhoneService.selectCcCallPhoneList(new CcCallPhone().setUuid(uuid)); if (!CollectionUtils.isEmpty(callPhoneList)) { String date = DateUtils.parseDateToStr("yyyy-MM-dd", new Date(callPhoneList.get(0).getCalloutTime())); String ccHisLogFiles = ccLogFiles.replace(".log", "." + date + ".0.log"); logger.info(ccHisLogFiles); ccLogs = fsConfService.getLogs(uuid, ccHisLogFiles, "cc"); } else { List inboundCdrList = inboundCdrService.selectCcInboundCdrList(new CcInboundCdr().setUuid(uuid)); if (!CollectionUtils.isEmpty(inboundCdrList)) { String date = DateUtils.parseDateToStr("yyyy-MM-dd", new Date(inboundCdrList.get(0).getInboundTime())); String ccHisLogFiles = ccLogFiles.replace(".log", "." + date + ".0.log"); logger.info(ccHisLogFiles); ccLogs = fsConfService.getLogs(uuid, ccHisLogFiles, "cc"); } else { List outboundCdrList = outboundCdrService.selectCcOutboundCdrList(new CcOutboundCdr().setUuid(uuid)); if (!CollectionUtils.isEmpty(outboundCdrList)) { String date = DateUtils.parseDateToStr("yyyy-MM-dd", new Date(outboundCdrList.get(0).getStartTime())); String ccHisLogFiles = ccLogFiles.replace(".log", "." + date + ".0.log"); logger.info(ccHisLogFiles); ccLogs = fsConfService.getLogs(uuid, ccHisLogFiles, "cc"); } } } } String errorLogFiles = ccLogFiles.replace("easycallcenter365.log", "easycallcenter365-ERROR.log"); String errorLogs = fsConfService.getLogs("", errorLogFiles, "error"); // 生成TXT文件内容 StringBuilder fileContent = new StringBuilder(); fileContent.append("========================================\n"); fileContent.append("UUID: ").append(uuid).append("\n"); fileContent.append("下载时间: ").append(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())).append("\n"); fileContent.append("========================================\n\n"); fileContent.append("【FreeSwitch 日志】\n"); fileContent.append("========================================\n"); fileContent.append(StringUtils.isNotBlank(fsLogs) ? fsLogs : "无日志内容\n"); fileContent.append("\n\n"); fileContent.append("【CallCenter 日志】\n"); fileContent.append("========================================\n"); fileContent.append(StringUtils.isNotBlank(ccLogs) ? ccLogs : "无日志内容\n"); fileContent.append("【Error 日志】\n"); fileContent.append("========================================\n"); fileContent.append(StringUtils.isNotBlank(errorLogs) ? errorLogs : "无日志内容\n"); fileContent.append("\n\n"); // 设置响应头,实现浏览器下载 String fileName = "logs_" + uuid + "_" + System.currentTimeMillis() + ".txt"; try { response.setContentType("text/plain;charset=UTF-8"); response.setHeader("Content-Disposition", "attachment; filename=\"" + URLEncoder.encode(fileName, "UTF-8") + "\""); response.setHeader("Cache-Control", "no-cache"); response.setContentLength(fileContent.toString().getBytes(StandardCharsets.UTF_8).length); // 写入文件内容 try (OutputStream out = response.getOutputStream()) { out.write(fileContent.toString().getBytes(StandardCharsets.UTF_8)); out.flush(); } } catch (IOException e) { logger.error("下载日志文件失败", e); } } @RequiresPermissions("cc:profileconf:view") @GetMapping("/profileconf") public String profile() { ccGatewaysService.refreshGatewaysFiles(); return "cc/profileconf/profileconf"; } @RequiresPermissions("cc:profileconf:add") @GetMapping("/profileconf/add/{profileType}") public String addProfile(@PathVariable("profileType") String profileType, ModelMap mmap) { mmap.put("profileType", profileType); return "cc/profileconf/add"; } @RequiresPermissions("cc:profileconf:edit") @GetMapping("/profileconf/edit/{profileName}") public String editProfile(@PathVariable("profileName") String profileName, ModelMap mmap) { mmap.put("profileName", profileName); return "cc/profileconf/edit"; } /** * 查询分机管理列表 */ @RequiresPermissions("cc:profileconf:list") @PostMapping("/profileList") @ResponseBody public TableDataInfo profileList() { startPage(); List list = fsConfService.selectProfileList(); return getDataTable(list); } @PostMapping(value = "/setProfileConf") @ResponseBody public AjaxResult setProfileConf(@RequestBody JSONArray params) { String profileName = ""; String profileType = ""; String operaType = ""; JSONArray xmlParams = new JSONArray(); for (int i = 0; i < params.size(); i++) { JSONObject param = params.getJSONObject(i); // 不需要写入文件的属性 if ("_profileType".equals(param.getString("name"))) { profileType = param.getString("value"); continue; } if ("_operaType".equals(param.getString("name"))) { operaType = param.getString("value"); continue; } // 需要写入文件的属性 if ("profileName".equals(param.getString("name"))) { profileName = param.getString("value"); } xmlParams.add(param); } logger.info("profileName:" + profileName); logger.info("profileType:" + profileType); logger.info("operaType:" + operaType); String saveSuccess = fsConfService.setProfileConf(profileName, profileType, xmlParams); if(!StringUtils.isEmpty(saveSuccess)){ return AjaxResult.error(saveSuccess); } if ("add".equals(operaType)) { // 新增后启动 EslMessage eslMessage = EslConnectionUtil.sendSyncApiCommand("sofia", "profile " + profileName + " start"); if (null != eslMessage) { logger.info(StringUtils.joinWith("/r/n", eslMessage.getBodyLines().toArray())); } } else if ("edit".equals(operaType)) { // 修改后重启 EslMessage eslMessage = EslConnectionUtil.sendSyncApiCommand("sofia", "profile " + profileName + " restart"); if (null != eslMessage) { logger.info(StringUtils.joinWith("/r/n", eslMessage.getBodyLines().toArray())); } } return AjaxResult.success("设置成功!"); } @GetMapping(value = "/getProfileConf") @ResponseBody public AjaxResult getProfileConf(@RequestParam(required = false) String profileName, @RequestParam(required = false) String profileType) { // 配置文件所有配置 JSONObject confAllVars = fsConfService.getProfileConf(profileName, profileType); // 可配置的基本配置,其他的为隐藏的高级配置 JSONObject fsVars = fsVariablesService.getFsVariablesByCat(3); // key: 参数名, value:别名 JSONArray baseConfigs = new JSONArray(); JSONArray advancedConfigs = new JSONArray(); for (String name: confAllVars.keySet()) { JSONObject var = new JSONObject(); var.put("name", name); var.put("value", confAllVars.getString(name)); if (fsVars.keySet().contains(name)) { // 基本配置 var.put("aliasName", fsVars.getString(name)); // 别名 baseConfigs.add(var); } else { // 高级配置 var.put("aliasName", name); // 高级配置没有别名 advancedConfigs.add(var); } } JSONObject result = new JSONObject(); result.put("baseConfigs", baseConfigs); result.put("advancedConfigs", advancedConfigs); return AjaxResult.success("success", result); } @GetMapping(value = "/getProfileStatus") @ResponseBody public AjaxResult getProfileStatus(@RequestParam String profileName) { JSONObject result = new JSONObject(); EslMessage eslMessage = EslConnectionUtil.sendSyncApiCommand("sofia", "xmlstatus"); if (null != eslMessage) { logger.info(StringUtils.joinWith("\r\n", eslMessage.getBodyLines().toArray())); List list = convertProfileStatusXml(StringUtils.joinWith("", eslMessage.getBodyLines().toArray())); logger.info(JSONObject.toJSONString(list)); result.put("data", list); } else { result.put("msg", "系统错误"); } return AjaxResult.success("success", result); } /** * profileStatus格式转换 * @param xml * @return */ private List convertProfileStatusXml(String xml) { List list = new ArrayList<>(); try { DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = factory.newDocumentBuilder(); InputSource is = new InputSource(new StringReader(xml)); Document doc = builder.parse(is); // 根节点 Node profiles = doc.getDocumentElement(); // 下层数据节点(profile、gateway、alias等) NodeList children = profiles.getChildNodes(); for (int i = 0; i < children.getLength(); i++) { // 比如profile节点 Node child = children.item(i); if (child.getNodeType() == Node.ELEMENT_NODE) { Element element = (Element) children.item(i); Node name = element.getElementsByTagName("name").item(0); Node type = element.getElementsByTagName("type").item(0); Node data = element.getElementsByTagName("data").item(0); Node state = element.getElementsByTagName("state").item(0); ProfileStatusModel model = new ProfileStatusModel(); if (null != name && StringUtils.isNotEmpty(name.getTextContent())) { model.setName(name.getTextContent().trim()); } if (null != type && StringUtils.isNotEmpty(type.getTextContent())) { model.setType(type.getTextContent().trim()); } if (null != data && StringUtils.isNotEmpty(data.getTextContent())) { model.setData(data.getTextContent().trim()); } if (null != state && StringUtils.isNotEmpty(state.getTextContent())) { model.setState(state.getTextContent().trim()); } list.add(model); } } } catch (Exception e) { e.printStackTrace(); } return list; } @GetMapping(value = "/startProfile") @ResponseBody public AjaxResult startProfile(@RequestParam String profileName) { JSONObject result = new JSONObject(); EslMessage eslMessage = EslConnectionUtil.sendSyncApiCommand("sofia", "profile " + profileName + " start"); if (null != eslMessage) { result.put("msg", eslMessage.getBodyLines()); } else { result.put("msg", "系统错误"); } return AjaxResult.success("success", result); } @GetMapping(value = "/stopProfile") @ResponseBody public AjaxResult stopProfile(@RequestParam String profileName) { JSONObject result = new JSONObject(); EslMessage eslMessage = EslConnectionUtil.sendSyncApiCommand("sofia", "profile " + profileName + " stop"); if (null != eslMessage) { result.put("msg", eslMessage.getBodyLines()); } else { result.put("msg", "系统错误"); } return AjaxResult.success("success", result); } @GetMapping(value = "/restartProfile") @ResponseBody public AjaxResult restartProfile(@RequestParam String profileName) { JSONObject result = new JSONObject(); EslMessage eslMessage = EslConnectionUtil.sendSyncApiCommand("sofia", "profile " + profileName + " restart"); if (null != eslMessage) { result.put("msg", eslMessage.getBodyLines()); } else { result.put("msg", "系统错误"); } return AjaxResult.success("success", result); } @GetMapping(value = "/getExtnumList") @ResponseBody public AjaxResult getExtnumList(@RequestParam String profileName) { JSONObject result = new JSONObject(); EslMessage eslMessage = EslConnectionUtil.sendSyncApiCommand("sofia", "xmlstatus profile " + profileName + " reg"); if (null != eslMessage) { logger.info(StringUtils.joinWith("\r\n", eslMessage.getBodyLines().toArray())); List list = convertProfileRegExtnumXml(StringUtils.joinWith("", eslMessage.getBodyLines().toArray())); logger.info(JSONObject.toJSONString(list)); result.put("data", list); } else { result.put("msg", "系统错误"); } return AjaxResult.success("success", result); } private List convertProfileRegExtnumXml(String xml) { List list = new ArrayList<>(); try { DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = factory.newDocumentBuilder(); InputSource is = new InputSource(new StringReader(xml)); Document doc = builder.parse(is); NodeList children = doc.getElementsByTagName("registration"); for (int i = 0; i < children.getLength(); i++) { // 比如profile节点 Node child = children.item(i); if (child.getNodeType() == Node.ELEMENT_NODE) { Element element = (Element) children.item(i); Node user = element.getElementsByTagName("user").item(0); Node networkIp = element.getElementsByTagName("network-ip").item(0); Node networkPort = element.getElementsByTagName("network-port").item(0); Node status = element.getElementsByTagName("status").item(0); Node agent = element.getElementsByTagName("agent").item(0); ProfileRegExtnumModel model = new ProfileRegExtnumModel(); if (null != user && StringUtils.isNotEmpty(user.getTextContent())) { model.setUser(user.getTextContent().trim().split("@")[0]); } if (null != networkIp && StringUtils.isNotEmpty(networkIp.getTextContent())) { model.setNetworkIp(networkIp.getTextContent().trim()); } if (null != networkPort && StringUtils.isNotEmpty(networkPort.getTextContent())) { model.setNetworkPort(networkPort.getTextContent().trim()); } if (null != status && StringUtils.isNotEmpty(status.getTextContent())) { model.setStatus(status.getTextContent().trim()); } if (null != agent && StringUtils.isNotEmpty(agent.getTextContent())) { String agentValue = agent.getTextContent().trim(); if (agentValue.length() > 16) { agentValue = agentValue.substring(0, 14) + "..."; } model.setAgent(agentValue); } list.add(model); } } } catch (Exception e) { e.printStackTrace(); } return list; } /** * ASR(亚马逊)参数配置 * @return */ @GetMapping(value = "/awsasrconf") public String awsAsrConf() { return "cc/awsasrconf/awsasrconf"; } /** * 获取亚马逊ASR配置 * @return */ @GetMapping(value = "/getAwsAsrConf") @ResponseBody public AjaxResult getAwsAsrConf() { String asrFileName = "/autoload_configs/aws_asr.conf.xml"; return getConfigFileJsonData(asrFileName, 5); } /** * 保存ASR配置 * @param params * @return */ @PostMapping(value = "/setAwsAsrConf") @ResponseBody public AjaxResult setAwsAsrConf(@RequestBody JSONArray params) { String asrFileName = "/autoload_configs/aws_asr.conf.xml"; String moduleName = "mod_aws_asr"; return saveAndReloadAsrModule(asrFileName, moduleName, params, "aws"); } /** * TTS(亚马逊)参数配置 * @return */ @RequiresPermissions("cc:awsttsconf:view") @GetMapping(value = "/awsttsconf") public String awsTtsConf() { return "cc/awsttsconf/awsttsconf"; } /** * 获取亚马逊tts配置 * @return */ @GetMapping(value = "/getAwsTtsConf") @ResponseBody public AjaxResult getAwsTtsConf() { String ttsFileName = "/autoload_configs/aws_tts.conf.xml"; return getConfigFileJsonData(ttsFileName, 5); } /** * 保存TTS配置 * @param params * @return */ @PostMapping(value = "/setAwsTtsConf") @ResponseBody public AjaxResult setAwsTtsConf(@RequestBody JSONArray params) { String asrFileName = "/autoload_configs/aws_tts.conf.xml"; String moduleName = "mod_aws_tts"; AjaxResult result = saveAndReloadTtsModule("aws-tts-account-json", asrFileName, moduleName, params); return result; } /** * ASR(deepgram)参数配置 * @return */ @GetMapping(value = "/deepgramasrconf") public String deepgramAsrConf() { return "cc/deepgramasrconf/deepgramasrconf"; } /** * 获取Deepgram ASR配置 * @return */ @GetMapping(value = "/getDeepgramAsrConf") @ResponseBody public AjaxResult getDeepgramAsrConf() { String asrFileName = "/autoload_configs/deepgram_asr.conf.xml"; return getConfigFileJsonData(asrFileName, 5); } /** * 保存ASR配置 * @param params * @return */ @PostMapping(value = "/setDeepgramAsrConf") @ResponseBody public AjaxResult setDeepgramAsrConf(@RequestBody JSONArray params) { String asrFileName = "/autoload_configs/deepgram_asr.conf.xml"; String moduleName = "mod_deepgram_asr"; return saveAndReloadAsrModule(asrFileName, moduleName, params, "deepgram"); } /** * TTS(deepgram)参数配置 * @return */ @RequiresPermissions("cc:deepgramttsconf:view") @GetMapping(value = "/deepgramttsconf") public String deepgramTtsConf() { return "cc/deepgramttsconf/deepgramttsconf"; } /** * 获取deepgram tts配置 * @return */ @GetMapping(value = "/getDeepgramTtsConf") @ResponseBody public AjaxResult getDeepgramTtsConf() { String ttsFileName = "/autoload_configs/deepgram_tts.conf.xml"; return getConfigFileJsonData(ttsFileName, 5); } /** * 保存TTS配置 * @param params * @return */ @PostMapping(value = "/setDeepgramTtsConf") @ResponseBody public AjaxResult setDeepgramTtsConf(@RequestBody JSONArray params) { String asrFileName = "/autoload_configs/deepgram_tts.conf.xml"; String moduleName = "mod_deepgram_tts"; AjaxResult result = saveAndReloadTtsModule("deepgram-tts-account-json", asrFileName, moduleName, params); return result; } }