Commit d3bda85a9333e02cc463cad8e8a1535cd5b3caf1

Authored by Volodymyr Babak
1 parent 4327f4d3

Added routing key and secret

... ... @@ -89,6 +89,10 @@
89 89 <artifactId>queue</artifactId>
90 90 </dependency>
91 91 <dependency>
  92 + <groupId>org.thingsboard.common</groupId>
  93 + <artifactId>edge-api</artifactId>
  94 + </dependency>
  95 + <dependency>
92 96 <groupId>org.thingsboard</groupId>
93 97 <artifactId>dao</artifactId>
94 98 <type>test-jar</type>
... ...
  1 +/**
  2 + * Copyright © 2016-2019 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.service.edge.rpc;
  17 +
  18 +import com.google.common.io.Resources;
  19 +import io.grpc.Server;
  20 +import io.grpc.ServerBuilder;
  21 +import io.grpc.stub.StreamObserver;
  22 +import lombok.extern.slf4j.Slf4j;
  23 +import org.springframework.beans.factory.annotation.Value;
  24 +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
  25 +import org.springframework.stereotype.Service;
  26 +import org.thingsboard.server.common.edge.gen.EdgeProtos;
  27 +import org.thingsboard.server.common.edge.gen.EdgeRpcServiceGrpc;
  28 +
  29 +import javax.annotation.PostConstruct;
  30 +import javax.annotation.PreDestroy;
  31 +import java.io.File;
  32 +import java.io.IOException;
  33 +
  34 +@Service
  35 +@Slf4j
  36 +@ConditionalOnProperty(prefix = "edges.rpc", value = "enabled", havingValue = "true")
  37 +public class EdgeGrpcService extends EdgeRpcServiceGrpc.EdgeRpcServiceImplBase {
  38 +
  39 + @Value("${edges.rpc.port}")
  40 + private int rpcPort;
  41 + @Value("${edges.rpc.ssl.enabled}")
  42 + private boolean sslEnabled;
  43 + @Value("${edges.rpc.ssl.cert}")
  44 + private String certFileResource;
  45 + @Value("${edges.rpc.ssl.privateKey}")
  46 + private String privateKeyResource;
  47 +
  48 + private Server server;
  49 +
  50 + @PostConstruct
  51 + public void init() {
  52 + log.info("Initializing Edge RPC service!");
  53 + ServerBuilder builder = ServerBuilder.forPort(rpcPort).addService(this);
  54 + if (sslEnabled) {
  55 + try {
  56 + File certFile = new File(Resources.getResource(certFileResource).toURI());
  57 + File privateKeyFile = new File(Resources.getResource(privateKeyResource).toURI());
  58 + builder.useTransportSecurity(certFile, privateKeyFile);
  59 + } catch (Exception e) {
  60 + log.error("Unable to set up SSL context. Reason: " + e.getMessage(), e);
  61 + throw new RuntimeException("Unable to set up SSL context!", e);
  62 + }
  63 + }
  64 + server = builder.build();
  65 + log.info("Going to start Edge RPC server using port: {}", rpcPort);
  66 + try {
  67 + server.start();
  68 + } catch (IOException e) {
  69 + log.error("Failed to start Edge RPC server!", e);
  70 + throw new RuntimeException("Failed to start Edge RPC server!");
  71 + }
  72 + log.info("Edge RPC service initialized!");
  73 + }
  74 +
  75 +
  76 + @PreDestroy
  77 + public void destroy() {
  78 + if (server != null) {
  79 + server.shutdownNow();
  80 + }
  81 + }
  82 +
  83 + @Override
  84 + public StreamObserver<EdgeProtos.UplinkMsg> sendUplink(StreamObserver<EdgeProtos.DownlinkMsg> responseObserver) {
  85 + log.info("sendUplink [{}]", responseObserver);
  86 + return new StreamObserver<EdgeProtos.UplinkMsg>() {
  87 +
  88 + @Override
  89 + public void onNext(EdgeProtos.UplinkMsg uplinkMsg) {
  90 + log.info("onNext [{}]", uplinkMsg);
  91 + }
  92 +
  93 + @Override
  94 + public void onError(Throwable throwable) {
  95 + log.info("onError", throwable);
  96 + }
  97 +
  98 + @Override
  99 + public void onCompleted() {
  100 + log.info("onCompleted");
  101 + }
  102 + };
  103 + }
  104 +}
... ...
... ... @@ -495,6 +495,17 @@ transport:
495 495 bind_port: "${COAP_BIND_PORT:5683}"
496 496 timeout: "${COAP_TIMEOUT:10000}"
497 497
  498 +# Edges parameters
  499 +edges:
  500 + rpc:
  501 + enabled: "${EDGES_RPC_ENABLED:true}"
  502 + port: "${EDGES_RPC_PORT:60061}"
  503 + ssl:
  504 + # Enable/disable SSL support
  505 + enabled: "${EDGES_RPC_SSL_ENABLED:false}"
  506 + cert: "${EDGES_RPC_SSL_CERT:certChainFile.pem}"
  507 + privateKey: "${EDGES_RPC_SSL_PRIVATE_KEY:privateKeyFile.pem}"
  508 +
498 509 swagger:
499 510 api_path_regex: "${SWAGGER_API_PATH_REGEX:/api.*}"
500 511 security_path_regex: "${SWAGGER_SECURITY_PATH_REGEX:/api.*}"
... ...
... ... @@ -26,6 +26,7 @@ import org.thingsboard.server.common.data.page.TextPageData;
26 26 import org.thingsboard.server.common.data.page.TextPageLink;
27 27
28 28 import java.util.List;
  29 +import java.util.Optional;
29 30
30 31 public interface EdgeService {
31 32
... ... @@ -35,6 +36,8 @@ public interface EdgeService {
35 36
36 37 Edge findEdgeByTenantIdAndName(TenantId tenantId, String name);
37 38
  39 + Optional<Edge> findEdgeByRoutingKey(TenantId tenantId, String routingKey);
  40 +
38 41 Edge saveEdge(Edge edge);
39 42
40 43 Edge assignEdgeToCustomer(TenantId tenantId, EdgeId edgeId, CustomerId customerId);
... ...
... ... @@ -44,6 +44,8 @@ public class Edge extends SearchTextBasedWithAdditionalInfo<EdgeId> implements H
44 44 private String name;
45 45 private String type;
46 46 private String label;
  47 + private String routingKey;
  48 + private String secret;
47 49 private transient JsonNode configuration;
48 50
49 51 public Edge() {
... ... @@ -60,6 +62,8 @@ public class Edge extends SearchTextBasedWithAdditionalInfo<EdgeId> implements H
60 62 this.customerId = edge.getCustomerId();
61 63 this.type = edge.getType();
62 64 this.name = edge.getName();
  65 + this.routingKey = edge.getRoutingKey();
  66 + this.secret = edge.getSecret();
63 67 this.configuration = edge.getConfiguration();
64 68 }
65 69
... ...
  1 +<!--
  2 +
  3 + Copyright © 2016-2019 The Thingsboard Authors
  4 +
  5 + Licensed under the Apache License, Version 2.0 (the "License");
  6 + you may not use this file except in compliance with the License.
  7 + You may obtain a copy of the License at
  8 +
  9 + http://www.apache.org/licenses/LICENSE-2.0
  10 +
  11 + Unless required by applicable law or agreed to in writing, software
  12 + distributed under the License is distributed on an "AS IS" BASIS,
  13 + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14 + See the License for the specific language governing permissions and
  15 + limitations under the License.
  16 +
  17 +-->
  18 +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  19 + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  20 + <modelVersion>4.0.0</modelVersion>
  21 + <parent>
  22 + <groupId>org.thingsboard</groupId>
  23 + <version>2.4.1-SNAPSHOT</version>
  24 + <artifactId>common</artifactId>
  25 + </parent>
  26 + <groupId>org.thingsboard.common</groupId>
  27 + <artifactId>edge-api</artifactId>
  28 + <packaging>jar</packaging>
  29 +
  30 + <name>Thingsboard Server Remote Edge wrapper</name>
  31 + <url>https://thingsboard.io</url>
  32 +
  33 + <properties>
  34 + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  35 + <main.dir>${basedir}/../..</main.dir>
  36 + </properties>
  37 +
  38 + <dependencies>
  39 + <dependency>
  40 + <groupId>org.thingsboard.common</groupId>
  41 + <artifactId>data</artifactId>
  42 + </dependency>
  43 + <dependency>
  44 + <groupId>org.thingsboard.common</groupId>
  45 + <artifactId>message</artifactId>
  46 + </dependency>
  47 + <dependency>
  48 + <groupId>com.google.code.gson</groupId>
  49 + <artifactId>gson</artifactId>
  50 + </dependency>
  51 + <dependency>
  52 + <groupId>org.slf4j</groupId>
  53 + <artifactId>slf4j-api</artifactId>
  54 + </dependency>
  55 + <dependency>
  56 + <groupId>org.slf4j</groupId>
  57 + <artifactId>log4j-over-slf4j</artifactId>
  58 + </dependency>
  59 + <dependency>
  60 + <groupId>ch.qos.logback</groupId>
  61 + <artifactId>logback-core</artifactId>
  62 + </dependency>
  63 + <dependency>
  64 + <groupId>ch.qos.logback</groupId>
  65 + <artifactId>logback-classic</artifactId>
  66 + </dependency>
  67 + <dependency>
  68 + <groupId>org.springframework</groupId>
  69 + <artifactId>spring-context</artifactId>
  70 + </dependency>
  71 + <dependency>
  72 + <groupId>org.springframework.boot</groupId>
  73 + <artifactId>spring-boot-starter-web</artifactId>
  74 + </dependency>
  75 + <dependency>
  76 + <groupId>io.netty</groupId>
  77 + <artifactId>netty-all</artifactId>
  78 + <scope>provided</scope>
  79 + </dependency>
  80 + <dependency>
  81 + <groupId>com.google.guava</groupId>
  82 + <artifactId>guava</artifactId>
  83 + </dependency>
  84 + <dependency>
  85 + <groupId>io.grpc</groupId>
  86 + <artifactId>grpc-netty</artifactId>
  87 + <exclusions>
  88 + <exclusion>
  89 + <artifactId>netty-transport</artifactId>
  90 + <groupId>io.netty</groupId>
  91 + </exclusion>
  92 + <exclusion>
  93 + <artifactId>netty-common</artifactId>
  94 + <groupId>io.netty</groupId>
  95 + </exclusion>
  96 + </exclusions>
  97 + </dependency>
  98 + <dependency>
  99 + <groupId>io.grpc</groupId>
  100 + <artifactId>grpc-protobuf</artifactId>
  101 + </dependency>
  102 + <dependency>
  103 + <groupId>io.grpc</groupId>
  104 + <artifactId>grpc-stub</artifactId>
  105 + </dependency>
  106 + <dependency>
  107 + <groupId>com.google.protobuf</groupId>
  108 + <artifactId>protobuf-java</artifactId>
  109 + </dependency>
  110 + </dependencies>
  111 +
  112 + <build>
  113 + <plugins>
  114 + <plugin>
  115 + <groupId>org.xolstice.maven.plugins</groupId>
  116 + <artifactId>protobuf-maven-plugin</artifactId>
  117 + </plugin>
  118 + </plugins>
  119 + </build>
  120 +
  121 + <distributionManagement>
  122 + <repository>
  123 + <id>thingsboard-repo-deploy</id>
  124 + <name>ThingsBoard Repo Deployment</name>
  125 + <url>https://repo.thingsboard.io/artifactory/libs-release-public</url>
  126 + </repository>
  127 + </distributionManagement>
  128 +
  129 +</project>
... ...
  1 +/**
  2 + * Copyright © 2016-2019 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.edge.rpc;
  17 +
  18 +import com.google.common.io.Resources;
  19 +import io.grpc.ManagedChannel;
  20 +import io.grpc.netty.GrpcSslContexts;
  21 +import io.grpc.netty.NettyChannelBuilder;
  22 +import io.grpc.stub.StreamObserver;
  23 +import lombok.extern.slf4j.Slf4j;
  24 +import org.springframework.beans.factory.annotation.Value;
  25 +import org.springframework.stereotype.Service;
  26 +import org.thingsboard.server.common.edge.gen.EdgeProtos;
  27 +import org.thingsboard.server.common.edge.gen.EdgeRpcServiceGrpc;
  28 +
  29 +import javax.net.ssl.SSLException;
  30 +import java.io.File;
  31 +import java.net.URISyntaxException;
  32 +
  33 +@Service
  34 +@Slf4j
  35 +public class EdgeGrpcClient implements EdgeRpcClient {
  36 +
  37 + @Value("${cloud.rpc.host}")
  38 + private String rpcHost;
  39 + @Value("${cloud.rpc.port}")
  40 + private int rpcPort;
  41 + @Value("${cloud.rpc.timeout}")
  42 + private int timeoutSecs;
  43 + @Value("${cloud.rpc.ssl.enabled}")
  44 + private boolean sslEnabled;
  45 + @Value("${cloud.rpc.ssl.cert}")
  46 + private String certResource;
  47 +
  48 + private ManagedChannel channel;
  49 +
  50 + private StreamObserver<EdgeProtos.UplinkMsg> inputStream;
  51 +
  52 + @Override
  53 + public void connect() {
  54 + NettyChannelBuilder builder = NettyChannelBuilder.forAddress(rpcHost, rpcPort).usePlaintext();
  55 + if (sslEnabled) {
  56 + try {
  57 + builder.sslContext(GrpcSslContexts.forClient().trustManager(new File(Resources.getResource(certResource).toURI())).build());
  58 + } catch (URISyntaxException | SSLException e) {
  59 + log.error("Failed to initialize channel!", e);
  60 + throw new RuntimeException(e);
  61 + }
  62 + }
  63 + channel = builder.build();
  64 + EdgeRpcServiceGrpc.EdgeRpcServiceStub stub = EdgeRpcServiceGrpc.newStub(channel);
  65 + StreamObserver<EdgeProtos.DownlinkMsg> responseObserver = new StreamObserver<EdgeProtos.DownlinkMsg>() {
  66 + @Override
  67 + public void onNext(EdgeProtos.DownlinkMsg downlinkMsg) {
  68 + log.info("onNext [{}]", downlinkMsg);
  69 + }
  70 +
  71 + @Override
  72 + public void onError(Throwable throwable) {
  73 +
  74 + }
  75 +
  76 + @Override
  77 + public void onCompleted() {
  78 +
  79 + }
  80 + };
  81 + inputStream = stub.sendUplink(responseObserver);
  82 + inputStream.onNext(EdgeProtos.UplinkMsg.newBuilder().setMsgType(EdgeProtos.UplinkMsgType.DELETE_DEVICE_MESSAGE).build());
  83 + }
  84 +}
... ...
  1 +/**
  2 + * Copyright © 2016-2019 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.edge.rpc;
  17 +
  18 +public interface EdgeRpcClient {
  19 +
  20 + void connect();
  21 +}
... ...
  1 +/**
  2 + * Copyright © 2016-2019 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +syntax = "proto3";
  17 +
  18 +option java_package = "org.thingsboard.server.common.edge.gen";
  19 +option java_outer_classname = "EdgeProtos";
  20 +
  21 +package edge;
  22 +
  23 +// Interface exported by the ThingsBoard PRC Edge.
  24 +service EdgeRpcService {
  25 +
  26 + rpc sendUplink(stream UplinkMsg) returns (stream DownlinkMsg) {}
  27 +
  28 +}
  29 +
  30 +/**
  31 + * Data Structures;
  32 + */
  33 +message UplinkMsg {
  34 + UplinkMsgType msgType = 1;
  35 +}
  36 +
  37 +message DownlinkMsg {
  38 + DownlinkMsgType msgType = 1;
  39 +}
  40 +
  41 +enum UplinkMsgType {
  42 + SAVE_DEVICE_MESSAGE = 0;
  43 + DELETE_DEVICE_MESSAGE = 1;
  44 +}
  45 +
  46 +enum DownlinkMsgType {
  47 + SAVE_ENTITY_MESSAGE = 0;
  48 + DELETE_ENTITY_MESSAGE = 1;
  49 +}
