桩注册/心跳/费率模型验证

This commit is contained in:
ZZ 2021-07-17 16:49:41 +08:00
parent 0135134fd0
commit a58670c1bc
14 changed files with 236 additions and 58 deletions

View File

@ -10,10 +10,10 @@ import org.springframework.context.annotation.ImportResource;
*
* @author zz
*/
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class })
@ImportResource(locations={"classpath:svcmainlogic.xml"})
public class XhpcPPApplication
{
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
@ImportResource(locations = {"classpath:svcmainlogic.xml"})
public class XhpcPPApplication {
public static void main(String[] args) {
SpringApplication.run(XhpcPPApplication.class, args);
@ -28,4 +28,5 @@ public class XhpcPPApplication
" | | \\ / \\ / \n" +
" ''-' `'-' `-..-' ");
}
}

View File

@ -1,16 +1,37 @@
package com.xhpc.pp.config;
import com.xhpc.pp.utils.SpringContextHolder;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import static com.ruoyi.common.core.utils.GetIpAndPort.getLocalIP;
@Configuration
public class EarlierBeanConf {
final
SpringContextHolder springContextHolder;
final SpringContextHolder springContextHolder;
@Value("${server.port}")
private String port;
private static String PORT;
private static String ipAndPort;
public EarlierBeanConf(SpringContextHolder springContextHolder) {
this.springContextHolder = springContextHolder;
}
@Value("${server.port}")
public void setPort(String port) {
EarlierBeanConf.PORT = port;
}
public static String getLocalIPAndPort() {
if (ipAndPort == null) {
ipAndPort = getLocalIP().concat("#").concat(PORT);
}
return ipAndPort;
}
}

View File

@ -22,8 +22,9 @@ public class TestController {
NamingService namingService = NacosFactory.createNamingService(serverAddr);
List<Instance> ppInstances = namingService.getAllInstances("xhpc-power-pole");
// todo clean dead host pole cache
String ipAndPort = GetIpAndPort.getIpAndPort();
return ipAndPort;
}
}

View File

