1 //******************************************************************
3 // Copyright 2014 Intel Corporation.
5 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
7 // Licensed under the Apache License, Version 2.0 (the "License");
8 // you may not use this file except in compliance with the License.
9 // You may obtain a copy of the License at
11 // http://www.apache.org/licenses/LICENSE-2.0
13 // Unless required by applicable law or agreed to in writing, software
14 // distributed under the License is distributed on an "AS IS" BASIS,
15 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 // See the License for the specific language governing permissions and
17 // limitations under the License.
19 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
26 #include "WrapResource.h"
27 #include "LineInput.h"
29 #define NEED_CLIENT { if (!m_client) return LR_NoClient; }
31 LineInput::LineInput(MiddleClient *client)
32 : m_client(client), m_server(nullptr),
33 m_obsCB(nullptr), m_observer(nullptr)
35 m_obsCB = std::bind(&LineInput::obsCB, this,
43 void LineInput::setServer(MiddleServer *server) {
55 getline(&line, &len, stdin);
60 m_observer->cancelObserve();
63 if (line[n - 1] == '\n') {
69 LineResult lr = processLine(line, result, m_obsCB);
78 LineResult LineInput::processLine(string command, stringstream& result, observecb_t cb)
82 if (parseLine(command, elems) != LR_OK) {
83 cerr << "syntax error" << endl;
89 if (elems[0] == "quit" || elems[0] == "exit")
92 if (elems.size() == 1) {
93 if (elems[0] == "help") {
94 return processHelp(elems, result);
95 } else if (elems[0] == "find") {
96 NEED_CLIENT return processFind(elems, result);
97 } else if (elems[0] == "show") {
98 NEED_CLIENT return processShow(elems, result);
100 } else if (elems.size() == 2) {
101 if (elems[0] == "details") {
102 NEED_CLIENT return processDetails(elems, result);
103 } else if (elems[0] == "get") {
104 NEED_CLIENT return processGet(elems, result);
105 } else if (elems[0] == "observe") {
106 NEED_CLIENT return processObserve(elems, result, cb);
107 } else if (elems[0] == "cancel") {
108 NEED_CLIENT return processCancel(elems, result);
111 if (elems[0] == "put") {
112 NEED_CLIENT return processPut(elems, result);
116 return processUnrecognized(elems, result);
119 LineResult LineInput::processHelp(elements_t& elems, stringstream& ss)
122 "\tfind\t\tFind resources\n"
123 "\tshow\t\tShow resources\n"
124 "\tdetails n\tShow details of resource n\n"
125 "\tget n\t\tGet value(s) of resource n\n"
126 "\tput n v\t\tPut value(s) to resource n\n"
127 "\tobserve n\tObserve value(s) of resource n\n"
128 "\thelp\t\tThis usage message\n"
129 "\nResource can be identified by Resource ID or Show index\n"
130 "\nValue in 'put' can be key=value or key:value\n\n"
135 LineResult LineInput::processUnrecognized(elements_t& elems, stringstream& ss)
137 ss << "Command not recognized\n";
138 processHelp(elems, ss);
139 return LR_Unrecognized;
142 LineResult LineInput::processFind(elements_t& elems, stringstream& ss)
144 m_client->findResources();
148 void LineInput::registerResourceWithServer(std::string & url) {
150 std::size_t index = url.rfind("/");
151 if (index != std::string::npos) {
152 type = url.substr(index+1);
154 const std::string resType = type;
155 const std::string iface = "MB_INTERFACE";
156 m_server->registerResource(url, resType, iface);
159 LineResult LineInput::processShow(elements_t& elems, stringstream& ss)
162 m_resourceList.clear();
163 resourcemap_t& pmap = m_client->m_resourceMap;
165 for (resourcemap_t::iterator it = pmap.begin(); it != pmap.end(); it++) {
166 string resID = it->first;
167 ss << index++ << '\t' << resID << '\n';
168 m_resourceList.push_back(resID);
170 registerResourceWithServer(resID);
177 LineResult LineInput::processDetails(elements_t& elems, stringstream& ss)
179 WrapResource *wres = resolveResource(elems[1], ss);
181 return LR_NoResource;
183 ss << wres->getResourceID() + " [ ";
184 for (auto &types : wres->getResourceTypes()) {
188 for (auto &ifs : wres->getResourceInterfaces()) {
195 void printJSONAsTable(std::string &jsonString) {
196 std::string str = jsonString;
197 std::string key, value;
198 size_t found = str.find("rep");
199 if (found == std::string::npos) { // not found
202 str = str.substr(found+5);
204 found = str.find(":");
205 if (found == std::string::npos) {
208 key = str.substr(1, found-1);
209 str = str.substr(found);
210 found = str.find(",");
211 if (found != std::string::npos) {
212 value = str.substr(1, found-1);
213 str = str.substr(found);
215 found = str.find("}");
216 if (found != std::string::npos) {
217 value = str.substr(1, found-1);
218 str = str.substr(found);
221 cout << key << "\t:" << value << endl;
225 LineResult LineInput::processGet(elements_t& elems, stringstream& ss)
227 WrapResource *wres = resolveResource(elems[1], ss);
229 return LR_NoResource;
231 token_t token = wres->getResource();
233 WrapRequest *wreq = wres->waitResource(token);
235 ss << "Get timed out\n";
239 std::string jsonRep = wreq->m_rep.getJSONRepresentation();
240 //ss << jsonRep << endl;
241 printJSONAsTable(jsonRep);
245 LineResult LineInput::processPut(elements_t& elems, stringstream& ss)
247 WrapResource *wres = resolveResource(elems[1], ss);
249 return LR_NoResource;
252 OCRepresentation rep;
255 for (size_t i = 2; i < elems.size(); i++) {
256 string elem = elems[i];
257 char *s = (char *)elem.c_str(); // elem string is intentionally damaged
258 char *key = strtok(s, "=:");
259 char *value = strtok(nullptr, "");
261 ss << "missing separator in element starting with " << key << '\n';
265 char delim = value[0];
266 size_t len = strlen(value);
267 if (delim == '\'' || delim == '"') {
268 if (len > 1 && delim == value[len - 1]) {
269 value[len - 1] = '\0';
273 string v(value, len);
274 stringmap_t formats = wres->getFormats();
276 format = formats.at(key);
278 cerr << "element in arg " << i << " has no format\n";
281 if (format == "bool") {
282 bool b = v != "0" && v != "false";
283 rep.setValue(key, b);
284 } else if (format == "number") {
286 int n = (int)strtol(value, &end, 10);
287 if (size_t(end - value) != len) {
288 double d = atof(value);
289 rep.setValue(key, d);
291 rep.setValue(key, n);
293 } else { // assume string
294 rep.setValue(key, v);
300 token_t token = wres->putResource(rep);
302 WrapRequest *wreq = wres->waitResource(token);
304 ss << "Get timed out\n";
311 LineResult LineInput::processObserve(elements_t& elems, stringstream& ss, observecb_t cb)
313 WrapResource *wres = resolveResource(elems[1], ss);
315 return LR_NoResource;
317 wres->observeResource(cb);
321 LineResult LineInput::processCancel(elements_t& elems, stringstream& ss)
323 WrapResource *wres = resolveResource(elems[1], ss);
325 return LR_NoResource;
327 wres->cancelObserve();
328 m_observer = nullptr;
332 WrapResource *LineInput::resolveResource(string resID, stringstream& ss)
335 string useID = resID;
336 int index = std::stoi(useID, &len);
338 if (len == resID.size()) { // it's an index, not a uri
339 if (size_t(index) >= m_resourceList.size()) {
340 cout << "Resource index out of range (use 'show')\n";
343 useID = m_resourceList[index]; // now it's a uri
346 resourcemap_t::iterator it = m_client->m_resourceMap.find(useID);
347 if (it == m_client->m_resourceMap.end()) {
348 cout << resID << " is currently not available\n";
355 void LineInput::obsCB(token_t token, const HeaderOptions& headerOptions, const OCRepresentation& rep, const int eCode, const int sequenceNumber)
359 cout << "cb " << eCode << " " << sequenceNumber << '\n';
360 cout << rep.getJSONRepresentation() << "\n";
363 ParseState LineInput::finishElem(char*& e, elements_t& elems)
366 elems.push_back(m_elem);
371 ParseState LineInput::putCharInElem(char c, char *& e, ParseState newState)
374 if (size_t(e - m_elem) >= sizeof (m_elem))
375 throw 20; // hightly unlikely exception
380 * See processHelp() above for line format
382 LineResult LineInput::parseLine(string lineIn, elements_t& elems)
387 size_t len = lineIn.size();
388 ParseState state = PS_Between;
389 const char *line = lineIn.c_str();
394 if (size_t(d - line) >= len) {
396 if (state == PS_Infirst || state == PS_Endsecond || (state == PS_Insecond && !delim)) {
397 state = finishElem(e, elems);
406 isSep1 = c == ' ' || c == '\t';
407 isSep2 = c == '=' || c == ':';
415 state = putCharInElem(c, e, PS_Infirst);
419 state = finishElem(e, elems);
424 state = PS_Startsecond;
426 putCharInElem(c, e, state);
429 if (isSep1 || isSep2)
431 if (c == '\'' || c == '"' || c == '|')
433 state = putCharInElem(c, e, PS_Insecond);
436 if (isSep1 && delim == 0) {
437 state = finishElem(e, elems);
441 state = PS_Endsecond;
447 state = finishElem(e, elems);