Skip to content

Commit bee703f

Browse files
authored
Replaced EAM dependency with a custom download intent (#149)
1 parent 85d6bf8 commit bee703f

File tree

11 files changed

+102
-50
lines changed

11 files changed

+102
-50
lines changed

gateway-network-function/README.md

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,9 @@ This module provides examples for the following functionality:
77
## How to Use This Module
88
### Requirements
99
The following are required:
10-
1. Two Gateway instances connected via the Gateway Area Network.
10+
1. Two Gateway instances connected via the Gateway Network.
1111
2. This module must be installed on both Gateways.
1212

13-
> [!NOTE]
14-
> `getRemoteLogEntries()` will work once the above requirements are met.
15-
> `getRemoteLogFile()` and `pushRemoteLogFile()` require an additional step: a Controller/Agent EAM configuration between the two Gateways must be created with the Controller being the issue of the script call and the Agent being the target of the script call.
16-
1713
### Example Scripts
1814
#### Retrieve Logs as Dataset
1915
This retrieves log entries and places them in a dataset. The dataset is sorted in reverse chronological order, with the most recent entry being first in the dataset.
@@ -47,7 +43,7 @@ bytes = system.example.gn.getRemoteLogFile(remote_gateway)
4743

4844
now=datetime.datetime.now().strftime("%m%d%Y_%H%M%S")
4945
save_file="/tmp/%s_%s-system_logs.idb" % (remote_gateway, now)
50-
print("Successfully downloaded system_logs.idb, saving to '%s'" % save_file)
46+
print("Successfully downloaded system_logs.idb, copying to local machine at '%s'" % save_file)
5147
system.file.writeFile(save_file, bytes)
5248
```
5349

gateway-network-function/gateway-network-function-build/pom.xml

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
<parent>
88
<artifactId>gateway-network-function</artifactId>
99
<groupId>com.inductiveautomation.examples</groupId>
10-
<version>2.0.0-SNAPSHOT</version>
10+
<version>2.0.1-SNAPSHOT</version>
1111
</parent>
1212

1313
<artifactId>gateway-network-function-build</artifactId>
@@ -84,13 +84,6 @@
8484
<moduleVersion>${project.version}</moduleVersion>
8585
<requiredIgnitionVersion>${ignition-platform-version}</requiredIgnitionVersion>
8686

87-
<depends>
88-
<depend>
89-
<scope>G</scope>
90-
<moduleId>com.inductiveautomation.eam</moduleId>
91-
</depend>
92-
</depends>
93-
9487
<hooks>
9588
<hook>
9689
<scope>C</scope>

gateway-network-function/gateway-network-function-client/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
<parent>
88
<artifactId>gateway-network-function</artifactId>
99
<groupId>com.inductiveautomation.examples</groupId>
10-
<version>2.0.0-SNAPSHOT</version>
10+
<version>2.0.1-SNAPSHOT</version>
1111
</parent>
1212

1313
<artifactId>gateway-network-function-client</artifactId>

gateway-network-function/gateway-network-function-common/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
<parent>
88
<artifactId>gateway-network-function</artifactId>
99
<groupId>com.inductiveautomation.examples</groupId>
10-
<version>2.0.0-SNAPSHOT</version>
10+
<version>2.0.1-SNAPSHOT</version>
1111
</parent>
1212

1313
<artifactId>gateway-network-function-common</artifactId>

gateway-network-function/gateway-network-function-designer/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
<parent>
88
<artifactId>gateway-network-function</artifactId>
99
<groupId>com.inductiveautomation.examples</groupId>
10-
<version>2.0.0-SNAPSHOT</version>
10+
<version>2.0.1-SNAPSHOT</version>
1111
</parent>
1212

1313
<artifactId>gateway-network-function-designer</artifactId>

gateway-network-function/gateway-network-function-gateway/pom.xml

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
<parent>
88
<artifactId>gateway-network-function</artifactId>
99
<groupId>com.inductiveautomation.examples</groupId>
10-
<version>2.0.0-SNAPSHOT</version>
10+
<version>2.0.1-SNAPSHOT</version>
1111
</parent>
1212

1313
<artifactId>gateway-network-function-gateway</artifactId>
@@ -29,14 +29,6 @@
2929
<scope>provided</scope>
3030
</dependency>
3131

32-
<dependency>
33-
<groupId>com.inductiveautomation.eam</groupId>
34-
<artifactId>eam-gateway</artifactId>
35-
<version>5.3.0-SNAPSHOT</version>
36-
<type>jar</type>
37-
<scope>provided</scope>
38-
</dependency>
39-
4032
<dependency>
4133
<artifactId>gateway-network-function-common</artifactId>
4234
<groupId>com.inductiveautomation.examples</groupId>

gateway-network-function/gateway-network-function-gateway/src/main/java/com/inductiveautomation/ignition/examples/gn/GatewayHook.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,18 @@
55
import java.nio.file.Files;
66
import java.util.Optional;
77
import java.util.UUID;
8+
import java.util.concurrent.atomic.AtomicInteger;
89

910
import com.inductiveautomation.ignition.common.BundleUtil;
1011
import com.inductiveautomation.ignition.common.licensing.LicenseState;
1112
import com.inductiveautomation.ignition.common.logging.LogEvent;
1213
import com.inductiveautomation.ignition.common.script.ScriptManager;
1314
import com.inductiveautomation.ignition.common.script.hints.PropertiesFileDocProvider;
15+
import com.inductiveautomation.ignition.examples.gn.intent.HandleLogFileIntent;
1416
import com.inductiveautomation.ignition.examples.gn.protoserializers.LogEventSerializer;
1517
import com.inductiveautomation.ignition.examples.gn.service.GetLogsService;
1618
import com.inductiveautomation.ignition.examples.gn.service.GetLogsServiceImpl;
19+
import com.inductiveautomation.ignition.gateway.gan.GatewayNetworkManager;
1720
import com.inductiveautomation.ignition.gateway.model.AbstractGatewayModuleHook;
1821
import com.inductiveautomation.ignition.gateway.model.GatewayContext;
1922
import com.inductiveautomation.ignition.gateway.rpc.GatewayRpcImplementation;
@@ -31,6 +34,7 @@ public class GatewayHook extends AbstractGatewayModuleHook {
3134
private GetLogsGatewayFunctions gatewayFunctions;
3235
private GatewayRpcImplementation rpc;
3336
private GetLogsService getLogsService;
37+
private final AtomicInteger taskIdAcc = new AtomicInteger();
3438

3539
@Override
3640
public void setup(GatewayContext gatewayContext) {
@@ -51,6 +55,10 @@ public void setup(GatewayContext gatewayContext) {
5155
ServiceManager sm = context.getGatewayNetworkManager().getServiceManager();
5256
getLogsService = new GetLogsServiceImpl(context, this);
5357
sm.registerService(GetLogsService.class, getLogsService);
58+
59+
// Intent setup
60+
GatewayNetworkManager gm = context.getGatewayNetworkManager();
61+
gm.registerIntent(new HandleLogFileIntent());
5462
}
5563

5664
@Override
@@ -64,6 +72,10 @@ public void shutdown() {
6472
ServiceManager sm = context.getGatewayNetworkManager().getServiceManager();
6573
sm.unregisterService(GetLogsService.class);
6674

75+
// Remove intents
76+
GatewayNetworkManager gm = context.getGatewayNetworkManager();
77+
gm.unregisterIntent(HandleLogFileIntent.NAME);
78+
6779
// Remove properties files
6880
BundleUtil.get().removeBundle(getClass());
6981
}
@@ -109,4 +121,12 @@ public File getTempLogFile() throws IOException {
109121

110122
return tempLog;
111123
}
124+
125+
/**
126+
* A central incrementer that can be used to register temporary intents
127+
*
128+
*/
129+
public Integer getNextIntentId() {
130+
return taskIdAcc.getAndIncrement();
131+
}
112132
}

gateway-network-function/gateway-network-function-gateway/src/main/java/com/inductiveautomation/ignition/examples/gn/GetLogsGatewayFunctions.java

Lines changed: 17 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,9 @@
1111
import java.util.concurrent.CompletableFuture;
1212
import java.util.concurrent.TimeUnit;
1313

14-
import com.inductiveautomation.eam.gateway.intents.ReceiveDownloadIntent;
15-
import com.inductiveautomation.eam.gateway.module.EAMGatewayHook;
1614
import com.inductiveautomation.ignition.common.logging.LogEvent;
1715
import com.inductiveautomation.ignition.common.script.hints.NoHint;
16+
import com.inductiveautomation.ignition.examples.gn.intent.HandleLogFileIntent;
1817
import com.inductiveautomation.ignition.examples.gn.service.GetLogsService;
1918
import com.inductiveautomation.ignition.gateway.gan.GatewayNetworkManager;
2019
import com.inductiveautomation.ignition.gateway.model.GatewayContext;
@@ -103,28 +102,26 @@ public byte[] getLogFileInternal(String remoteServer) throws IOException {
103102
else {
104103
/* Getting a file as a service call result is a bit tricky with the gateway network. The file must be
105104
streamed between gateways, and service call results can't be streamed directly. To get around this,
106-
we have to use the built-in ReceiveDownloadIntent and a CompletableFuture. We register a new
107-
CompletableFuture with the ReceiveDownloadIntent using a unique download id. Then we pass that id to the
108-
service call. The other gateway will retrieve the file and then make a ReceiveDownloadIntent gateway
109-
network call. It passes the file stream and download id as part of the call. On this gateway, the
110-
ReceiveDownloadIntent fires and locates our waiting CompletableFuture using the download id. It completes
111-
our CompletableFuture and passes over the full path of the downloaded log file (the file is stored in a
112-
temporary location, but can be moved as needed).
113-
114-
NB. The gateways must have EAM configured, and be setup in a Controller/Agent configuration. If EAM
115-
hasn't been configured on the instance yet, the ReceiveDownloadIntent will not be available.
105+
we have to use the HandleLogFileIntent and a CompletableFuture. The intent's receive() function on this
106+
gateway fires when it receives the streamed log file, and it will complete the CompletableFuture
107+
created here.
108+
109+
We register a new CompletableFuture with the HandleLogFileIntent using a unique download id. Then we pass
110+
that id to the service call. The other gateway will retrieve the file and then make a HandleLogFileIntent
111+
gateway network call. It passes the file stream and download id as part of the call. On this gateway,
112+
HandleLogFileIntent#receive() fires and internally retrieves our waiting CompletableFuture using the
113+
download id. It completes our CompletableFuture and passes over the full path of the downloaded log file
114+
(the file is stored in a temporary location, but can be moved as needed).
116115
*/
117-
ReceiveDownloadIntent downloadIntent = (ReceiveDownloadIntent)
118-
gm.retrieveIntent(ReceiveDownloadIntent.NAME)
119-
.orElseThrow(() -> new IllegalStateException(
120-
"ReceiveDownloadIntent not registered; EAM has not been configured."
121-
));
116+
HandleLogFileIntent logFileIntent = (HandleLogFileIntent) gm.retrieveIntent(HandleLogFileIntent.NAME)
117+
.orElseThrow(() ->
118+
new IllegalStateException("HandleLogFileIntent not registered in gateway network manager"));
122119

123120
String localGwbkPath = null;
124121
CompletableFuture<String> downloadFuture = new CompletableFuture<>();
125122

126-
int nextId = EAMGatewayHook.getInstance().getNextIntentId();
127-
downloadIntent.addPendingFuture(nextId, downloadFuture);
123+
int nextId = this.gatewayHook.getNextIntentId();
124+
logFileIntent.addPendingFuture(nextId, downloadFuture);
128125

129126
String response = null;
130127
try {
@@ -141,7 +138,7 @@ our CompletableFuture and passes over the full path of the downloaded log file (
141138
} catch (Exception e) {
142139
// Clean up the CompletableFuture since it will never be completed normally.
143140
downloadFuture.cancel(true);
144-
downloadIntent.removePendingFuture(nextId);
141+
logFileIntent.removePendingFuture(nextId);
145142
throw new IOException(e.getMessage());
146143
}
147144
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package com.inductiveautomation.ignition.examples.gn.intent;
2+
3+
import java.util.Map;
4+
import java.util.concurrent.CompletableFuture;
5+
6+
import com.google.common.collect.Maps;
7+
import com.inductiveautomation.metro.api.DiagnosticIdentifier;
8+
import com.inductiveautomation.metro.api.Intent;
9+
import com.inductiveautomation.metro.api.IntentInfo;
10+
import com.inductiveautomation.metro.api.ServerId;
11+
import com.inductiveautomation.metro.impl.codecs.SimpleStreamAwareObject;
12+
import org.apache.log4j.Logger;
13+
14+
@IntentInfo(system = "GatewayNetworkExample", task = "handleLogFile",
15+
description = "Handles a log file streamed over the Gateway Network")
16+
public class HandleLogFileIntent implements Intent<SimpleStreamAwareObject, Void> {
17+
public static final String NAME = "handle_log_file";
18+
private final Map<Integer, CompletableFuture<String>> futuresMap = Maps.newConcurrentMap();
19+
private final Logger logger = Logger.getLogger("HandleLogFileIntent");
20+
21+
@Override
22+
public String getName() {
23+
return NAME;
24+
}
25+
26+
@Override
27+
public Void receive(ServerId sourceServerAddr, SimpleStreamAwareObject sso) throws Exception {
28+
String localFilePath = sso.getFilePath();
29+
String localFileName = sso.getFileName();
30+
int downloadId = sso.getDownloadId();
31+
32+
// Grab the future from the map and return the local file path of the streamed file
33+
CompletableFuture<String> future = futuresMap.remove(downloadId);
34+
35+
if (future == null) {
36+
logger.error(String.format("No future found for download for file '%s' downloaded to '%s' from server '%s'",
37+
localFileName,
38+
localFilePath,
39+
sourceServerAddr.toDescriptiveString()));
40+
} else {
41+
future.complete(localFilePath);
42+
}
43+
44+
return null;
45+
}
46+
47+
public void addPendingFuture(Integer downloadId, CompletableFuture<String> future) {
48+
futuresMap.put(downloadId, future);
49+
}
50+
51+
public void removePendingFuture(Integer downloadId) {
52+
futuresMap.remove(downloadId);
53+
}
54+
}

gateway-network-function/gateway-network-function-gateway/src/main/java/com/inductiveautomation/ignition/examples/gn/service/GetLogsServiceImpl.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,12 @@
77
import java.util.Date;
88
import java.util.List;
99

10-
import com.inductiveautomation.eam.gateway.intents.ReceiveDownloadIntent;
1110
import com.inductiveautomation.ignition.common.logging.LogEvent;
1211
import com.inductiveautomation.ignition.common.logging.LogQueryConfig;
1312
import com.inductiveautomation.ignition.common.logging.LogQueryConfig.LogQueryConfigBuilder;
1413
import com.inductiveautomation.ignition.common.logging.LogResults;
1514
import com.inductiveautomation.ignition.examples.gn.GatewayHook;
15+
import com.inductiveautomation.ignition.examples.gn.intent.HandleLogFileIntent;
1616
import com.inductiveautomation.ignition.gateway.model.GatewayContext;
1717
import com.inductiveautomation.metro.api.Message;
1818
import com.inductiveautomation.metro.api.MessageQueue;
@@ -85,7 +85,7 @@ public String requestLogFile(ServerId requestingServer, int downloadId) {
8585
MessageQueue queue = server.getQueue(ServerInterface.DIAGNOSTIC_INFO_QUEUE_ID).orElse(server);
8686

8787
// This is already a response, so we use a post operation, which itself does not check for a response.
88-
queue.post(Message.buildWithDiagnosticMsg(ReceiveDownloadIntent.NAME, ReceiveDownloadIntent.class, sso));
88+
queue.post(Message.buildWithDiagnosticMsg(HandleLogFileIntent.NAME, HandleLogFileIntent.class, sso));
8989
return SUCCESS_MSG;
9090
}
9191
}

0 commit comments

Comments
 (0)