Skip to content

Commit 6e074ee

Browse files
authored
Merge pull request #1 from MichaelElmore1/dev
Support for control streams
2 parents 4c6185a + 2de0118 commit 6e074ee

9 files changed

Lines changed: 318 additions & 6 deletions
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
#include <string>
2+
3+
#include "pch.h"
4+
#include "CppUnitTest.h"
5+
#include "TestHelper.h"
6+
#include "../OSHConnect/OSHNode.h"
7+
#include "../OSHConnect/OSHSystem.h"
8+
9+
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
10+
11+
namespace OSHConnectTest {
12+
/// <summary>
13+
/// Tests for OSHConnect integration with an OpenSensorHub node.
14+
/// Note: These tests require a running OpenSensorHub node at localhost:8282
15+
/// with a system and control stream available for testing.
16+
/// </summary>
17+
TEST_CLASS(ControlStreamIntegrationTest) {
18+
TestHelper helper = TestHelper();
19+
20+
TEST_METHOD(TestControlStreams) {
21+
auto systems = helper.node.discoverSystems();
22+
auto system = TestHelper::assertNotEmptyAndGetFirst(systems);
23+
auto controlStreams = system.discoverControlStreams();
24+
Assert::IsFalse(controlStreams.empty());
25+
auto& controlStream = TestHelper::assertNotEmptyAndGetFirst(controlStreams);
26+
std::cout << "Control Stream: " << controlStream.getId() << std::endl;
27+
28+
auto commands = controlStream.fetchCommands();
29+
for (const auto& command : commands) {
30+
std::cout << "Command: " << command.toJson().dump(2) << std::endl;
31+
}
32+
}
33+
};
34+
}

OSHConnect-test/OSHConnect-test.vcxproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,7 @@
167167
</Link>
168168
</ItemDefinitionGroup>
169169
<ItemGroup>
170+
<ClCompile Include="ControlStreamIntegrationTest.cpp" />
170171
<ClCompile Include="DataStreamIntegrationTest.cpp" />
171172
<ClCompile Include="NodeManagerTest.cpp" />
172173
<ClCompile Include="ObservationIntegrationTest.cpp" />

OSHConnect-test/OSHConnect-test.vcxproj.filters

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,9 @@
4242
<ClCompile Include="WebsocketIntegrationTest.cpp">
4343
<Filter>Source Files\IntegrationTests</Filter>
4444
</ClCompile>
45+
<ClCompile Include="ControlStreamIntegrationTest.cpp">
46+
<Filter>Source Files\IntegrationTests</Filter>
47+
</ClCompile>
4548
</ItemGroup>
4649
<ItemGroup>
4750
<ClInclude Include="pch.h">

OSHConnect/OSHConnect.vcxproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,7 @@
143143
<ClInclude Include="framework.h" />
144144
<ClInclude Include="NodeManager.h" />
145145
<ClInclude Include="OSHConnect.h" />
146+
<ClInclude Include="OSHControlStream.h" />
146147
<ClInclude Include="OSHDataStream.h" />
147148
<ClInclude Include="OSHNode.h" />
148149
<ClInclude Include="OSHSystem.h" />

OSHConnect/OSHConnect.vcxproj.filters

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,9 @@
6969
<ClInclude Include="StreamManager.h">
7070
<Filter>Header Files</Filter>
7171
</ClInclude>
72+
<ClInclude Include="OSHControlStream.h">
73+
<Filter>Header Files</Filter>
74+
</ClInclude>
7275
</ItemGroup>
7376
<ItemGroup>
7477
<ClCompile Include="OSHConnect.cpp">

