Showing
24 changed files
with
552 additions
and
8 deletions
@@ -89,6 +89,10 @@ | @@ -89,6 +89,10 @@ | ||
89 | <artifactId>queue</artifactId> | 89 | <artifactId>queue</artifactId> |
90 | </dependency> | 90 | </dependency> |
91 | <dependency> | 91 | <dependency> |
92 | + <groupId>org.thingsboard.common</groupId> | ||
93 | + <artifactId>edge-api</artifactId> | ||
94 | + </dependency> | ||
95 | + <dependency> | ||
92 | <groupId>org.thingsboard</groupId> | 96 | <groupId>org.thingsboard</groupId> |
93 | <artifactId>dao</artifactId> | 97 | <artifactId>dao</artifactId> |
94 | <type>test-jar</type> | 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,6 +495,17 @@ transport: | ||
495 | bind_port: "${COAP_BIND_PORT:5683}" | 495 | bind_port: "${COAP_BIND_PORT:5683}" |
496 | timeout: "${COAP_TIMEOUT:10000}" | 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 | swagger: | 509 | swagger: |
499 | api_path_regex: "${SWAGGER_API_PATH_REGEX:/api.*}" | 510 | api_path_regex: "${SWAGGER_API_PATH_REGEX:/api.*}" |
500 | security_path_regex: "${SWAGGER_SECURITY_PATH_REGEX:/api.*}" | 511 | security_path_regex: "${SWAGGER_SECURITY_PATH_REGEX:/api.*}" |
@@ -26,6 +26,7 @@ import org.thingsboard.server.common.data.page.TextPageData; | @@ -26,6 +26,7 @@ import org.thingsboard.server.common.data.page.TextPageData; | ||
26 | import org.thingsboard.server.common.data.page.TextPageLink; | 26 | import org.thingsboard.server.common.data.page.TextPageLink; |
27 | 27 | ||
28 | import java.util.List; | 28 | import java.util.List; |
29 | +import java.util.Optional; | ||
29 | 30 | ||
30 | public interface EdgeService { | 31 | public interface EdgeService { |
31 | 32 | ||
@@ -35,6 +36,8 @@ public interface EdgeService { | @@ -35,6 +36,8 @@ public interface EdgeService { | ||
35 | 36 | ||
36 | Edge findEdgeByTenantIdAndName(TenantId tenantId, String name); | 37 | Edge findEdgeByTenantIdAndName(TenantId tenantId, String name); |
37 | 38 | ||
39 | + Optional<Edge> findEdgeByRoutingKey(TenantId tenantId, String routingKey); | ||
40 | + | ||
38 | Edge saveEdge(Edge edge); | 41 | Edge saveEdge(Edge edge); |
39 | 42 | ||
40 | Edge assignEdgeToCustomer(TenantId tenantId, EdgeId edgeId, CustomerId customerId); | 43 | Edge assignEdgeToCustomer(TenantId tenantId, EdgeId edgeId, CustomerId customerId); |
@@ -44,6 +44,8 @@ public class Edge extends SearchTextBasedWithAdditionalInfo<EdgeId> implements H | @@ -44,6 +44,8 @@ public class Edge extends SearchTextBasedWithAdditionalInfo<EdgeId> implements H | ||
44 | private String name; | 44 | private String name; |
45 | private String type; | 45 | private String type; |
46 | private String label; | 46 | private String label; |
47 | + private String routingKey; | ||
48 | + private String secret; | ||
47 | private transient JsonNode configuration; | 49 | private transient JsonNode configuration; |
48 | 50 | ||
49 | public Edge() { | 51 | public Edge() { |
@@ -60,6 +62,8 @@ public class Edge extends SearchTextBasedWithAdditionalInfo<EdgeId> implements H | @@ -60,6 +62,8 @@ public class Edge extends SearchTextBasedWithAdditionalInfo<EdgeId> implements H | ||
60 | this.customerId = edge.getCustomerId(); | 62 | this.customerId = edge.getCustomerId(); |
61 | this.type = edge.getType(); | 63 | this.type = edge.getType(); |
62 | this.name = edge.getName(); | 64 | this.name = edge.getName(); |
65 | + this.routingKey = edge.getRoutingKey(); | ||
66 | + this.secret = edge.getSecret(); | ||
63 | this.configuration = edge.getConfiguration(); | 67 | this.configuration = edge.getConfiguration(); |
64 | } | 68 | } |
65 | 69 |
common/edge-api/pom.xml
0 → 100644
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 | +} |
common/edge-api/src/main/proto/edge.proto
0 → 100644
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 | +} |
@@ -46,6 +46,7 @@ import org.thingsboard.server.dao.entity.AbstractEntityService; | @@ -46,6 +46,7 @@ import org.thingsboard.server.dao.entity.AbstractEntityService; | ||
46 | import org.thingsboard.server.dao.exception.DataValidationException; | 46 | import org.thingsboard.server.dao.exception.DataValidationException; |
47 | import org.thingsboard.server.dao.service.DataValidator; | 47 | import org.thingsboard.server.dao.service.DataValidator; |
48 | import org.thingsboard.server.dao.service.PaginatedRemover; | 48 | import org.thingsboard.server.dao.service.PaginatedRemover; |
49 | +import org.thingsboard.server.dao.service.Validator; | ||
49 | import org.thingsboard.server.dao.tenant.TenantDao; | 50 | import org.thingsboard.server.dao.tenant.TenantDao; |
50 | 51 | ||
51 | import javax.annotation.Nullable; | 52 | import javax.annotation.Nullable; |
@@ -111,6 +112,13 @@ public class BaseEdgeService extends AbstractEntityService implements EdgeServic | @@ -111,6 +112,13 @@ public class BaseEdgeService extends AbstractEntityService implements EdgeServic | ||
111 | return edgeOpt.orElse(null); | 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 | @CacheEvict(cacheNames = EDGE_CACHE, key = "{#edge.tenantId, #edge.name}") | 122 | @CacheEvict(cacheNames = EDGE_CACHE, key = "{#edge.tenantId, #edge.name}") |
115 | @Override | 123 | @Override |
116 | public Edge saveEdge(Edge edge) { | 124 | public Edge saveEdge(Edge edge) { |
@@ -86,4 +86,9 @@ public class CassandraEdgeDao extends CassandraAbstractSearchTextDao<EdgeEntity, | @@ -86,4 +86,9 @@ public class CassandraEdgeDao extends CassandraAbstractSearchTextDao<EdgeEntity, | ||
86 | public ListenableFuture<List<EntitySubtype>> findTenantEdgeTypesAsync(UUID tenantId) { | 86 | public ListenableFuture<List<EntitySubtype>> findTenantEdgeTypesAsync(UUID tenantId) { |
87 | return null; | 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,5 +116,12 @@ public interface EdgeDao extends Dao<Edge> { | ||
116 | */ | 116 | */ |
117 | ListenableFuture<List<EntitySubtype>> findTenantEdgeTypesAsync(UUID tenantId); | 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,7 +361,8 @@ public class ModelConstants { | ||
361 | public static final String EDGE_CONFIGURATION_PROPERTY = "configuration"; | 361 | public static final String EDGE_CONFIGURATION_PROPERTY = "configuration"; |
362 | public static final String EDGE_ADDITIONAL_INFO_PROPERTY = ADDITIONAL_INFO_PROPERTY; | 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,7 +5,7 @@ | ||
5 | * you may not use this file except in compliance with 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 | 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 | * Unless required by applicable law or agreed to in writing, software | 10 | * Unless required by applicable law or agreed to in writing, software |
11 | * distributed under the License is distributed on an "AS IS" BASIS, | 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,6 +37,8 @@ import static org.thingsboard.server.dao.model.ModelConstants.EDGE_CONFIGURATION | ||
37 | import static org.thingsboard.server.dao.model.ModelConstants.EDGE_CUSTOMER_ID_PROPERTY; | 37 | import static org.thingsboard.server.dao.model.ModelConstants.EDGE_CUSTOMER_ID_PROPERTY; |
38 | import static org.thingsboard.server.dao.model.ModelConstants.EDGE_LABEL_PROPERTY; | 38 | import static org.thingsboard.server.dao.model.ModelConstants.EDGE_LABEL_PROPERTY; |
39 | import static org.thingsboard.server.dao.model.ModelConstants.EDGE_NAME_PROPERTY; | 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 | import static org.thingsboard.server.dao.model.ModelConstants.EDGE_TENANT_ID_PROPERTY; | 42 | import static org.thingsboard.server.dao.model.ModelConstants.EDGE_TENANT_ID_PROPERTY; |
41 | import static org.thingsboard.server.dao.model.ModelConstants.EDGE_TYPE_PROPERTY; | 43 | import static org.thingsboard.server.dao.model.ModelConstants.EDGE_TYPE_PROPERTY; |
42 | import static org.thingsboard.server.dao.model.ModelConstants.ID_PROPERTY; | 44 | import static org.thingsboard.server.dao.model.ModelConstants.ID_PROPERTY; |
@@ -70,6 +72,12 @@ public class EdgeEntity implements SearchTextEntity<Edge> { | @@ -70,6 +72,12 @@ public class EdgeEntity implements SearchTextEntity<Edge> { | ||
70 | @Column(name = SEARCH_TEXT_PROPERTY) | 72 | @Column(name = SEARCH_TEXT_PROPERTY) |
71 | private String searchText; | 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 | @Column(name = EDGE_CONFIGURATION_PROPERTY, codec = JsonCodec.class) | 81 | @Column(name = EDGE_CONFIGURATION_PROPERTY, codec = JsonCodec.class) |
74 | private JsonNode configuration; | 82 | private JsonNode configuration; |
75 | 83 | ||
@@ -90,6 +98,8 @@ public class EdgeEntity implements SearchTextEntity<Edge> { | @@ -90,6 +98,8 @@ public class EdgeEntity implements SearchTextEntity<Edge> { | ||
90 | this.type = edge.getType(); | 98 | this.type = edge.getType(); |
91 | this.name = edge.getName(); | 99 | this.name = edge.getName(); |
92 | this.label = edge.getLabel(); | 100 | this.label = edge.getLabel(); |
101 | + this.routingKey = edge.getRoutingKey(); | ||
102 | + this.secret = edge.getSecret(); | ||
93 | this.configuration = edge.getConfiguration(); | 103 | this.configuration = edge.getConfiguration(); |
94 | this.additionalInfo = edge.getAdditionalInfo(); | 104 | this.additionalInfo = edge.getAdditionalInfo(); |
95 | } | 105 | } |
@@ -112,6 +122,8 @@ public class EdgeEntity implements SearchTextEntity<Edge> { | @@ -112,6 +122,8 @@ public class EdgeEntity implements SearchTextEntity<Edge> { | ||
112 | edge.setType(type); | 122 | edge.setType(type); |
113 | edge.setName(name); | 123 | edge.setName(name); |
114 | edge.setLabel(label); | 124 | edge.setLabel(label); |
125 | + edge.setRoutingKey(routingKey); | ||
126 | + edge.setSecret(secret); | ||
115 | edge.setConfiguration(configuration); | 127 | edge.setConfiguration(configuration); |
116 | edge.setAdditionalInfo(additionalInfo); | 128 | edge.setAdditionalInfo(additionalInfo); |
117 | return edge; | 129 | return edge; |
@@ -5,7 +5,7 @@ | @@ -5,7 +5,7 @@ | ||
5 | * you may not use this file except in compliance with 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 | 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 | * Unless required by applicable law or agreed to in writing, software | 10 | * Unless required by applicable law or agreed to in writing, software |
11 | * distributed under the License is distributed on an "AS IS" BASIS, | 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
@@ -35,11 +35,12 @@ import javax.persistence.Column; | @@ -35,11 +35,12 @@ import javax.persistence.Column; | ||
35 | import javax.persistence.Entity; | 35 | import javax.persistence.Entity; |
36 | import javax.persistence.Table; | 36 | import javax.persistence.Table; |
37 | 37 | ||
38 | -import static org.thingsboard.server.dao.model.ModelConstants.ASSET_CUSTOMER_ID_PROPERTY; | ||
39 | import static org.thingsboard.server.dao.model.ModelConstants.EDGE_COLUMN_FAMILY_NAME; | 38 | import static org.thingsboard.server.dao.model.ModelConstants.EDGE_COLUMN_FAMILY_NAME; |
40 | import static org.thingsboard.server.dao.model.ModelConstants.EDGE_CUSTOMER_ID_PROPERTY; | 39 | import static org.thingsboard.server.dao.model.ModelConstants.EDGE_CUSTOMER_ID_PROPERTY; |
41 | import static org.thingsboard.server.dao.model.ModelConstants.EDGE_LABEL_PROPERTY; | 40 | import static org.thingsboard.server.dao.model.ModelConstants.EDGE_LABEL_PROPERTY; |
42 | import static org.thingsboard.server.dao.model.ModelConstants.EDGE_NAME_PROPERTY; | 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 | import static org.thingsboard.server.dao.model.ModelConstants.EDGE_TENANT_ID_PROPERTY; | 44 | import static org.thingsboard.server.dao.model.ModelConstants.EDGE_TENANT_ID_PROPERTY; |
44 | import static org.thingsboard.server.dao.model.ModelConstants.EDGE_TYPE_PROPERTY; | 45 | import static org.thingsboard.server.dao.model.ModelConstants.EDGE_TYPE_PROPERTY; |
45 | import static org.thingsboard.server.dao.model.ModelConstants.SEARCH_TEXT_PROPERTY; | 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,6 +70,12 @@ public class EdgeEntity extends BaseSqlEntity<Edge> implements SearchTextEntity< | ||
69 | @Column(name = SEARCH_TEXT_PROPERTY) | 70 | @Column(name = SEARCH_TEXT_PROPERTY) |
70 | private String searchText; | 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 | @Type(type = "json") | 79 | @Type(type = "json") |
73 | @Column(name = ModelConstants.EDGE_CONFIGURATION_PROPERTY) | 80 | @Column(name = ModelConstants.EDGE_CONFIGURATION_PROPERTY) |
74 | private JsonNode configuration; | 81 | private JsonNode configuration; |
@@ -94,6 +101,8 @@ public class EdgeEntity extends BaseSqlEntity<Edge> implements SearchTextEntity< | @@ -94,6 +101,8 @@ public class EdgeEntity extends BaseSqlEntity<Edge> implements SearchTextEntity< | ||
94 | this.type = edge.getType(); | 101 | this.type = edge.getType(); |
95 | this.name = edge.getName(); | 102 | this.name = edge.getName(); |
96 | this.label = edge.getLabel(); | 103 | this.label = edge.getLabel(); |
104 | + this.routingKey = edge.getRoutingKey(); | ||
105 | + this.secret = edge.getSecret(); | ||
97 | this.configuration = edge.getConfiguration(); | 106 | this.configuration = edge.getConfiguration(); |
98 | this.additionalInfo = edge.getAdditionalInfo(); | 107 | this.additionalInfo = edge.getAdditionalInfo(); |
99 | } | 108 | } |
@@ -125,6 +134,8 @@ public class EdgeEntity extends BaseSqlEntity<Edge> implements SearchTextEntity< | @@ -125,6 +134,8 @@ public class EdgeEntity extends BaseSqlEntity<Edge> implements SearchTextEntity< | ||
125 | edge.setType(type); | 134 | edge.setType(type); |
126 | edge.setName(name); | 135 | edge.setName(name); |
127 | edge.setLabel(label); | 136 | edge.setLabel(label); |
137 | + edge.setRoutingKey(routingKey); | ||
138 | + edge.setSecret(secret); | ||
128 | edge.setConfiguration(configuration); | 139 | edge.setConfiguration(configuration); |
129 | edge.setAdditionalInfo(additionalInfo); | 140 | edge.setAdditionalInfo(additionalInfo); |
130 | return edge; | 141 | return edge; |
@@ -76,4 +76,5 @@ public interface EdgeRepository extends CrudRepository<EdgeEntity, String> { | @@ -76,4 +76,5 @@ public interface EdgeRepository extends CrudRepository<EdgeEntity, String> { | ||
76 | 76 | ||
77 | List<EdgeEntity> findEdgesByTenantIdAndIdIn(String tenantId, List<String> edgeIds); | 77 | List<EdgeEntity> findEdgesByTenantIdAndIdIn(String tenantId, List<String> edgeIds); |
78 | 78 | ||
79 | + EdgeEntity findByRoutingKey(String routingKey); | ||
79 | } | 80 | } |
@@ -5,7 +5,7 @@ | @@ -5,7 +5,7 @@ | ||
5 | * you may not use this file except in compliance with 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 | 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 | * Unless required by applicable law or agreed to in writing, software | 10 | * Unless required by applicable law or agreed to in writing, software |
11 | * distributed under the License is distributed on an "AS IS" BASIS, | 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,6 +126,12 @@ public class JpaEdgeDao extends JpaAbstractSearchTextDao<EdgeEntity, Edge> imple | ||
126 | return service.submit(() -> convertTenantEdgeTypesToDto(tenantId, edgeRepository.findTenantEdgeTypes(fromTimeUUID(tenantId)))); | 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 | private List<EntitySubtype> convertTenantEdgeTypesToDto(UUID tenantId, List<String> types) { | 135 | private List<EntitySubtype> convertTenantEdgeTypesToDto(UUID tenantId, List<String> types) { |
130 | List<EntitySubtype> list = Collections.emptyList(); | 136 | List<EntitySubtype> list = Collections.emptyList(); |
131 | if (types != null && !types.isEmpty()) { | 137 | if (types != null && !types.isEmpty()) { |
@@ -257,6 +257,8 @@ CREATE TABLE IF NOT EXISTS edge ( | @@ -257,6 +257,8 @@ CREATE TABLE IF NOT EXISTS edge ( | ||
257 | type varchar(255), | 257 | type varchar(255), |
258 | name varchar(255), | 258 | name varchar(255), |
259 | label varchar(255), | 259 | label varchar(255), |
260 | + routing_key varchar(255), | ||
261 | + secret varchar(255), | ||
260 | search_text varchar(255), | 262 | search_text varchar(255), |
261 | tenant_id varchar(31) | 263 | tenant_id varchar(31) |
262 | ); | 264 | ); |
@@ -407,6 +407,11 @@ | @@ -407,6 +407,11 @@ | ||
407 | <version>${project.version}</version> | 407 | <version>${project.version}</version> |
408 | </dependency> | 408 | </dependency> |
409 | <dependency> | 409 | <dependency> |
410 | + <groupId>org.thingsboard.common</groupId> | ||
411 | + <artifactId>edge-api</artifactId> | ||
412 | + <version>${project.version}</version> | ||
413 | + </dependency> | ||
414 | + <dependency> | ||
410 | <groupId>org.thingsboard</groupId> | 415 | <groupId>org.thingsboard</groupId> |
411 | <artifactId>dao</artifactId> | 416 | <artifactId>dao</artifactId> |
412 | <version>${project.version}</version> | 417 | <version>${project.version}</version> |
@@ -27,7 +27,7 @@ | @@ -27,7 +27,7 @@ | ||
27 | 27 | ||
28 | <div layout="row"> | 28 | <div layout="row"> |
29 | <md-button ngclipboard data-clipboard-action="copy" | 29 | <md-button ngclipboard data-clipboard-action="copy" |
30 | - ngclipboard-success="onEdgeIdCopied(e)" | 30 | + ngclipboard-success="onEdgeIdCopied()" |
31 | data-clipboard-text="{{edge.id.id}}" ng-show="!isEdit" | 31 | data-clipboard-text="{{edge.id.id}}" ng-show="!isEdit" |
32 | class="md-raised"> | 32 | class="md-raised"> |
33 | <md-icon md-svg-icon="mdi:clipboard-arrow-left"></md-icon> | 33 | <md-icon md-svg-icon="mdi:clipboard-arrow-left"></md-icon> |
@@ -69,4 +69,34 @@ | @@ -69,4 +69,34 @@ | ||
69 | <textarea ng-model="edge.additionalInfo.description" rows="2"></textarea> | 69 | <textarea ng-model="edge.additionalInfo.description" rows="2"></textarea> |
70 | </md-input-container> | 70 | </md-input-container> |
71 | </fieldset> | 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 | </md-content> | 102 | </md-content> |
@@ -20,7 +20,7 @@ import edgeFieldsetTemplate from './edge-fieldset.tpl.html'; | @@ -20,7 +20,7 @@ import edgeFieldsetTemplate from './edge-fieldset.tpl.html'; | ||
20 | /* eslint-enable import/no-unresolved, import/default */ | 20 | /* eslint-enable import/no-unresolved, import/default */ |
21 | 21 | ||
22 | /*@ngInject*/ | 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 | var linker = function (scope, element) { | 24 | var linker = function (scope, element) { |
25 | var template = $templateCache.get(edgeFieldsetTemplate); | 25 | var template = $templateCache.get(edgeFieldsetTemplate); |
26 | element.html(template); | 26 | element.html(template); |
@@ -32,6 +32,10 @@ export default function EdgeDirective($compile, $templateCache, $translate, $mdD | @@ -32,6 +32,10 @@ export default function EdgeDirective($compile, $templateCache, $translate, $mdD | ||
32 | 32 | ||
33 | scope.$watch('edge', function(newVal) { | 33 | scope.$watch('edge', function(newVal) { |
34 | if (newVal) { | 34 | if (newVal) { |
35 | + if (!scope.edge.id) { | ||
36 | + scope.edge.routingKey = utils.guid(''); | ||
37 | + scope.edge.secret = generateSecret(20); | ||
38 | + } | ||
35 | if (scope.edge.customerId && scope.edge.customerId.id !== types.id.nullUid) { | 39 | if (scope.edge.customerId && scope.edge.customerId.id !== types.id.nullUid) { |
36 | scope.isAssignedToCustomer = true; | 40 | scope.isAssignedToCustomer = true; |
37 | customerService.getShortCustomerInfo(scope.edge.customerId.id).then( | 41 | customerService.getShortCustomerInfo(scope.edge.customerId.id).then( |
@@ -48,12 +52,38 @@ export default function EdgeDirective($compile, $templateCache, $translate, $mdD | @@ -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 | scope.onEdgeIdCopied = function() { | 67 | scope.onEdgeIdCopied = function() { |
52 | toast.showSuccess($translate.instant('edge.id-copied-message'), 750, angular.element(element).parent().parent(), 'bottom left'); | 68 | toast.showSuccess($translate.instant('edge.id-copied-message'), 750, angular.element(element).parent().parent(), 'bottom left'); |
53 | }; | 69 | }; |
54 | 70 | ||
55 | $compile(element.contents())(scope); | 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 | return { | 88 | return { |
59 | restrict: "E", | 89 | restrict: "E", |
@@ -602,6 +602,16 @@ export default function ImportExport($log, $translate, $q, $mdDialog, $document, | @@ -602,6 +602,16 @@ export default function ImportExport($log, $translate, $q, $mdDialog, $document, | ||
602 | } | 602 | } |
603 | ); | 603 | ); |
604 | return deferred.promise; | 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,7 +777,13 @@ | ||
777 | "unassign-from-edge": "Unassign from edge", | 777 | "unassign-from-edge": "Unassign from edge", |
778 | "dashboards": "Edge Dashboards", | 778 | "dashboards": "Edge Dashboards", |
779 | "manage-edge-rulechains": "Manage edge rule chains", | 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 | "error": { | 788 | "error": { |
783 | "unable-to-connect": "Unable to connect to the server! Please check your internet connection.", | 789 | "unable-to-connect": "Unable to connect to the server! Please check your internet connection.", |