Skip to content

Commit d034207

Browse files
committed
Merge branch 'master_community' into seeds
2 parents c1a1b3d + fd1db0c commit d034207

File tree

6 files changed

+230
-7
lines changed

6 files changed

+230
-7
lines changed

.gitignore

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,10 @@ __pycache__
1313
.coverage
1414
htmlcov/
1515

16-
# IDE project files
16+
# IDE Visual Studio files
17+
.vs
18+
19+
# IDE VSCode project files
1720
/nbproject/
1821
.vscode
1922
.ycm_extra_conf.py

docs/NetworkAPI_REST.md

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,15 +30,15 @@ Network (key is id)
3030
Parameters (key is parameter name)
3131
Inputs (key is input name)
3232
Outputs (key is output name)
33-
Links (key is link name)
33+
Links (key is "from_region.from_output", "to_region.to_input")
3434
```
3535

3636
So a full key structure would look like:
3737
```
3838
/network/<id>/region/<region name>/param/<param name>
39-
/network/<id>/region/<region name>/Input/<param name>
39+
/network/<id>/region/<region name>/input/<param name>
4040
/network/<id>/region/<region name>/output/<param name>
41-
/network/<id>/link/<link name>
41+
/network/<id>/link/<from>/<to>
4242
```
4343

4444
## REST Operators
@@ -76,6 +76,15 @@ Protocol for the NetworkAPI REST feature for all operations currently implemente
7676
7777
GET /network/<id>/region/<region name>/output/<output name>
7878
Get the value of a region's output. Returns a JSON encoded Array object.
79+
80+
DELETE /network/<id>/region/<region name>
81+
Delete the specified region
82+
83+
DELETE /network/<id>/link/<source name>/<dest_name>
84+
Delete the specified link
85+
86+
DELETE /network/<id>/ALL
87+
Delete the entire Network object.
7988
8089
GET /network/<id>/run?iterations=<iterations>
8190
Execute all regions in phase order. Repeat <iterations> times. Returns OK.
@@ -129,4 +138,4 @@ JSON example:
129138
{addLink: {src: "encoder.encoded", dest: "sp.bottomUpIn"}},
130139
{addLink: {src: "sp.bottomUpOut", dest: "tm.bottomUpIn"}}
131140
]}
132-
```
141+
```

src/examples/rest/server_core.hpp

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,9 @@
1616
// /network/<id>/region/<name>/param/<name>
1717
// /network/<id>/region/<name>/input/<name>
1818
// /network/<id>/region/<name>/output/<name>
19-
// /network/<id>/link/<name>
19+
// /network/<id>/link/<source_name>/<dest_name>
20+
// Note: source_name syntax is "region_name.output_name"
21+
// dest_name syntax is "region_name.input_name"
2022
//
2123
// The expected protocol for the NetworkAPI application is as follows:
2224
//
@@ -35,6 +37,12 @@
3537
// Get the value of a region's input. Returns a JSON encoded array.
3638
// GET /network/<id>/region/<region name>/output/<output name>
3739
// Get the value of a region's output. Returns a JSON encoded array.
40+
// DELETE /network/<id>/region/<region name>
41+
// Deletes a region. Must not be in any links.
42+
// DELETE /network/<id>/link/<source_name>/<dest_name>
43+
// Deletes a link.
44+
// DELETE /network/<id>/ALL
45+
// Deletes the entire Network object
3846
// GET /network/<id>/run?iterations=<iterations>
3947
// Execute all regions in phase order. Repeat <iterations> times.
4048
// GET /network/<id>/region/<region name>/command?data=<command>
@@ -165,6 +173,42 @@ class RESTserver {
165173
std::string result = interface->get_output_request(id, region_name, output_name);
166174
res.set_content(result + "\n", "text/plain");
167175
});
176+
177+
// DELETE /network/<id>/region/<region name>
178+
// Deletes a region. Must not be in any links.
179+
svr.Delete("/network/.*/region/.*", [](const Request &req, Response &res) {
180+
std::vector<std::string> flds = split(req.path, '/');
181+
std::string id = flds[2];
182+
std::string region_name = flds[4];
183+
184+
RESTapi *interface = RESTapi::getInstance();
185+
std::string result = interface->delete_region_request(id, region_name);
186+
res.set_content(result + "\n", "text/plain");
187+
});
188+
189+
// DELETE /network/<id>/link/<name>
190+
// Deletes a link.
191+
svr.Delete("/network/.*/link/.*/.*", [](const Request &req, Response &res) {
192+
std::vector<std::string> flds = split(req.path, '/');
193+
std::string id = flds[2];
194+
std::string source_name = flds[4];
195+
std::string dest_name = flds[5];
196+
197+
RESTapi *interface = RESTapi::getInstance();
198+
std::string result = interface->delete_link_request(id, source_name, dest_name);
199+
res.set_content(result + "\n", "text/plain");
200+
});
201+
202+
// DELETE /network/<id>/ALL
203+
// Deletes the entire Network object
204+
svr.Delete("/network/.*/ALL", [](const Request &req, Response &res) {
205+
std::vector<std::string> flds = split(req.path, '/');
206+
std::string id = flds[2];
207+
208+
RESTapi *interface = RESTapi::getInstance();
209+
std::string result = interface->delete_network_request(id);
210+
res.set_content(result + "\n", "text/plain");
211+
});
168212

169213

170214
// GET /network/<id>/run?iterations=<iterations>

src/htm/engine/RESTapi.cpp

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,58 @@ std::string RESTapi::get_param_request(const std::string &id,
174174
}
175175
}
176176

177+
std::string RESTapi::delete_region_request(const std::string &id, const std::string &region_name) {
178+
try {
179+
auto itr = resource_.find(id);
180+
NTA_CHECK(itr != resource_.end()) << "Context for resource '" + id + "' not found.";
181+
itr->second.t = time(0);
182+
183+
std::string response = "OK";
184+
itr->second.net->removeRegion(region_name);
185+
186+
return response;
187+
} catch (Exception &e) {
188+
return std::string("ERROR: ") + e.getMessage();
189+
}
190+
}
191+
192+
std::string RESTapi::delete_link_request(const std::string &id,
193+
const std::string &source_name,
194+
const std::string &dest_name) {
195+
try {
196+
auto itr = resource_.find(id);
197+
NTA_CHECK(itr != resource_.end()) << "Context for resource '" + id + "' not found.";
198+
itr->second.t = time(0);
199+
200+
std::vector<std::string> args;
201+
args = split(source_name, '.');
202+
NTA_CHECK(args.size() == 2) << "Expected syntax <region>.<output> for source name. Found " << source_name;
203+
std::string source_region = args[0];
204+
std::string source_output = args[1];
205+
206+
args = split(dest_name, '.');
207+
NTA_CHECK(args.size() == 2) << "Expected syntax <region>.<input> for destination name. Found " << dest_name;
208+
std::string dest_region = args[0];
209+
std::string dest_input = args[1];
210+
211+
std::string response = "OK";
212+
itr->second.net->removeLink(source_region, dest_region, source_output, dest_input);
213+
return response;
214+
215+
} catch (Exception &e) {
216+
return std::string("ERROR: ") + e.getMessage();
217+
}
218+
}
219+
220+
std::string RESTapi::delete_network_request(const std::string &id) {
221+
auto itr = resource_.find(id);
222+
NTA_CHECK(itr != resource_.end()) << "Context for resource '" + id + "' not found.";
223+
224+
resource_.erase(itr);
225+
return "OK";
226+
}
227+
228+
177229
std::string RESTapi::run_request(const std::string &id, const std::string &iterations) {
178230
try {
179231
auto itr = resource_.find(id);

src/htm/engine/RESTapi.hpp

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,10 @@
4242
* There is a maximum of 65535 active Network class resources.
4343
* A Network resource will timeout without activity in 24 hrs.
4444
*
45+
* The methods in the class are called from examples/rest/server_core.hpp
46+
* which is compiled with the rest server. An application can use the server
47+
* AS-IS or replace the server and server_core.hpp to sute its needs.
48+
*
4549
* LIMITATIONS:
4650
* 1) Only built-in C++ regions can be used. There are plans to
4751
* eventually allow connecting to Python regions and dynamically
@@ -247,6 +251,62 @@ class RESTapi
247251
const std::string &region_name,
248252
const std::string &param_name);
249253

254+
255+
/**
256+
* @b Description:
257+
* Handler for a DELETE "link" request message.
258+
* This will remove the link with matching source and destination names.
259+
*
260+
* @param id Identifier for the resource context (a Network class instance).
261+
* Client should pass the id returned by the previous "configure"
262+
* request message.
263+
*
264+
*
265+
* @param source_name The name of the region that is the source of data.
266+
*
267+
* @param dest_name The name of the region that is destination of data.
268+
*
269+
* @retval If success returns Ok.
270+
* Otherwise returns error message starting with "ERROR: ".
271+
*/
272+
std::string delete_link_request(const std::string &id,
273+
const std::string &source_name,
274+
const std::string &dest_name);
275+
276+
277+
/**
278+
* @b Description:
279+
* Handler for a DELETE "region" request message.
280+
* This will remove the region with matching name.
281+
*
282+
* @param id Identifier for the resource context (a Network class instance).
283+
* Client should pass the id returned by the previous "configure"
284+
* request message.
285+
*
286+
*
287+
* @param region_name The name of the region that is to be removed.
288+
*
289+
* @retval If success returns Ok.
290+
* Otherwise returns error message starting with "ERROR: ".
291+
*/
292+
std::string delete_region_request(const std::string &id, const std::string &region_name);
293+
294+
/**
295+
* @b Description:
296+
* Handler for a DELETE "network" request message.
297+
* This will remove the entire Network object.
298+
*
299+
* @param id Identifier for the resource context (a Network class instance).
300+
* Client should pass the id returned by the previous "configure"
301+
* request message.
302+
*
303+
*
304+
* @retval If success returns Ok.
305+
* Otherwise returns error message starting with "ERROR: ".
306+
*/
307+
std::string delete_network_request(const std::string &id);
308+
309+
250310
/**
251311
* @b Description:
252312
* Handler for a "run" request message.

src/test/unit/engine/RESTapiTest.cpp

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ TEST(RESTapiTest, example) {
129129
{addLink: {src: "sp.bottomUpOut", dest: "tm.bottomUpIn"}}
130130
]})";
131131

132-
132+
// create the network object
133133
res = client.Post("/network", config, "application/json");
134134
ASSERT_TRUE(res && res->status/100 == 2 && res->body.size() == 5) << "Failed Response to POST /network request.";
135135
std::string id = res->body.substr(0,4);
@@ -170,4 +170,59 @@ TEST(RESTapiTest, example) {
170170

171171
threadObj.join(); // wait until server thread has stopped.
172172
}
173+
174+
TEST(RESTapiTest, test_delete) {
175+
std::thread threadObj(serverThread); // start REST server
176+
std::this_thread::sleep_for(std::chrono::seconds(1)); // give server time to start
177+
178+
// Client thread.
179+
const httplib::Params noParams;
180+
char message[1000];
181+
182+
httplib::Client client("127.0.0.1", port);
183+
client.set_timeout_sec(30);
184+
185+
// Configure a NetworkAPI example
186+
// See Network.configure() for syntax.
187+
// Simple situation Encoder ==> SP ==> TM
188+
// Compare this to the napi_sine example.
189+
std::string config = R"(
190+
{network: [
191+
{addRegion: {name: "encoder", type: "RDSEEncoderRegion", params: {size: 1000, sparsity: 0.2, radius: 0.03, seed: 2019, noise: 0.01}}},
192+
{addRegion: {name: "sp", type: "SPRegion", params: {columnCount: 2048, globalInhibition: true}}},
193+
{addRegion: {name: "tm", type: "TMRegion", params: {cellsPerColumn: 8, orColumnOutputs: true}}},
194+
{addLink: {src: "encoder.encoded", dest: "sp.bottomUpIn"}},
195+
{addLink: {src: "sp.bottomUpOut", dest: "tm.bottomUpIn"}}
196+
]})";
197+
198+
// create the network object
199+
auto res = client.Post("/network", config, "application/json");
200+
ASSERT_TRUE(res && res->status / 100 == 2 && res->body.size() == 5) << "Failed Response to POST /network request.";
201+
std::string id = res->body.substr(0, 4);
202+
203+
// Now delete the second link.
204+
snprintf(message, sizeof(message), "/network/%s/link/sp.bottomUpOut/tm.bottomUpIn", id.c_str());
205+
res = client.Delete(message);
206+
ASSERT_TRUE(res && res->status / 100 == 2) << " DELETE link message failed.";
207+
EXPECT_STREQ(trim(res->body).c_str(), "OK") << "Response to DELETE Link request";
208+
209+
// Delete a region
210+
snprintf(message, sizeof(message), "/network/%s/region/tm", id.c_str());
211+
res = client.Delete(message);
212+
ASSERT_TRUE(res && res->status / 100 == 2) << " DELETE region message failed.";
213+
EXPECT_STREQ(trim(res->body).c_str(), "OK") << "Response to DELETE Link request";
214+
215+
// Delete a Network
216+
snprintf(message, sizeof(message), "/network/%s/ALL", id.c_str());
217+
res = client.Delete(message);
218+
ASSERT_TRUE(res && res->status / 100 == 2) << " DELETE region message failed.";
219+
EXPECT_STREQ(trim(res->body).c_str(), "OK") << "Response to DELETE Link request";
220+
221+
222+
223+
// wrap up
224+
res = client.Get("/stop"); // stop the server.
225+
threadObj.join(); // wait until server thread has stopped.
226+
}
227+
173228
} // namespace testing

0 commit comments

Comments
 (0)