Merge "Merge branch 'cloud-interface'"
[platform/upstream/iotivity.git] / resource / examples / simpleclient.cpp
1 //******************************************************************
2 //
3 // Copyright 2014 Intel Mobile Communications GmbH All Rights Reserved.
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 // OCClient.cpp : Defines the entry point for the console application.
22 //
23 #ifdef HAVE_UNISTD_H
24 #include <unistd.h>
25 #endif
26 #ifdef HAVE_PTHREAD_H
27 #include <pthread.h>
28 #endif
29 #ifdef HAVE_WINDOWS_H
30 #include <Windows.h>
31 #endif
32 #include <string>
33 #include <map>
34 #include <cstdlib>
35 #include <mutex>
36 #include <condition_variable>
37 #include "OCPlatform.h"
38 #include "OCApi.h"
39
40 #define maxSequenceNumber 0xFFFFFF
41
42 using namespace OC;
43
44 static const char* SVR_DB_FILE_NAME = "./oic_svr_db_client.dat";
45 typedef std::map<OCResourceIdentifier, std::shared_ptr<OCResource>> DiscoveredResourceMap;
46
47 DiscoveredResourceMap discoveredResources;
48 std::shared_ptr<OCResource> curResource;
49 static ObserveType OBSERVE_TYPE_TO_USE = ObserveType::Observe;
50 static OCConnectivityType TRANSPORT_TYPE_TO_USE = OCConnectivityType::CT_ADAPTER_IP;
51 std::mutex curResourceLock;
52
53 class Light
54 {
55 public:
56
57     bool m_state;
58     int m_power;
59     std::string m_name;
60
61     Light() : m_state(false), m_power(0), m_name("")
62     {
63     }
64 };
65
66 Light mylight;
67
68 int observe_count()
69 {
70     static int oc = 0;
71     return ++oc;
72 }
73
74 void onObserve(const HeaderOptions /*headerOptions*/, const OCRepresentation& rep,
75                     const int& eCode, const int& sequenceNumber)
76 {
77     try
78     {
79         if(eCode == OC_STACK_OK && sequenceNumber != maxSequenceNumber + 1)
80         {
81             if(sequenceNumber == OC_OBSERVE_REGISTER)
82             {
83                 std::cout << "Observe registration action is successful" << std::endl;
84             }
85
86             std::cout << "OBSERVE RESULT:"<<std::endl;
87             std::cout << "\tSequenceNumber: "<< sequenceNumber << std::endl;
88             rep.getValue("state", mylight.m_state);
89             rep.getValue("power", mylight.m_power);
90             rep.getValue("name", mylight.m_name);
91
92             std::cout << "\tstate: " << mylight.m_state << std::endl;
93             std::cout << "\tpower: " << mylight.m_power << std::endl;
94             std::cout << "\tname: " << mylight.m_name << std::endl;
95
96             if(observe_count() == 11)
97             {
98                 std::cout<<"Cancelling Observe..."<<std::endl;
99                 OCStackResult result = curResource->cancelObserve();
100
101                 std::cout << "Cancel result: "<< result <<std::endl;
102                 sleep(10);
103                 std::cout << "DONE"<<std::endl;
104                 std::exit(0);
105             }
106         }
107         else
108         {
109             if(eCode == OC_STACK_OK)
110             {
111                 std::cout << "Observe registration failed or de-registration action failed/succeeded" << std::endl;
112             }
113             else
114             {
115                 std::cout << "onObserve Response error: " << eCode << std::endl;
116                 std::exit(-1);
117             }
118         }
119     }
120     catch(std::exception& e)
121     {
122         std::cout << "Exception: " << e.what() << " in onObserve" << std::endl;
123     }
124
125 }
126
127 void onPost2(const HeaderOptions& /*headerOptions*/,
128         const OCRepresentation& rep, const int eCode)
129 {
130     try
131     {
132         if(eCode == OC_STACK_OK || eCode == OC_STACK_RESOURCE_CREATED
133                 || eCode == OC_STACK_RESOURCE_CHANGED)
134         {
135             std::cout << "POST request was successful" << std::endl;
136
137             if(rep.hasAttribute("createduri"))
138             {
139                 std::cout << "\tUri of the created resource: "
140                     << rep.getValue<std::string>("createduri") << std::endl;
141             }
142             else
143             {
144                 rep.getValue("state", mylight.m_state);
145                 rep.getValue("power", mylight.m_power);
146                 rep.getValue("name", mylight.m_name);
147
148                 std::cout << "\tstate: " << mylight.m_state << std::endl;
149                 std::cout << "\tpower: " << mylight.m_power << std::endl;
150                 std::cout << "\tname: " << mylight.m_name << std::endl;
151             }
152
153             if (OBSERVE_TYPE_TO_USE == ObserveType::Observe)
154                 std::cout << std::endl << "Observe is used." << std::endl << std::endl;
155             else if (OBSERVE_TYPE_TO_USE == ObserveType::ObserveAll)
156                 std::cout << std::endl << "ObserveAll is used." << std::endl << std::endl;
157
158             curResource->observe(OBSERVE_TYPE_TO_USE, QueryParamsMap(), &onObserve);
159
160         }
161         else
162         {
163             std::cout << "onPost2 Response error: " << eCode << std::endl;
164             std::exit(-1);
165         }
166     }
167     catch(std::exception& e)
168     {
169         std::cout << "Exception: " << e.what() << " in onPost2" << std::endl;
170     }
171
172 }
173
174 void onPost(const HeaderOptions& /*headerOptions*/,
175         const OCRepresentation& rep, const int eCode)
176 {
177     try
178     {
179         if(eCode == OC_STACK_OK || eCode == OC_STACK_RESOURCE_CREATED
180                 || eCode == OC_STACK_RESOURCE_CHANGED)
181         {
182             std::cout << "POST request was successful" << std::endl;
183
184             if(rep.hasAttribute("createduri"))
185             {
186                 std::cout << "\tUri of the created resource: "
187                     << rep.getValue<std::string>("createduri") << std::endl;
188             }
189             else
190             {
191                 rep.getValue("state", mylight.m_state);
192                 rep.getValue("power", mylight.m_power);
193                 rep.getValue("name", mylight.m_name);
194
195                 std::cout << "\tstate: " << mylight.m_state << std::endl;
196                 std::cout << "\tpower: " << mylight.m_power << std::endl;
197                 std::cout << "\tname: " << mylight.m_name << std::endl;
198             }
199
200             OCRepresentation rep2;
201
202             std::cout << "Posting light representation..."<<std::endl;
203
204             mylight.m_state = true;
205             mylight.m_power = 55;
206
207             rep2.setValue("state", mylight.m_state);
208             rep2.setValue("power", mylight.m_power);
209
210             curResource->post(rep2, QueryParamsMap(), &onPost2);
211         }
212         else
213         {
214             std::cout << "onPost Response error: " << eCode << std::endl;
215             std::exit(-1);
216         }
217     }
218     catch(std::exception& e)
219     {
220         std::cout << "Exception: " << e.what() << " in onPost" << std::endl;
221     }
222 }
223
224 // Local function to put a different state for this resource
225 void postLightRepresentation(std::shared_ptr<OCResource> resource)
226 {
227     if(resource)
228     {
229         OCRepresentation rep;
230
231         std::cout << "Posting light representation..."<<std::endl;
232
233         mylight.m_state = false;
234         mylight.m_power = 105;
235
236         rep.setValue("state", mylight.m_state);
237         rep.setValue("power", mylight.m_power);
238
239         // Invoke resource's post API with rep, query map and the callback parameter
240         resource->post(rep, QueryParamsMap(), &onPost);
241     }
242 }
243
244 // callback handler on PUT request
245 void onPut(const HeaderOptions& /*headerOptions*/, const OCRepresentation& rep, const int eCode)
246 {
247     try
248     {
249         if (eCode == OC_STACK_OK || eCode == OC_STACK_RESOURCE_CHANGED)
250         {
251             std::cout << "PUT request was successful" << std::endl;
252
253             rep.getValue("state", mylight.m_state);
254             rep.getValue("power", mylight.m_power);
255             rep.getValue("name", mylight.m_name);
256
257             std::cout << "\tstate: " << mylight.m_state << std::endl;
258             std::cout << "\tpower: " << mylight.m_power << std::endl;
259             std::cout << "\tname: " << mylight.m_name << std::endl;
260
261             postLightRepresentation(curResource);
262         }
263         else
264         {
265             std::cout << "onPut Response error: " << eCode << std::endl;
266             std::exit(-1);
267         }
268     }
269     catch(std::exception& e)
270     {
271         std::cout << "Exception: " << e.what() << " in onPut" << std::endl;
272     }
273 }
274
275 // Local function to put a different state for this resource
276 void putLightRepresentation(std::shared_ptr<OCResource> resource)
277 {
278     if(resource)
279     {
280         OCRepresentation rep;
281
282         std::cout << "Putting light representation..."<<std::endl;
283
284         mylight.m_state = true;
285         mylight.m_power = 15;
286
287         rep.setValue("state", mylight.m_state);
288         rep.setValue("power", mylight.m_power);
289
290         // Invoke resource's put API with rep, query map and the callback parameter
291         resource->put(rep, QueryParamsMap(), &onPut);
292     }
293 }
294
295 // Callback handler on GET request
296 void onGet(const HeaderOptions& /*headerOptions*/, const OCRepresentation& rep, const int eCode)
297 {
298     try
299     {
300         if(eCode == OC_STACK_OK)
301         {
302             std::cout << "GET request was successful" << std::endl;
303             std::cout << "Resource URI: " << rep.getUri() << std::endl;
304
305             rep.getValue("state", mylight.m_state);
306             rep.getValue("power", mylight.m_power);
307             rep.getValue("name", mylight.m_name);
308
309             std::cout << "\tstate: " << mylight.m_state << std::endl;
310             std::cout << "\tpower: " << mylight.m_power << std::endl;
311             std::cout << "\tname: " << mylight.m_name << std::endl;
312
313             putLightRepresentation(curResource);
314         }
315         else
316         {
317             std::cout << "onGET Response error: " << eCode << std::endl;
318             std::exit(-1);
319         }
320     }
321     catch(std::exception& e)
322     {
323         std::cout << "Exception: " << e.what() << " in onGet" << std::endl;
324     }
325 }
326
327 // Local function to get representation of light resource
328 void getLightRepresentation(std::shared_ptr<OCResource> resource)
329 {
330     if(resource)
331     {
332         std::cout << "Getting Light Representation..."<<std::endl;
333         // Invoke resource's get API with the callback parameter
334
335         QueryParamsMap test;
336         resource->get(test, &onGet);
337     }
338 }
339
340 // Callback to found resources
341 void foundResource(std::shared_ptr<OCResource> resource)
342 {
343     std::cout << "In foundResource\n";
344     std::string resourceURI;
345     std::string hostAddress;
346     try
347     {
348         {
349             std::lock_guard<std::mutex> lock(curResourceLock);
350             if(discoveredResources.find(resource->uniqueIdentifier()) == discoveredResources.end())
351             {
352                 std::cout << "Found resource " << resource->uniqueIdentifier() <<
353                     " for the first time on server with ID: "<< resource->sid()<<std::endl;
354                 discoveredResources[resource->uniqueIdentifier()] = resource;
355             }
356             else
357             {
358                 std::cout<<"Found resource "<< resource->uniqueIdentifier() << " again!"<<std::endl;
359             }
360
361             if(curResource)
362             {
363                 std::cout << "Found another resource, ignoring"<<std::endl;
364                 return;
365             }
366         }
367
368         // Do some operations with resource object.
369         if(resource)
370         {
371             std::cout<<"DISCOVERED Resource:"<<std::endl;
372             // Get the resource URI
373             resourceURI = resource->uri();
374             std::cout << "\tURI of the resource: " << resourceURI << std::endl;
375
376             // Get the resource host address
377             hostAddress = resource->host();
378             std::cout << "\tHost address of the resource: " << hostAddress << std::endl;
379
380             // Get the resource types
381             std::cout << "\tList of resource types: " << std::endl;
382             for(auto &resourceTypes : resource->getResourceTypes())
383             {
384                 std::cout << "\t\t" << resourceTypes << std::endl;
385             }
386
387             // Get the resource interfaces
388             std::cout << "\tList of resource interfaces: " << std::endl;
389             for(auto &resourceInterfaces : resource->getResourceInterfaces())
390             {
391                 std::cout << "\t\t" << resourceInterfaces << std::endl;
392             }
393
394             if(resourceURI == "/a/light")
395             {
396                 if (resource->connectivityType() & TRANSPORT_TYPE_TO_USE)
397                 {
398                     curResource = resource;
399                     // Get the resource host address
400                     std::cout << "\tAddress of selected resource: " << resource->host() << std::endl;
401
402                     // Call a local function which will internally invoke get API on the resource pointer
403                     getLightRepresentation(resource);
404                 }
405             }
406         }
407         else
408         {
409             // Resource is invalid
410             std::cout << "Resource is invalid" << std::endl;
411         }
412
413     }
414     catch(std::exception& e)
415     {
416         std::cerr << "Exception in foundResource: "<< e.what() << std::endl;
417     }
418 }
419
420 void printUsage()
421 {
422     std::cout << std::endl;
423     std::cout << "---------------------------------------------------------------------\n";
424     std::cout << "Usage : simpleclient <ObserveType> <TransportType>" << std::endl;
425     std::cout << "   ObserveType : 1 - Observe" << std::endl;
426     std::cout << "   ObserveType : 2 - ObserveAll" << std::endl;
427     std::cout << "   TransportType : 1 - IP" << std::endl;
428     std::cout << "   TransportType : 2 - TCP" << std::endl;
429     std::cout << "---------------------------------------------------------------------\n\n";
430 }
431
432 void checkObserverValue(int value)
433 {
434     if (value == 1)
435     {
436         OBSERVE_TYPE_TO_USE = ObserveType::Observe;
437         std::cout << "<===Setting ObserveType to Observe===>\n\n";
438     }
439     else if (value == 2)
440     {
441         OBSERVE_TYPE_TO_USE = ObserveType::ObserveAll;
442         std::cout << "<===Setting ObserveType to ObserveAll===>\n\n";
443     }
444     else
445     {
446         std::cout << "<===Invalid ObserveType selected."
447                   <<" Setting ObserveType to Observe===>\n\n";
448     }
449 }
450
451 void checkTransportValue(int value)
452 {
453     if (1 == value)
454     {
455         TRANSPORT_TYPE_TO_USE = OCConnectivityType::CT_ADAPTER_IP;
456         std::cout << "<===Setting TransportType to IP===>\n\n";
457     }
458     else if (2 == value)
459     {
460         TRANSPORT_TYPE_TO_USE = OCConnectivityType::CT_ADAPTER_TCP;
461         std::cout << "<===Setting TransportType to TCP===>\n\n";
462     }
463     else
464     {
465         std::cout << "<===Invalid TransportType selected."
466                   <<" Setting TransportType to IP===>\n\n";
467     }
468 }
469
470 static FILE* client_open(const char* /*path*/, const char *mode)
471 {
472     return fopen(SVR_DB_FILE_NAME, mode);
473 }
474
475 int main(int argc, char* argv[]) {
476
477     std::ostringstream requestURI;
478     OCPersistentStorage ps {client_open, fread, fwrite, fclose, unlink };
479     try
480     {
481         printUsage();
482         if (argc == 1)
483         {
484             std::cout << "<===Setting ObserveType to Observe and ConnectivityType to IP===>\n\n";
485         }
486         else if (argc == 2)
487         {
488             checkObserverValue(std::stoi(argv[1]));
489         }
490         else if (argc == 3)
491         {
492             checkObserverValue(std::stoi(argv[1]));
493             checkTransportValue(std::stoi(argv[2]));
494         }
495         else
496         {
497             std::cout << "<===Invalid number of command line arguments===>\n\n";
498             return -1;
499         }
500     }
501     catch(std::exception& )
502     {
503         std::cout << "<===Invalid input arguments===>\n\n";
504         return -1;
505     }
506
507     // Create PlatformConfig object
508     PlatformConfig cfg {
509         OC::ServiceType::InProc,
510         OC::ModeType::Both,
511         "0.0.0.0",
512         0,
513         OC::QualityOfService::HighQos,
514         &ps
515     };
516
517     OCPlatform::Configure(cfg);
518     try
519     {
520         // makes it so that all boolean values are printed as 'true/false' in this stream
521         std::cout.setf(std::ios::boolalpha);
522         // Find all resources
523         requestURI << OC_RSRVD_WELL_KNOWN_URI;// << "?rt=core.light";
524
525         OCPlatform::findResource("", requestURI.str(),
526                 CT_DEFAULT, &foundResource);
527         std::cout<< "Finding Resource... " <<std::endl;
528
529         // Find resource is done twice so that we discover the original resources a second time.
530         // These resources will have the same uniqueidentifier (yet be different objects), so that
531         // we can verify/show the duplicate-checking code in foundResource(above);
532         OCPlatform::findResource("", requestURI.str(),
533                 CT_DEFAULT, &foundResource);
534         std::cout<< "Finding Resource for second time..." << std::endl;
535
536         // A condition variable will free the mutex it is given, then do a non-
537         // intensive block until 'notify' is called on it.  In this case, since we
538         // don't ever call cv.notify, this should be a non-processor intensive version
539         // of while(true);
540         std::mutex blocker;
541         std::condition_variable cv;
542         std::unique_lock<std::mutex> lock(blocker);
543         cv.wait(lock);
544
545     }catch(OCException& e)
546     {
547         oclog() << "Exception in main: "<<e.what();
548     }
549
550     return 0;
551 }
552
553