... ...
... ... @@ -40,6 +40,7 @@
40 40 <module>queue</module>
41 41 <module>transport</module>
42 42 <module>dao-api</module>
  43 + <module>edge-api</module>
43 44 </modules>
44 45
45 46 </project>
... ...
... ... @@ -46,6 +46,7 @@ import org.thingsboard.server.dao.entity.AbstractEntityService;
46 46 import org.thingsboard.server.dao.exception.DataValidationException;
47 47 import org.thingsboard.server.dao.service.DataValidator;
48 48 import org.thingsboard.server.dao.service.PaginatedRemover;
  49 +import org.thingsboard.server.dao.service.Validator;
49 50 import org.thingsboard.server.dao.tenant.TenantDao;
50 51
51 52 import javax.annotation.Nullable;
... ... @@ -111,6 +112,13 @@ public class BaseEdgeService extends AbstractEntityService implements EdgeServic
111 112 return edgeOpt.orElse(null);
112 113 }
113 114
  115 + @Override
  116 + public Optional<Edge> findEdgeByRoutingKey(TenantId tenantId, String routingKey) {
  117 + log.trace("Executing findEdgeByRoutingKey [{}]", routingKey);
  118 + Validator.validateString(routingKey, "Incorrect edge routingKey for search request.");
  119 + return edgeDao.findByRoutingKey(tenantId.getId(), routingKey);
  120 + }
  121 +
