commit campaign dial
This commit is contained in:
parent
896f4c7d11
commit
5ac2544e12
@ -42,6 +42,19 @@
|
||||
<groupId>com.pudonghot.yo</groupId>
|
||||
<artifactId>yo-web-common</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-openfeign</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.github.openfeign</groupId>
|
||||
<artifactId>feign-httpclient</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.github.openfeign</groupId>
|
||||
<artifactId>feign-jackson</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-actuator</artifactId>
|
||||
|
@ -1,12 +1,14 @@
|
||||
package com.pudonghot.yo.campaign;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.cloud.openfeign.EnableFeignClients;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
/**
|
||||
* @author Donghuang
|
||||
* @date Jul 18, 2020 17:25:36
|
||||
*/
|
||||
@EnableFeignClients
|
||||
@SpringBootApplication
|
||||
public class YoCampaign {
|
||||
|
||||
|
@ -0,0 +1,54 @@
|
||||
package com.pudonghot.yo.campaign.feign.config;
|
||||
|
||||
import feign.Retryer;
|
||||
import feign.codec.Decoder;
|
||||
import feign.codec.Encoder;
|
||||
import feign.RequestInterceptor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import feign.jackson.JacksonDecoder;
|
||||
import feign.form.spring.SpringFormEncoder;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import static java.util.concurrent.TimeUnit.SECONDS;
|
||||
import org.springframework.beans.factory.ObjectFactory;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.cloud.openfeign.support.SpringEncoder;
|
||||
import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
|
||||
import org.springframework.cloud.openfeign.support.ResponseEntityDecoder;
|
||||
|
||||
/**
|
||||
* @author Donghuang
|
||||
* @date Jul 22, 2020 14:08:16
|
||||
*/
|
||||
@Slf4j
|
||||
@Configuration
|
||||
public class FeignClientConfiguration {
|
||||
|
||||
@Autowired
|
||||
private ObjectFactory<HttpMessageConverters> messageConverters;
|
||||
|
||||
@Bean
|
||||
public RequestInterceptor requestInterceptor() {
|
||||
return reqTpl -> {
|
||||
log.debug("Add OpenAPI access token [{}].");
|
||||
reqTpl.header("x-ac-token", "YoQinwei");
|
||||
};
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Encoder feignEncoder() {
|
||||
return new SpringFormEncoder(new SpringEncoder(messageConverters));
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Decoder feignDecoder(final ObjectMapper objectMapper) {
|
||||
return new ResponseEntityDecoder(new JacksonDecoder(objectMapper));
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Retryer feignRetryer() {
|
||||
return new Retryer.Default(100, SECONDS.toMillis(1), 4);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,60 @@
|
||||
package com.pudonghot.yo.campaign.feign.response;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
import com.fasterxml.jackson.annotation.JsonAlias;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
/**
|
||||
* @author Donghuang
|
||||
* @date Jul 22, 2020 14:17:40
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString
|
||||
public class RespCallingList {
|
||||
@JsonAlias("rtncode")
|
||||
@JsonProperty("rtncode")
|
||||
private String code;
|
||||
@JsonAlias("message")
|
||||
@JsonProperty("message")
|
||||
private String error;
|
||||
|
||||
@JsonAlias("taskid")
|
||||
@JsonProperty("taskid")
|
||||
private String campaignKey;
|
||||
@JsonAlias("taskname")
|
||||
@JsonProperty("taskname")
|
||||
private String campaignName;
|
||||
@JsonAlias("taskdata")
|
||||
@JsonProperty("taskdata")
|
||||
private CallingData[] data;
|
||||
|
||||
/**
|
||||
* is response success
|
||||
* @return true if code == 0
|
||||
*/
|
||||
public boolean isSuccess() {
|
||||
return "0".equals(code);
|
||||
}
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString
|
||||
public static class CallingData {
|
||||
private String phone;
|
||||
@JsonAlias("outid")
|
||||
@JsonProperty("outid")
|
||||
private String id;
|
||||
|
||||
/**
|
||||
* to pair (phone, id)
|
||||
* @return pair
|
||||
*/
|
||||
public Pair<String, String> toPair() {
|
||||
return Pair.of(phone, id);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
package com.pudonghot.yo.campaign.feign.service;
|
||||
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import com.pudonghot.yo.campaign.feign.response.RespCallingList;
|
||||
import com.pudonghot.yo.campaign.feign.config.FeignClientConfiguration;
|
||||
|
||||
/**
|
||||
* @author Donghuang <br>
|
||||
* donghuang@wacai.com <br>
|
||||
* Jan 07, 2020 14:36:47
|
||||
*/
|
||||
@FeignClient(url = "${yo.campaign.feign.calling-list.base-url}",
|
||||
name = "CampaignFeign",
|
||||
configuration = FeignClientConfiguration.class)
|
||||
public interface FeignCallingListService {
|
||||
|
||||
/**
|
||||
* fetch calling list
|
||||
* @param numData num data
|
||||
* @param campaignKey campaign key
|
||||
* @param campaignName campaign name
|
||||
* @return calling list
|
||||
*/
|
||||
@RequestMapping("/${yo.campaign.feign.calling-list.channel}")
|
||||
RespCallingList fetchCallingList(
|
||||
@RequestParam("datanum")
|
||||
int numData,
|
||||
@RequestParam("taskid")
|
||||
String campaignKey,
|
||||
@RequestParam("taskname")
|
||||
String campaignName);
|
||||
}
|
@ -1,8 +1,11 @@
|
||||
package com.pudonghot.yo.campaign.service;
|
||||
|
||||
import com.pudonghot.yo.model.domain.Campaign;
|
||||
import com.wacai.tigon.service.BaseQueryService;
|
||||
|
||||
/**
|
||||
* @author Donghuang
|
||||
* @date Jul 18, 2020 17:24:50
|
||||
*/
|
||||
public interface CampaignService {
|
||||
public interface CampaignService extends BaseQueryService<Integer, Campaign> {
|
||||
}
|
||||
|
@ -1,12 +1,89 @@
|
||||
package com.pudonghot.yo.campaign.service.impl;
|
||||
|
||||
import java.util.stream.Stream;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import java.util.stream.Collectors;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import com.wacai.tigon.mybatis.Search;
|
||||
import com.pudonghot.yo.mapper.CampaignMapper;
|
||||
import com.pudonghot.yo.model.domain.Campaign;
|
||||
import org.springframework.stereotype.Service;
|
||||
import com.pudonghot.yo.mapper.AgentStatusMapper;
|
||||
import com.pudonghot.yo.fsagent.api.CampaignDialService;
|
||||
import com.pudonghot.yo.campaign.service.CampaignService;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import com.pudonghot.yo.fsagent.api.request.ReqCampaignDial;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import com.wacai.tigon.service.support.BaseQueryServiceSupport;
|
||||
import com.pudonghot.yo.campaign.feign.response.RespCallingList;
|
||||
import com.pudonghot.yo.campaign.feign.service.FeignCallingListService;
|
||||
import static com.pudonghot.yo.model.domain.Campaign.TargetType.QUEUE;
|
||||
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
|
||||
|
||||
/**
|
||||
* @author Donghuang
|
||||
* @date Jul 18, 2020 17:25:17
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
public class CampaignServiceImpl implements CampaignService {
|
||||
@RequiredArgsConstructor(onConstructor_ = @Autowired)
|
||||
public class CampaignServiceImpl
|
||||
extends BaseQueryServiceSupport<Integer, Campaign, CampaignMapper>
|
||||
implements CampaignService {
|
||||
private final ThreadPoolTaskExecutor taskExecutor;
|
||||
|
||||
@Autowired
|
||||
private AgentStatusMapper agentStatusMapper;
|
||||
@Autowired
|
||||
private FeignCallingListService callingListService;
|
||||
@Autowired
|
||||
private CampaignDialService dialService;
|
||||
|
||||
@Scheduled(fixedRateString = "${yo.campaign.task-scheduler.fixed-rate:180000}", initialDelayString = "${yo.campaign.task-scheduler.init-delay:32000}")
|
||||
public void taskScheduler() {
|
||||
scan(new Search(Campaign.ACTIVE, true)
|
||||
.eq(Campaign.STATUS, Campaign.Status.RUNNING), campaign -> {
|
||||
if (campaign.getTargetType() == QUEUE) {
|
||||
log.info("Queue campaign [{}] is running, dial.", campaign);
|
||||
taskExecutor.execute(() -> dial(campaign));
|
||||
}
|
||||
else {
|
||||
log.info("Campaign [{}] target is not queue, ignore.", campaign);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void dial(final Campaign campaign) {
|
||||
log.info("Campaign [{}] dial.", campaign);
|
||||
final Integer queueId = campaign.getTargetId();
|
||||
final int countOnlineAgentOfQueue =
|
||||
agentStatusMapper.countOnlineOfQueue(queueId);
|
||||
if (countOnlineAgentOfQueue == 0) {
|
||||
log.warn("Campaign [{}] has no online agent, ignore.");
|
||||
return;
|
||||
}
|
||||
|
||||
final int countIdleAgentOfQueue =
|
||||
agentStatusMapper.countIdleOfQueue(queueId);
|
||||
|
||||
if (countIdleAgentOfQueue == 0) {
|
||||
log.warn("Campaign [{}] has no idle agent, ignore.");
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO campaign dial
|
||||
// Outbound = (readyAgent + expNum) * z * speedAdjust - taskNum;
|
||||
final RespCallingList callingList =
|
||||
callingListService.fetchCallingList(
|
||||
countIdleAgentOfQueue, campaign.getCampaignKey(), campaign.getName());
|
||||
if (callingList.isSuccess()) {
|
||||
final ReqCampaignDial req= new ReqCampaignDial();
|
||||
req.setCampaignId(campaign.getId());
|
||||
req.setCallingList(Stream.of(callingList.getData()).map(RespCallingList.CallingData::toPair).collect(Collectors.toList()));
|
||||
dialService.queueDial(req);
|
||||
}
|
||||
else {
|
||||
log.error("Fetch calling list error caused. code [{}], message [{}].", callingList.getCode(), callingList.getError());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -21,3 +21,14 @@ spring.redis.host=172.18.4.35
|
||||
spring.redis.port=6379
|
||||
spring.redis.password=123456
|
||||
|
||||
# Dubbo
|
||||
|
||||
## Dubbo Registry
|
||||
dubbo.registry.address=zookeeper://172.18.4.35:2181
|
||||
dubbo.registry.file=${user.home}/dubbo-cache/${spring.application.name}/dubbo.cache
|
||||
yo.fsagent.dubbo.service.version=1.0.0
|
||||
|
||||
# Calling List
|
||||
yo.campaign.feign.calling-list.base-url=http://localhost:1116
|
||||
yo.campaign.feign.calling-list.channel=campaign.json
|
||||
|
||||
|
@ -2,10 +2,13 @@
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:task="http://www.springframework.org/schema/task"
|
||||
xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans
|
||||
http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/task
|
||||
http://www.springframework.org/schema/task/spring-task.xsd">
|
||||
http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/task
|
||||
http://www.springframework.org/schema/task/spring-task.xsd
|
||||
http://dubbo.apache.org/schema/dubbo
|
||||
http://dubbo.apache.org/schema/dubbo/dubbo.xsd">
|
||||
|
||||
<task:executor id="taskExecutor"
|
||||
pool-size="${yo.task.executor.pool-size:8}"
|
||||
@ -14,4 +17,11 @@
|
||||
<task:scheduler id="taskScheduler" pool-size="${yo.task.scheduler.pool-size:8}" />
|
||||
<task:annotation-driven executor="taskExecutor"
|
||||
scheduler="taskScheduler" proxy-target-class="true" />
|
||||
|
||||
<dubbo:reference id="dialService"
|
||||
interface="com.pudonghot.yo.fsagent.api.DialService"
|
||||
version="${yo.fsagent.dubbo.service.version}" />
|
||||
<dubbo:reference id="campaignDialService"
|
||||
interface="com.pudonghot.yo.fsagent.api.CampaignDialService"
|
||||
version="${yo.fsagent.dubbo.service.version}" />
|
||||
</beans>
|
||||
|
@ -0,0 +1,30 @@
|
||||
package com.pudonghot.yo.campaign;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import com.pudonghot.yo.campaign.feign.response.RespCallingList;
|
||||
import com.pudonghot.yo.campaign.feign.service.FeignCallingListService;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
/**
|
||||
* @author Donghuang <br>
|
||||
* Dec 12, 2019 23:59:37
|
||||
*/
|
||||
@Slf4j
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@SpringBootTest(classes = YoCampaign.class)
|
||||
public class FeignCallingListServiceTest {
|
||||
|
||||
@Autowired
|
||||
private FeignCallingListService callingListService;
|
||||
|
||||
@Test
|
||||
public void testFetchCallingList() {
|
||||
final RespCallingList callingList =
|
||||
callingListService.fetchCallingList(1, "11223", "44556");
|
||||
log.info("Calling list [{}].", callingList);
|
||||
}
|
||||
}
|
@ -1,14 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans
|
||||
http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://dubbo.apache.org/schema/dubbo
|
||||
http://dubbo.apache.org/schema/dubbo/dubbo.xsd">
|
||||
|
||||
<dubbo:reference id="demoService"
|
||||
interface="com.pudonghot.yo.fsagent.api.DemoService"
|
||||
version="${yo.fsagent.dubbo.service.version}"
|
||||
/>
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans
|
||||
http://www.springframework.org/schema/beans/spring-beans.xsd">
|
||||
</beans>
|
||||
|
Binary file not shown.
@ -9,12 +9,12 @@ import com.wacai.tigon.mybatis.Search;
|
||||
import com.pudonghot.yo.model.domain.*;
|
||||
import com.wacai.tigon.model.ViewModel;
|
||||
import org.springframework.util.Assert;
|
||||
import com.pudonghot.yo.util.PhoneNumberUtils;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import com.pudonghot.yo.cms.form.SessionForm;
|
||||
import org.springframework.stereotype.Service;
|
||||
import com.pudonghot.yo.cellphone.CellphoneInfo;
|
||||
import com.pudonghot.yo.common.util.MobileUtils;
|
||||
import com.pudonghot.yo.cms.service.TrunkService;
|
||||
import com.pudonghot.yo.cellphone.CellphoneService;
|
||||
import com.pudonghot.yo.cms.service.AreaCodeService;
|
||||
@ -172,7 +172,7 @@ public class TrunkServiceImpl
|
||||
}
|
||||
|
||||
private String getTrunk(final String callerNumber) {
|
||||
if (MobileUtils.checkMobile(callerNumber)) {
|
||||
if (PhoneNumberUtils.isMobile(callerNumber)) {
|
||||
final CellphoneInfo cellphoneInfo =
|
||||
cellphoneService.lookup(callerNumber);
|
||||
Assert.state(cellphoneInfo != null,
|
||||
|
17
deploy.sh
17
deploy.sh
@ -19,11 +19,17 @@ deploy_server() {
|
||||
local server="$1"
|
||||
local app="$2"
|
||||
local jar="$3"
|
||||
local port="$4"
|
||||
if [ -z "$port" ]; then
|
||||
port='22'
|
||||
fi
|
||||
|
||||
local target_dir="/data/program/$app"
|
||||
local target_jar="$target_dir/lib/main.jar"
|
||||
scp $jar $server:"${target_jar}_new"
|
||||
ssh $server "$target_dir/bin/stop.sh; mv $target_jar {$target_jar}_prev"
|
||||
ssh $server "mv ${target_jar}_new $target_jar && $target_dir/bin/start.sh"
|
||||
scp -P $port $jar $server:"${target_jar}_new"
|
||||
ssh -p $port $server "$target_dir/bin/stop.sh;
|
||||
mv $target_jar {$target_jar}_prev;
|
||||
mv ${target_jar}_new $target_jar && $target_dir/bin/start.sh"
|
||||
}
|
||||
|
||||
prg_path=$(get_real_path "$0")
|
||||
@ -35,7 +41,7 @@ WORK_DIR=$(pwd)
|
||||
echo "Work dir [$WORK_DIR]"
|
||||
|
||||
if [ -z "$1" ] && [ -z "$2" ]; then
|
||||
echo 'Usage: ./deploy.sh cms|fsagent|openapi test|prod'
|
||||
echo 'Usage: ./deploy.sh cms|fsagent|openapi test|prod [nb]'
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@ -58,8 +64,9 @@ echo "JAR [$JAR] found"
|
||||
if [ "$2" == "test" ]; then
|
||||
echo "Deploy test."
|
||||
deploy_server 'appweb@118.24.251.131' $APP $JAR
|
||||
elif ["$2" == "prod" ]; then
|
||||
elif [ "$2" == "prod" ]; then
|
||||
echo "Deploy prod."
|
||||
deploy_server 'xiandou@113.87.175.72' $APP $JAR '51022'
|
||||
fi
|
||||
|
||||
popd > /dev/null
|
||||
|
@ -1,12 +1,18 @@
|
||||
package com.pudonghot.yo.fsagent.controller;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Arrays;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
import com.pudonghot.yo.fsagent.api.DialService;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import com.pudonghot.yo.fsagent.api.response.RespDial;
|
||||
import com.pudonghot.yo.fsagent.api.CampaignDialService;
|
||||
import com.pudonghot.yo.fsagent.api.request.ReqAgentDial;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import com.pudonghot.yo.fsagent.api.request.ReqAgentDial;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import com.pudonghot.yo.fsagent.api.request.ReqCampaignDial;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
/**
|
||||
@ -18,9 +24,24 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
public class DialController {
|
||||
@Autowired
|
||||
private DialService dialService;
|
||||
@Autowired
|
||||
private CampaignDialService campaignDialService;
|
||||
|
||||
@PostMapping("/dial")
|
||||
public RespDial dial(@RequestBody final ReqAgentDial req) {
|
||||
return dialService.agentDial(req);
|
||||
}
|
||||
|
||||
@PostMapping("/campaign-dial")
|
||||
public List<String> campaignDial(
|
||||
@RequestParam("campaignId")
|
||||
final Integer campaignId,
|
||||
@RequestParam("phone")
|
||||
final String calledNumber) {
|
||||
|
||||
final ReqCampaignDial req = new ReqCampaignDial();
|
||||
req.setCampaignId(campaignId);
|
||||
req.setCallingList(Arrays.asList(Pair.of(calledNumber, calledNumber)));
|
||||
return campaignDialService.queueDial(req);
|
||||
}
|
||||
}
|
||||
|
@ -38,6 +38,7 @@ public class DialplanController extends BaseDialplanController {
|
||||
final Map<String, String> params) {
|
||||
|
||||
log.info("XML dialplan of domain [{}] [{}] -> [{}].", domain, channel, calledNumber);
|
||||
log.debug("XML dialplan params [{}].", params);
|
||||
|
||||
for (final DialplanService dialplanService : dialplanServices) {
|
||||
final DialplanConfig dialplanConfig = dialplanService.find(params);
|
||||
|
@ -10,6 +10,7 @@ import org.springframework.stereotype.Controller;
|
||||
import com.pudonghot.yo.model.agentevent.AgentEvent;
|
||||
import com.pudonghot.yo.service.CommonChannelService;
|
||||
import com.pudonghot.yo.fsagent.service.AgentService;
|
||||
import com.pudonghot.yo.service.CommonCallDataService;
|
||||
import org.freeswitch.esl.client.transport.event.Event;
|
||||
import com.pudonghot.yo.fsagent.api.IvrTransferService;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
@ -36,6 +37,8 @@ public class IvrController {
|
||||
private CommonAgentEventQueueService agentEventQueueService;
|
||||
@Autowired
|
||||
private CommonChannelService channelService;
|
||||
@Autowired
|
||||
private CommonCallDataService commonCallDataService;
|
||||
|
||||
@PostMapping("/ivr/confirm")
|
||||
public void confirm(
|
||||
@ -103,7 +106,8 @@ public class IvrController {
|
||||
}
|
||||
|
||||
eventData.put("callid", callId);
|
||||
eventData.put("calldata", ivrTransferService.getCallData(strAgentId));
|
||||
eventData.put("calldata",
|
||||
commonCallDataService.getIvrCallData(strAgentId));
|
||||
|
||||
agentEventQueueService.publish(new AgentEvent(
|
||||
AgentEvent_IVR_Result,
|
||||
|
@ -0,0 +1,29 @@
|
||||
package com.pudonghot.yo.fsagent.event;
|
||||
|
||||
import lombok.Getter;
|
||||
import com.pudonghot.yo.model.domain.Agent;
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
|
||||
/**
|
||||
* @author Donghuang
|
||||
* @date Jul 22, 2020 19:53:59
|
||||
*/
|
||||
public class CampaignCallEstablishedEvent extends ApplicationEvent {
|
||||
@Getter
|
||||
private final String callUuid;
|
||||
|
||||
/**
|
||||
* Create a new {@code ApplicationEvent}.
|
||||
*
|
||||
* @param agent the object on which the event initially occurred or with
|
||||
* which the event is associated (never {@code null})
|
||||
*/
|
||||
public CampaignCallEstablishedEvent(final Agent agent, String callUuid) {
|
||||
super(agent);
|
||||
this.callUuid = callUuid;
|
||||
}
|
||||
|
||||
public Agent getAgent() {
|
||||
return (Agent) getSource();
|
||||
}
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
package com.pudonghot.yo.fsagent.listener;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import com.pudonghot.yo.model.domain.Agent;
|
||||
import org.springframework.stereotype.Component;
|
||||
import com.pudonghot.yo.model.agentevent.AgentEvent;
|
||||
import com.pudonghot.yo.service.CommonCallDataService;
|
||||
import org.springframework.context.event.EventListener;
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
import com.pudonghot.yo.service.CommonAgentEventQueueService;
|
||||
import static com.pudonghot.yo.model.agentevent.EventType.*;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import com.pudonghot.yo.fsagent.event.CampaignCallEstablishedEvent;
|
||||
|
||||
/**
|
||||
* @author Donghuang
|
||||
* @date Jul 23, 2020 09:50:06
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class CampaignCallEstablishedListener {
|
||||
|
||||
@Autowired
|
||||
private CommonAgentEventQueueService agentEventQueueService;
|
||||
@Autowired
|
||||
private CommonCallDataService commonCallDataService;
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Async
|
||||
@EventListener(value = CampaignCallEstablishedEvent.class)
|
||||
public void onCampaignCallEstablished(final CampaignCallEstablishedEvent event) {
|
||||
final Agent agent = event.getAgent();
|
||||
final String callUuid = event.getCallUuid();
|
||||
agentEventQueueService.publish(
|
||||
new AgentEvent(AgentOther_TaskData,
|
||||
agent.getId(),
|
||||
agent.getAccount(),
|
||||
commonCallDataService.getCampaignCallData(callUuid)));
|
||||
}
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
package com.pudonghot.yo.fsagent.listener;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.stereotype.Component;
|
||||
import com.pudonghot.yo.service.CommonCallDataService;
|
||||
import org.freeswitch.esl.client.transport.event.Event;
|
||||
import org.springframework.context.event.EventListener;
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
/**
|
||||
* @author Donghuang
|
||||
* @date Jul 23, 2020 19:51:09
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class CampaignChannelDestroy {
|
||||
@Autowired
|
||||
private CommonCallDataService callDataService;
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Async
|
||||
@EventListener(value = Event.class,
|
||||
condition = "#root.args[0].getName() == 'CHANNEL_DESTROY'" +
|
||||
" and #root.args[0].getDialType() == 'CAMPAIGN'")
|
||||
public void onCampaignChannelDestroy(final Event event) {
|
||||
log.debug("On campaign channel destroy event [{}].", event.getHeaders());
|
||||
|
||||
final String strCampaignId = event.getHeader("variable_x_campaign_id");
|
||||
if (StringUtils.isNotBlank(strCampaignId)) {
|
||||
log.info("Campaign [{}] call hangup, decrease campaign channel.", strCampaignId);
|
||||
final Integer campaignId = Integer.parseInt(strCampaignId);
|
||||
callDataService.decrCampaignChannel(campaignId);
|
||||
}
|
||||
}
|
||||
}
|
@ -4,11 +4,12 @@ import java.util.Map;
|
||||
import java.util.HashMap;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import com.pudonghot.yo.model.domain.Agent;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.stereotype.Component;
|
||||
import com.pudonghot.yo.fsagent.util.CallStrUtils;
|
||||
import com.pudonghot.yo.fsagent.util.EslEventUtils;
|
||||
import com.pudonghot.yo.model.agentevent.AgentEvent;
|
||||
import com.pudonghot.yo.fsagent.service.AgentService;
|
||||
import com.pudonghot.yo.fsagent.util.CallStrUtils;
|
||||
import org.freeswitch.esl.client.transport.event.Event;
|
||||
import org.springframework.context.event.EventListener;
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
@ -37,7 +38,7 @@ public class ChannelAnswer {
|
||||
@EventListener(value = Event.class,
|
||||
condition = "#root.args[0].getName() == 'CHANNEL_ANSWER'")
|
||||
public void onChannelAnswer(final Event event) {
|
||||
log.debug("On channel answer event [{}] [{}].", event, event.getHeaders());
|
||||
log.debug("On channel answer event [{}].", event.getHeaders());
|
||||
|
||||
final CallStrUtils.ChannelInfo channelInfo =
|
||||
CallStrUtils.getChannelInfo(event);
|
||||
@ -58,7 +59,12 @@ public class ChannelAnswer {
|
||||
// feature:0普通呼入,7普通外呼, 51内部求助
|
||||
eventData.put("feature", "7");
|
||||
eventData.put("caller", channelInfo.getNumber());
|
||||
eventData.put("called", event.getOtherNumber());
|
||||
|
||||
String calledNumber = event.getCalledNumber();
|
||||
if (StringUtils.isBlank(calledNumber)) {
|
||||
calledNumber = event.getOtherNumber();
|
||||
}
|
||||
eventData.put("called", calledNumber);
|
||||
}
|
||||
else {
|
||||
// feature:0普通呼入,7普通外呼, 51内部求助
|
||||
|
@ -27,7 +27,7 @@ public class ChannelCreate {
|
||||
@EventListener(value = Event.class,
|
||||
condition = "#root.args[0].getName() == 'CHANNEL_CREATE'")
|
||||
public void onChannelCreate(final Event event) {
|
||||
log.debug("On channel create event [{}] [{}].", event, event.getHeaders());
|
||||
log.debug("On channel create event [{}].", event.getHeaders());
|
||||
|
||||
final CallStrUtils.ChannelInfo channelInfo = CallStrUtils.getChannelInfo(event);
|
||||
|
||||
|
@ -44,7 +44,7 @@ public class ChannelDestroy {
|
||||
@EventListener(value = Event.class,
|
||||
condition = "#root.args[0].getName() == 'CHANNEL_DESTROY'")
|
||||
public void onChannelDestroy(final Event event) {
|
||||
log.debug("On channel destroy event [{}] [{}].", event, event.getHeaders());
|
||||
log.debug("On channel destroy event [{}].", event.getHeaders());
|
||||
|
||||
final String callUuid = event.getCallUuid();
|
||||
final String channelName = event.getChannelName();
|
||||
|
@ -52,7 +52,9 @@ public class ChannelHangupComplete {
|
||||
final Map<String, Object> eventData = new HashMap<>(8);
|
||||
eventData.put("callid", event.getCallUuid());
|
||||
|
||||
if (EslEventUtils.isCaller(event)) {
|
||||
final String hangupCause = event.getHangupCause();
|
||||
if (EslEventUtils.isCaller(event) &&
|
||||
!"NORMAL_UNSPECIFIED".equalsIgnoreCase(hangupCause)) {
|
||||
agentEventQueueService.publish(
|
||||
new AgentEvent(
|
||||
AgentEvent_Connect_Fail,
|
||||
@ -60,7 +62,7 @@ public class ChannelHangupComplete {
|
||||
agent.getAccount(),
|
||||
eventData));
|
||||
}
|
||||
else if ("NO_ANSWER".equals(event.getHangupCause())) {
|
||||
else if ("NO_ANSWER".equalsIgnoreCase(hangupCause)) {
|
||||
agentEventQueueService.publish(
|
||||
new AgentEvent(
|
||||
AgentEvent_No_Answer,
|
||||
|
@ -36,7 +36,7 @@ public class ChannelProgress {
|
||||
@EventListener(value = Event.class,
|
||||
condition = "#root.args[0].getName() == 'CHANNEL_PROGRESS'")
|
||||
public void onChannelProgress(final Event event) {
|
||||
log.debug("On channel progress event [{}] [{}].", event, event.getHeaders());
|
||||
log.debug("On channel progress event [{}].", event.getHeaders());
|
||||
|
||||
final String channelName = event.getChannelName();
|
||||
log.info("On channel [{}] answer event.", channelName);
|
||||
|
@ -65,15 +65,15 @@ public abstract class BaseDialplanService implements DialplanService {
|
||||
|
||||
protected String getParam(final Map<String, String> params, final String name, final String... names) {
|
||||
|
||||
String val = params.get(name);
|
||||
final String val = params.get(name);
|
||||
if (StringUtils.isNotBlank(val)) {
|
||||
return val;
|
||||
}
|
||||
|
||||
for (String n : names) {
|
||||
val = params.get(n);
|
||||
if (StringUtils.isNotBlank(val)) {
|
||||
return val;
|
||||
for (final String alterName : names) {
|
||||
final String alterVal = params.get(alterName);
|
||||
if (StringUtils.isNotBlank(alterVal)) {
|
||||
return alterVal;
|
||||
}
|
||||
}
|
||||
|
||||
@ -88,6 +88,10 @@ public abstract class BaseDialplanService implements DialplanService {
|
||||
return getParam(params, "Channel-Presence-ID", "variable_presence_id");
|
||||
}
|
||||
|
||||
public String getConnId(final Map<String, String> params) {
|
||||
return getParam(params, "variable_x_conn_id", "variable_call_uuid", "variable_uuid");
|
||||
}
|
||||
|
||||
protected ChannelInfo getChannelInfo(final Map<String, String> params) {
|
||||
return CallStrUtils.parseChannelName(getChannelName(params), getPresenceId(params));
|
||||
}
|
||||
|
@ -3,12 +3,16 @@ package com.pudonghot.yo.fsagent.service.dialplan.impl;
|
||||
import java.util.Map;
|
||||
import java.util.HashMap;
|
||||
import com.pudonghot.yo.model.domain.Agent;
|
||||
import com.pudonghot.yo.util.PhoneNumberUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import com.pudonghot.yo.fsagent.service.dialplan.Call;
|
||||
import com.pudonghot.yo.model.domain.CallDetailRecord;
|
||||
import com.pudonghot.yo.fsagent.event.CampaignCallEstablishedEvent;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import com.pudonghot.yo.fsagent.service.dialplan.DialplanConfig;
|
||||
|
||||
/**
|
||||
@ -18,6 +22,8 @@ import com.pudonghot.yo.fsagent.service.dialplan.DialplanConfig;
|
||||
@Order(20)
|
||||
@Service
|
||||
public class DialplanService20CampaignToIdAndType extends BaseDialplanService {
|
||||
@Autowired
|
||||
private ApplicationContext appContext;
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
@ -36,14 +42,20 @@ public class DialplanService20CampaignToIdAndType extends BaseDialplanService {
|
||||
model.put("connId", connId);
|
||||
model.put("calledAgent", calledAgent);
|
||||
|
||||
final String otherDn = StringUtils.defaultIfBlank(
|
||||
getVarCalledNumber(call),
|
||||
call.getCallerChannel().getNumber());
|
||||
String otherDn = getVarCalledNumber(call);
|
||||
if (StringUtils.isBlank(otherDn)) {
|
||||
otherDn = PhoneNumberUtils.cleanupMobile(
|
||||
call.getCallerChannel().getNumber());
|
||||
}
|
||||
|
||||
model.put("calledNumber", otherDn);
|
||||
model.put("privacyNumber",
|
||||
numberPrivacyService.generate(calledAgent, otherDn));
|
||||
recFile(model, connId, calledAgent.getAccount(), md5(otherDn));
|
||||
|
||||
appContext.publishEvent(
|
||||
new CampaignCallEstablishedEvent(
|
||||
calledAgent, getConnId(call.getParams())));
|
||||
return new DialplanConfig(call.getTenant(), "campaign-to-agent.xml", model);
|
||||
}
|
||||
|
||||
|
@ -27,10 +27,10 @@ public class DialplanService28AgentToTrunkPrefix extends BaseDialplanService {
|
||||
|
||||
return onCallerAgent(call, callerAgent -> {
|
||||
|
||||
final String calledNumber = call.getCalledNumber();
|
||||
final String dialedNumber = call.getCalledNumber();
|
||||
final Pair<Trunk, String> trunkInfo =
|
||||
trunkService.parseDialTarget(
|
||||
callerAgent.getTenantId(), calledNumber);
|
||||
callerAgent.getTenantId(), dialedNumber);
|
||||
|
||||
if (trunkInfo != null) {
|
||||
final Trunk trunk = trunkInfo.getLeft();
|
||||
@ -45,9 +45,10 @@ public class DialplanService28AgentToTrunkPrefix extends BaseDialplanService {
|
||||
gatewayService.genGatewayName(trunk.getGatewayId()));
|
||||
|
||||
// number without trunk prefix
|
||||
final String targetNumber = trunkInfo.getRight();
|
||||
model.put("targetNumber", targetNumber);
|
||||
recFile(model, connId, callerAgent.getAccount(), md5(targetNumber));
|
||||
final String calledNumber = trunkInfo.getRight();
|
||||
model.put("calledNumber", calledNumber);
|
||||
model.put("targetNumber", trunkService.calledNumber(trunk, calledNumber));
|
||||
recFile(model, connId, callerAgent.getAccount(), md5(calledNumber));
|
||||
return new DialplanConfig(call.getTenant(), "trunk-outbound.xml", model);
|
||||
}
|
||||
return null;
|
||||
|
@ -0,0 +1,148 @@
|
||||
package com.pudonghot.yo.fsagent.service.dubbo.impl;
|
||||
|
||||
import java.util.*;
|
||||
import com.pudonghot.yo.mapper.*;
|
||||
import com.wacai.tigon.json.JSON;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import com.pudonghot.yo.model.domain.*;
|
||||
import org.springframework.util.Assert;
|
||||
import com.pudonghot.yo.model.domain.Queue;
|
||||
import com.wacai.tigon.sequence.IdSequence;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
import org.apache.commons.lang3.RandomUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import com.pudonghot.yo.fsagent.api.request.*;
|
||||
import org.freeswitch.esl.client.inbound.Client;
|
||||
import org.apache.dubbo.config.annotation.Service;
|
||||
import com.pudonghot.yo.fsagent.service.TrunkService;
|
||||
import com.pudonghot.yo.service.CommonCallDataService;
|
||||
import com.pudonghot.yo.fsagent.api.CampaignDialService;
|
||||
import static org.slf4j.helpers.MessageFormatter.arrayFormat;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
/**
|
||||
* @author Donghuang <br>
|
||||
* Dec 09, 2019 16:30:25
|
||||
*/
|
||||
@Slf4j
|
||||
@Service(version = "${yo.fsagent.dubbo.service.version}", register = false)
|
||||
public class CampaignDialServiceImpl implements CampaignDialService {
|
||||
|
||||
@Autowired
|
||||
private CampaignMapper campaignMapper;
|
||||
@Autowired
|
||||
private Client fsClient;
|
||||
@Autowired
|
||||
private IdSequence idSeq;
|
||||
@Autowired
|
||||
private TenantMapper tenantMapper;
|
||||
@Autowired
|
||||
private TrunkStrategyMapper trunkStrategyMapper;
|
||||
@Autowired
|
||||
private QueueMapper queueMapper;
|
||||
@Autowired
|
||||
private TrunkService trunkService;
|
||||
@Autowired
|
||||
private CommonCallDataService commonCallDataService;
|
||||
@Autowired
|
||||
private JSON json;
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public List<String> queueDial(final ReqCampaignDial req) {
|
||||
final Integer campaignId = req.getCampaignId();
|
||||
final Campaign campaign = campaignMapper.find(campaignId);
|
||||
Assert.state(campaign != null,
|
||||
() -> "No campaign [" + campaignId + "] found");
|
||||
Assert.state(campaign.getActive(),
|
||||
() -> "Campaign [" + campaignId + "] is not active");
|
||||
Assert.state(campaign.getStatus() == Campaign.Status.RUNNING,
|
||||
() -> "Campaign [" + campaignId + "] is not running");
|
||||
Assert.state(campaign.getTargetType() == Campaign.TargetType.QUEUE,
|
||||
() -> "Campaign [" + campaignId + "] target type is not QUEUE");
|
||||
|
||||
final Queue queue = queueMapper.find(campaign.getTargetId());
|
||||
Assert.state(queue != null,
|
||||
() -> "Campaign [" + campaignId + "] queue not found");
|
||||
Assert.state(queue.getActive(),
|
||||
() -> "Campaign [" + campaignId + "] queue is not active");
|
||||
|
||||
final Tenant tenant = tenantMapper.find(campaign.getTenantId());
|
||||
Assert.state(tenant != null,
|
||||
() -> "Campaign [" + campaignId + "] tenant not found");
|
||||
Assert.state(tenant.getActive(),
|
||||
() -> "Campaign [" + campaignId + "] tenant is not active");
|
||||
|
||||
final List<Pair<String, String>> callingList = req.getCallingList();
|
||||
final List<String> callUuidList = new ArrayList<>(callingList.size());
|
||||
|
||||
for (final Pair<String, String> callingRec : callingList) {
|
||||
final String calledNumber = callingRec.getLeft();
|
||||
|
||||
final List<TrunkStrategy> trunkStrategies =
|
||||
trunkStrategyMapper.listOfCampaign(campaignId);
|
||||
Assert.state(!trunkStrategies.isEmpty(),
|
||||
() -> "Campaign [" + campaignId + "] has no trunk strategies configured");
|
||||
|
||||
final TrunkStrategy trunkStrategy =
|
||||
trunkStrategies.size() == 1 ?
|
||||
trunkStrategies.iterator().next() :
|
||||
trunkStrategies.get(
|
||||
RandomUtils.nextInt(0, trunkStrategies.size()));
|
||||
|
||||
final Pair<Trunk, String> trunkDialStr =
|
||||
trunkService.dialStr(trunkStrategy.getId(), calledNumber, null);
|
||||
final Trunk trunk = trunkDialStr.getLeft();
|
||||
final List<String> globalVars = Arrays.asList(
|
||||
"ignore_early_media=true",
|
||||
"x_dial_type=CAMPAIGN",
|
||||
"x_call_type=OUTBOUND",
|
||||
"x_tenant_id=" + tenant.getId(),
|
||||
"x_tenant_code=" + tenant.getCode(),
|
||||
"x_account=SYSTEM",
|
||||
"x_called_number=" + calledNumber,
|
||||
"x_trunk_id=" + trunk.getId(),
|
||||
"x_cpn=" + trunk.getCpn()
|
||||
);
|
||||
|
||||
final String uuid = idSeq.get();
|
||||
callUuidList.add(uuid);
|
||||
|
||||
final List<String> channelVars = Arrays.asList(
|
||||
"x_campaign_id=" + campaignId,
|
||||
"x_conn_id=" + uuid,
|
||||
"origination_uuid=" + uuid,
|
||||
"sip_invite_call_id=" + uuid,
|
||||
"originate_timeout=30",
|
||||
"x_role=CALLED",
|
||||
"origination_caller_id_number=" + trunk.getCpn(),
|
||||
"continue_on_fail=true",
|
||||
"hangup_after_bridge=true"
|
||||
);
|
||||
|
||||
// originate {x_dial_type=CAMPAIGN,x_tenant_id=13,x_tenant_code=GOBLIN,x_account=SYSTEM,x_called_number=13764268709,x_trunk_id=12,x_cpn=28165766}[originate_timeout=30,x_role=CALLED,origination_caller_id_number=28165766]sofia/gateway/GW000001/013764268709 4.Q XML d1.wacai.info
|
||||
fsClient.bgApi(format("originate {{}}[{}]{} {}.Q XML {}",
|
||||
StringUtils.join(globalVars, ","),
|
||||
StringUtils.join(channelVars, ","),
|
||||
trunkDialStr.getRight(),
|
||||
queue.getId(),
|
||||
tenant.getRealm()));
|
||||
|
||||
final Map<String, Object> callData = new HashMap<>(4);
|
||||
callData.put("outid", callingRec.getRight());
|
||||
callData.put("phone", calledNumber);
|
||||
callData.put("taskid", campaign.getCampaignKey());
|
||||
callData.put("taskname", campaign.getName());
|
||||
commonCallDataService.saveCampaignCallData(uuid,
|
||||
json.toJSONString(callData));
|
||||
commonCallDataService.incrCampaignChannel(campaignId);
|
||||
}
|
||||
return callUuidList;
|
||||
}
|
||||
|
||||
String format(final String tpl, final Object... args) {
|
||||
return arrayFormat(tpl, args).getMessage();
|
||||
}
|
||||
}
|
@ -43,8 +43,6 @@ public class DialServiceImpl implements DialService {
|
||||
private QueueMapper queueMapper;
|
||||
@Autowired
|
||||
private AgentService agentService;
|
||||
@Value("${yo.fsagent.recording.file-ext:.ogg}")
|
||||
private String recordingFileExt;
|
||||
|
||||
@Autowired
|
||||
private DialerAgent dialerAgent;
|
||||
|
@ -1,9 +1,6 @@
|
||||
package com.pudonghot.yo.fsagent.service.dubbo.impl;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.redisson.api.RMapCache;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import org.redisson.api.RedissonClient;
|
||||
import com.pudonghot.yo.model.domain.Agent;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
@ -11,8 +8,8 @@ import com.pudonghot.yo.fs.model.domain.Channel;
|
||||
import org.freeswitch.esl.client.inbound.Client;
|
||||
import org.apache.dubbo.config.annotation.Service;
|
||||
import com.pudonghot.yo.service.CommonChannelService;
|
||||
import com.pudonghot.yo.service.CommonCallDataService;
|
||||
import com.pudonghot.yo.fsagent.api.IvrTransferService;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import com.pudonghot.yo.fsagent.service.dialplan.DialplanService;
|
||||
|
||||
@ -23,21 +20,13 @@ import com.pudonghot.yo.fsagent.service.dialplan.DialplanService;
|
||||
@Slf4j
|
||||
@Service(version = "${yo.fsagent.dubbo.service.version}", register = false)
|
||||
public class IvrTransferServiceImpl implements IvrTransferService {
|
||||
private final RMapCache<String, String> CALL_DATA_CACHE;
|
||||
|
||||
@Autowired
|
||||
private Client fsClient;
|
||||
@Autowired
|
||||
private CommonChannelService commonChannelService;
|
||||
@Value("${yo.fsagent.ivr-transfer.call-data-timeout-seconds:120}")
|
||||
private long callDataTimeoutSeconds;
|
||||
|
||||
public IvrTransferServiceImpl(
|
||||
@Autowired
|
||||
final RedissonClient redisson) {
|
||||
|
||||
this.CALL_DATA_CACHE = redisson.getMapCache("CALL_DATA_CACHE");
|
||||
}
|
||||
@Autowired
|
||||
private CommonCallDataService commonCallDataService;
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
@ -82,7 +71,7 @@ public class IvrTransferServiceImpl implements IvrTransferService {
|
||||
"confirm.IVR/XML/" + realm);
|
||||
|
||||
if (StringUtils.isNotBlank(callData)) {
|
||||
saveCallData(agentId, callData);
|
||||
commonCallDataService.saveIvrCallData(agentId, callData);
|
||||
}
|
||||
}
|
||||
|
||||
@ -102,26 +91,6 @@ public class IvrTransferServiceImpl implements IvrTransferService {
|
||||
return agentFifo(realm, agentId, DialplanService.Suffix.CHANNEL_UNHOLD);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void saveCallData(final String agentId, final String callData) {
|
||||
CALL_DATA_CACHE.put(
|
||||
cacheKey(agentId),
|
||||
callData,
|
||||
callDataTimeoutSeconds,
|
||||
TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public String getCallData(final String agentId) {
|
||||
return CALL_DATA_CACHE.get(cacheKey(agentId));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@ -131,8 +100,4 @@ public class IvrTransferServiceImpl implements IvrTransferService {
|
||||
final DialplanService.Suffix suffix) {
|
||||
return "AGENT_" + agentId + suffix.getSuffix() + "/XML/" + realm;
|
||||
}
|
||||
|
||||
String cacheKey(final String agentId) {
|
||||
return "IVR_CALL_DATA:" + agentId;
|
||||
}
|
||||
}
|
||||
|
@ -2,26 +2,27 @@ package com.pudonghot.yo.fsagent.service.impl;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.pudonghot.yo.fsagent.service.GatewayService;
|
||||
import com.pudonghot.yo.fsagent.service.TrunkService;
|
||||
import com.pudonghot.yo.mapper.GatewayMapper;
|
||||
import com.pudonghot.yo.mapper.SequenceMapper;
|
||||
import com.pudonghot.yo.mapper.TrunkMapper;
|
||||
import com.pudonghot.yo.mapper.TrunkStrategyMapper;
|
||||
import com.pudonghot.yo.model.domain.Gateway;
|
||||
import com.pudonghot.yo.model.domain.Sequence;
|
||||
import com.pudonghot.yo.model.domain.Trunk;
|
||||
import com.pudonghot.yo.model.domain.TrunkStrategy;
|
||||
import com.wacai.tigon.mybatis.Search;
|
||||
import com.pudonghot.yo.util.PhoneNumberUtils;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import com.wacai.tigon.mybatis.Search;
|
||||
import org.springframework.util.Assert;
|
||||
import com.pudonghot.yo.mapper.TrunkMapper;
|
||||
import com.pudonghot.yo.model.domain.Trunk;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.RandomUtils;
|
||||
import com.pudonghot.yo.mapper.GatewayMapper;
|
||||
import com.pudonghot.yo.model.domain.Gateway;
|
||||
import com.pudonghot.yo.mapper.SequenceMapper;
|
||||
import com.pudonghot.yo.model.domain.Sequence;
|
||||
import org.springframework.stereotype.Service;
|
||||
import com.pudonghot.yo.cellphone.CellphoneInfo;
|
||||
import com.pudonghot.yo.mapper.TrunkStrategyMapper;
|
||||
import com.pudonghot.yo.model.domain.TrunkStrategy;
|
||||
import com.pudonghot.yo.cellphone.CellphoneService;
|
||||
import com.pudonghot.yo.fsagent.service.TrunkService;
|
||||
import com.pudonghot.yo.fsagent.service.GatewayService;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import com.wacai.tigon.service.support.BaseQueryServiceSupport;
|
||||
|
||||
@ -69,7 +70,7 @@ public class TrunkServiceImpl
|
||||
Assert.state(TrunkStrategy.Strategy.RANDOM == trunkStrategy.getStrategy(),
|
||||
"Random trunk strategy supports only");
|
||||
|
||||
final List<Trunk> trunks = mapper.listOfStrategyId(strategyId);
|
||||
final List<Trunk> trunks = mapper.listOfStrategy(strategyId);
|
||||
Assert.state(!trunks.isEmpty(),
|
||||
() -> "No trunk found of strategy [" + trunkStrategy.getName() + "]");
|
||||
|
||||
@ -127,8 +128,11 @@ public class TrunkServiceImpl
|
||||
new Search(Trunk.TENANT_ID, tenantId)
|
||||
.eq(Trunk.PREFIX, prefix)
|
||||
.eq(Trunk.ACTIVE, true));
|
||||
|
||||
if (trunk != null) {
|
||||
return Pair.of(trunk, calledNumber.substring(prefixLength));
|
||||
return Pair.of(trunk,
|
||||
PhoneNumberUtils.cleanupMobile(
|
||||
calledNumber.substring(prefixLength)));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -41,7 +41,7 @@ dubbo.application.qos-port=22222
|
||||
dubbo.application.qos-accept-foreign-ip=false
|
||||
|
||||
## Dubbo Registry
|
||||
dubbo.registry.address=zookeeper://172.16.67.223:2181
|
||||
dubbo.registry.address=zookeeper://172.18.4.35:2181
|
||||
dubbo.registry.file=${user.home}/dubbo-cache/${spring.application.name}/dubbo.cache
|
||||
|
||||
# Service Version
|
||||
|
@ -5,22 +5,11 @@
|
||||
<extension name="CampaignToAgent">
|
||||
<condition>
|
||||
<!-- <#noparse> -->
|
||||
<action application="set" data="absolute_codec_string=PCMA" />
|
||||
<!--<action application="set" data="ringback=$${us-ring}" />-->
|
||||
<!--<action application="set" data="transfer_ringback=$${hold_music}" />-->
|
||||
<action application="set" data="call_timeout=30" />
|
||||
<action application="set" data="hangup_after_bridge=true" />
|
||||
<action application="set" data="continue_on_fail=true" />
|
||||
<!-- </#noparse> -->
|
||||
|
||||
<action application="set" data="x_conn_id=${connId}" />
|
||||
<action application="set" data="x_role=CALLED" />
|
||||
<action application="set" data="x_tenant_id=${tenant.id}" />
|
||||
<action application="set" data="x_tenant_code=${tenant.code}" />
|
||||
<action application="set" data="x_account=${calledAgent.account}" />
|
||||
|
||||
<action application="set" data="x_dial_type=CAMPAIGN" />
|
||||
<action application="set" data="x_call_type=OUTBOUND" />
|
||||
<action application="set" data="x_agent_type=${calledAgent.type}" />
|
||||
|
||||
<!-- Recording -->
|
||||
@ -33,16 +22,16 @@
|
||||
"originate_timeout=30",
|
||||
"odbc-cdr-ignore-leg=true",
|
||||
"origination_uuid=${connId}",
|
||||
"sip_invite_call_id=${r'${sip_call_id}'}",
|
||||
|
||||
"origination_caller_id_number=${privacyNumber.number}",
|
||||
"origination_caller_id_name=${privacyNumber.name}",
|
||||
"sip_contact_user=${privacyNumber.number}",
|
||||
|
||||
"sip_invite_call_id=${r'${sip_call_id}'}",
|
||||
|
||||
"x_role=CALLER",
|
||||
"x_account=${calledAgent.account}",
|
||||
"x_agent_type=${calledAgent.type}",
|
||||
"x_called_number=${calledNumber}",
|
||||
|
||||
"x_tenant_id=${tenant.id}",
|
||||
"x_tenant_code=${tenant.code}",
|
||||
|
@ -18,6 +18,9 @@
|
||||
<action application="set" data="x_dial_type=MANUAL" />
|
||||
<action application="set" data="x_call_type=OUTBOUND" />
|
||||
|
||||
<action application="set" data="effective_caller_id_number=${trunk.cpn}" />
|
||||
<action application="set" data="effective_caller_id_name=${trunk.cpn}" />
|
||||
|
||||
<!-- Recording -->
|
||||
<#include "rec.xml">
|
||||
<!-- /Recording -->
|
||||
@ -34,20 +37,16 @@
|
||||
"x_dial_type=MANUAL",
|
||||
"x_call_type=OUTBOUND",
|
||||
"x_agent_type=${callerAgent.type}",
|
||||
"x_called_number=${targetNumber}",
|
||||
"x_called_number=${calledNumber}",
|
||||
"x_trunk_id=${trunk.id}",
|
||||
"x_cpn=${trunk.cpn}",
|
||||
|
||||
"origination_uuid=${connId}",
|
||||
"sip_invite_call_id=${r'${sip_call_id}'}",
|
||||
|
||||
"sip_contact_user=${callerAgent.agent}",
|
||||
"callee_id_number=${callerAgent.agent}",
|
||||
"callee_id_name=${callerAgent.account}",
|
||||
"sip_h_Call-Info=${callerAgent.agent}@${tenant.realm}",
|
||||
|
||||
"sip_from_user=${trunk.cpn}",
|
||||
"origination_caller_id_number=${trunk.cpn}",
|
||||
"origination_caller_id_name=${callerAgent.account}"
|
||||
"origination_caller_id_name=${trunk.cpn}"
|
||||
]>
|
||||
-->
|
||||
|
||||
|
@ -0,0 +1,18 @@
|
||||
package com.pudonghot.yo.fsagent.api;
|
||||
|
||||
import java.util.List;
|
||||
import com.pudonghot.yo.fsagent.api.request.ReqCampaignDial;
|
||||
|
||||
/**
|
||||
* @author Donghuang <br>
|
||||
* Dec 09, 2019 16:25:19
|
||||
*/
|
||||
public interface CampaignDialService {
|
||||
|
||||
/**
|
||||
* campaign dial
|
||||
* @param req request
|
||||
* @return call uuid
|
||||
*/
|
||||
List<String> queueDial(ReqCampaignDial req);
|
||||
}
|
@ -33,20 +33,4 @@ public interface IvrTransferService {
|
||||
* @return agent unhold fifo dialplan name
|
||||
*/
|
||||
String agentUnholdFifo(String realm, String agentId);
|
||||
|
||||
/**
|
||||
* save call data
|
||||
*
|
||||
* @param agentId agent id
|
||||
* @param callData call data
|
||||
*/
|
||||
void saveCallData(String agentId, String callData);
|
||||
|
||||
/**
|
||||
* get call data
|
||||
*
|
||||
* @param agentId agent id
|
||||
* @return call data
|
||||
*/
|
||||
String getCallData(String agentId);
|
||||
}
|
||||
|
@ -0,0 +1,20 @@
|
||||
package com.pudonghot.yo.fsagent.api.request;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
import java.util.List;
|
||||
import java.io.Serializable;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
/**
|
||||
* @author Donghuang
|
||||
* @date Mar 24, 2020 15:22:13
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString
|
||||
public class ReqCampaignDial implements Serializable {
|
||||
private Integer campaignId;
|
||||
private List<Pair<String, String>> callingList;
|
||||
}
|
@ -141,6 +141,26 @@ public class Event {
|
||||
return getHeader("variable_x_conn_id");
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method.
|
||||
* get called number
|
||||
*
|
||||
* @return called number
|
||||
*/
|
||||
public String getCalledNumber() {
|
||||
return getHeader("variable_x_called_number");
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method.
|
||||
* get dial type
|
||||
*
|
||||
* @return dial type
|
||||
*/
|
||||
public String getDialType() {
|
||||
return getHeader("variable_x_dial_type");
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method.
|
||||
* get other number
|
||||
|
@ -32,6 +32,34 @@ public interface AgentStatusMapper extends BaseMapper<Integer, AgentStatus> {
|
||||
@Param("lockKey") String lockKey,
|
||||
@Param("limit") int limit);
|
||||
|
||||
/**
|
||||
* count online agent of queue
|
||||
* @param queueId queue id
|
||||
* @return online agent count of queue
|
||||
*/
|
||||
int countOnlineOfQueue(@Param("queueId") Integer queueId);
|
||||
|
||||
/**
|
||||
* count idle agent of queue
|
||||
* @param queueId queue id
|
||||
* @return idle agent count of queue
|
||||
*/
|
||||
int countIdleOfQueue(@Param("queueId") Integer queueId);
|
||||
|
||||
/**
|
||||
* count online agent of group
|
||||
* @param groupId group id
|
||||
* @return online agent count of group
|
||||
*/
|
||||
int countOnlineOfGroup(@Param("groupId") Integer groupId);
|
||||
|
||||
/**
|
||||
* count idle agent of group
|
||||
* @param groupId group id
|
||||
* @return idle agent count of group
|
||||
*/
|
||||
int countIdleOfGroup(@Param("groupId") Integer groupId);
|
||||
|
||||
/**
|
||||
* ACW clean up
|
||||
*
|
||||
|
@ -32,27 +32,7 @@
|
||||
update <include refid="table" /> s
|
||||
join (
|
||||
select s.id
|
||||
from <include refid="table"/> s
|
||||
|
||||
join br_agent a
|
||||
on a.id = s.agent_id
|
||||
|
||||
join br_queue_agent qa
|
||||
on qa.agent_id = a.id
|
||||
|
||||
where qa.queue_id = #{queueId}
|
||||
and a.active = 1
|
||||
and s.registered = 1
|
||||
and s.state = 'IDLE'
|
||||
and (s.status = 'READY' or
|
||||
(s.status = 'ACW' and
|
||||
<![CDATA[
|
||||
s.acw_time <= now() - interval a.wrap_up_time second
|
||||
]]>
|
||||
)
|
||||
)
|
||||
and s.lock_key is null
|
||||
|
||||
<include refid="idleOfQueue" />
|
||||
<if test="limit > 0">
|
||||
order by rand()
|
||||
limit #{limit}
|
||||
@ -60,7 +40,6 @@
|
||||
) t
|
||||
on s.id = t.id
|
||||
set s.lock_key = #{lockKey},
|
||||
s.status = 'READY',
|
||||
s.acw_time = null,
|
||||
s.updated_time = now()
|
||||
</update>
|
||||
@ -69,23 +48,7 @@
|
||||
update <include refid="table" /> s
|
||||
join (
|
||||
select s.id
|
||||
from <include refid="table"/> s
|
||||
|
||||
join br_agent a
|
||||
on a.id = s.agent_id
|
||||
|
||||
where a.group_id = #{groupId}
|
||||
and a.active = 1
|
||||
and s.registered = 1
|
||||
and s.state = 'IDLE'
|
||||
and (s.status = 'READY' or
|
||||
(s.status = 'ACW' and
|
||||
<![CDATA[
|
||||
s.acw_time < now() - interval a.wrap_up_time second
|
||||
]]>
|
||||
)
|
||||
)
|
||||
and s.lock_key is null
|
||||
<include refid="idleOfGroup" />
|
||||
|
||||
<if test="limit > 0">
|
||||
order by rand()
|
||||
@ -94,11 +57,49 @@
|
||||
) t
|
||||
on s.id = t.id
|
||||
set s.lock_key = #{lockKey},
|
||||
s.status = 'READY',
|
||||
s.acw_time = null,
|
||||
s.updated_time = now()
|
||||
</update>
|
||||
|
||||
<select id="countOnlineOfQueue" resultType="int">
|
||||
select count(s.id)
|
||||
from <include refid="table"/> s
|
||||
|
||||
join br_agent a
|
||||
on a.id = s.agent_id
|
||||
|
||||
join br_queue_agent qa
|
||||
on qa.agent_id = a.id
|
||||
|
||||
where qa.queue_id = #{queueId}
|
||||
and a.active = 1
|
||||
and s.registered = 1
|
||||
and s.status = 'READY'
|
||||
</select>
|
||||
|
||||
<select id="countIdleOfQueue" resultType="int">
|
||||
select count(s.id)
|
||||
<include refid="idleOfQueue" />
|
||||
</select>
|
||||
|
||||
<select id="countOnlineOfGroup" resultType="int">
|
||||
select count(s.id)
|
||||
from <include refid="table"/> s
|
||||
|
||||
join br_agent a
|
||||
on a.id = s.agent_id
|
||||
|
||||
where a.group_id = #{groupId}
|
||||
and a.active = 1
|
||||
and s.registered = 1
|
||||
and s.status = 'READY'
|
||||
</select>
|
||||
|
||||
<select id="countIdleOfGroup" resultType="int">
|
||||
select count(s.id)
|
||||
<include refid="idleOfGroup" />
|
||||
</select>
|
||||
|
||||
<update id="acwCleanup">
|
||||
update <include refid="table" /> s
|
||||
|
||||
@ -115,4 +116,41 @@
|
||||
where s.state = 'ACW'
|
||||
and s.acw_time is not null
|
||||
</update>
|
||||
|
||||
<sql id="idleOfQueue">
|
||||
from <include refid="table"/> s
|
||||
|
||||
join br_agent a
|
||||
on a.id = s.agent_id
|
||||
|
||||
join br_queue_agent qa
|
||||
on qa.agent_id = a.id
|
||||
|
||||
where qa.queue_id = #{queueId}
|
||||
<include refid="idleCondition" />
|
||||
</sql>
|
||||
|
||||
<sql id="idleOfGroup">
|
||||
from <include refid="table"/> s
|
||||
|
||||
join br_agent a
|
||||
on a.id = s.agent_id
|
||||
|
||||
where a.group_id = #{groupId}
|
||||
<include refid="idleCondition" />
|
||||
</sql>
|
||||
|
||||
<sql id="idleCondition">
|
||||
and a.active = 1
|
||||
and s.registered = 1
|
||||
and s.status = 'READY'
|
||||
and s.lock_key is null
|
||||
and (s.state = 'IDLE' or
|
||||
(s.status = 'ACW' and
|
||||
<![CDATA[
|
||||
s.acw_time < now() - interval a.wrap_up_time second
|
||||
]]>
|
||||
)
|
||||
)
|
||||
</sql>
|
||||
</mapper>
|
||||
|
@ -12,22 +12,43 @@ import com.pudonghot.yo.model.domain.Trunk;
|
||||
public interface TrunkMapper extends BaseMapper<Integer, Trunk> {
|
||||
|
||||
/**
|
||||
* list trunks of agent group id
|
||||
* list trunks of strategy
|
||||
*
|
||||
* @param strategyId strategy id
|
||||
* @return outbound prefixes
|
||||
* @return trunks
|
||||
*/
|
||||
List<Trunk> listOfStrategyId(
|
||||
List<Trunk> listOfStrategy(
|
||||
@Param("strategyId")
|
||||
Integer strategyId);
|
||||
|
||||
|
||||
/**
|
||||
* find trunk of strategy
|
||||
*
|
||||
* @param strategyId strategy id
|
||||
* @return trunk found
|
||||
*/
|
||||
Trunk findOfStrategy(
|
||||
@Param("strategyId")
|
||||
Integer strategyId);
|
||||
|
||||
/**
|
||||
* list trunks of agent group id
|
||||
* list trunks of agent group
|
||||
*
|
||||
* @param agentGroupId agent group id
|
||||
* @return outbound prefixes
|
||||
* @return trunks found
|
||||
*/
|
||||
List<Trunk> listOfAgentGroupId(
|
||||
List<Trunk> listOfAgentGroup(
|
||||
@Param("agentGroupId")
|
||||
Integer agentGroupId);
|
||||
|
||||
/**
|
||||
* find trunk of agent group
|
||||
*
|
||||
* @param agentGroupId agent group id
|
||||
* @return trunk found
|
||||
*/
|
||||
Trunk findOfAgentGroup(
|
||||
@Param("agentGroupId")
|
||||
Integer agentGroupId);
|
||||
}
|
||||
|
@ -9,7 +9,17 @@
|
||||
-->
|
||||
<mapper namespace="com.pudonghot.yo.mapper.TrunkMapper">
|
||||
|
||||
<select id="listOfStrategyId" resultType="com.pudonghot.yo.model.domain.Trunk">
|
||||
<select id="listOfStrategy" resultType="com.pudonghot.yo.model.domain.Trunk">
|
||||
<include refid="selectOfStrategy" />
|
||||
</select>
|
||||
|
||||
<select id="findOfStrategyId" resultType="com.pudonghot.yo.model.domain.Trunk">
|
||||
<include refid="selectOfStrategy" />
|
||||
order by rand()
|
||||
limit 1
|
||||
</select>
|
||||
|
||||
<sql id="selectOfStrategy">
|
||||
select t.* from br_trunk t
|
||||
|
||||
join br_gateway gw
|
||||
@ -30,9 +40,19 @@
|
||||
|
||||
where ts.id = #{strategyId}
|
||||
and t.active = 1
|
||||
</sql>
|
||||
|
||||
<select id="listOfAgentGroup" resultType="com.pudonghot.yo.model.domain.Trunk">
|
||||
<include refid="selectOfStrategy" />
|
||||
</select>
|
||||
|
||||
<select id="listOfAgentGroupId" resultType="com.pudonghot.yo.model.domain.Trunk">
|
||||
<select id="findOfAgentGroup" resultType="com.pudonghot.yo.model.domain.Trunk">
|
||||
<include refid="selectOfStrategy" />
|
||||
order by rand()
|
||||
limit 1
|
||||
</select>
|
||||
|
||||
<sql id="listOfAgentGroup">
|
||||
select t.* from br_trunk t
|
||||
|
||||
join br_gateway gw
|
||||
@ -55,7 +75,7 @@
|
||||
|
||||
where agts.agent_group_id = #{agentGroupId}
|
||||
and t.active = 1
|
||||
</select>
|
||||
</sql>
|
||||
|
||||
<select id="list" resultType="com.pudonghot.yo.model.domain.Trunk">
|
||||
select
|
||||
|
@ -1,11 +1,33 @@
|
||||
package com.pudonghot.yo.mapper;
|
||||
|
||||
import com.pudonghot.yo.model.domain.TrunkStrategy;
|
||||
import java.util.List;
|
||||
import com.wacai.tigon.mybatis.BaseMapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import com.pudonghot.yo.model.domain.TrunkStrategy;
|
||||
|
||||
/**
|
||||
* @author Donghuang <br>
|
||||
* Nov 30, 2019 18:42:04
|
||||
*/
|
||||
public interface TrunkStrategyMapper extends BaseMapper<Integer, TrunkStrategy> {
|
||||
|
||||
/**
|
||||
* list trunk strategies of campaign
|
||||
*
|
||||
* @param campaignId campaign id
|
||||
* @return trunk strategies of campaign
|
||||
*/
|
||||
List<TrunkStrategy> listOfCampaign(
|
||||
@Param("campaignId")
|
||||
Integer campaignId);
|
||||
|
||||
/**
|
||||
* list trunk strategies of agent group
|
||||
*
|
||||
* @param agentGroupId agent group id
|
||||
* @return trunk strategies of agent group
|
||||
*/
|
||||
List<TrunkStrategy> listOfAgentGroup(
|
||||
@Param("agentGroupId")
|
||||
Integer agentGroupId);
|
||||
}
|
||||
|
@ -8,4 +8,23 @@
|
||||
*/
|
||||
-->
|
||||
<mapper namespace="com.pudonghot.yo.mapper.TrunkStrategyMapper">
|
||||
|
||||
<select id="listOfCampaign" resultType="com.pudonghot.yo.model.domain.TrunkStrategy">
|
||||
select t.* from
|
||||
<include refid="table" /> t
|
||||
join br_campaign_trunk_strategy cts
|
||||
on t.id = cts.trunk_strategy_id
|
||||
where cts.campaign_id = #{campaignId}
|
||||
and t.active = 1
|
||||
</select>
|
||||
|
||||
<select id="listOfAgentGroup" resultType="com.pudonghot.yo.model.domain.TrunkStrategy">
|
||||
select t.* from
|
||||
<include refid="table" /> t
|
||||
join br_agent_group_trunk_strategy agts
|
||||
on t.id = agts.trunk_strategy_id
|
||||
where agts.agent_group_id = #{agentGroupId}
|
||||
and t.active = 1
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
|
@ -32,6 +32,10 @@ public class AgentStatusMapperTest {
|
||||
|
||||
@Test
|
||||
public void testAcwCleanup() {
|
||||
mapper.countOnlineOfQueue(1);
|
||||
mapper.countIdleOfQueue(1);
|
||||
mapper.countOnlineOfGroup(1);
|
||||
mapper.countIdleOfGroup(1);
|
||||
mapper.acwCleanup();
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,10 @@
|
||||
package com.pudonghot.yo.model;
|
||||
|
||||
import lombok.Getter;
|
||||
import java.util.Date;
|
||||
import java.time.ZoneId;
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
import com.pudonghot.yo.util.TimeUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import com.fasterxml.jackson.annotation.JsonValue;
|
||||
@ -34,6 +37,16 @@ public class DailyTime implements Serializable {
|
||||
this.val = val;
|
||||
}
|
||||
|
||||
public boolean before(final Date date) {
|
||||
return secondOfDay < LocalDateTime.ofInstant(date.toInstant(),
|
||||
ZoneId.systemDefault()).toLocalTime().toSecondOfDay();
|
||||
}
|
||||
|
||||
public boolean after(final Date date) {
|
||||
return secondOfDay > LocalDateTime.ofInstant(date.toInstant(),
|
||||
ZoneId.systemDefault()).toLocalTime().toSecondOfDay();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
|
@ -1,10 +1,14 @@
|
||||
package com.pudonghot.yo;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import org.junit.Test;
|
||||
import java.util.Date;
|
||||
import java.time.LocalTime;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import com.pudonghot.yo.model.DailyTime;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.pudonghot.yo.model.agentevent.AgentEvent;
|
||||
import org.junit.Test;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.time.DateFormatUtils;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
|
||||
/**
|
||||
* @author Donghuang <br>
|
||||
@ -26,4 +30,20 @@ public class TestDriver {
|
||||
final String result = objectMapper.writeValueAsString(agentEvent);
|
||||
log.info("Result: [{}].", result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDailyTime() {
|
||||
log.info("ToSecondOfDay: [{}].", LocalTime.now().toSecondOfDay());
|
||||
log.info("SecondOfDay: [{}].",
|
||||
new DailyTime(DateFormatUtils.format(new Date(), "HH:mm")).getSecondOfDay());
|
||||
|
||||
log.info("DailyTime: [{}].", new DailyTime("09:11").getSecondOfDay());
|
||||
log.info("DailyTime: [{}].", new DailyTime("00:00"));
|
||||
log.info("DailyTime: [{}].", new DailyTime("19:00:04"));
|
||||
log.info("DailyTime: [{}].", new DailyTime("23:00").getSecondOfDay());
|
||||
log.info("DailyTime: [{}].", new DailyTime("09:00:04").getSecondOfDay());
|
||||
log.info("DailyTime: [{}].", new DailyTime("00:00").getSecondOfDay());
|
||||
log.info("DailyTime: [{}].", new DailyTime("09:00").before(new Date()));
|
||||
log.info("DailyTime: [{}].", new DailyTime("23:00:03").after(new Date()));
|
||||
}
|
||||
}
|
||||
|
BIN
lib/ops/install-springboot-app/cas.zip
Normal file
BIN
lib/ops/install-springboot-app/cas.zip
Normal file
Binary file not shown.
BIN
lib/ops/install-springboot-app/fs-conf.zip
Normal file
BIN
lib/ops/install-springboot-app/fs-conf.zip
Normal file
Binary file not shown.
@ -16,13 +16,20 @@ get_real_path() {
|
||||
}
|
||||
|
||||
install_server() {
|
||||
SERVER="$1"
|
||||
APP="$2"
|
||||
TARGET_DIR="/data/program/$APP"
|
||||
LOGS_DIR="/data/program/logs/$APP"
|
||||
ssh "$SERVER" "mkdir -p $TARGET_DIR"
|
||||
ssh "$SERVER" "tar -xzv -C $TARGET_DIR" < springboot-app.tar.gz
|
||||
ssh "$SERVER" "mkdir -p $LOGS_DIR && ln -sf $LOGS_DIR $TARGET_DIR/logs"
|
||||
local SERVER="$1"
|
||||
local APP="$2"
|
||||
local PORT="$3"
|
||||
if [ -z "$PORT" ]; then
|
||||
PORT='22'
|
||||
fi
|
||||
|
||||
local BASE_DIR='/data/program'
|
||||
local TARGET_DIR="$BASE_DIR/$APP"
|
||||
local LOGS_DIR="$BASE_DIR/logs/$APP"
|
||||
|
||||
ssh -p "$PORT" "$SERVER" "mkdir -p $TARGET_DIR"
|
||||
ssh -p "$PORT" "$SERVER" "tar -xzv -C $TARGET_DIR" < springboot-app.tar.gz
|
||||
ssh -p "$PORT" "$SERVER" "mkdir -p $LOGS_DIR && ln -sf $LOGS_DIR $TARGET_DIR/logs"
|
||||
}
|
||||
|
||||
|
||||
@ -42,8 +49,9 @@ fi
|
||||
if [ "$2" == "test" ]; then
|
||||
echo "Install test."
|
||||
install_server 'appweb@118.24.251.131' $1
|
||||
elif ["$2" == "prod" ]; then
|
||||
echo "Deploy prod."
|
||||
elif [ "$2" == "prod" ]; then
|
||||
echo "Install prod."
|
||||
install_server 'xiandou@113.87.175.72' $1 '51022'
|
||||
fi
|
||||
|
||||
popd > /dev/null
|
||||
|
@ -0,0 +1,63 @@
|
||||
package com.pudonghot.yo.service;
|
||||
|
||||
/**
|
||||
* @author Donghuang
|
||||
* @date Jul 23, 2020 09:57:09
|
||||
*/
|
||||
public interface CommonCallDataService {
|
||||
|
||||
/**
|
||||
* save call data
|
||||
*
|
||||
* @param agentId agent id
|
||||
* @param callData call data
|
||||
*/
|
||||
void saveIvrCallData(String agentId, String callData);
|
||||
|
||||
/**
|
||||
* get call data
|
||||
*
|
||||
* @param agentId agent id
|
||||
* @return call data
|
||||
*/
|
||||
String getIvrCallData(String agentId);
|
||||
|
||||
|
||||
/**
|
||||
* save call data
|
||||
*
|
||||
* @param callUuid call uuid
|
||||
* @param callData call data
|
||||
*/
|
||||
void saveCampaignCallData(String callUuid, String callData);
|
||||
|
||||
/**
|
||||
* get call data
|
||||
*
|
||||
* @param callUuid call uuid
|
||||
* @return call data
|
||||
*/
|
||||
String getCampaignCallData(String callUuid);
|
||||
|
||||
/**
|
||||
* get campaign channel
|
||||
*
|
||||
* @param campaignId campaign id
|
||||
* @return count of campaign channel
|
||||
*/
|
||||
int getCampaignChannel(Integer campaignId);
|
||||
|
||||
/**
|
||||
* increase campaign channel
|
||||
*
|
||||
* @param campaignId campaign id
|
||||
*/
|
||||
int incrCampaignChannel(Integer campaignId);
|
||||
|
||||
/**
|
||||
* decrease campaign channel
|
||||
*
|
||||
* @param campaignId campaign id
|
||||
*/
|
||||
int decrCampaignChannel(Integer campaignId);
|
||||
}
|
@ -16,7 +16,6 @@ import com.pudonghot.yo.service.CommonChannelService;
|
||||
import com.pudonghot.yo.service.CommonDelayScheduleService;
|
||||
import com.pudonghot.yo.service.CommonAgentStatusService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import static com.pudonghot.yo.model.exception.ErrorCode.AGENT_UPDATE_STATUS_FAIL;
|
||||
|
||||
/**
|
||||
* @author Donghuang <br>
|
||||
@ -198,7 +197,7 @@ public class CommonAgentStatusServiceImpl
|
||||
@Override
|
||||
public void inACall(final Agent agent) {
|
||||
log.info("Agent [{}] in a call.", agent);
|
||||
updateState(agent);
|
||||
updateState(agent, AgentStatus.State.IN_A_CALL);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -216,8 +215,11 @@ public class CommonAgentStatusServiceImpl
|
||||
public void acw(final Agent agent) {
|
||||
log.info("ACW agent [{}].", agent);
|
||||
|
||||
final AgentStatus agentStatus = findInACallAgentStatus(agent);
|
||||
final AgentStatus agentStatus =
|
||||
findInACallAgentStatus(agent);
|
||||
|
||||
if (agentStatus == null) {
|
||||
log.info("No agent status found, ignore.");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -227,7 +229,7 @@ public class CommonAgentStatusServiceImpl
|
||||
delayScheduleService.acw(agent);
|
||||
}
|
||||
else {
|
||||
setState(agent, agentStatus);
|
||||
agentStatus.setState(AgentStatus.State.IDLE);
|
||||
}
|
||||
|
||||
log.info("Update agent status [{}].", agentStatus);
|
||||
@ -260,8 +262,12 @@ public class CommonAgentStatusServiceImpl
|
||||
log.info("End ACW agent [{}].", agent);
|
||||
|
||||
final AgentStatus agentStatus = findValidAgentStatus(agent);
|
||||
AssertUtils.state(agentStatus.getState() == AgentStatus.State.ACW,
|
||||
AGENT_UPDATE_STATUS_FAIL);
|
||||
|
||||
if (agentStatus.getState() != AgentStatus.State.ACW) {
|
||||
log.info("Current state is not ACW, ignore.");
|
||||
return;
|
||||
}
|
||||
|
||||
clear(agentStatus);
|
||||
setState(agent, agentStatus);
|
||||
agentStatus.setAcwTime(null);
|
||||
@ -283,8 +289,7 @@ public class CommonAgentStatusServiceImpl
|
||||
@Override
|
||||
public void idle(final Agent agent) {
|
||||
log.info("Idle agent [{}] call [{}].", agent);
|
||||
|
||||
updateState(agent);
|
||||
updateState(agent, AgentStatus.State.IDLE);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -319,10 +324,10 @@ public class CommonAgentStatusServiceImpl
|
||||
return agentStatus;
|
||||
}
|
||||
|
||||
private void updateState(final Agent agent) {
|
||||
private void updateState(final Agent agent, final AgentStatus.State state) {
|
||||
final AgentStatus agentStatus = findValidAgentStatus(agent);
|
||||
clear(agentStatus);
|
||||
setState(agent, agentStatus);
|
||||
agentStatus.setState(state);
|
||||
|
||||
log.info("Update agent status [{}].", agentStatus);
|
||||
agentStatusMapper.update(agentStatus);
|
||||
|
@ -0,0 +1,101 @@
|
||||
package com.pudonghot.yo.service.impl;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.redisson.api.RMapCache;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import org.redisson.api.RedissonClient;
|
||||
import com.pudonghot.yo.service.CommonCallDataService;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
|
||||
/**
|
||||
* @author Donghuang
|
||||
* @date Jul 23, 2020 10:04:23
|
||||
*/
|
||||
@Slf4j
|
||||
public class CommonCallDataServiceImpl implements CommonCallDataService {
|
||||
private final RMapCache<String, String> CACHE;
|
||||
private final RMapCache<Integer, Integer> CAMPAIGN_CHANNEL;
|
||||
@Value("${yo.common-service.call-data.timeout-seconds:120}")
|
||||
private long callDataTimeoutSeconds;
|
||||
|
||||
public CommonCallDataServiceImpl(final RedissonClient redisson) {
|
||||
this.CACHE = redisson.getMapCache("CALL_DATA");
|
||||
this.CAMPAIGN_CHANNEL = redisson.getMapCache("CAMPAIGN_CHANNEL");
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void saveIvrCallData(final String agentId, final String callData) {
|
||||
log.info("Save IVR call data [{}] -> [{}].", agentId, callData);
|
||||
put(ivrCacheKey(agentId), callData);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public String getIvrCallData(final String agentId) {
|
||||
log.debug("Get IVR call data [{}].", agentId);
|
||||
return CACHE.get(ivrCacheKey(agentId));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void saveCampaignCallData(String callUuid, String callData) {
|
||||
log.info("Save campaign call data [{}] -> [{}].", callUuid, callData);
|
||||
put(callUuid, callData);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public String getCampaignCallData(final String callUuid) {
|
||||
log.debug("Get campaign call data [{}].", callUuid);
|
||||
return CACHE.get(callUuid);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public int getCampaignChannel(final Integer campaignId) {
|
||||
final int val = CAMPAIGN_CHANNEL.getOrDefault(campaignId, 0);
|
||||
log.debug("Get campaign [{}] channel [{}].", campaignId, val);
|
||||
return val;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public int incrCampaignChannel(final Integer campaignId) {
|
||||
final int val = CAMPAIGN_CHANNEL.addAndGet(campaignId, 1);
|
||||
log.debug("Increase campaign [{}] channel [{}].", campaignId, val);
|
||||
return val;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public int decrCampaignChannel(final Integer campaignId) {
|
||||
final int val = CAMPAIGN_CHANNEL.addAndGet(campaignId, -1);
|
||||
log.debug("Decrease campaign [{}] channel [{}].", campaignId, val);
|
||||
return val;
|
||||
}
|
||||
|
||||
private void put(final String key, final String value) {
|
||||
log.debug("Call data cache [{}] -> [{}].", key, value);
|
||||
CACHE.put(
|
||||
key, value, callDataTimeoutSeconds, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
private String ivrCacheKey(final String agentId) {
|
||||
return "IVR_CALL_DATA:" + agentId;
|
||||
}
|
||||
}
|
@ -8,4 +8,5 @@
|
||||
<bean class="com.pudonghot.yo.service.impl.CommonAgentStatusServiceImpl" />
|
||||
<bean class="com.pudonghot.yo.service.impl.CommonAgentEventQueueServiceImpl" />
|
||||
<bean class="com.pudonghot.yo.service.impl.CommonChannelServiceImpl" />
|
||||
<bean class="com.pudonghot.yo.service.impl.CommonCallDataServiceImpl" />
|
||||
</beans>
|
||||
|
@ -0,0 +1,26 @@
|
||||
package com.pudonghot.yo.service;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
/**
|
||||
* @author Donghuang
|
||||
* @date Jul 23, 2020 19:44:47
|
||||
*/
|
||||
@Slf4j
|
||||
@SpringBootTest(classes = TestDriver.class)
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
public class CommonCallDataServiceTest {
|
||||
@Autowired
|
||||
private CommonCallDataService callDataService;
|
||||
|
||||
@Test
|
||||
public void testRun() {
|
||||
log.info("Channels [{}].", callDataService.incrCampaignChannel(1));
|
||||
log.info("Channels [{}].", callDataService.decrCampaignChannel(2));
|
||||
}
|
||||
}
|
@ -1,56 +0,0 @@
|
||||
package com.pudonghot.yo.common.util;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
|
||||
/**
|
||||
* 手机号工具类
|
||||
* Created by bingpo on 17/12/28.
|
||||
*/
|
||||
public class MobileUtils {
|
||||
|
||||
public static final int MOBILE_LENGTH = 11;
|
||||
private static final String MOBILE_REG_EXP = "^1(3[0-9]|4[579]|5[0-35-9]|7[0135678]|8[0-9])\\d{8}$";
|
||||
|
||||
/**
|
||||
* 验证手机号码
|
||||
* <p>
|
||||
* 移动号码段:134,135,136,137,138,139,147,150,151,152,157,158,159,170,178,182,183,184,187,188
|
||||
* 联通号码段:130,131,132,145,155,156,171,175,176,185,186
|
||||
* 电信号码段:133,149,153,170,173,177,180,181,189
|
||||
*
|
||||
* @param mobile 手机号
|
||||
* @return 是否为手机号
|
||||
*/
|
||||
public static boolean checkMobile(String mobile) {
|
||||
return StringUtils.length(mobile) == MOBILE_LENGTH && mobile.matches(MOBILE_REG_EXP);
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理手机号
|
||||
*
|
||||
* @param mobile 手机号
|
||||
* @return 处理后的手机号
|
||||
*/
|
||||
public static String formatMobile(String mobile) {
|
||||
if (StringUtils.length(mobile) > MOBILE_LENGTH) {
|
||||
return mobile.substring(mobile.length() - MOBILE_LENGTH);
|
||||
}
|
||||
return mobile;
|
||||
}
|
||||
|
||||
/**
|
||||
* 去掉手机号的前缀
|
||||
*
|
||||
* @param mobileStr mobileStr
|
||||
* @return 去掉前缀后的手机号
|
||||
*/
|
||||
public static String trimMobilePrefix(String mobileStr) {
|
||||
if (StringUtils.length(mobileStr) > MOBILE_LENGTH) {
|
||||
final String mobile = mobileStr.substring(mobileStr.length() - MOBILE_LENGTH);
|
||||
return checkMobile(mobile) ? mobile : mobileStr;
|
||||
}
|
||||
return mobileStr;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
package com.pudonghot.yo.util;
|
||||
|
||||
/**
|
||||
* @author Donghuang
|
||||
* @date Jul 20, 2020 18:27:52
|
||||
*/
|
||||
public class PhoneNumberUtils {
|
||||
|
||||
public static final int MOBILE_LENGTH = 11;
|
||||
private static final String MOBILE_REG_EXP = "^1[3-9]\\d{8}$";
|
||||
|
||||
/**
|
||||
* 验证手机号码
|
||||
* <p>
|
||||
* 移动号码段:134,135,136,137,138,139,147,150,151,152,157,158,159,170,178,182,183,184,187,188
|
||||
* 联通号码段:130,131,132,145,155,156,171,175,176,185,186
|
||||
* 电信号码段:133,149,153,170,173,177,180,181,189
|
||||
*
|
||||
* @param mobile 手机号
|
||||
* @return 是否为手机号
|
||||
*/
|
||||
public static boolean isMobile(final String mobile) {
|
||||
return mobile.length() == MOBILE_LENGTH
|
||||
&& mobile.matches(MOBILE_REG_EXP);
|
||||
}
|
||||
|
||||
/**
|
||||
* cleanup mobile
|
||||
* 01378888666 -> 1378888666
|
||||
* @param mobile mobile number
|
||||
* @return mobile cleaned
|
||||
*/
|
||||
public static String cleanupMobile(final String mobile) {
|
||||
if (mobile.length() > MOBILE_LENGTH) {
|
||||
final String trim = mobile.substring(
|
||||
mobile.length() - MOBILE_LENGTH);
|
||||
return isMobile(trim) ? trim : mobile;
|
||||
}
|
||||
return mobile;
|
||||
}
|
||||
}
|
@ -13,7 +13,7 @@ public class TimeUtils {
|
||||
* 00:00 - 23:59
|
||||
*/
|
||||
public static final Pattern TIME_PATTERN =
|
||||
Pattern.compile("^((?:[01]?[0-9])|(?:2[0-3])):([0-5]?[0-9])$");
|
||||
Pattern.compile("^([01]?[0-9]|2[0-3]):([0-5]?[0-9])(?::([0-5]?[0-9]))?$");
|
||||
|
||||
/**
|
||||
* @param time HH:mm
|
||||
@ -23,8 +23,10 @@ public class TimeUtils {
|
||||
if (StringUtils.isNotBlank(time)) {
|
||||
final Matcher matcher = TIME_PATTERN.matcher(time);
|
||||
if (matcher.find()) {
|
||||
final String sec = matcher.group(3);
|
||||
return Integer.parseInt(matcher.group(1)) * 60 * 60 +
|
||||
Integer.parseInt(matcher.group(2)) * 60;
|
||||
Integer.parseInt(matcher.group(2)) * 60 +
|
||||
(StringUtils.isNotBlank(sec) ? Integer.parseInt(sec) : 0);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
@ -1,6 +1,5 @@
|
||||
package com.pudonghot.yo.openapi.controller;
|
||||
|
||||
import com.pudonghot.yo.fsagent.api.IvrTransferService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import com.pudonghot.yo.model.domain.Agent;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
@ -13,6 +12,7 @@ import com.pudonghot.yo.model.exception.AssertUtils;
|
||||
import com.pudonghot.yo.openapi.service.AgentService;
|
||||
import com.pudonghot.yo.openapi.auth.SessionAbility;
|
||||
import com.pudonghot.yo.service.CommonChannelService;
|
||||
import com.pudonghot.yo.fsagent.api.IvrTransferService;
|
||||
import com.pudonghot.yo.openapi.request.ReqAgentDialout;
|
||||
import com.pudonghot.yo.fsagent.api.request.ReqAgentDial;
|
||||
import com.pudonghot.yo.service.CommonAgentStatusService;
|
||||
|
@ -0,0 +1,48 @@
|
||||
package com.pudonghot.yo.openapi.controller;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import com.pudonghot.yo.model.domain.Agent;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import com.pudonghot.yo.openapi.request.ReqCampaign;
|
||||
import com.pudonghot.yo.openapi.auth.SessionAbility;
|
||||
import com.pudonghot.yo.openapi.service.AgentService;
|
||||
import com.pudonghot.yo.service.CommonAgentStatusService;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
/**
|
||||
* @author Donghuang
|
||||
* @date Jul 02, 2020 11:53:21
|
||||
*/
|
||||
@Slf4j
|
||||
@Controller
|
||||
public class CampaignController implements SessionAbility {
|
||||
|
||||
@Autowired
|
||||
private AgentService agentService;
|
||||
@Autowired
|
||||
private CommonAgentStatusService agentStatusService;
|
||||
|
||||
@RequestMapping("/resource/task/{account}")
|
||||
public void addToQueue(
|
||||
@PathVariable("account")
|
||||
final String account,
|
||||
@Valid final ReqCampaign form) {
|
||||
final Agent agent = agentService.findValid(
|
||||
form.getTenantId(), account);
|
||||
agentStatusService.findValidAgentStatus(agent);
|
||||
// TODO Add agent to queue
|
||||
}
|
||||
|
||||
@RequestMapping("/resource/task/start")
|
||||
public void start(@Valid final ReqCampaign form) {
|
||||
// TODO start campaign
|
||||
}
|
||||
|
||||
@RequestMapping("/resource/task/stop")
|
||||
public void stop(@Valid final ReqCampaign form) {
|
||||
// TODO stop campaign
|
||||
}
|
||||
}
|
@ -1,28 +0,0 @@
|
||||
package com.pudonghot.yo.openapi.controller;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import com.pudonghot.yo.fsagent.api.DialService;
|
||||
import com.pudonghot.yo.openapi.dto.request.AgentDial;
|
||||
import com.pudonghot.yo.fsagent.api.request.ReqAgentDial;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import com.pudonghot.yo.openapi.dto.response.AgentDialResp;
|
||||
|
||||
/**
|
||||
* @author Donghuang <br>
|
||||
* Jan 03, 2020 18:20:59
|
||||
*/
|
||||
@Slf4j
|
||||
@Controller
|
||||
@RequestMapping("/v1")
|
||||
public class DialController {
|
||||
@Autowired
|
||||
private DialService dialService;
|
||||
|
||||
@RequestMapping("/dial")
|
||||
public AgentDialResp dial(final AgentDial req) {
|
||||
return new AgentDialResp(dialService.agentDial(
|
||||
req.copy(new ReqAgentDial())).getUuid());
|
||||
}
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
package com.pudonghot.yo.openapi.request;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
import javax.validation.constraints.NotBlank;
|
||||
|
||||
/**
|
||||
* @author Donghuang
|
||||
* @date Jul 09, 2020 11:09:01
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString
|
||||
public class ReqCampaign extends BaseForm {
|
||||
@NotBlank
|
||||
private String campaignKey;
|
||||
private String campaignName;
|
||||
|
||||
public void setTaskid(final String taskId) {
|
||||
this.campaignKey = taskId;
|
||||
}
|
||||
|
||||
public void setTaskname(final String taskName) {
|
||||
this.campaignName = taskName;
|
||||
}
|
||||
}
|
@ -31,6 +31,6 @@ yo.openapi.default-tenant=GOBLIN
|
||||
# Dubbo
|
||||
|
||||
## Dubbo Registry
|
||||
dubbo.registry.address=zookeeper://172.16.67.223:2181
|
||||
dubbo.registry.address=zookeeper://172.18.4.35:2181
|
||||
dubbo.registry.file=${user.home}/dubbo-cache/${spring.application.name}/dubbo.cache
|
||||
yo.fsagent.dubbo.service.version=1.0.0
|
||||
|
@ -1,7 +1,7 @@
|
||||
package com.pudonghot.yo.state.service.impl;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import com.wacai.tigon.mybatis.Search;
|
||||
@ -60,6 +60,8 @@ public class AgentStatusScheduleServiceImpl implements AgentStatusScheduleServic
|
||||
update.put(AgentStatus.REGISTERED, false);
|
||||
agentStatusMapper.update(update,
|
||||
new Search(AgentStatus.CHECK_REG_KEY, checkRegKey));
|
||||
log.info("ACW cleanup.");
|
||||
agentStatusMapper.acwCleanup();
|
||||
}
|
||||
|
||||
private Map<String, Object> checkRegKeyUpdate(final String checkRegKey) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user