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