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 const ssize_t n = getline(&line, &len, stdin);
59 m_observer->cancelObserve();
62 if (line[n - 1] == '\n') {
68 LineResult lr = processLine(line, result, m_obsCB);
77 LineResult LineInput::processLine(string command, stringstream& result, observecb_t cb)
81 if (parseLine(command, elems) != LR_OK) {
82 cerr << "syntax error" << endl;
88 if (elems[0] == "quit" || elems[0] == "exit")
91 if (elems.size() == 1) {
92 if (elems[0] == "help") {
93 return processHelp(elems, result);
94 } else if (elems[0] == "find") {
95 NEED_CLIENT return processFind(elems, result);
96 } else if (elems[0] == "show") {
97 NEED_CLIENT return processShow(elems, result);
99 } else if (elems.size() == 2) {
100 if (elems[0] == "details") {
101 NEED_CLIENT return processDetails(elems, result);
102 } else if (elems[0] == "get") {
103 NEED_CLIENT return processGet(elems, result);
104 } else if (elems[0] == "observe") {
105 NEED_CLIENT return processObserve(elems, result, cb);
106 } else if (elems[0] == "cancel") {
107 NEED_CLIENT return processCancel(elems, result);
110 if (elems[0] == "put") {
111 NEED_CLIENT return processPut(elems, result);
115 return processUnrecognized(elems, result);
118 LineResult LineInput::processHelp(elements_t& /*elems*/, stringstream& ss)
121 "\tfind\t\tFind resources\n"
122 "\tshow\t\tShow resources\n"
123 "\tdetails n\tShow details of resource n\n"
124 "\tget n\t\tGet value(s) of resource n\n"
125 "\tput n v\t\tPut value(s) to resource n\n"
126 "\tobserve n\tObserve value(s) of resource n\n"
127 "\thelp\t\tThis usage message\n"
128 "\nResource can be identified by Resource ID or Show index\n"
129 "\nValue in 'put' can be key=value or key:value\n\n"
134 LineResult LineInput::processUnrecognized(elements_t& elems, stringstream& ss)
136 ss << "Command not recognized\n";
137 processHelp(elems, ss);
138 return LR_Unrecognized;
141 LineResult LineInput::processFind(elements_t& /*elems*/, stringstream& /*ss*/)
143 m_client->findResources();
147 void LineInput::registerResourceWithServer(std::string & url) {
149 std::size_t index = url.rfind("/");
150 if (index != std::string::npos) {
151 type = url.substr(index+1);
153 const std::string resType = type;
154 const std::string iface = "MB_INTERFACE";
155 m_server->registerResource(url, resType, iface);
158 LineResult LineInput::processShow(elements_t& /*elems*/, stringstream& ss)
161 m_resourceList.clear();
162 resourcemap_t& pmap = m_client->m_resourceMap;
164 for (resourcemap_t::iterator it = pmap.begin(); it != pmap.end(); it++) {
165 string resID = it->first;
166 ss << index++ << '\t' << resID << '\n';
167 m_resourceList.push_back(resID);
169 registerResourceWithServer(resID);
176 LineResult LineInput::processDetails(elements_t& elems, stringstream& ss)
178 WrapResource *wres = resolveResource(elems[1], ss);
180 return LR_NoResource;
182 ss << wres->getResourceID() + " [ ";
183 for (auto &types : wres->getResourceTypes()) {
187 for (auto &ifs : wres->getResourceInterfaces()) {
194 void printJSONAsTable(std::string &jsonString) {
195 std::string str = jsonString;
196 std::string key, value;
197 size_t found = str.find("rep");
198 if (found == std::string::npos) { // not found
201 str = str.substr(found+5);
203 found = str.find(":");
204 if (found == std::string::npos) {
207 key = str.substr(1, found-1);
208 str = str.substr(found);
209 found = str.find(",");
210 if (found != std::string::npos) {
211 value = str.substr(1, found-1);
212 str = str.substr(found);
214 found = str.find("}");
215 if (found != std::string::npos) {
216 value = str.substr(1, found-1);
217 str = str.substr(found);
220 cout << key << "\t:" << value << endl;
224 LineResult LineInput::processGet(elements_t& elems, stringstream& ss)
226 WrapResource *wres = resolveResource(elems[1], ss);
228 return LR_NoResource;
230 token_t token = wres->getResource();
232 WrapRequest *wreq = wres->waitResource(token);
234 ss << "Get timed out\n";
238 std::string jsonRep ;//= wreq->m_rep.getJSONRepresentation();
239 //ss << jsonRep << endl;
240 printJSONAsTable(jsonRep);
244 LineResult LineInput::processPut(elements_t& elems, stringstream& ss)
246 WrapResource *wres = resolveResource(elems[1], ss);
248 return LR_NoResource;
251 OCRepresentation rep;
254 for (size_t i = 2; i < elems.size(); i++) {
255 string elem = elems[i];
256 char *s = (char *)elem.c_str(); // elem string is intentionally damaged
257 char *key = strtok(s, "=:");
258 char *value = strtok(nullptr, "");
260 ss << "missing separator in element starting with " << key << '\n';
264 char delim = value[0];
265 size_t len = strlen(value);
266 if (delim == '\'' || delim == '"') {
267 if (len > 1 && delim == value[len - 1]) {
268 value[len - 1] = '\0';
272 string v(value, len);
273 stringmap_t formats = wres->getFormats();
275 format = formats.at(key);
277 cerr << "element in arg " << i << " has no format\n";
280 if (format == "bool") {
281 bool b = v != "0" && v != "false";
282 rep.setValue(key, b);
283 } else if (format == "number") {
285 int n = (int)strtol(value, &end, 10);
286 if (size_t(end - value) != len) {
287 double d = atof(value);
288 rep.setValue(key, d);
290 rep.setValue(key, n);
292 } else { // assume string
293 rep.setValue(key, v);
299 token_t token = wres->putResource(rep);
301 WrapRequest *wreq = wres->waitResource(token);
303 ss << "Get timed out\n";
310 LineResult LineInput::processObserve(elements_t& elems, stringstream& ss, observecb_t cb)
312 WrapResource *wres = resolveResource(elems[1], ss);
314 return LR_NoResource;
316 wres->observeResource(cb);
320 LineResult LineInput::processCancel(elements_t& elems, stringstream& ss)
322 WrapResource *wres = resolveResource(elems[1], ss);
324 return LR_NoResource;
326 wres->cancelObserve();
327 m_observer = nullptr;
331 WrapResource *LineInput::resolveResource(string resID, stringstream& /*ss*/)
334 string useID = resID;
335 int index = std::stoi(useID, &len);
337 if (len == resID.size()) { // it's an index, not a uri
338 if (size_t(index) >= m_resourceList.size()) {
339 cout << "Resource index out of range (use 'show')\n";
342 useID = m_resourceList[index]; // now it's a uri
345 resourcemap_t::iterator it = m_client->m_resourceMap.find(useID);
346 if (it == m_client->m_resourceMap.end()) {
347 cout << resID << " is currently not available\n";
354 void LineInput::obsCB(token_t /*token*/,
355 const HeaderOptions& /*headerOptions*/,
356 const OCRepresentation& /*rep*/,
358 const int sequenceNumber)
362 cout << "cb " << eCode << " " << sequenceNumber << '\n';
363 //cout << rep.getJSONRepresentation() << "\n";
366 ParseState LineInput::finishElem(char*& e, elements_t& elems)
369 elems.push_back(m_elem);
374 ParseState LineInput::putCharInElem(char c, char *& e, ParseState newState)
377 if (size_t(e - m_elem) >= sizeof (m_elem))
378 throw 20; // hightly unlikely exception
383 * See processHelp() above for line format
385 LineResult LineInput::parseLine(string lineIn, elements_t& elems)
388 char c, *e, delim = 0;
390 size_t len = lineIn.size();
391 ParseState state = PS_Between;
392 const char *line = lineIn.c_str();
397 if (size_t(d - line) >= len) {
399 if (state == PS_Infirst || state == PS_Endsecond || (state == PS_Insecond && !delim)) {
400 state = finishElem(e, elems);
409 isSep1 = c == ' ' || c == '\t';
410 isSep2 = c == '=' || c == ':';
418 state = putCharInElem(c, e, PS_Infirst);
422 state = finishElem(e, elems);
427 state = PS_Startsecond;
429 putCharInElem(c, e, state);
432 if (isSep1 || isSep2)
434 if (c == '\'' || c == '"' || c == '|')
436 state = putCharInElem(c, e, PS_Insecond);
439 if (isSep1 && delim == 0) {
440 state = finishElem(e, elems);
444 state = PS_Endsecond;
450 state = finishElem(e, elems);