@ -15,11 +15,13 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.*;
import static com.ruoyi.common.core.utils.GetIpAndPort.getLocalIP;
import static com.xhpc.pp.config.EarlierBeanConf.getLocalIPAndPort;
import static com.xhpc.pp.server.ChargingPileServer.REDIS;
import static com.xhpc.pp.service.RegisterLogic.REGISTERED;
import static com.xhpc.pp.tx.ServiceResult.OK;
import static com.xhpc.pp.utils.security.CRCCalculator.calcCrc;
public class ChargingPileBinaryHandler implements ClientBinaryHandler {
@ -27,15 +29,17 @@ public class ChargingPileBinaryHandler implements ClientBinaryHandler {
private static final Logger log = LoggerFactory.getLogger(ChargingPileBinaryHandler.class);
private static final String SERVICE_REGISTER = "01";
private static final String SERVICE_HB = "03";
private static final String DATA_TYPE_STRING = "string";
private static final String DATA_TYPE_INT = "int";
private static final String DATA_TYPE_LONG = "long";
// private static final String DATA_TYPE_HEX = "hex";
private ServiceMainLogic servicemainLogic;
private final ServiceMainLogic servicemainLogic;
public ChargingPileBinaryHandler() {
servicemainLogic = SpringContextHolder.getBean("ServiceMainLogic");
}
@ -47,21 +51,20 @@ public class ChargingPileBinaryHandler implements ClientBinaryHandler {
for (byte[] d : dataList) {
String dataStr = HexUtils.toHex(d);
String poleNo = ChargingPileServer.getPoleNo(handler);
if (d.length <= 2|| !dataStr.startsWith("68")) {
log.info("received data <<<< {}, from pole <<<< {}", dataStr, poleNo);
if (d.length <= 2 || !dataStr.startsWith("68")) {
log.info("received invalid data <<<< {}, len[{}]", dataStr, d.length);
return;
} else if (poleNo!=null) {
log.info("received data <<<< {}, from pole <<<< {}", dataStr, poleNo);
continue;
}
int len = HexUtils.toInteger(d, 1, 2);
if (d.length < len) {
log.error("incorrect input data length {}", d.length);
return;
continue;
}
String crc = calcCrc(d);
if (!dataStr.endsWith(crc)) {
log.error("incorrect input data crc {}", crc);
return;
continue;
}
process(handler, d);
}
@ -74,25 +77,39 @@ public class ChargingPileBinaryHandler implements ClientBinaryHandler {
String serviceName = HexUtils.toHex(data, 5, 6);
String version = ChargingPileServer.getVersion(handler.getName());
String poleNo = ChargingPileServer.getPoleNo(handler);
Map<String, Object> req = analysis(data, serviceName, version);
String poleNo = (String) req.get("poleNo");
ServiceParameter sp = new ServiceParameter(serviceName, poleNo, req);
ServiceResult result = servicemainLogic.process(sp);
handler.sendClientBinary(result.getBinary());
log.info("server send msg >>>> [{}] |{}|", poleNo, HexUtils.toHex(result.getBinary()));
String resultCode = result.getCode();
if (SERVICE_REGISTER.equals(serviceName) && OK.equals(resultCode)) {
reg(handler, poleNo, req);
} /*else if (SERVICE_HB.equals(serviceName)) {
}*/
if (result.getBinary() != null) {
log.info("server send msg >>>> [{}] |{}|", poleNo, HexUtils.toHex(result.getBinary()));
handler.sendClientBinary(result.getBinary());
}
if (SERVICE_REGISTER.equals(serviceName)) {
log.info("pole registered >>>> [{}] ", poleNo);
ChargingPileServer.putHandler((String) req.get("poleNo"), handler);
ChargingPileServer.putVersion(handler.getName(), (String) req.get("version"));
}
}
private void reg(ClientHandler handler, String poleNo, Map<String, Object> req) {
ChargingPileServer.putHandler(poleNo, handler);
ChargingPileServer.putVersion(handler.getName(), (String) req.get("version"));
Map<String, Object> poleCache = REDIS.getCacheMap(poleNo);
poleCache.put("Status", REGISTERED);
poleCache.put("Server", getLocalIPAndPort());
REDIS.setCacheMap(poleNo, poleCache);
Set<String> polesAtHost = REDIS.getCacheSet(getLocalIP());
polesAtHost.add(poleNo);
log.info("pole registered >>>> [{}] ", poleNo);
}
private List<byte[]> parseDataList(byte[] data) {
List<byte[]> dataList = new ArrayList<>();
int processedLen, len = HexUtils.toInteger(data, 1, 2)+4;
int processedLen, len = HexUtils.toInteger(data, 1, 2) + 4;
processedLen = 0;
int start = 0;
while (start < data.length) {
@ -100,10 +117,10 @@ public class ChargingPileBinaryHandler implements ClientBinaryHandler {
log.error("incorrect input data[{}] len[{}]", data, data.length);
break;
}
dataList.add(ArrayUtils.subarray(data, start, start+len));
dataList.add(ArrayUtils.subarray(data, start, start + len));
processedLen += len;
start = processedLen;
len = HexUtils.toInteger(data, start+1, start + 2)+4;
len = HexUtils.toInteger(data, start + 1, start + 2) + 4;
}
if (dataList.size() > 1) {
log.info("detected stick package size[{}]", dataList.size());

View File

@ -7,26 +7,25 @@ import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.net.SocketTimeoutException;
@Lazy(false)
@Component
public class ChargingPileEventHandler implements ClientEventHandler {
private static final Logger log = LoggerFactory.getLogger(ChargingPileEventHandler.class);
public ChargingPileEventHandler() {
}
@Override
public void gotConnected(ClientHandler handler) throws SocketTimeoutException, IOException {
public void gotConnected(ClientHandler handler) {
log.info("got connected -> " + handler.getName() + " <-" + handler.getSocket().getRemoteSocketAddress().toString());
// TODO 连接时获取终端唯一标示断开连接时根据唯一标示绑定的桩号更新桩状态
// 请求注册
}
@Override
public void lostConnection(ClientHandler handler) {
String poleNo = ChargingPileServer.getPoleNo(handler);
log.info("lost connection -> [{}] {} <- {}",
poleNo, handler.getName(), handler.getSocket().getRemoteSocketAddress().toString());
@ -36,7 +35,8 @@ public class ChargingPileEventHandler implements ClientEventHandler {
}
@Override
public void closingConnection(ClientHandler handler) throws IOException {
public void closingConnection(ClientHandler handler) {
log.info("closing connection -> " + handler.getName() + " <-");
}

View File

@ -1,5 +1,6 @@
package com.xhpc.pp.server;
import com.ruoyi.common.redis.service.RedisService;
import com.xhpc.pp.service.FieldService;
import com.xhpc.pp.utils.security.HexUtils;
import org.quickserver.net.server.ClientHandler;
@ -15,9 +16,14 @@ import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.io.IOException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import static com.xhpc.pp.service.RegisterLogic.DISCONNECTED;
/**
@ -29,16 +35,33 @@ public class ChargingPileServer {
public static final String default_version = "0A";
private static final Logger log = LoggerFactory.getLogger(ChargingPileServer.class);
private static Map<String, ClientHandler> handlerMapper = new HashMap<>();
private static Map<String, ClientHandler> handlerMap = new HashMap<>();
private static Map<String, String> versionMapper = new HashMap<>();
private static Map<String, String> poleMapper = new HashMap<>();
private static Map<String, String> poleMap = new HashMap<>();
public static RedisService REDIS;
private QuickServer server;
@Autowired
private FieldService fieldService;
@Autowired
public RedisService redisService;
@PostConstruct
public void init() {
REDIS = redisService;
REDIS.deleteObject("PILE_SN_POOL");
Set<String> PILE_SN_POOL = new HashSet<>();
//todo add pile sn whitelist
PILE_SN_POOL.add("55031412782305");
REDIS.setCacheSet("PILE_SN_POOL", PILE_SN_POOL);
}
@Autowired
public ChargingPileServer(@Value("${ppsvc.server}") String host, @Value("${ppsvc.port}") int port) {
try {
QuickServerConfig config;
server = new QuickServer();
@ -65,15 +88,20 @@ public class ChargingPileServer {
}
public static void putHandler(String poleNo, ClientHandler handler) {
handlerMapper.put(poleNo, handler);
poleMapper.put(handler.getName(), poleNo);
handlerMap.put(poleNo, handler);
poleMap.put(handler.getName(), poleNo);
}
public static void removeHandler(String poleNo) {
ClientHandler handler = handlerMapper.remove(poleNo);
ClientHandler handler = handlerMap.remove(poleNo);
Map<String, Object> cacheMap = REDIS.getCacheMap(poleNo);
cacheMap.put("Status", DISCONNECTED);
REDIS.setCacheMap(poleNo, cacheMap);
if (handler != null) {
log.info("remove hanlder [{}], poleNo[{}]", handler.getName(), poleNo);
poleMapper.remove(handler.getName());
log.info("remove handler [{}] for [{}]", handler.getName(), poleNo);
poleMap.remove(handler.getName());
versionMapper.remove(handler.getName());
}
}
@ -87,7 +115,7 @@ public class ChargingPileServer {
poleNo = "0000000000000000" + poleNo;
poleNo = poleNo.substring(poleNo.length() - 16);
}
ClientHandler handler = handlerMapper.get(poleNo);
ClientHandler handler = handlerMap.get(poleNo);
if (handler == null || !handler.isOpen()) {
log.error("send message failed. [{}] connection lost", poleNo);
removeHandler(poleNo);
@ -101,25 +129,30 @@ public class ChargingPileServer {
}
public static void putVersion(String handler, String version) {
versionMapper.put(handler, version);
}
public static String getVersion(String handler) {
String version = versionMapper.get(handler);
if (version == null)
version =default_version;
version = default_version;
return version;
}
public static ClientHandler getHandler(String poleNo) {
return handlerMapper.get(poleNo);
public static ClientHandler getHandler(String pole) {
return handlerMap.get(pole);
}
public static String getPoleNo(ClientHandler handler) {
return poleMapper.get(handler.getName());
return poleMap.get(handler.getName());
}
public void shutDown() {
try {
if (server != null)
server.stopServer();
@ -127,4 +160,5 @@ public class ChargingPileServer {
log.error("Server could not stop: " + e);
}
}
}

View File

@ -0,0 +1,44 @@
package com.xhpc.pp.service;
import com.xhpc.pp.tx.ServiceParameter;
import com.xhpc.pp.tx.ServiceResult;
import com.xhpc.pp.tx.logic.ServiceLogic;
import com.xhpc.pp.utils.security.CRCCalculator;
import com.xhpc.pp.utils.security.HexUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
import java.util.Map;
import static com.xhpc.pp.server.ChargingPileServer.REDIS;
@Lazy
@Component("HBLogic")
public class HBLogic implements ServiceLogic {
private static Logger log = LoggerFactory.getLogger(HBLogic.class);
@Override
public ServiceResult service(ServiceParameter sp) throws Exception {
Map<String, Object> req = sp.getParameters();
String poleNo = (String) req.get("poleNo");
String gunId = (String) req.get("gunId");
String gunStatus = (String) req.get("gunStatus");
int gunStatusInt = 0;
if (ServiceResult.HEX_FAIL.equals(gunStatus))
gunStatusInt = 1;
String gunKey = poleNo.concat(gunId);
Map<String, Integer> cacheGun = REDIS.getCacheMap(gunKey);
int cacheGunStatus = cacheGun.get(gunKey);
if ((1 == cacheGunStatus && 0 == gunStatusInt) || (0 == cacheGunStatus && 1 == gunStatusInt)) {
cacheGun.put(gunKey, gunStatusInt);
}
String resultStr = "680D00000004".concat(poleNo).concat(gunId).concat(ServiceResult.HEX_OK);
resultStr = resultStr.concat(CRCCalculator.calcCrc(resultStr));
return new ServiceResult(HexUtils.toBytes(resultStr), ServiceResult.OK);
}
}

View File

@ -0,0 +1,42 @@
package com.xhpc.pp.service;
import com.xhpc.pp.tx.ServiceParameter;
import com.xhpc.pp.tx.ServiceResult;
import com.xhpc.pp.tx.logic.ServiceLogic;
import com.xhpc.pp.utils.security.CRCCalculator;
import com.xhpc.pp.utils.security.HexUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
import java.util.Map;
import static com.xhpc.pp.server.ChargingPileServer.REDIS;
@Lazy
@Component("RateModelValidateLogic")
public class RateModelValidateLogic implements ServiceLogic {
private static Logger log = LoggerFactory.getLogger(RateModelValidateLogic.class);
@Override
public ServiceResult service(ServiceParameter sp) throws Exception {
Map<String, Object> req = sp.getParameters();
String poleNo = (String) req.get("poleNo");
String rateModelId = (String) req.get("rateModelId");
Map<String, Integer> cachePole = REDIS.getCacheMap(poleNo);
String resultCode = ServiceResult.OK;
String hexCode = ServiceResult.HEX_OK;
Integer rateModelIdCache = cachePole.get("rateModelId");
if (Integer.parseInt(rateModelId) != rateModelIdCache) {
hexCode = ServiceResult.HEX_FAIL;
resultCode = ServiceResult.FAIL;
}
String resultStr = "680E00000006".concat(poleNo).concat(String.format("%04d", rateModelIdCache)).concat(hexCode);
resultStr = resultStr.concat(CRCCalculator.calcCrc(resultStr));
return new ServiceResult(HexUtils.toBytes(resultStr), resultCode);
}
}

View File

@ -2,7 +2,6 @@ package com.xhpc.pp.service;
import com.xhpc.pp.tx.ServiceParameter;
import com.xhpc.pp.tx.ServiceResult;
import com.xhpc.pp.tx.TxException;
import com.xhpc.pp.tx.logic.ServiceLogic;
import com.xhpc.pp.utils.security.CRCCalculator;
import com.xhpc.pp.utils.security.HexUtils;
@ -12,23 +11,33 @@ import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
import java.util.Map;
import java.util.Set;
import static com.xhpc.pp.server.ChargingPileServer.REDIS;
@Lazy
@Component("RegisterLogic")
public class RegisterLogic implements ServiceLogic {
public static final String DISCONNECTED = "Disconnected";
public static final String REGISTERED = "Registered";
private static Logger log = LoggerFactory.getLogger(RegisterLogic.class);
@Override
public ServiceResult service(ServiceParameter sp) throws TxException {
public ServiceResult service(ServiceParameter sp) throws Exception {
Map<String, Object> req = sp.getParameters();
if (req == null) {
throw TxException.INVALID_PARAMETER;
}
String resultCode = ServiceResult.OK;
String hexCode = ServiceResult.HEX_OK;
String poleNo = (String) req.get("poleNo");
String resultStr = "680C00000002".concat(poleNo).concat("00");
Set<String> pileSnPool = REDIS.getCacheSet("PILE_SN_POOL");
//todo set rate model to cache
if (!pileSnPool.contains(poleNo)) {
hexCode = ServiceResult.HEX_FAIL;
resultCode = ServiceResult.FAIL;
}
String resultStr = "680C00000002".concat(poleNo).concat(hexCode);
resultStr = resultStr.concat(CRCCalculator.calcCrc(resultStr));
return new ServiceResult(HexUtils.toBytes(resultStr), ServiceResult.OK);
return new ServiceResult(HexUtils.toBytes(resultStr), resultCode);
}
}

View File

@ -25,6 +25,9 @@ public class ServiceMainLogic {
try {
ServiceLogic logic = getServiceLogic(sp.getServiceName());
// startTransaction(sp);
if (sp.getParameters() == null) {
throw TxException.INVALID_PARAMETER;
}
result = logic.service(sp);
// commitTransaction(sp);
} catch (TxException e) {

View File

@ -7,6 +7,8 @@ public class ServiceResult {
public static final String OK = "0";
public static final String FAIL = "1";
public static final String HEX_OK = "00";
public static final String HEX_FAIL = "01";
private String code;
private byte[] binary;

View File

@ -19,7 +19,7 @@ public class SpringContextHolder implements ApplicationContextAware, DisposableB
private static ApplicationContext applicationContext = null;
private static Logger logger = LoggerFactory.getLogger(SpringContextHolder.class);
private static final Logger logger = LoggerFactory.getLogger(SpringContextHolder.class);
/**
* 取得存储在静态变量中的ApplicationContext.
@ -85,7 +85,7 @@ public class SpringContextHolder implements ApplicationContextAware, DisposableB
*/
private static void assertContextInjected() {
Validate.validState(applicationContext != null, "applicaitonContext属性未注入, 请在applicationContext.xml中定义SpringContextHolder.");
Validate.validState(applicationContext != null, "applicaitonContext属性未注入.");
}
}

View File

@ -32,6 +32,7 @@ public class HexUtils {
}
public static String toString(byte[] data) {
return new String(data);
}
@ -72,6 +73,7 @@ public class HexUtils {
}
public static String toIntString(String hex) {
return toIntString(hex, 4);
}

View File

@ -6,8 +6,10 @@
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">
<util:map id="serviceLogics">
<util:map id="serviceLogics">
<entry key="01" value-ref="RegisterLogic"/>
<entry key="03" value-ref="HBLogic"/>
<entry key="05" value-ref="RateModelValidateLogic"/>
</util:map>
</beans>