OSHConnect/OSHControlStream.h

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
#pragma once
2+
3+
#include <string>
4+
#include <vector>
5+
#include <CSAPI/DataModels/ControlStream.h>
6+
#include <CSAPI/DataModels/Command.h>
7+
#include <CSAPI/Query/CommandsOfControlStreamQuery.h>
8+
9+
namespace OSHConnect {
10+
class OSHSystem;
11+
12+
class OSHControlStream {
13+
private:
14+
OSHSystem* parentSystem;
15+
ConnectedSystemsAPI::DataModels::ControlStream controlStreamResource;
16+
17+
friend class OSHSystem;
18+
19+
public:
20+
OSHControlStream(OSHSystem* parentSystem, const ConnectedSystemsAPI::DataModels::ControlStream& controlStreamResource)
21+
: parentSystem(parentSystem), controlStreamResource(controlStreamResource) {
22+
}
23+
24+
/// <summary>
25+
/// Query the node for the latest commands of this control stream with the specified parameters.
26+
/// </summary>
27+
std::vector<ConnectedSystemsAPI::DataModels::Command> fetchCommands(std::string query = "") {
28+
auto response = getConSysAPI().getCommandsAPI().fetchCommandsOfControlStream(getId(), query);
29+
std::cout << "fetchCommands: " << response.getResponseBody() << std::endl;
30+
if (response.isSuccessful() && !response.getItems().empty()) {
31+
return response.getItems();
32+
}
33+
return {};
34+
}
35+
36+
/// <summary>
37+
/// Query the node for the latest commands of this control stream with the specified parameters.
38+
/// </summary>
39+
std::vector<ConnectedSystemsAPI::DataModels::Command> fetchCommands(const ConnectedSystemsAPI::Query::CommandsOfControlStreamQuery& query) {
40+
return fetchCommands(query.toString());
41+
}
42+
43+
/// <summary>
44+
/// Query the node for a specific command of this control stream by its ID.
45+
/// </summary>
46+
/// <param name="commandId">The ID of the command to fetch.</param>
47+
/// <returns>The command with the specified ID, or an empty command if not found.</returns>
48+
ConnectedSystemsAPI::DataModels::Command fetchCommandById(const std::string& commandId) {
49+
auto response = getConSysAPI().getCommandsAPI().fetchCommandById(commandId);
50+
if (response.isSuccessful()) {
51+
return response.getItem();
52+
}
53+
return ConnectedSystemsAPI::DataModels::Command{};
54+
}
55+
56+
/// <summary>
57+
/// Refresh the control stream properties from the server.
58+
/// </summary>
59+
/// <returns>True if the refresh was successful, false otherwise.</returns>
60+
bool refreshControlStream() {
61+
auto response = getConSysAPI().getControlStreamsAPI().getControlStreamById(getId());
62+
if (response.isSuccessful()) {
63+
controlStreamResource = response.getItem();
64+
return true;
65+
}
66+
return false;
67+
}
68+
69+
/// <summary>
70+
/// Create a new command for this control stream on the OpenSensorHub node using the provided command resource.
71+
/// </summary>
72+
/// <param name="command">The command resource to create.</param>
73+
/// <returns>The created command if successful, or std::nullopt if creation failed.</returns>
74+
std::string createCommand(const ConnectedSystemsAPI::DataModels::Command& command) {
75+
auto response = getConSysAPI().getCommandsAPI().createCommand(getId(), command);
76+
for (const auto& [headerKey, headerValues] : response.getHeaders()) {
77+
for (const auto& headerValue : headerValues) {
78+
if (headerKey == "Location") {
79+
// Extract command ID from Location header if available.
80+
// The Location header is in the format: /commands/{commandId}
81+
std::string location = headerValue;
82+
size_t lastSlashPos = location.find_last_of('/');
83+
if (lastSlashPos != std::string::npos && lastSlashPos + 1 < location.size()) {
84+
std::string newCommandId = location.substr(lastSlashPos + 1);
85+
return newCommandId;
86+
}
87+
}
88+
}
89+
}
90+
return "";
91+
}
92+
93+
/// <summary>
94+
/// Update an existing observation of this data stream on the OpenSensorHub node using the provided observation resource.
95+
/// </summary>
96+
/// <param name="observationId">The ID of the observation to update.</param>
97+
/// <param name="updatedCommand">The updated command resource.</param>
98+
/// <returns>True if the update was successful, false otherwise.</returns>
99+
bool updateCommand(const std::string& commandId, const ConnectedSystemsAPI::DataModels::Command& updatedCommand) {
100+
auto response = getConSysAPI().getCommandsAPI().updateCommand(commandId, updatedCommand);
101+
return response.isSuccessful();
102+
}
103+
104+
/// <summary>
105+
/// Delete an existing command of this control stream on the OpenSensorHub node by its ID.
106+
/// </summary>
107+
/// <param name="commandId">The ID of the command to delete.</param>
108+
/// <returns>True if the deletion was successful, false otherwise.</returns>
109+
bool deleteCommand(const std::string& commandId) {
110+
auto response = getConSysAPI().getCommandsAPI().deleteCommand(commandId);
111+
return response.isSuccessful();
112+
}
113+
114+
/// <summary>
115+
/// The ID of the control stream. Same as controlStreamResource.getId().
116+
/// </summary>
117+
const std::string& getId() const { return controlStreamResource.getId().value(); }
118+
119+
/// <summary>
120+
/// The control stream resource representing this control stream.
121+
/// </summary>
122+
ConnectedSystemsAPI::DataModels::ControlStream getControlStreamResource() const { return controlStreamResource; }
123+
124+
/// <summary>
125+
/// The ConnectedSystemsAPI instance used to communicate with the server.
126+
/// </summary>
127+
ConnectedSystemsAPI::ConSysAPI& getConSysAPI();
128+
129+
OSHSystem* getParentSystem() const { return parentSystem; }
130+
};
131+
}

OSHConnect/OSHDataStream.h

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,6 @@
77
#include <CSAPI/ConnectedSystemsAPI.h>
88
#include <CSAPI/Query/ObservationsOfDataStreamQuery.h>
99

10-
#include "Constants/Service.h"
11-
1210
namespace OSHConnect {
1311
class OSHSystem;
1412

@@ -28,7 +26,7 @@ namespace OSHConnect {
2826
/// Query the node for the latest observations of this data stream with the specified parameters.
2927
/// </summary>
3028
std::vector<ConnectedSystemsAPI::DataModels::Observation> fetchObservations(std::string query = "") {
31-
auto response = getConSysAPI().getObservationsAPI().getObservationsOfDataStream(getId(), query);
29+
auto response = getConSysAPI().getObservationsAPI().fetchObservationsOfDataStream(getId(), query);
3230
if (response.isSuccessful() && !response.getItems().empty()) {
3331
return response.getItems();
3432
}
@@ -48,7 +46,7 @@ namespace OSHConnect {
4846
/// <param name="observationId">The ID of the observation to fetch.</param>
4947
/// <returns>The observation with the specified ID, or an empty observation if not found.</returns>
5048
ConnectedSystemsAPI::DataModels::Observation fetchObservationById(const std::string& observationId) {
51-
auto response = getConSysAPI().getObservationsAPI().getObservationById(observationId);
49+
auto response = getConSysAPI().getObservationsAPI().fetchObservationById(observationId);
5250
if (response.isSuccessful()) {
5351
return response.getItem();
5452
}

0 commit comments

Comments
 (0)