114 122 @CacheEvict(cacheNames = EDGE_CACHE, key = "{#edge.tenantId, #edge.name}")
115 123 @Override
116 124 public Edge saveEdge(Edge edge) {
... ...
... ... @@ -86,4 +86,9 @@ public class CassandraEdgeDao extends CassandraAbstractSearchTextDao<EdgeEntity,
86 86 public ListenableFuture<List<EntitySubtype>> findTenantEdgeTypesAsync(UUID tenantId) {
87 87 return null;
88 88 }
  89 +
  90 + @Override
  91 + public Optional<Edge> findByRoutingKey(UUID tenantId, String routingKey) {
  92 + return Optional.empty();
  93 + }
89 94 }
... ...
... ... @@ -116,5 +116,12 @@ public interface EdgeDao extends Dao<Edge> {
116 116 */
117 117 ListenableFuture<List<EntitySubtype>> findTenantEdgeTypesAsync(UUID tenantId);
118 118
  119 + /**
  120 + * Find edge by routing Key.
  121 + *
  122 + * @param routingKey the edge routingKey
  123 + * @return the optional edge object
  124 + */
  125 + Optional<Edge> findByRoutingKey(UUID tenantId, String routingKey);
119 126
120 127 }
... ...
... ... @@ -361,7 +361,8 @@ public class ModelConstants {
361 361 public static final String EDGE_CONFIGURATION_PROPERTY = "configuration";
362 362 public static final String EDGE_ADDITIONAL_INFO_PROPERTY = ADDITIONAL_INFO_PROPERTY;
363 363
364   - public static final String EDGE_BY_TENANT_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME = "edge_by_tenant_and_search_text";
  364 + public static final String EDGE_ROUTING_KEY_PROPERTY = "routing_key";
  365 + public static final String EDGE_SECRET_PROPERTY = "secret";
365 366
366 367
367 368 /**
... ...
... ... @@ -5,7 +5,7 @@
5 5 * you may not use this file except in compliance with the License.
6 6 * You may obtain a copy of the License at
7 7 *
8   - * http://www.apache.org/licenses/LICENSE-2.0
  8 + * http://www.apache.org/licenses/LICENSE-2.0
9 9 *
10 10 * Unless required by applicable law or agreed to in writing, software
11 11 * distributed under the License is distributed on an "AS IS" BASIS,
... ... @@ -37,6 +37,8 @@ import static org.thingsboard.server.dao.model.ModelConstants.EDGE_CONFIGURATION
37 37 import static org.thingsboard.server.dao.model.ModelConstants.EDGE_CUSTOMER_ID_PROPERTY;
38 38 import static org.thingsboard.server.dao.model.ModelConstants.EDGE_LABEL_PROPERTY;
39 39 import static org.thingsboard.server.dao.model.ModelConstants.EDGE_NAME_PROPERTY;
  40 +import static org.thingsboard.server.dao.model.ModelConstants.EDGE_ROUTING_KEY_PROPERTY;
  41 +import static org.thingsboard.server.dao.model.ModelConstants.EDGE_SECRET_PROPERTY;
40 42 import static org.thingsboard.server.dao.model.ModelConstants.EDGE_TENANT_ID_PROPERTY;
41 43 import static org.thingsboard.server.dao.model.ModelConstants.EDGE_TYPE_PROPERTY;
42 44 import static org.thingsboard.server.dao.model.ModelConstants.ID_PROPERTY;
... ... @@ -70,6 +72,12 @@ public class EdgeEntity implements SearchTextEntity<Edge> {
70 72 @Column(name = SEARCH_TEXT_PROPERTY)
71 73 private String searchText;
72 74
  75 + @Column(name = EDGE_ROUTING_KEY_PROPERTY)
  76 + private String routingKey;
  77 +
  78 + @Column(name = EDGE_SECRET_PROPERTY)
  79 + private String secret;
  80 +
73 81 @Column(name = EDGE_CONFIGURATION_PROPERTY, codec = JsonCodec.class)
74 82 private JsonNode configuration;
75 83
... ... @@ -90,6 +98,8 @@ public class EdgeEntity implements SearchTextEntity<Edge> {
90 98 this.type = edge.getType();
91 99 this.name = edge.getName();
92 100 this.label = edge.getLabel();
  101 + this.routingKey = edge.getRoutingKey();
  102 + this.secret = edge.getSecret();
93 103 this.configuration = edge.getConfiguration();
94 104 this.additionalInfo = edge.getAdditionalInfo();
95 105 }
... ... @@ -112,6 +122,8 @@ public class EdgeEntity implements SearchTextEntity<Edge> {
112 122 edge.setType(type);
113 123 edge.setName(name);
114 124 edge.setLabel(label);
  125 + edge.setRoutingKey(routingKey);
  126 + edge.setSecret(secret);
115 127 edge.setConfiguration(configuration);
116 128 edge.setAdditionalInfo(additionalInfo);
117 129 return edge;
... ...
... ... @@ -5,7 +5,7 @@
5 5 * you may not use this file except in compliance with the License.
6 6 * You may obtain a copy of the License at
7 7 *
8   - * http://www.apache.org/licenses/LICENSE-2.0
  8 + * http://www.apache.org/licenses/LICENSE-2.0
9 9 *
10 10 * Unless required by applicable law or agreed to in writing, software
11 11 * distributed under the License is distributed on an "AS IS" BASIS,
... ... @@ -35,11 +35,12 @@ import javax.persistence.Column;
35 35 import javax.persistence.Entity;
36 36 import javax.persistence.Table;
37 37
38   -import static org.thingsboard.server.dao.model.ModelConstants.ASSET_CUSTOMER_ID_PROPERTY;
39 38 import static org.thingsboard.server.dao.model.ModelConstants.EDGE_COLUMN_FAMILY_NAME;
40 39 import static org.thingsboard.server.dao.model.ModelConstants.EDGE_CUSTOMER_ID_PROPERTY;
41 40 import static org.thingsboard.server.dao.model.ModelConstants.EDGE_LABEL_PROPERTY;
42 41 import static org.thingsboard.server.dao.model.ModelConstants.EDGE_NAME_PROPERTY;
  42 +import static org.thingsboard.server.dao.model.ModelConstants.EDGE_ROUTING_KEY_PROPERTY;
  43 +import static org.thingsboard.server.dao.model.ModelConstants.EDGE_SECRET_PROPERTY;
43 44 import static org.thingsboard.server.dao.model.ModelConstants.EDGE_TENANT_ID_PROPERTY;
44 45 import static org.thingsboard.server.dao.model.ModelConstants.EDGE_TYPE_PROPERTY;
45 46 import static org.thingsboard.server.dao.model.ModelConstants.SEARCH_TEXT_PROPERTY;
... ... @@ -69,6 +70,12 @@ public class EdgeEntity extends BaseSqlEntity<Edge> implements SearchTextEntity<
69 70 @Column(name = SEARCH_TEXT_PROPERTY)
70 71 private String searchText;
71 72
  73 + @Column(name = EDGE_ROUTING_KEY_PROPERTY)
  74 + private String routingKey;
  75 +
  76 + @Column(name = EDGE_SECRET_PROPERTY)
  77 + private String secret;
  78 +
72 79 @Type(type = "json")
73 80 @Column(name = ModelConstants.EDGE_CONFIGURATION_PROPERTY)
74 81 private JsonNode configuration;
... ... @@ -94,6 +101,8 @@ public class EdgeEntity extends BaseSqlEntity<Edge> implements SearchTextEntity<
94 101 this.type = edge.getType();
95 102 this.name = edge.getName();
96 103 this.label = edge.getLabel();
  104 + this.routingKey = edge.getRoutingKey();
  105 + this.secret = edge.getSecret();
97 106 this.configuration = edge.getConfiguration();
98 107 this.additionalInfo = edge.getAdditionalInfo();
99 108 }
... ... @@ -125,6 +134,8 @@ public class EdgeEntity extends BaseSqlEntity<Edge> implements SearchTextEntity<
125 134 edge.setType(type);
126 135 edge.setName(name);
127 136 edge.setLabel(label);
  137 + edge.setRoutingKey(routingKey);
  138 + edge.setSecret(secret);
128 139 edge.setConfiguration(configuration);
129 140 edge.setAdditionalInfo(additionalInfo);
130 141 return edge;
... ...
... ... @@ -76,4 +76,5 @@ public interface EdgeRepository extends CrudRepository<EdgeEntity, String> {
76 76
77 77 List<EdgeEntity> findEdgesByTenantIdAndIdIn(String tenantId, List<String> edgeIds);
78 78
  79 + EdgeEntity findByRoutingKey(String routingKey);
79 80 }
... ...
... ... @@ -5,7 +5,7 @@
5 5 * you may not use this file except in compliance with the License.
6 6 * You may obtain a copy of the License at
7 7 *
8   - * http://www.apache.org/licenses/LICENSE-2.0
  8 + * http://www.apache.org/licenses/LICENSE-2.0
9 9 *
10 10 * Unless required by applicable law or agreed to in writing, software
11 11 * distributed under the License is distributed on an "AS IS" BASIS,
... ... @@ -126,6 +126,12 @@ public class JpaEdgeDao extends JpaAbstractSearchTextDao<EdgeEntity, Edge> imple
126 126 return service.submit(() -> convertTenantEdgeTypesToDto(tenantId, edgeRepository.findTenantEdgeTypes(fromTimeUUID(tenantId))));
127 127 }
128 128
  129 + @Override
  130 + public Optional<Edge> findByRoutingKey(UUID tenantId, String routingKey) {
  131 + Edge edge = DaoUtil.getData(edgeRepository.findByRoutingKey(routingKey));
  132 + return Optional.ofNullable(edge);
  133 + }
  134 +
129 135 private List<EntitySubtype> convertTenantEdgeTypesToDto(UUID tenantId, List<String> types) {
130 136 List<EntitySubtype> list = Collections.emptyList();
131 137 if (types != null && !types.isEmpty()) {
... ...
... ... @@ -257,6 +257,8 @@ CREATE TABLE IF NOT EXISTS edge (
257 257 type varchar(255),
258 258 name varchar(255),
259 259 label varchar(255),
  260 + routing_key varchar(255),
  261 + secret varchar(255),
260 262 search_text varchar(255),
261 263 tenant_id varchar(31)
262 264 );
\ No newline at end of file
... ...
... ... @@ -407,6 +407,11 @@
407 407 <version>${project.version}</version>
408 408 </dependency>
409 409 <dependency>
  410 + <groupId>org.thingsboard.common</groupId>
  411 + <artifactId>edge-api</artifactId>
  412 + <version>${project.version}</version>
  413 + </dependency>
  414 + <dependency>
410 415 <groupId>org.thingsboard</groupId>
411 416 <artifactId>dao</artifactId>
412 417 <version>${project.version}</version>
... ...
... ... @@ -27,7 +27,7 @@
27 27
28 28 <div layout="row">
29 29 <md-button ngclipboard data-clipboard-action="copy"
30   - ngclipboard-success="onEdgeIdCopied(e)"
  30 + ngclipboard-success="onEdgeIdCopied()"
31 31 data-clipboard-text="{{edge.id.id}}" ng-show="!isEdit"
32 32 class="md-raised">
33 33 <md-icon md-svg-icon="mdi:clipboard-arrow-left"></md-icon>
... ... @@ -69,4 +69,34 @@
69 69 <textarea ng-model="edge.additionalInfo.description" rows="2"></textarea>
70 70 </md-input-container>
71 71 </fieldset>
  72 + <div layout="row">
  73 + <md-input-container class="md-block" flex>
  74 + <label translate>edge.edge-key</label>
  75 + <input ng-model="edge.routingKey" disabled>
  76 + </md-input-container>
  77 + <md-button class="md-icon-button" style="margin-top: 14px;"
  78 + ngclipboard data-clipboard-action="copy"
  79 + ngclipboard-success="onEdgeInfoCopied('key')"
  80 + data-clipboard-text="{{edge.routingKey}}">
  81 + <md-icon md-svg-icon="mdi:clipboard-arrow-left"></md-icon>
  82 + <md-tooltip md-direction="top">
  83 + {{ 'edge.copy-edge-key' | translate }}
  84 + </md-tooltip>
  85 + </md-button>
  86 + </div>
  87 + <div layout="row">
  88 + <md-input-container class="md-block" flex>
  89 + <label translate>edge.edge-secret</label>
  90 + <input ng-model="edge.secret" disabled>
  91 + </md-input-container>
  92 + <md-button class="md-icon-button" style="margin-top: 14px;"
  93 + ngclipboard data-clipboard-action="copy"
  94 + data-clipboard-text="{{edge.secret}}"
  95 + ngclipboard-success="onEdgeInfoCopied('secret')">
  96 + <md-icon md-svg-icon="mdi:clipboard-arrow-left"></md-icon>
  97 + <md-tooltip md-direction="top">
  98 + {{ 'edge.copy-edge-secret' | translate }}
  99 + </md-tooltip>
  100 + </md-button>
  101 + </div>
72 102 </md-content>
... ...
... ... @@ -20,7 +20,7 @@ import edgeFieldsetTemplate from './edge-fieldset.tpl.html';
20 20 /* eslint-enable import/no-unresolved, import/default */
21 21
22 22 /*@ngInject*/
23   -export default function EdgeDirective($compile, $templateCache, $translate, $mdDialog, $document, toast, types, customerService) {
  23 +export default function EdgeDirective($compile, $templateCache, $translate, $mdDialog, $document, utils, toast, types, customerService) {
24 24 var linker = function (scope, element) {
25 25 var template = $templateCache.get(edgeFieldsetTemplate);
26 26 element.html(template);
... ... @@ -32,6 +32,10 @@ export default function EdgeDirective($compile, $templateCache, $translate, $mdD
32 32
33 33 scope.$watch('edge', function(newVal) {
34 34 if (newVal) {
  35 + if (!scope.edge.id) {
  36 + scope.edge.routingKey = utils.guid('');
  37 + scope.edge.secret = generateSecret(20);
  38 + }
35 39 if (scope.edge.customerId && scope.edge.customerId.id !== types.id.nullUid) {
36 40 scope.isAssignedToCustomer = true;
37 41 customerService.getShortCustomerInfo(scope.edge.customerId.id).then(
... ... @@ -48,12 +52,38 @@ export default function EdgeDirective($compile, $templateCache, $translate, $mdD
48 52 }
49 53 });
50 54
  55 + function generateSecret(length) {
  56 + if (angular.isUndefined(length) || length == null) {
  57 + length = 1;
  58 + }
  59 + var l = length > 10 ? 10 : length;
  60 + var str = Math.random().toString(36).substr(2, l);
  61 + if(str.length >= length){
  62 + return str;
  63 + }
  64 + return str.concat(generateSecret(length - str.length));
  65 + }
  66 +
51 67 scope.onEdgeIdCopied = function() {
52 68 toast.showSuccess($translate.instant('edge.id-copied-message'), 750, angular.element(element).parent().parent(), 'bottom left');
53 69 };
54 70
55 71 $compile(element.contents())(scope);
56 72
  73 + scope.onEdgeInfoCopied = function(type) {
  74 + let translateInstant = "";
  75 + switch (type) {
  76 + case 'key':
  77 + translateInstant = "edge.edge-key-copied-message";
  78 + break;
  79 + case 'secret':
  80 + translateInstant = "edge.edge-secret-copied-message";
  81 + break;
  82 + }
  83 + toast.showSuccess($translate.instant(translateInstant), 750, angular.element(element).parent().parent(), 'top left');
  84 + };
  85 +
  86 +
57 87 };
58 88 return {
59 89 restrict: "E",
... ...
... ... @@ -602,6 +602,16 @@ export default function ImportExport($log, $translate, $q, $mdDialog, $document,
602 602 }
603 603 );
604 604 return deferred.promise;
  605 + case types.entityType.edge:
  606 + openImportDialogCSV($event, entityType, 'edge.import', 'edge.edge-file').then(
  607 + function success() {
  608 + deferred.resolve();
  609 + },
  610 + function fail() {
  611 + deferred.reject();
  612 + }
  613 + );
  614 + return deferred.promise;
605 615 }
606 616
607 617 }
... ...
... ... @@ -777,7 +777,13 @@
777 777 "unassign-from-edge": "Unassign from edge",
778 778 "dashboards": "Edge Dashboards",
779 779 "manage-edge-rulechains": "Manage edge rule chains",
780   - "rulechains": "Edge Rule Chains"
  780 + "rulechains": "Edge Rule Chains",
  781 + "edge-key": "Edge key",
  782 + "copy-edge-key": "Copy edge key",
  783 + "edge-key-copied-message": "Edge key has been copied to clipboard",
  784 + "edge-secret": "Edge secret",
  785 + "copy-edge-secret": "Copy edge secret",
  786 + "edge-secret-copied-message": "Edge secret has been copied to clipboard"
781 787 },
782 788 "error": {
783 789 "unable-to-connect": "Unable to connect to the server! Please check your internet connection.",
... ...