增加http业务组件

V0.5.x
xiwa 2022-04-24 04:59:23 +08:00
parent b9d6054198
commit a0e23dea2b
34 changed files with 449 additions and 269 deletions

BIN
.DS_Store vendored

Binary file not shown.

View File

View File

@ -41,7 +41,7 @@ public final class JsonUtil {
public static Object toObject(ScriptObjectMirror mirror) { public static Object toObject(ScriptObjectMirror mirror) {
if (mirror.isEmpty()) { if (mirror.isEmpty()) {
return null; return new Object();
} }
if (mirror.isArray()) { if (mirror.isArray()) {
List<Object> list = new ArrayList<>(); List<Object> list = new ArrayList<>();

BIN
manager/.DS_Store vendored

Binary file not shown.

View File

@ -0,0 +1,58 @@
package cc.iotkit.manager.config;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
import javax.servlet.http.HttpServletRequest;
import java.util.Map;
@ControllerAdvice
public class ResponseResultHandler implements ResponseBodyAdvice<Object> {
@Override
public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
String wrapResponse = request.getHeader("wrap-response");
return "json".equals(wrapResponse);
}
@Override
public Object beforeBodyWrite(Object body, MethodParameter returnType,
MediaType selectedContentType,
Class<? extends HttpMessageConverter<?>> selectedConverterType,
ServerHttpRequest request, ServerHttpResponse response) {
if (body instanceof GlobalExceptionHandler.RequestResult) {
GlobalExceptionHandler.RequestResult requestResult = (GlobalExceptionHandler.RequestResult) body;
return new ApiResponse(Integer.parseInt(requestResult.getCode()), requestResult.getMessage(),
"", System.currentTimeMillis());
} else if (body instanceof Map) {
Map map = (Map) body;
//spring mvc内部异常
if (map.containsKey("timestamp") && map.containsKey("status") && map.containsKey("error")) {
return new ApiResponse((Integer) map.get("status"), (String) map.get("error"),
"", System.currentTimeMillis());
}
}
return new ApiResponse(200, "", body, System.currentTimeMillis());
}
@Data
@NoArgsConstructor
@AllArgsConstructor
public static class ApiResponse {
private int status;
private String message;
private Object data;
private long timestamp;
}
}

View File

@ -10,6 +10,7 @@ import cc.iotkit.manager.model.query.DeviceQuery;
import cc.iotkit.manager.service.DataOwnerService; import cc.iotkit.manager.service.DataOwnerService;
import cc.iotkit.manager.service.DeviceService; import cc.iotkit.manager.service.DeviceService;
import cc.iotkit.manager.utils.AuthUtil; import cc.iotkit.manager.utils.AuthUtil;
import cc.iotkit.model.InvokeResult;
import cc.iotkit.model.Paging; import cc.iotkit.model.Paging;
import cc.iotkit.model.device.DeviceInfo; import cc.iotkit.model.device.DeviceInfo;
import cc.iotkit.model.device.message.DeviceProperty; import cc.iotkit.model.device.message.DeviceProperty;
@ -55,44 +56,21 @@ public class DeviceController {
private DeviceBehaviourService behaviourService; private DeviceBehaviourService behaviourService;
@PostMapping(Constants.API.DEVICE_INVOKE_SERVICE) @PostMapping(Constants.API.DEVICE_INVOKE_SERVICE)
public String invokeService(@PathVariable("deviceId") String deviceId, public InvokeResult invokeService(@PathVariable("deviceId") String deviceId,
@PathVariable("service") String service, @PathVariable("service") String service,
@RequestBody Map<String, Object> args) { @RequestBody Map<String, Object> args) {
if (StringUtils.isBlank(deviceId) || StringUtils.isBlank(service)) { if (StringUtils.isBlank(deviceId) || StringUtils.isBlank(service)) {
throw new RuntimeException("deviceId/service is blank."); throw new RuntimeException("deviceId/service is blank.");
} }
dataOwnerService.checkWriteRole(); dataOwnerService.checkWriteRole();
return deviceService.invokeService(deviceId, service, args); return new InvokeResult(deviceService.invokeService(deviceId, service, args));
} }
@PostMapping(Constants.API.DEVICE_SET_PROPERTIES) @PostMapping(Constants.API.DEVICE_SET_PROPERTIES)
public String setProperty(@PathVariable("deviceId") String deviceId, public InvokeResult setProperty(@PathVariable("deviceId") String deviceId,
@RequestBody Map<String, Object> args) { @RequestBody Map<String, Object> args) {
dataOwnerService.checkWriteRole(); dataOwnerService.checkWriteRole();
return deviceService.setProperty(deviceId, args); return new InvokeResult(deviceService.setProperty(deviceId, args));
}
@PostMapping("/list")
public Paging<DeviceInfo> getDevices(int page,
int size,
String pk,
Boolean online,
String dn) {
Criteria condition = new Criteria();
if (!AuthUtil.isAdmin()) {
condition.and("uid").is(AuthUtil.getUserId());
}
if (StringUtils.isNotBlank(pk)) {
condition.and("productKey").is(pk);
}
if (StringUtils.isNotBlank(dn)) {
condition.and("deviceName").regex(".*" + dn + ".*");
}
if (online != null) {
condition.and("state.online").is(online);
}
return deviceDao.find(condition, size, page);
} }
@PostMapping("/list/{size}/{page}") @PostMapping("/list/{size}/{page}")
@ -121,8 +99,8 @@ public class DeviceController {
condition.and("deviceName").regex(".*" + dn + ".*"); condition.and("deviceName").regex(".*" + dn + ".*");
} }
String state = query.getState(); String state = query.getState();
if (state != null) { if (StringUtils.isNotBlank(state)) {
condition.and("state.online").is(state); condition.and("state.online").is(state.equals("online"));
} }
return deviceDao.find(condition, size, page); return deviceDao.find(condition, size, page);

View File

@ -3,7 +3,7 @@ package cc.iotkit.manager.controller;
import cc.iotkit.common.exception.BizException; import cc.iotkit.common.exception.BizException;
import cc.iotkit.common.utils.JsonUtil; import cc.iotkit.common.utils.JsonUtil;
import cc.iotkit.common.utils.ReflectUtil; import cc.iotkit.common.utils.ReflectUtil;
import cc.iotkit.comps.DeviceComponentManager; import cc.iotkit.comps.ComponentManager;
import cc.iotkit.comps.config.ComponentConfig; import cc.iotkit.comps.config.ComponentConfig;
import cc.iotkit.dao.ProtocolComponentRepository; import cc.iotkit.dao.ProtocolComponentRepository;
import cc.iotkit.dao.ProtocolConverterRepository; import cc.iotkit.dao.ProtocolConverterRepository;
@ -50,7 +50,7 @@ public class ProtocolController {
private UserInfoRepository userInfoRepository; private UserInfoRepository userInfoRepository;
@Autowired @Autowired
private DeviceComponentManager deviceComponentManager; private ComponentManager componentManager;
@PostMapping("/uploadJar") @PostMapping("/uploadJar")
public String uploadJar(@RequestParam("file") MultipartFile file, String id) { public String uploadJar(@RequestParam("file") MultipartFile file, String id) {
@ -112,8 +112,9 @@ public class ProtocolController {
ProtocolComponent oldComponent = getAndCheckComponent(id); ProtocolComponent oldComponent = getAndCheckComponent(id);
component = ReflectUtil.copyNoNulls(component, oldComponent); component = ReflectUtil.copyNoNulls(component, oldComponent);
try { try {
deviceComponentManager.deRegister(id); componentManager.deRegister(id);
protocolComponentRepository.save(component); protocolComponentRepository.save(component);
} catch (Throwable e) { } catch (Throwable e) {
throw new BizException("add protocol component error", e); throw new BizException("add protocol component error", e);
@ -144,7 +145,7 @@ public class ProtocolController {
script = JsonUtil.parse(script, String.class); script = JsonUtil.parse(script, String.class);
FileUtils.writeStringToFile(file, script, "UTF-8", false); FileUtils.writeStringToFile(file, script, "UTF-8", false);
deviceComponentManager.deRegister(id); componentManager.deRegister(id);
} catch (Throwable e) { } catch (Throwable e) {
throw new BizException("save protocol component script error", e); throw new BizException("save protocol component script error", e);
} }
@ -164,7 +165,7 @@ public class ProtocolController {
public void deleteComponent(@PathVariable("id") String id) { public void deleteComponent(@PathVariable("id") String id) {
ProtocolComponent component = getAndCheckComponent(id); ProtocolComponent component = getAndCheckComponent(id);
try { try {
deviceComponentManager.deRegister(id); componentManager.deRegister(id);
Path path = Paths.get(String.format("%s/%s", componentConfig.getComponentDir(), id)) Path path = Paths.get(String.format("%s/%s", componentConfig.getComponentDir(), id))
.toAbsolutePath().normalize(); .toAbsolutePath().normalize();
@ -190,8 +191,10 @@ public class ProtocolController {
@PathVariable("page") int page) { @PathVariable("page") int page) {
Page<ProtocolComponent> components = protocolComponentRepository.findAll( Page<ProtocolComponent> components = protocolComponentRepository.findAll(
PageRequest.of(page - 1, size, Sort.by(Sort.Order.desc("createAt")))); PageRequest.of(page - 1, size, Sort.by(Sort.Order.desc("createAt"))));
components.getContent().forEach(c -> c.setState(deviceComponentManager.isRunning(c.getId()) ? components.getContent().forEach(c -> c.setState(
ProtocolComponent.STATE_RUNNING : ProtocolComponent.STATE_STOPPED)); componentManager.isRunning(c.getId()) ?
ProtocolComponent.STATE_RUNNING : ProtocolComponent.STATE_STOPPED
));
return new Paging<>(components.getTotalElements(), components.getContent()); return new Paging<>(components.getTotalElements(), components.getContent());
} }
@ -294,14 +297,17 @@ public class ProtocolController {
public void changeComponentState(@PathVariable("id") String id, public void changeComponentState(@PathVariable("id") String id,
@PathVariable("state") String state) { @PathVariable("state") String state) {
ProtocolComponent component = getAndCheckComponent(id); ProtocolComponent component = getAndCheckComponent(id);
String converterId = component.getConverter(); if(ProtocolComponent.TYPE_DEVICE.equals(component.getType())){
getAndCheckConverter(converterId); String converterId = component.getConverter();
getAndCheckConverter(converterId);
}
if (ProtocolComponent.STATE_RUNNING.equals(state)) { if (ProtocolComponent.STATE_RUNNING.equals(state)) {
deviceComponentManager.register(component); componentManager.register(component);
deviceComponentManager.start(component.getId()); componentManager.start(component.getId());
component.setState(ProtocolComponent.STATE_RUNNING); component.setState(ProtocolComponent.STATE_RUNNING);
} else { } else {
deviceComponentManager.deRegister(id); componentManager.deRegister(id);
component.setState(ProtocolComponent.STATE_STOPPED); component.setState(ProtocolComponent.STATE_STOPPED);
} }
protocolComponentRepository.save(component); protocolComponentRepository.save(component);

View File

@ -2,23 +2,17 @@ package cc.iotkit.manager.controller.aligenie;
import cc.iotkit.common.Constants; import cc.iotkit.common.Constants;
import cc.iotkit.common.exception.BizException; import cc.iotkit.common.exception.BizException;
import cc.iotkit.common.exception.OfflineException;
import cc.iotkit.common.utils.JsonUtil;
import cc.iotkit.common.utils.UniqueIdUtil; import cc.iotkit.common.utils.UniqueIdUtil;
import cc.iotkit.dao.*; import cc.iotkit.dao.*;
import cc.iotkit.manager.service.DataOwnerService; import cc.iotkit.manager.service.DataOwnerService;
import cc.iotkit.manager.service.DeviceService; import cc.iotkit.manager.service.DeviceService;
import cc.iotkit.manager.utils.AuthUtil;
import cc.iotkit.model.InvokeResult;
import cc.iotkit.model.UserInfo; import cc.iotkit.model.UserInfo;
import cc.iotkit.model.aligenie.AligenieDevice; import cc.iotkit.model.aligenie.AligenieDevice;
import cc.iotkit.model.aligenie.AligenieProduct; import cc.iotkit.model.aligenie.AligenieProduct;
import cc.iotkit.model.device.DeviceInfo; import cc.iotkit.model.device.DeviceInfo;
import cc.iotkit.model.device.message.ThingModelMessage; import cc.iotkit.model.device.message.ThingModelMessage;
import io.swagger.annotations.ApiOperation;
import lombok.Data; import lombok.Data;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.pulsar.client.api.Producer; import org.apache.pulsar.client.api.Producer;
import org.apache.pulsar.client.api.PulsarClient; import org.apache.pulsar.client.api.PulsarClient;
import org.apache.pulsar.client.api.PulsarClientException; import org.apache.pulsar.client.api.PulsarClientException;
@ -131,44 +125,6 @@ public class AligenieDeviceController {
.build()); .build());
} }
@ApiOperation("设备服务调用")
@PostMapping("/invoke/{deviceId}/{service}")
public InvokeResult invokeService(@PathVariable("deviceId") String deviceId,
@PathVariable("service") String service,
String args) {
InvokeResult result = new InvokeResult("", InvokeResult.FAILED_UNKNOWN);
AligenieDevice device = aligenieDeviceRepository.findByUidAndDeviceId(AuthUtil.getUserId(), deviceId);
if (device == null) {
result.setCode(InvokeResult.FAILED_NO_AUTH);
return result;
}
if (StringUtils.isBlank(deviceId) || StringUtils.isBlank(service)) {
log.error("deviceId/service is blank");
result.setCode(InvokeResult.FAILED_PARAM_ERROR);
return result;
}
try {
String requestId;
if ("set".equals(service)) {
requestId = deviceService.setProperty(deviceId,
JsonUtil.parse(args, Map.class), false);
} else {
requestId = deviceService.invokeService(deviceId,
service, JsonUtil.parse(args, Map.class), false);
}
result.setRequestId(requestId);
result.setCode(InvokeResult.SUCCESS);
} catch (OfflineException e) {
log.error("sendMsg failed", e);
result.setCode(InvokeResult.FAILED_OFFLINE);
return result;
}
return result;
}
@Data @Data
public static class Device { public static class Device {
private String deviceId; private String deviceId;

View File

@ -1,7 +1,5 @@
package cc.iotkit.manager.controller.api; package cc.iotkit.manager.controller.api;
import cc.iotkit.common.exception.OfflineException;
import cc.iotkit.common.utils.JsonUtil;
import cc.iotkit.dao.AppDesignRepository; import cc.iotkit.dao.AppDesignRepository;
import cc.iotkit.dao.DeviceRepository; import cc.iotkit.dao.DeviceRepository;
import cc.iotkit.dao.SpaceDeviceRepository; import cc.iotkit.dao.SpaceDeviceRepository;
@ -10,7 +8,6 @@ import cc.iotkit.manager.model.vo.AppPageNode;
import cc.iotkit.manager.service.AppDesignService; import cc.iotkit.manager.service.AppDesignService;
import cc.iotkit.manager.service.DeviceService; import cc.iotkit.manager.service.DeviceService;
import cc.iotkit.manager.utils.AuthUtil; import cc.iotkit.manager.utils.AuthUtil;
import cc.iotkit.model.InvokeResult;
import cc.iotkit.model.device.DeviceInfo; import cc.iotkit.model.device.DeviceInfo;
import cc.iotkit.model.space.SpaceDevice; import cc.iotkit.model.space.SpaceDevice;
import io.swagger.annotations.ApiImplicitParam; import io.swagger.annotations.ApiImplicitParam;
@ -20,10 +17,12 @@ import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Example; import org.springframework.data.domain.Example;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@Slf4j @Slf4j
@ -72,74 +71,6 @@ public class DeviceController {
.collect(Collectors.toList()); .collect(Collectors.toList());
} }
@ApiOperation("设备服务调用")
@ApiImplicitParams({
@ApiImplicitParam(value = "设备ID", name = "deviceId", required = true, dataType = "String"),
@ApiImplicitParam(value = "服务名", name = "service", required = true, dataType = "String"),
@ApiImplicitParam(value = "参数", name = "args", required = true, dataType = "String"),
})
@PostMapping("/{deviceId}/service/{service}")
public InvokeResult invokeService(@PathVariable("deviceId") String deviceId,
@PathVariable("service") String service,
String args) {
InvokeResult result = new InvokeResult("", InvokeResult.FAILED_UNKNOWN);
SpaceDevice device = checkOwner(deviceId);
if (device == null) {
result.setCode(InvokeResult.FAILED_NO_AUTH);
return result;
}
if (StringUtils.isBlank(deviceId) || StringUtils.isBlank(service)) {
log.error("deviceId/service is blank");
result.setCode(InvokeResult.FAILED_PARAM_ERROR);
return result;
}
try {
String requestId;
if ("property/set".equals(service)) {
requestId = deviceService.setProperty(deviceId,
JsonUtil.parse(args, Map.class));
} else {
requestId = deviceService.invokeService(deviceId, service,
JsonUtil.parse(args, Map.class));
}
result.setRequestId(requestId);
result.setCode(InvokeResult.SUCCESS);
} catch (OfflineException e) {
log.error("sendMsg failed", e);
result.setCode(InvokeResult.FAILED_OFFLINE);
return result;
}
return result;
}
@ApiOperation("设备属性调用")
@ApiImplicitParams({
@ApiImplicitParam(value = "设备ID", name = "deviceId", required = true, dataType = "String"),
@ApiImplicitParam(value = "参数", name = "args", required = true, dataType = "String"),
})
@PostMapping("/{deviceId}/service/property/set")
public InvokeResult setProperty(@PathVariable("deviceId") String deviceId,
String args) {
checkOwner(deviceId);
if (StringUtils.isBlank(deviceId) || StringUtils.isBlank(args)) {
throw new RuntimeException("deviceId/args is blank.");
}
return invokeService(deviceId, "property/set", args);
}
/**
*
*/
private SpaceDevice checkOwner(String deviceId) {
return spaceDeviceRepository.findOne(Example.of(SpaceDevice.builder()
.uid(AuthUtil.getUserId()).deviceId(deviceId).build()))
.orElse(null);
}
@GetMapping("/detailPage/{deviceId}") @GetMapping("/detailPage/{deviceId}")
public List<AppPageNode> deviceDetailPage(@PathVariable("deviceId") String deviceId) { public List<AppPageNode> deviceDetailPage(@PathVariable("deviceId") String deviceId) {
DeviceInfo device = deviceRepository.findById(deviceId).orElseThrow(() -> new RuntimeException("device not found")); DeviceInfo device = deviceRepository.findById(deviceId).orElseThrow(() -> new RuntimeException("device not found"));

View File

View File

@ -9,13 +9,12 @@ import lombok.NoArgsConstructor;
@AllArgsConstructor @AllArgsConstructor
public class InvokeResult { public class InvokeResult {
public static final String SUCCESS = "success";
public static final String FAILED_UNKNOWN = "unknown";
public static final String FAILED_OFFLINE = "offline";
public static final String FAILED_PARAM_ERROR = "param_error";
public static final String FAILED_NO_AUTH = "no_auth";
private String requestId; private String requestId;
private String code; private long time;
public InvokeResult(String requestId) {
this.requestId = requestId;
this.time = System.currentTimeMillis();
}
} }

View File

@ -27,6 +27,7 @@
<properties> <properties>
<java.version>1.8</java.version> <java.version>1.8</java.version>
<keycloak-spring.version>17.0.0</keycloak-spring.version> <keycloak-spring.version>17.0.0</keycloak-spring.version>
<vertx.version>4.2.2</vertx.version>
</properties> </properties>
<dependencyManagement> <dependencyManagement>
@ -175,25 +176,25 @@
<dependency> <dependency>
<groupId>io.vertx</groupId> <groupId>io.vertx</groupId>
<artifactId>vertx-core</artifactId> <artifactId>vertx-core</artifactId>
<version>4.2.6</version> <version>${vertx.version}</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.vertx</groupId> <groupId>io.vertx</groupId>
<artifactId>vertx-mqtt</artifactId> <artifactId>vertx-mqtt</artifactId>
<version>4.2.6</version> <version>${vertx.version}</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.vertx</groupId> <groupId>io.vertx</groupId>
<artifactId>vertx-web-proxy</artifactId> <artifactId>vertx-web-proxy</artifactId>
<version>4.2.6</version> <version>${vertx.version}</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.vertx</groupId> <groupId>io.vertx</groupId>
<artifactId>vertx-web-client</artifactId> <artifactId>vertx-web-client</artifactId>
<version>4.2.6</version> <version>${vertx.version}</version>
</dependency> </dependency>
<dependency> <dependency>

Binary file not shown.

View File

@ -42,6 +42,11 @@
<artifactId>slf4j-api</artifactId> <artifactId>slf4j-api</artifactId>
</dependency> </dependency>
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-web-client</artifactId>
</dependency>
<dependency> <dependency>
<groupId>commons-io</groupId> <groupId>commons-io</groupId>
<artifactId>commons-io</artifactId> <artifactId>commons-io</artifactId>

View File

@ -1,14 +1,16 @@
package cc.iotkit.comp.biz; package cc.iotkit.comps;
import cc.iotkit.common.Constants; import cc.iotkit.common.Constants;
import io.vertx.core.Vertx; import io.vertx.core.Vertx;
import io.vertx.core.buffer.Buffer; import io.vertx.core.buffer.Buffer;
import io.vertx.core.http.HttpMethod;
import io.vertx.ext.web.client.HttpRequest; import io.vertx.ext.web.client.HttpRequest;
import io.vertx.ext.web.client.WebClient; import io.vertx.ext.web.client.WebClient;
import io.vertx.ext.web.client.WebClientOptions; import io.vertx.ext.web.client.WebClientOptions;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Data; import lombok.Data;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.util.HashMap; import java.util.HashMap;
@ -20,6 +22,7 @@ import java.util.concurrent.atomic.AtomicReference;
/** /**
* API * API
*/ */
@Slf4j
public class ApiTool { public class ApiTool {
private static final Vertx vertx; private static final Vertx vertx;
@ -48,17 +51,19 @@ public class ApiTool {
ApiTool.timeout = timeout; ApiTool.timeout = timeout;
} }
private static String getPath(String path) {
return Paths.get(Constants.API.DEVICE_BASE, path).toString();
}
/** /**
* *
*/ */
public static ApiResponse getDevices(String token) { public static ApiResponse getDevices(String token) {
HttpRequest<Buffer> request = client HttpRequest<Buffer> request = client
.post(port, host, Paths.get(Constants.API.DEVICE_BASE, Constants.API.DEVICE_LIST .post(port, host, getPath(Constants.API.DEVICE_LIST
.replace("size", "1000") .replace("{size}", "1000")
.replace("page", "1")).toString()) .replace("{page}", "1")));
.timeout(timeout) return send(token, HttpMethod.POST, request, new HashMap<>());
.putHeader("authorization", "Bearer " + token);
return sendJson(request, new HashMap<>());
} }
/** /**
@ -66,11 +71,9 @@ public class ApiTool {
*/ */
public static ApiResponse getDeviceDetail(String token, String deviceId) { public static ApiResponse getDeviceDetail(String token, String deviceId) {
HttpRequest<Buffer> request = client HttpRequest<Buffer> request = client
.post(port, host, Paths.get(Constants.API.DEVICE_BASE, Constants.API.DEVICE_DETAIL .get(port, host, getPath(Constants.API.DEVICE_DETAIL
.replace("deviceId", deviceId)).toString()) .replace("{deviceId}", deviceId)));
.timeout(timeout) return send(token, HttpMethod.GET, request, new HashMap<>());
.putHeader("authorization", "Bearer " + token);
return sendJson(request, new HashMap<>());
} }
/** /**
@ -78,11 +81,9 @@ public class ApiTool {
*/ */
public static ApiResponse setProperties(String token, String deviceId, Map<String, Object> properties) { public static ApiResponse setProperties(String token, String deviceId, Map<String, Object> properties) {
HttpRequest<Buffer> request = client HttpRequest<Buffer> request = client
.post(port, host, Paths.get(Constants.API.DEVICE_BASE, Constants.API.DEVICE_SET_PROPERTIES .post(port, host, getPath(Constants.API.DEVICE_SET_PROPERTIES
.replace("deviceId", deviceId)).toString()) .replace("{deviceId}", deviceId)));
.timeout(timeout) return send(token, HttpMethod.POST, request, properties);
.putHeader("authorization", "Bearer " + token);
return sendJson(request, properties);
} }
/** /**
@ -90,48 +91,70 @@ public class ApiTool {
*/ */
public static ApiResponse invokeService(String token, String deviceId, String service, Map<String, Object> params) { public static ApiResponse invokeService(String token, String deviceId, String service, Map<String, Object> params) {
HttpRequest<Buffer> request = client HttpRequest<Buffer> request = client
.post(port, host, Paths.get(Constants.API.DEVICE_BASE, Constants.API.DEVICE_INVOKE_SERVICE .post(port, host, getPath(Constants.API.DEVICE_INVOKE_SERVICE
.replace("deviceId", deviceId) .replace("{deviceId}", deviceId)
.replace("service", service)).toString()) .replace("{service}", service)));
.timeout(timeout) return send(token, HttpMethod.POST, request, params);
.putHeader("authorization", "Bearer " + token);
return sendJson(request, params);
} }
private static ApiResponse sendJson(HttpRequest<Buffer> request, Map<String, Object> params) { private static ApiResponse send(String token, HttpMethod method, HttpRequest<Buffer> request, Map<String, Object> params) {
AtomicReference<ApiResponse> apiResponse = new AtomicReference<>(new ApiResponse(500, "", null)); request = request
.timeout(timeout)
.putHeader("wrap-response", "json")
.putHeader("authorization", "Bearer " + token);
AtomicReference<ApiResponse> apiResponse = new AtomicReference<>(
new ApiResponse(500, "", null, System.currentTimeMillis()));
try { try {
//转为同步模式便于提供给js调用 //转为同步模式便于提供给js调用
CountDownLatch wait = new CountDownLatch(1); CountDownLatch wait = new CountDownLatch(1);
request.sendJson(params)
.onSuccess((response) -> { if (method == HttpMethod.POST) {
System.out.println(response.bodyAsString()); request.sendJson(params)
apiResponse.set(response.bodyAsJson(ApiResponse.class)); .onSuccess((response) -> {
wait.countDown(); System.out.println(response.bodyAsString());
}) apiResponse.set(response.bodyAsJson(ApiResponse.class));
.onFailure((err) -> { wait.countDown();
err.printStackTrace(); })
wait.countDown(); .onFailure((err) -> {
}); err.printStackTrace();
wait.countDown();
});
} else if (method == HttpMethod.GET) {
request.send()
.onSuccess((response) -> {
apiResponse.set(response.bodyAsJson(ApiResponse.class));
wait.countDown();
})
.onFailure((err) -> {
err.printStackTrace();
wait.countDown();
});
}
if (wait.await(timeout, TimeUnit.MILLISECONDS)) { if (wait.await(timeout, TimeUnit.MILLISECONDS)) {
return apiResponse.get(); return apiResponse.get();
} else { } else {
apiResponse.get().setCode(500); apiResponse.get().setStatus(500);
apiResponse.get().setMessage("request timeout"); apiResponse.get().setMessage("request timeout");
} }
} catch (Throwable e) { } catch (Throwable e) {
apiResponse.get().setCode(500); apiResponse.get().setStatus(500);
apiResponse.get().setMessage(e.getMessage()); apiResponse.get().setMessage(e.getMessage());
} }
return apiResponse.get(); return apiResponse.get();
} }
public static void log(String msg) {
log.info(msg);
}
@Data @Data
@NoArgsConstructor @NoArgsConstructor
@AllArgsConstructor @AllArgsConstructor
public static class ApiResponse { public static class ApiResponse {
private int code; private int status;
private String message; private String message;
private Object data; private Object data;
private long timestamp;
} }
} }

View File

@ -61,16 +61,16 @@ public class BizComponentManager {
} catch (Throwable e) { } catch (Throwable e) {
throw new BizException("get component instance error"); throw new BizException("get component instance error");
} }
componentInstance.create(new CompConfig(300, component.getConfig()));
try { try {
String componentScript = FileUtils.readFileToString(path. String componentScript = FileUtils.readFileToString(path.
resolve(ProtocolComponent.SCRIPT_FILE_NAME).toFile(), "UTF-8"); resolve(ProtocolComponent.SCRIPT_FILE_NAME).toFile(), "UTF-8");
componentInstance.setScript(componentScript); componentInstance.setScript(componentScript);
register(id, componentInstance);
} catch (IOException e) { } catch (IOException e) {
throw new BizException("get component script error", e); throw new BizException("get component script error", e);
} }
componentInstance.create(new CompConfig(300, component.getConfig()));
register(id, componentInstance);
} }
public void register(String id, IComponent component) { public void register(String id, IComponent component) {

View File

@ -0,0 +1,48 @@
package cc.iotkit.comps;
import cc.iotkit.model.protocol.ProtocolComponent;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Slf4j
@Component
public class ComponentManager {
@Autowired
private BizComponentManager bizComponentManager;
@Autowired
private DeviceComponentManager deviceComponentManager;
public void register(ProtocolComponent component) {
String type = component.getType();
if (ProtocolComponent.TYPE_BIZ.equals(type)) {
bizComponentManager.register(component);
} else if (ProtocolComponent.TYPE_DEVICE.equals(type)) {
deviceComponentManager.register(component);
}
}
public void deRegister(String id) {
bizComponentManager.deRegister(id);
deviceComponentManager.deRegister(id);
}
public void start(String id) {
bizComponentManager.start(id);
deviceComponentManager.start(id);
}
public void stop(String id) {
bizComponentManager.stop(id);
deviceComponentManager.stop(id);
}
public boolean isRunning(String id) {
return bizComponentManager.isRunning(id) || deviceComponentManager.isRunning(id);
}
}

View File

@ -50,7 +50,8 @@ public class DeviceComponentManager {
@PostConstruct @PostConstruct
public void init() { public void init() {
try { try {
List<ProtocolComponent> componentList = componentRepository.findByState(ProtocolComponent.STATE_RUNNING); List<ProtocolComponent> componentList = componentRepository.findByStateAndType(
ProtocolComponent.STATE_RUNNING, ProtocolComponent.TYPE_DEVICE);
for (ProtocolComponent component : componentList) { for (ProtocolComponent component : componentList) {
register(component); register(component);
start(component.getId()); start(component.getId());

View File

@ -43,19 +43,19 @@
<dependency> <dependency>
<groupId>io.vertx</groupId> <groupId>io.vertx</groupId>
<artifactId>vertx-core</artifactId> <artifactId>vertx-core</artifactId>
<version>4.2.6</version> <version>4.2.2</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.vertx</groupId> <groupId>io.vertx</groupId>
<artifactId>vertx-web-proxy</artifactId> <artifactId>vertx-web-proxy</artifactId>
<version>4.2.6</version> <version>4.2.2</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.vertx</groupId> <groupId>io.vertx</groupId>
<artifactId>vertx-mqtt</artifactId> <artifactId>vertx-mqtt</artifactId>
<version>4.2.6</version> <version>4.2.2</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>

Binary file not shown.

View File

@ -0,0 +1,69 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<parent>
<artifactId>protocol-gateway</artifactId>
<groupId>cc.iotkit</groupId>
<version>0.1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>http-biz-component</artifactId>
<build>
<plugins>
<plugin>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.4</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
<configuration>
<artifactSet>
<includes>
<include>io.vertx:vertx-web-proxy</include>
<include>io.vertx:vertx-web</include>
<include>io.vertx:vertx-bridge-common</include>
<include>io.vertx:vertx-http-proxy</include>
<include>io.vertx:vertx-core</include>
<include>io.netty:netty-codec-http2</include>
</includes>
</artifactSet>
</configuration>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>8</source>
<target>8</target>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.22</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-web-proxy</artifactId>
<version>4.2.2</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>cc.iotkit</groupId>
<artifactId>component</artifactId>
<version>0.1.0-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
</dependencies>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
</project>

44
protocol-gateway/http-biz-component/pom.xml Normal file → Executable file
View File

@ -28,17 +28,49 @@
<artifactId>vertx-web-proxy</artifactId> <artifactId>vertx-web-proxy</artifactId>
</dependency> </dependency>
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-web-client</artifactId>
</dependency>
<dependency> <dependency>
<groupId>cc.iotkit</groupId> <groupId>cc.iotkit</groupId>
<artifactId>component</artifactId> <artifactId>component</artifactId>
</dependency> </dependency>
</dependencies> </dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.4</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
<configuration>
<artifactSet>
<includes>
<include>io.vertx:vertx-web-proxy</include>
<include>io.vertx:vertx-web</include>
<include>io.vertx:vertx-bridge-common</include>
<include>io.vertx:vertx-http-proxy</include>
<include>io.vertx:vertx-core</include>
<include>io.netty:netty-codec-http2</include>
</includes>
</artifactSet>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>8</source>
<target>8</target>
</configuration>
</plugin>
</plugins>
</build>
</project> </project>

View File

@ -6,6 +6,7 @@ import cc.iotkit.comp.IComponent;
import io.vertx.core.MultiMap; import io.vertx.core.MultiMap;
import io.vertx.core.Vertx; import io.vertx.core.Vertx;
import io.vertx.core.http.HttpServer; import io.vertx.core.http.HttpServer;
import io.vertx.core.http.HttpServerRequest;
import io.vertx.core.http.HttpServerResponse; import io.vertx.core.http.HttpServerResponse;
import io.vertx.core.json.JsonObject; import io.vertx.core.json.JsonObject;
import io.vertx.ext.web.Router; import io.vertx.ext.web.Router;
@ -14,16 +15,21 @@ import jdk.nashorn.api.scripting.NashornScriptEngine;
import jdk.nashorn.api.scripting.ScriptObjectMirror; import jdk.nashorn.api.scripting.ScriptObjectMirror;
import lombok.Data; import lombok.Data;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import javax.script.ScriptEngineManager; import javax.script.ScriptEngineManager;
import javax.script.ScriptException; import javax.script.ScriptException;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@Slf4j import static java.nio.charset.StandardCharsets.UTF_8;
@Data @Data
@Slf4j
public class HttpBizComponent implements IComponent { public class HttpBizComponent implements IComponent {
private final Vertx vertx = Vertx.vertx(); private final Vertx vertx = Vertx.vertx();
@ -32,7 +38,9 @@ public class HttpBizComponent implements IComponent {
private Object scriptObj; private Object scriptObj;
private HttpConfig config; private CompConfig config;
private HttpConfig httpConfig;
private String script; private String script;
@ -40,7 +48,7 @@ public class HttpBizComponent implements IComponent {
@Override @Override
public void create(CompConfig config) { public void create(CompConfig config) {
this.config = JsonUtil.parse(config.getOther(), HttpConfig.class); this.httpConfig = JsonUtil.parse(config.getOther(), HttpConfig.class);
try { try {
scriptObj = engine.eval(String.format("new (function () {\n%s})()", script)); scriptObj = engine.eval(String.format("new (function () {\n%s})()", script));
} catch (ScriptException e) { } catch (ScriptException e) {
@ -54,53 +62,75 @@ public class HttpBizComponent implements IComponent {
Router backendRouter = Router.router(vertx); Router backendRouter = Router.router(vertx);
backendRouter.route().handler(BodyHandler.create()) backendRouter.route().handler(BodyHandler.create())
.handler(rc -> { .handler(rc -> {
Map<String, Object> httpHeader = getData(rc.request().headers()); try {
log.info("request header:{}", JsonUtil.toJsonString(httpHeader)); Map<String, Object> httpHeader = getData(rc.request().headers());
Map<String, List<Object>> httpParams = getListData(rc.request().params()); log.info("request header:{}", JsonUtil.toJsonString(httpHeader));
log.info("request params:{}", JsonUtil.toJsonString(httpParams)); Map<String, List<Object>> httpParams = getListData(rc.request().params());
log.info("request params:{}", JsonUtil.toJsonString(httpParams));
String contentType = rc.request().headers().get("Content-Type"); HttpServerRequest httpRequest = rc.request();
JsonObject responseHeader = new JsonObject(); String contentType = httpRequest.headers().get("Content-Type");
if ("application/json".equals(contentType)) { JsonObject responseHeader = new JsonObject();
String bodyStr = rc.toString(); if ("application/json".equals(contentType)) {
Map body = JsonUtil.parse(bodyStr, Map.class); String bodyStr = rc.getBody().toString();
log.info("request body:{}", bodyStr); Map body = JsonUtil.parse(bodyStr, Map.class);
log.info("request body:{}", bodyStr);
String response = "unknown error"; String response = "unknown error";
String name = "onReceive"; String name = "onReceive";
if (((ScriptObjectMirror) scriptObj).get(name) != null) { if (((ScriptObjectMirror) scriptObj).get(name) != null) {
try { try {
Object result = engine.invokeMethod(scriptObj, name, body); Object result = engine.invokeMethod(scriptObj,
Object resultObj = JsonUtil.toObject((ScriptObjectMirror) result); name,
if (resultObj instanceof Map) { httpRequest.method().name(),
JsonObject data = JsonObject.mapFrom(resultObj); httpRequest.path(),
responseHeader = data.getJsonObject("header"); httpHeader,
response = data.getString("content"); httpParams,
body);
Object resultObj = JsonUtil.toObject((ScriptObjectMirror) result);
if (resultObj instanceof Map) {
JsonObject data = JsonObject.mapFrom(resultObj);
responseHeader = data.getJsonObject("header");
response = data.getString("content");
response = response == null ? "" : response;
}
} catch (Throwable e) {
log.error("invokeMethod onReceive error", e);
response = e.getMessage();
} }
} catch (Throwable e) { } else {
log.error("invokeMethod onReceive error", e); log.error("required [onReceive] method");
response = e.getMessage();
} }
HttpServerResponse httpServerResponse = rc.response();
//设置响应头
responseHeader.getMap().forEach((key, value) -> {
//大写转换
key = key.replaceAll("([A-Z])", "-$1").toLowerCase();
httpServerResponse.putHeader(key, value.toString());
});
log.info("response,header:{},content:{}", responseHeader, response);
//设置响应内容
httpServerResponse
.end(response);
} else { } else {
log.error("required [onReceive] method"); rc.response().end("");
} }
} catch (Throwable e) {
HttpServerResponse httpServerResponse = rc.response(); log.error("handle request error", e);
//设置响应头 rc.response().end("server error:" + e.getMessage());
responseHeader.getMap().forEach((key, value) -> {
//大写转换
key = key.replaceAll("([A-Z])", "-$1").toLowerCase();
httpServerResponse.putHeader(key, value.toString());
});
log.info("response,header:{},content:{}", responseHeader, response);
//设置响应内容
httpServerResponse
.end(response);
} }
}); });
backendServer.requestHandler(backendRouter).listen(config.getPort()); backendServer.requestHandler(backendRouter)
.listen(httpConfig.getPort(), (http) -> {
if (http.succeeded()) {
log.info("http server create succeed,port:{}", httpConfig.getPort());
} else {
log.error("http server create failed", http.cause());
}
});
} }
@Override @Override
@ -131,4 +161,11 @@ public class HttpBizComponent implements IComponent {
return data; return data;
} }
public static void main(String[] args) throws IOException {
HttpBizComponent component = new HttpBizComponent();
component.setScript(FileUtils.readFileToString(new File("/Users/sjg/home/gitee/open-source/iotkit-parent/protocol-gateway/http-biz-component/src/main/resources/component.js"), UTF_8));
component.create(new CompConfig(1000, "{\"port\":9081}"));
component.start();
}
} }

View File

@ -0,0 +1,36 @@
//引用api工具类
var apiTool = Java.type("cc.iotkit.comp.biz.ApiTool");
//api配置
apiTool.config("http://localhost",8086,3000);
this.onReceive=function(method,path,header,params,body){
//methodpost、get、delete...
//path请求路径
//headerhttp请求头数据,结构:{xx:xx,yy:yy}
//params请求参数结构{xx:[...],yy:[...]}
//body请求体当提交的数据为json格式时使用结构{xx:xx,yy:yy}
apiTool.log("onReceive method:"+method);
apiTool.log("onReceive path:"+path);
apiTool.log("onReceive header:"+header);
apiTool.log("onReceive params:"+params);
apiTool.log("onReceive body:"+body);
var duHeader=body.header;
var namespace=duHeader.namespace;
var requestName=duHeader.name;
var messageId=duHeader.messageId;
var duPayload=duHeader.payload;
var token=duHeader.accessToken;
//设备发现
if(namespace=="DuerOS.ConnectedHome.Discovery" && requestName=="DiscoverAppliancesRequest"){
}
return {
url:"xx",//不指定直接作为响应返回
header:{
contentType:"xx"
},
content:"xx"
}
}

View File

View File

@ -11,8 +11,8 @@ public class Application {
public static void main(String[] args) throws IOException { public static void main(String[] args) throws IOException {
if (args.length == 0) { if (args.length == 0) {
// Mqtt.broker = "tcp://127.0.0.1:1883"; Mqtt.broker = "tcp://127.0.0.1:1883";
Mqtt.broker = "tcp://120.76.96.206:1883"; // Mqtt.broker = "tcp://120.76.96.206:1883";
} else { } else {
Mqtt.broker = args[0]; Mqtt.broker = args[0];
} }

View File

@ -43,13 +43,13 @@
<dependency> <dependency>
<groupId>io.vertx</groupId> <groupId>io.vertx</groupId>
<artifactId>vertx-core</artifactId> <artifactId>vertx-core</artifactId>
<version>4.2.6</version> <version>4.2.2</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.vertx</groupId> <groupId>io.vertx</groupId>
<artifactId>vertx-mqtt</artifactId> <artifactId>vertx-mqtt</artifactId>
<version>4.2.6</version> <version>4.2.2</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>