CBOR rebase onto master for merge/review
[iotivity.git] / examples / OICMiddle / WrapResource.cpp
1 //******************************************************************
2 //
3 // Copyright 2014 Intel Corporation.
4 //
5 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
6 //
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
10 //
11 //      http://www.apache.org/licenses/LICENSE-2.0
12 //
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.
18 //
19 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
20
21 #include <chrono>
22 #include <sys/time.h>
23
24 #include "WrapResource.h"
25
26 unsigned long GetTickCount()
27 {
28     struct timeval tv;
29     if (gettimeofday(&tv, NULL) != 0)
30         return 0;
31     return (tv.tv_sec * 1000) + (tv.tv_usec / 1000);
32 }
33
34 WrapResource::WrapResource(string resourceID, ocresource_t resource)
35         : m_resourceID(resourceID), m_ocResource(resource),
36          m_listIndex(-1), m_x(0), m_repGetReady(false), m_gettingRep(false),
37          m_observeCB(nullptr), m_callbackRunning(false),
38          m_requestToken(0), m_observeRequest(nullptr),
39      m_typeRequest(nullptr)
40 {
41 }
42
43 string WrapResource::getResourceID() {
44     return m_resourceID;
45 }
46
47 token_t WrapResource::getResource()
48 {
49     WrapRequest *wreq;
50     QueryParamsMap m;
51
52     wreq = newRequest(RT_Get);
53     m_ocResource->get(m, wreq->m_getCB, QualityOfService::HighQos);
54     return wreq->m_token;
55 }
56
57 token_t WrapResource::putResource(OCRepresentation& rep)
58 {
59     WrapRequest *wreq;
60     QueryParamsMap m;
61
62     wreq = newRequest(RT_Put);
63     rep.setUri(m_ocResource->uri());
64     m_ocResource->put(rep, m, wreq->m_putCB, QualityOfService::HighQos);
65     return wreq->m_token;
66 }
67
68 token_t WrapResource::observeResource(observecb_t& cb)
69 {
70     WrapRequest *wreq;
71     QueryParamsMap m;
72     ObserveType type;
73
74     wreq = newRequest(RT_Observe);
75     m_observeRequest = wreq;
76     m_observeCB = cb;
77     m_callbackRunning = true;
78     type = ObserveType::Observe;
79     m_ocResource->observe(type, m, wreq->m_obsCB);
80     return wreq->m_token;
81 }
82
83 bool WrapResource::cancelObserve()
84 {
85     m_callbackRunning = false;
86     m_observeCB = nullptr;
87
88     if (!m_observeRequest)
89         return false;
90
91     OCStackResult result = m_ocResource->cancelObserve();
92     if (result != OC_STACK_OK)
93         return false;
94
95     m_observeRequest->m_touchTime = GetTickCount();
96     return true;
97 }
98
99 WrapRequest *WrapResource::waitResource(token_t token)
100 {
101     WrapRequest *wreq;
102     cv_status st;
103
104     try {
105         m_mutexMap.lock();
106         wreq = m_requestMap.at(token);
107         m_mutexMap.unlock();
108     } catch (const out_of_range& oor) {
109         m_mutexMap.unlock();
110         return nullptr;
111     }
112
113     std::unique_lock<std::mutex> lk(m_mutexGet);
114     st = wreq->m_cvGet.wait_for(lk, chrono::seconds(5));
115     return (st == cv_status::no_timeout) ? wreq : nullptr;
116 }
117
118 std::vector<std::string> WrapResource::getResourceTypes()
119 {
120     return m_ocResource->getResourceTypes();
121 }
122
123 std::vector<std::string> WrapResource::getResourceInterfaces()
124 {
125     return m_ocResource->getResourceInterfaces();
126 }
127
128 WrapRequest *WrapResource::newRequest(RequestType type)
129 {
130     WrapRequest *wreq = new WrapRequest(this, type, ++m_requestToken);
131     m_requestMap[m_requestToken] = wreq;
132     return wreq;
133 }
134
135 void WrapResource::resourceCallback(WrapRequest *wreq)
136 {
137     parseJSON(wreq);
138
139     if (wreq->m_forTypeOnly) {
140         wreq->m_typeReady = true;
141         return;
142     }
143
144     if (wreq->m_type == RT_Observe) {
145         if (!m_observeCB) {
146             if (m_callbackRunning)
147                 cout << "callback missing " << m_resourceID << '\n';
148             return;
149         }
150         m_observeCB(wreq->m_token, wreq->m_headerOptions, wreq->m_rep, wreq->m_eCode,
151                                     wreq->m_sequenceNumber);
152     } else {
153         wreq->m_cvGet.notify_one();
154     }
155
156     wreq->m_touchTime = GetTickCount();
157 }
158
159 /*
160  *  this parser infers types from json string since no other introspection
161  *  is available.  It also parses the key-value pairs.
162  */
163 void WrapResource::parseJSON(WrapRequest *wreq)
164 {
165     string sep = "\":";
166     string anchor = "\"rep\":{";
167     string json;// = wreq->m_rep.getJSONRepresentation();
168     string name, type, value, next;
169     size_t r, e, e1, s, c;
170
171     r = json.find(anchor);
172     if (r == string::npos) {
173         return;
174     }
175     c = r + anchor.length() - 1;
176     do {
177         c++;
178         if (json[c] != '"') {
179             if (json[c] == '}')
180                 break;
181             return;
182         }
183         c++;
184         e = json.find(sep, c);
185         if (e == string::npos) {
186             return;
187         }
188         name = json.substr(c, e - c);
189         s = e + sep.length();
190         char q = json[s];
191         switch (q) {
192         case 't':
193         case 'f':
194             type = "bool";
195             e1 = json.find_first_of(",}", s + 1);
196             if (e1 == string::npos) {
197                 return;
198             }
199             value = json.substr(s, e1 - s);
200             break;
201         case '"':
202             type = "string";
203             s++;
204             e1 = json.find_first_of("\"", s);
205             if (e1 == string::npos) {
206                 return;
207             }
208             value = json.substr(s, e1 - s);
209             e1++;
210             break;
211         case '0':
212         case '1':
213         case '2':
214         case '3':
215         case '4':
216         case '5':
217         case '6':
218         case '7':
219         case '8':
220         case '9':
221         case '.':
222             type = "number";
223             e1 = json.find_first_of(",}", s + 1);
224             if (e1 == string::npos) {
225                 return;
226             }
227             value = json.substr(s, e1 - s);
228             break;
229         default:
230             return;
231         }
232         wreq->m_valueMap[name] = value; // key-value map
233         m_typeMap[name] = type;         // key-type map
234         c = e1;
235     } while (json[c] == ',');
236 }
237
238 void WrapResource::findTypes()
239 {
240     delete m_typeRequest;
241     m_typeRequest = new WrapRequest(this, RT_Get, ++m_requestToken);
242     m_typeRequest->m_forTypeOnly = true;
243     getResource();
244 }
245
246 const stringmap_t& WrapResource::getFormats()
247 {
248     return m_typeMap;
249 }
250
251 /********** WrapRequest ***********/
252
253 WrapRequest::WrapRequest(WrapResource *wres, RequestType type, token_t token)
254             : m_eCode(0), m_sequenceNumber(0), m_parent(wres), m_type(type),
255               m_token(token), m_forTypeOnly(false), m_typeReady(false)
256 {
257     m_getCB = std::bind(&WrapRequest::getCB, this,
258         placeholders::_1, placeholders::_2, placeholders::_3);
259     m_putCB = std::bind(&WrapRequest::putCB, this,
260         placeholders::_1, placeholders::_2, placeholders::_3);
261     m_obsCB = std::bind(&WrapRequest::observeCB, this,
262         placeholders::_1, placeholders::_2, placeholders::_3, placeholders::_4);
263     m_touchTime = GetTickCount();
264 }
265
266 void WrapRequest::getCB(const HeaderOptions& headerOptions, const OCRepresentation& rep, int eCode)
267 {
268     m_headerOptions = headerOptions;
269     m_rep = rep;
270     m_eCode = eCode;
271     m_parent->resourceCallback(this);
272 }
273
274 void WrapRequest::putCB(const HeaderOptions& headerOptions, const OCRepresentation& rep, int eCode)
275 {
276     m_headerOptions = headerOptions;
277     m_rep = rep;
278     m_eCode = eCode;
279     m_parent->resourceCallback(this);
280 }
281
282 void WrapRequest::observeCB(const HeaderOptions& headerOptions, const OCRepresentation& rep, int eCode, int sequenceNumber)
283 {
284     m_headerOptions = headerOptions;
285     m_rep = rep;
286     m_eCode = eCode;
287     m_sequenceNumber = sequenceNumber;
288     m_parent->resourceCallback(this);
289 }