b5af26fc82041f3005afb971aa2d16e53fb69405
[platform/upstream/iotivity.git] / resource / examples / fridgeclient.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 /// This fridgeclient represents a client trying to discover the associated
22 /// fridgeserver.  The device resource is the only one available for discovery
23 /// on the server, so we have to take the fact that we know the device tag
24 /// to then generate a Resource object
25
26 #include <iostream>
27 #include <stdexcept>
28 #include <condition_variable>
29 #include <mutex>
30 #include <atomic>
31 #include "OCPlatform.h"
32 #include "OCApi.h"
33
34 using namespace OC;
35 namespace PH = std::placeholders;
36
37 // Option ID for API version and client token
38 const uint16_t API_VERSION = 2048;
39 const uint16_t TOKEN = 3000;
40
41 static void printUsage()
42 {
43     std::cout << "Usage: fridgeclient <0|1>" <<std::endl;
44     std::cout << "connectivityType: Default IP" << std::endl;
45     std::cout << "connectivityType 0: IP" << std::endl;
46 }
47 class ClientFridge
48 {
49     public:
50     ClientFridge(OCConnectivityType ct): m_callbackCount(0),
51         m_callsMade(0),m_connectivityType(ct)
52     {
53         std::ostringstream requestURI;
54         requestURI << OC_RSRVD_WELL_KNOWN_URI << "?rt=intel.fridge";
55         std::cout << "Fridge Client has started " <<std::endl;
56         FindCallback f (std::bind(&ClientFridge::foundDevice, this, PH::_1));
57         OCStackResult result = OCPlatform::findResource(
58                 "", requestURI.str(), CT_DEFAULT, f);
59
60         if(OC_STACK_OK != result)
61         {
62             throw new std::runtime_error("Fridge Find Resource Failed");
63         }
64
65         std::cout << "Waiting to discover fridge... "<<std::endl;
66         {
67             // we want to block this thread until the client has finished
68             // its duties, so we block on the CV until we have completed
69             // what we are looking to do
70             std::unique_lock<std::mutex> lk(m_mutex);
71             m_cv.wait(lk, [this]{ return m_callbackCount!=0 && m_callbackCount == m_callsMade;});
72         }
73     }
74
75     private:
76     void foundDevice(std::shared_ptr<OCResource> resource)
77     {
78         using namespace OC::OCPlatform;
79         std::string platformDiscoveryURI = "/oic/p";
80         std::string deviceDiscoveryURI   = "/oic/d";
81         if(resource && resource->uri() == "/device")
82         {
83             std::cout << "Discovered a device object"<<std::endl;
84             std::cout << "\tHost: "<<resource->host()<<std::endl;
85             std::cout << "\tURI:  "<<resource->uri() <<std::endl;
86         }
87
88         OCStackResult ret;
89
90         std::cout << "Querying for platform information... " << std::endl;
91
92         ret = OCPlatform::getPlatformInfo("", platformDiscoveryURI, CT_ADAPTER_IP, NULL);
93
94         if (ret == OC_STACK_OK)
95         {
96             std::cout << "Get platform information is done." << std::endl;
97         }
98         else
99         {
100             std::cout << "Get platform information failed." << std::endl;
101         }
102
103         std::cout << "Querying for device information... " << std::endl;
104
105         ret = OCPlatform::getDeviceInfo(resource->host(), deviceDiscoveryURI, 
106                                 resource->connectivityType(), NULL);
107
108         if (ret == OC_STACK_OK)
109         {
110             std::cout << "Getting device information is done." << std::endl;
111         }
112         else
113         {
114             std::cout << "Getting device information failed." << std::endl;
115         }
116
117         // we have now found a resource, so lets create a few resource objects
118         // for the other resources that we KNOW are associated with the intel.fridge
119         // server, and query them.
120         std::vector<std::string> lightTypes = {"intel.fridge.light"};
121         std::vector<std::string> ifaces = {DEFAULT_INTERFACE};
122         OCResource::Ptr light = constructResourceObject(resource->host(),
123                                 "/light", m_connectivityType, false, lightTypes, ifaces);
124
125         if(!light)
126         {
127             std::cout << "Error: Light Resource Object construction returned null\n";
128             return;
129         }
130
131         std::vector<std::string> doorTypes = {"intel.fridge.door"};
132         OCResource::Ptr leftdoor = constructResourceObject(resource->host(),
133                                 "/door/left", m_connectivityType, false, doorTypes, ifaces);
134
135         if(!leftdoor)
136         {
137             std::cout << "Error: Left Door Resource Object construction returned null\n";
138             return;
139         }
140
141         OCResource::Ptr rightdoor = constructResourceObject(resource->host(),
142                                 "/door/right", m_connectivityType, false, doorTypes, ifaces);
143
144         if(!rightdoor)
145         {
146             std::cout << "Error: Right Door Resource Object construction returned null\n";
147             return;
148         }
149
150         OCResource::Ptr randomdoor = constructResourceObject(resource->host(),
151                                 "/door/random", m_connectivityType, false, doorTypes, ifaces);
152         if(!randomdoor)
153         {
154             std::cout << "Error: Random Door Resource Object construction returned null\n";
155             return;
156         }
157
158         // Set header options with API version and token
159         HeaderOptions headerOptions;
160         try
161         {
162             // Set API version and client token
163             HeaderOption::OCHeaderOption apiVersion(API_VERSION, "v.1.0");
164             HeaderOption::OCHeaderOption clientToken(TOKEN, "21ae43gf");
165             headerOptions.push_back(apiVersion);
166             headerOptions.push_back(clientToken);
167         }
168         catch(OCException& e)
169         {
170             std::cout << "Error creating HeaderOption: " << e.what() << std::endl;
171         }
172
173
174         // Setting header options will send above options in all requests
175         // Header options are set per resource.
176         // Below, header options are set only for device resource
177         resource->setHeaderOptions(headerOptions);
178
179         ++m_callsMade;
180         resource->get(QueryParamsMap(), GetCallback(
181                 std::bind(&ClientFridge::getResponse, this, "Device", PH::_1,
182                     PH::_2, PH::_3, resource, 0)
183                 ));
184         ++m_callsMade;
185         light->get(QueryParamsMap(), GetCallback(
186                 std::bind(&ClientFridge::getResponse, this, "Fridge Light", PH::_1,
187                     PH::_2, PH::_3, light, 1)
188                 ));
189         ++m_callsMade;
190         leftdoor->get(QueryParamsMap(), GetCallback(
191                 std::bind(&ClientFridge::getResponse, this, "Left Door", PH::_1,
192                     PH::_2, PH::_3, leftdoor, 2)
193                 ));
194         ++m_callsMade;
195         rightdoor->get(QueryParamsMap(), GetCallback(
196                 std::bind(&ClientFridge::getResponse, this, "Right Door", PH::_1,
197                     PH::_2, PH::_3, rightdoor, 3)
198                 ));
199         ++m_callsMade;
200         randomdoor->get(QueryParamsMap(), GetCallback(
201                 std::bind(&ClientFridge::getResponse, this, "Random Door", PH::_1,
202                     PH::_2, PH::_3, randomdoor, 4)
203                 ));
204         ++m_callsMade;
205         resource->deleteResource(DeleteCallback(
206                 std::bind(&ClientFridge::deleteResponse, this, "Device", PH::_1,
207                     PH::_2, resource, 0)
208                 ));
209     }
210
211     // Note that resourceName, resource, and getId are all bound via the std::bind mechanism.
212     // it is possible to attach ANY arbitrary data to do whatever you would like here.  It may,
213     // however be a better fit to wrap each call in an object so a fuller context (and additional
214     // requests) can be easily made inside of a simple context
215     void getResponse(const std::string& resourceName, const HeaderOptions& headerOptions,
216                 const OCRepresentation& rep, const int eCode, OCResource::Ptr resource, int getId)
217     {
218         std::cout << "Got a response from get from the " << resourceName << std::endl;
219         std::cout << "Get ID is "<<getId<<" and resource URI is " << resource->uri() << std::endl;
220         std::cout << "Get eCode is "<< eCode << std::endl;
221         std::cout << "OCRepresentation uri is " << rep.getUri() << std::endl;
222
223         printHeaderOptions(headerOptions);
224
225         std::cout << "The Attribute Data is: "<<std::endl;
226
227         switch(getId)
228         {
229             case 0:
230                 {
231                     // Get on device
232                     std::string name;
233                     rep.getValue("device_name", name);
234                     std::cout << "Name of device: "<< name << std::endl;
235                     break;
236                 }
237             case 1:
238                 {
239                     bool isOn = false;
240                     rep.getValue("on",isOn);
241                     std::cout<<"The fridge light is "<< ((isOn)?"":"not ") <<"on"<<std::endl;
242                 }
243                 break;
244             case 2:
245             case 3:
246                 {
247                     bool isOpen = false;
248                     std::string side;
249                     rep.getValue("open", isOpen);
250                     rep.getValue("side", side);
251                     std::cout << "Door is "<<isOpen<<" and is on the "<<side<<std::endl;
252                 }
253                 break;
254             case 4:
255                 {
256                     // Get on random resource called.
257                     std::string name;
258                     rep.getValue("device_name", name);
259                     std::cout << "Name of fridge: "<< name << std::endl;
260                     break;
261                 }
262         }
263         ++m_callbackCount;
264
265         if(m_callbackCount == m_callsMade)
266         {
267             m_cv.notify_all();
268         }
269     }
270
271     //Callback function to handle response for deleteResource call.
272     void deleteResponse(const std::string& resourceName, const HeaderOptions& headerOptions,
273                 const int /*eCode*/, OCResource::Ptr resource, int deleteId)
274     {
275         std::cout << "Got a response from delete from the "<< resourceName << std::endl;
276         std::cout << "Delete ID is "<<deleteId<<" and resource URI is "<<resource->uri()<<std::endl;
277         printHeaderOptions(headerOptions);
278
279         ++m_callbackCount;
280
281         if(m_callbackCount == m_callsMade)
282         {
283             m_cv.notify_all();
284         }
285     }
286
287     //Function to print the headerOptions received from the server
288     void printHeaderOptions(const HeaderOptions& headerOptions)
289     {
290         for (auto it = headerOptions.begin(); it != headerOptions.end(); ++it)
291         {
292             if(it->getOptionID() == API_VERSION)
293             {
294                 std::cout << "Server API version in GET response: " <<
295                         it->getOptionData() << std::endl;
296             }
297         }
298     }
299
300     std::mutex m_mutex;
301     std::condition_variable m_cv;
302     std::atomic<int> m_callbackCount;
303     std::atomic<int> m_callsMade;
304     OCConnectivityType m_connectivityType;
305 };
306
307 int main(int argc, char* argv[])
308 {
309     OCConnectivityType connectivityType = CT_ADAPTER_IP;
310     if(argc == 2)
311     {
312         try
313         {
314             std::size_t inputValLen;
315             int optionSelected = std::stoi(argv[1], &inputValLen);
316
317             if(inputValLen == strlen(argv[1]))
318             {
319                 if(optionSelected == 0)
320                 {
321                     std::cout << "Using IP."<< std::endl;
322                     connectivityType = CT_ADAPTER_IP;
323                 }
324                 else
325                 {
326                     std::cout << "Invalid connectivity type selected. Using default IP" << std::endl;
327                     printUsage();
328                 }
329             }
330             else
331             {
332                 std::cout << "Invalid connectivity type selected. Using default IP" << std::endl;
333             }
334         }
335         catch(std::exception&)
336         {
337             std::cout << "Invalid input argument. Using IP as connectivity type" << std::endl;
338         }
339     }
340     else
341     {
342         printUsage();
343         std::cout << "Default input argument. Using IP as connectivity type" << std::endl;
344     }
345
346     PlatformConfig cfg
347     {
348         ServiceType::InProc,
349         ModeType::Client,
350         "0.0.0.0",
351         0,
352         QualityOfService::LowQos
353     };
354
355     OCPlatform::Configure(cfg);
356     ClientFridge cf(connectivityType);
357     return 0;
358 }
359