replace : iotivity -> iotivity-sec
[platform/upstream/iotivity.git] / service / resource-encapsulation / examples / linux / SampleResourceClient.cpp
index 8307f08..d7336ca 100644 (file)
-#include<iostream>
+//******************************************************************
+//
+// Copyright 2015 Samsung Electronics All Rights Reserved.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+#include <iostream>
 
 #include "RCSDiscoveryManager.h"
+#include "RCSRepresentation.h"
 #include "RCSRemoteResourceObject.h"
 #include "RCSResourceAttributes.h"
-#include "OCPlatform.h"
 #include "RCSAddress.h"
 
-using namespace std;
+#include "OCPlatform.h"
+
+#define DECLARE_MENU(FUNC, ...) { #FUNC, FUNC }
+
 using namespace OC;
 using namespace OIC::Service;
 
-std::shared_ptr<RCSRemoteResourceObject>  resource;
-RCSResourceAttributes resourceAttributes;
-bool startCachingFlag;
-bool isReady;
+struct CloseApp {};
 
-//callback function for discoverResource()
-void OnResourceDiscovered(std::shared_ptr<RCSRemoteResourceObject> foundResource)
+struct MenuItem
 {
+private:
+    typedef void(*Handler)();
+
+public:
+    const std::string title;
+    const Handler handler;
+};
+
+typedef void(*Runner)();
 
-    cout << "\nOnResourceDiscovered callback" << std::endl;
+constexpr int RESOURCE_TEMP = 1;
+constexpr int RESOURCE_LIGHT = 2;
 
-    std::string resourceURI = foundResource->getUri();
-    std::string hostAddress = foundResource->getAddress();
+const std::string RESOURCE_TYPE_TEMP = "oic.r.temperaturesensor";
+const std::string RESOURCE_TYPE_LIGHT = "oic.r.light";
 
-    cout << "\tResource URI : " << resourceURI << std::endl;
-    cout << "\tResource Host : " << hostAddress << std::endl;
+RCSRemoteResourceObject::Ptr g_selectedResource;
+std::vector<RCSRemoteResourceObject::Ptr> g_discoveredResources;
 
-    resource = foundResource;
-    isReady = true;
+std::string g_attrKey;
+
+Runner g_currentRun;
+
+std::ostream& operator<<(std::ostream& os, const RCSRemoteResourceObject::Ptr& object)
+{
+    return os << "\turi : " << object->getUri() << std::endl <<
+            "\thost address : " << object->getAddress();
 }
 
-//callback for StartMonitoring()
-void OnResourceStateChanged(ResourceState resourceState)
+std::ostream& operator<<(std::ostream& os, const MenuItem& item)
 {
+    return os << item.title;
+}
 
-    cout << "\nOnResourceStateChanged callback" << std::endl;
+void onSelected(const RCSRemoteResourceObject::Ptr& object)
+{
+    g_selectedResource = object;
+}
 
-    if (resourceState == ResourceState::NOT_MONITORING)
-        cout << "State changed to : NOT_MONITORING" << std::endl;
-    else if (resourceState == ResourceState::ALIVE)
-        cout << "State changed to : ALIVE" << std::endl;
-    else if (resourceState == ResourceState::REQUESTED)
-        cout << "State changed to : REQUESTED" << std::endl;
-    else if (resourceState == ResourceState::LOST_SIGNAL)
-        cout << "State changed to : LOST_SIGNAL" << std::endl;
-    else if (resourceState == ResourceState::DESTROYED)
-        cout << "State changed to : DESTROYED" << std::endl;
+void onSelected(const MenuItem& item)
+{
+    std::cout << item.title << " start.." << std::endl;
+    item.handler();
 }
 
-//callback for startCaching() [uptodate]
-void OnCacheUpdated(const RCSResourceAttributes atttribute )
+int processUserInput(int min = std::numeric_limits<int>::min(),
+        int max = std::numeric_limits<int>::max())
 {
-    cout << "\nOnCacheUpdated callback" << std::endl;
-    if (atttribute.empty())
+    assert(min <= max);
+
+    int input = 0;
+
+    std::cin >> input;
+    std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
+
+    if (!std::cin.fail() && min <= input && input <= max)
     {
-        std::cout << "Attribute is Empty" << std::endl;
+        return input;
     }
-    else
+
+    std::cin.clear();
+    std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
+
+    throw std::runtime_error("Invalid Input, please try again");
+}
+
+template<typename D>
+void displayItem(int width, int index, const D& data)
+{
+    std::cout.width(width);
+    std::cout << std::right << index << ". ";
+    std::cout << data << std::endl;
+}
+
+template<typename T>
+void displayItems(const std::vector<T>& items)
+{
+    std::cout << std::endl;
+
+    const auto width = (items.size() + 1) / 10 + 1;
+
+    for (size_t i = 0; i < items.size(); ++i)
     {
-        RCSResourceAttributes::const_iterator iter = atttribute.begin();
-        for (unsigned int i = 0; i < atttribute.size(); ++i)
-        {
-            std::cout << "key : " << iter->key() << "\nvalue : " << iter->value().toString() << std::endl;
-            ++iter;
-        }
+        displayItem(width, i + 1, items[i]);
+    }
+    displayItem(width, items.size() + 1, "quit");
+}
+
+template<typename T>
+void selectItem(const std::vector<T>& items)
+{
+    int selected = processUserInput(1, items.size() + 1) - 1;
+
+    if (selected == static_cast<int>(items.size()))
+    {
+        throw CloseApp();
+    }
+
+    onSelected(items[selected]);
+}
+
+template<typename T>
+void handleItems(const std::vector<T>& items)
+{
+    displayItems(items);
+    selectItem(items);
+}
+
+std::string inputInterface()
+{
+    std::string interfaceName;
+
+    std::cout << "\tInput the Interface you want to set : ";
+    std::cin >> interfaceName;
+
+    return interfaceName;
+}
+
+RCSResourceAttributes inputKeyValue()
+{
+    std::string key;
+
+    std::cout << "\tEnter the Key you want to set : ";
+    std::cin >> key;
+
+    std::cout << "\tEnter the value(INT) you want to set :";
+    RCSResourceAttributes attrs;
+    attrs[key] = processUserInput();
+
+    return attrs;
+}
+
+void printAttribute(const std::string& key, const RCSResourceAttributes::Value& value)
+{
+    std::cout << "\tkey : " << key << std::endl
+              << "\tvalue : " << value.toString() << std::endl;
+}
+
+void printAttributes(const RCSResourceAttributes& attributes)
+{
+    if (attributes.empty())
+    {
+       std::cout << "\tattributes is empty" << std::endl;
     }
 
+    for (const auto& attr : attributes)
+    {
+        printAttribute(attr.key(), attr.value());
+    }
 }
-//callback for getRemoteAttributes()
-void OnRemoteAttributesReceivedCallback(const RCSResourceAttributes &atttribute)
+
+void print(const std::string& name, const std::vector< std::string >& elements)
 {
+    if (elements.empty())
+    {
+       std::cout << "\t" << name << " is empty" << std::endl;
+       return;
+    }
 
-    std::cout << "\nOnRemoteAttributesReceivedCallback callback" << std::endl;
-    if (atttribute.empty())
+    std::cout << "\t" << name << " : " << std::endl;
+    for (const auto& item : elements)
+    {
+        std::cout << item << " ";
+    }
+    std::cout << std::endl;
+}
+
+void printUri(const std::string& uri)
+{
+    if (uri.empty())
     {
-        std::cout << "Got empty attribute " << std::endl;
+        std::cout << "\turi is empty" << std::endl;
     }
     else
     {
-        resourceAttributes = atttribute;
-        RCSResourceAttributes::const_iterator iter = atttribute.begin();
-        for (unsigned int i = 0; i < atttribute.size(); ++i)
-        {
-            std::cout << "key : " << iter->key() << "\nvalue : " << iter->value().toString() << std::endl;
-            ++iter;
-        }
+        std::cout << "\turi : " << uri << std::endl;
     }
 }
 
-//callback for setRemoteAttributes()
-void OnRemoteAttributesSetCallback(const RCSResourceAttributes &atttribute)
+void printRepresentation(const RCSRepresentation& rep)
 {
+    printUri(rep.getUri());
+    print("interfaces", rep.getInterfaces());
+    print("resourceTypes", rep.getResourceTypes());
+    printAttributes(rep.getAttributes());
 
-    std::cout << "\nOnRemoteAttributesSetCallback callback" << std::endl;
-    if (atttribute.empty())
+    const auto& children = rep.getChildren();
+
+    if (children.empty())
     {
-        std::cout << "Got empty attribute " << std::endl;
+        std::cout << "\tchildren is empty" << std::endl;
     }
     else
     {
-        resourceAttributes = atttribute;
-        RCSResourceAttributes::const_iterator iter = atttribute.begin();
-        for (unsigned int i = 0; i < atttribute.size(); ++i)
+        int cnt = 0;
+        for (const auto& child : children)
         {
-            std::cout << "key : " << iter->key() << "\nvalue : " << iter->value().toString() << std::endl;
-            ++iter;
+            std::cout << "========================================================" << std::endl;
+            std::cout << ++cnt << " chlid" << std::endl;
+            printRepresentation(child);
+            std::cout << "========================================================" << std::endl;
         }
     }
 }
 
-int main()
+void onResourceStateChanged(ResourceState resourceState)
 {
+    std::cout << "onResourceStateChanged callback" << std::endl;
 
-    RCSDiscoveryManager *discoveryManagerInstance =  RCSDiscoveryManager::getInstance();
-    bool cachingFlag = false;
+    switch (resourceState)
+    {
+        case ResourceState::NONE:
+            std::cout << "\tState changed to : NOT_MONITORING" << std::endl;
+            break;
 
-    //configuring the platform
-    PlatformConfig config
+        case ResourceState::ALIVE:
+            std::cout << "\tState changed to : ALIVE" << std::endl;
+            break;
+
+        case ResourceState::REQUESTED:
+            std::cout << "\tState changed to : REQUESTED" << std::endl;
+            break;
+
+        case ResourceState::LOST_SIGNAL:
+            std::cout << "\tState changed to : LOST_SIGNAL" << std::endl;
+            break;
+
+        case ResourceState::DESTROYED:
+            std::cout << "\tState changed to : DESTROYED" << std::endl;
+            break;
+    }
+}
+
+void onCacheUpdated(const RCSResourceAttributes& attributes, int eCode)
+{
+    std::cout << "onCacheUpdated callback : " << eCode << std::endl;
+
+    printAttributes(attributes);
+}
+
+void onRemoteAttributesReceived(const RCSResourceAttributes& attributes, int)
+{
+    std::cout << "onRemoteAttributesReceived callback" << std::endl;
+
+    printAttributes(attributes);
+}
+
+void onRemoteGetReceived(const HeaderOpts&, const RCSRepresentation& rep, int)
+{
+    std::cout << "onRemoteGetReceived callback" << std::endl;
+
+    printRepresentation(rep);
+}
+
+void onRemoteSetReceived(const HeaderOpts&, const RCSRepresentation& rep, int)
+{
+    std::cout << "onRemoteSetReceived callback" << std::endl;
+
+    printRepresentation(rep);
+}
+
+void startMonitoring()
+{
+    if (g_selectedResource->isMonitoring())
     {
-        OC::ServiceType::InProc, ModeType::Client, "0.0.0.0", 0, OC::QualityOfService::LowQos
-    };
-    OCPlatform::Configure(config);
+        std::cout << "\tAlready Started..." << std::endl;
+        return;
+    }
 
-    std::cout << "\nPlatform configured successfully" << std::endl;
-    std::string uri = "";
-    std::string address = "";
-    std::string rt = "core.TemperatureSensor";
+    g_selectedResource->startMonitoring(&onResourceStateChanged);
+    std::cout << "\tMonitoring Started..." << std::endl;
+}
 
-    try
+void stopMonitoring()
+{
+    if (!g_selectedResource->isMonitoring())
     {
+        std::cout << "\tMonitoring not started..." << std::endl;
+        return;
+    }
 
-        uri = OC_RSRVD_WELL_KNOWN_URI + uri + "?rt=" + rt;
+    g_selectedResource->stopMonitoring();
+    std::cout << "\tMonitoring stopped..." << std::endl;
+}
 
-        //getting the object of RCSAddress for multicast discovery
-        RCSAddress rcsAddress = RCSAddress::multicast();
+void getRemoteAttributes()
+{
+    g_selectedResource->getRemoteAttributes(onRemoteAttributesReceived);
+}
 
-        //discover the resource in the network
-        discoveryManagerInstance->discoverResource(rcsAddress, uri , &OnResourceDiscovered);
+void setRemoteAttributes()
+{
+    g_selectedResource->setRemoteAttributes(inputKeyValue(), onRemoteAttributesReceived);
+}
+
+void getWithInterface()
+{
+    RCSQueryParams queryParams;
+    queryParams.setResourceInterface(inputInterface());
+
+    g_selectedResource->get(queryParams, onRemoteGetReceived);
+}
+
+void setWithInterface()
+{
+    RCSQueryParams queryParams;
+    queryParams.setResourceInterface(inputInterface());
+
+    g_selectedResource->set(queryParams, inputKeyValue(), onRemoteSetReceived);
+}
+
+void startCaching(RCSRemoteResourceObject::CacheUpdatedCallback cb)
+{
+    if (g_selectedResource->isCaching())
+    {
+        std::cout << "\tAlready Started Caching..." << std::endl;
+        return;
     }
-    catch (InvalidParameterException e)
+
+    g_selectedResource->startCaching(std::move(cb));
+    std::cout << "\tCaching Started..." << std::endl;
+}
+
+void startCachingWithoutCallback()
+{
+    startCaching(nullptr);
+}
+
+void startCachingWithCallback()
+{
+    startCaching(onCacheUpdated);
+}
+
+void getResourceCacheState()
+{
+    switch(g_selectedResource->getCacheState())
     {
-        cout << "Exeception in discoverResource" << e.what() << std::endl;
+        case CacheState::READY:
+            std::cout << "\tCurrent Cache State : CACHE_STATE::READY" << std::endl;
+            break;
+
+        case CacheState::UNREADY:
+            std::cout << "\tCurrent Cache State : CACHE_STATE::UNREADY" << std::endl;
+            break;
+
+        case CacheState::LOST_SIGNAL:
+            std::cout << "\tCurrent Cache State : CACHE_STATE::LOST_SIGNAL" << std::endl;
+            break;
+
+        case CacheState::NONE:
+            std::cout << "\tCurrent Cache State : CACHE_STATE::NONE" << std::endl;
+            break;
     }
+}
+
+void getCachedAttributes()
+{
+    printAttributes(g_selectedResource->getCachedAttributes());
+}
 
-    bool isRun = true;
-    int userInput;
-    while (isRun)
+void getCachedAttribute()
+{
+    printAttribute(g_attrKey, g_selectedResource->getCachedAttribute(g_attrKey));
+}
+
+void stopCaching()
+{
+    if (!g_selectedResource->isCaching())
+    {
+        std::cout << "\tCaching not started..." << std::endl;
+        return;
+    }
+
+    g_selectedResource->stopCaching();
+    std::cout << "\tCaching stopped..." << std::endl;
+}
+
+std::string selectResourceType()
+{
+    std::cout << "========================================================" << std::endl;
+    std::cout << "1. Temperature Resource Discovery" << std::endl;
+    std::cout << "2. Light Resource Discovery" << std::endl;
+    std::cout << "========================================================" << std::endl;
+
+    switch (processUserInput(RESOURCE_TEMP, RESOURCE_LIGHT))
     {
-        while (isReady)
+        case RESOURCE_TEMP:
         {
-            cout << endl;
-            cout << "1 :: Start Hosting" << endl;
-            cout << "2 :: Stop Hosting" << endl;
-            cout << "3 :: Get Attribute" << endl;
-            cout << "4 :: Set Attribute" << endl;
-            cout << "5 :: Start caching (No update to Application)" << endl;
-            cout <<  "6 :: Start caching (Update the application when data change)" <<
-                 endl; //look for the datachange on server
-            cout << "7 :: Get Resource cache State" << endl;
-            cout << "8 :: Get Cached Attributes" << endl;
-            cout << "9 :: Get Cached Attribute"  << endl;
-            cout << "10 :: Stop caching" << endl;
-            cout << "11 :: QUIT" << endl;
-
-            cin >> userInput;
-
-            if (userInput == 1)
-            {
-                try
-                {
-                    resource->startMonitoring(&OnResourceStateChanged);
-                    cout << "\n\n**********  Hosting Started ***********" << std::endl;
-                }
-                catch (InvalidParameterException e)
-                {
-                    cout << "Exeception in startMonitoring :: " << e.what() << std::endl;
-                }
-            }
-            else if (userInput == 2)
-            {
-                resource->stopMonitoring();
-                cout << "\n\n******  Hosting stopped******" << std::endl;
-            }
-            else if (userInput == 3)
-            {
-                resource->getRemoteAttributes(&OnRemoteAttributesReceivedCallback);
-            }
-            else if (userInput == 4)
-            {
-                int temperatureValue;
-                if (0 == resourceAttributes.size())
-                {
-                    cout << "\n***First Get the Attributes from Remote Device : press 3 to get attributes***" <<
-                         std::endl;
-                }
-                else
-                {
-                    RCSResourceAttributes::const_iterator iter = resourceAttributes.begin();
-                    for (unsigned int i = 0; i < resourceAttributes.size(); ++i)
-                    {
-                        if ( iter->key() == "Temperature")
-                        {
-                            cout << "Enter the value you want to set :";
-                            cin >> temperatureValue;
-                            resourceAttributes["Temperature"]  = temperatureValue;
-                            resource->setRemoteAttributes(resourceAttributes, &OnRemoteAttributesSetCallback);
-                        }
-                        ++iter;
-                    }
-                }
-            }
-            else if (userInput == 5)
-            {
-                if (false == cachingFlag)
-                {
-                    resource->startCaching();
-                    cout << "**********  caching Started ***********" << std::endl;
-                    cachingFlag = true;
-                }
-                else
-                {
-                    cout << "***  Already Started... To start it again first stop it : press 10 ***" << std::endl;
-                }
-            }
-            else if (userInput == 6)
-            {
-                try
-                {
-                    if (false == cachingFlag)
-                    {
-                        resource->startCaching(&OnCacheUpdated);
-                        cout << "**********  caching Started ***********" << std::endl;
-                    }
-                    else
-                    {
-                        cout << "***  Already Started... To start it again first stop it : press 10 ***" << std::endl;
-                    }
-                }
-                catch (InvalidParameterException e)
-                {
-                    cout << "Exeception in startCaching :: " << e.what() << std::endl;
-                }
-            }
-            else if (userInput == 7)
-            {
-
-                CacheState state = resource->getResourceCacheState();
-                if (state == CacheState ::READY)
-                    cout << "Current Cache State : " << "CACHE_STATE ::READY" << std::endl;
-                else if (state == CacheState ::READY_YET)
-                    cout << "Current Cache State : " << "CACHE_STATE ::READY_YET" << std::endl;
-                else if (state == CacheState ::LOST_SIGNAL)
-                    cout << "Current Cache State : " << "CACHE_STATE ::LOST_SIGNAL" << std::endl;
-                else if (state == CacheState ::DESTROYED)
-                    cout << "Current Cache State : " << "CACHE_STATE ::DESTROYED" << std::endl;
-                else if (state == CacheState ::UPDATING)
-                    cout << "Current Cache State : " << "CACHE_STATE ::UPDATING" << std::endl;
-                else if (state == CacheState ::NONE)
-                    cout << "Current Cache State : " << "CACHE_STATE ::NONE" << std::endl;
-            }
-            else if (userInput == 8)
-            {
-                try
-                {
-                    RCSResourceAttributes atttribute = resource->getCachedAttributes();
-                    if (atttribute.empty())
-                    {
-                        cout << "Received cached attribute is empty" << std::endl;
-                    }
-                    else
-                    {
-                        RCSResourceAttributes::const_iterator iter = atttribute.begin();
-                        for (unsigned int i = 0; i < atttribute.size(); ++i)
-                        {
-                            std::cout << "\nkey : " << iter->key() << "\nvalue : " << iter->value().toString() << std::endl;
-                            ++iter;
-                        }
-                    }
-                }
-                catch (BadRequestException e)
-                {
-                    cout << "getCachedAttributes exception : " << e.what() << std::endl;
-                }
-            }
-            else if (userInput == 9)
-            {
-                std::string key = "Temperature";
-                try
-                {
-                    RCSResourceAttributes::Value valueObj = resource->getCachedAttribute(key);
-                    int value = valueObj.get< int >();
-                    cout << "\nkey : " << key << "\nValue : " << value << std::endl;
-                }
-                catch (BadRequestException e)
-                {
-                    cout << "getCachedAttribute exception : " << e.what() << std::endl;
-                }
-                catch (BadGetException e)
-                {
-                    cout << "Exeception in getCachedAttribute  BadGetException:: " << e.what() << std::endl;
-                }
-            }
-            else if (userInput == 10)
-            {
-                resource->stopCaching();
-                cachingFlag = false;
-                cout << "****** Caching stopped ******" << std::endl;
-            }
-            else if (userInput == 11)
-            {
-                isReady = false;
-                isRun = false;
-            }
-            else
-            {
-                cout << "***   Please enter the number between 1-11  ***" << std::endl;
-            }
+            g_attrKey = "Temperature";
+            return RESOURCE_TYPE_TEMP;
+        }
+        case RESOURCE_LIGHT:
+        {
+            g_attrKey = "Brightness";
+            return RESOURCE_TYPE_LIGHT;
         }
     }
-    return 0;
+
+    throw std::logic_error("unreachable");
 }
 
+RCSAddress inputAddress()
+{
+    std::cout << "========================================================" << std::endl;
+    std::cout << "Please input address (empty for multicast)" << std::endl;
+    std::cout << "========================================================" << std::endl;
+
+    std::string address;
+
+    if (std::cin.peek() != '\n')
+    {
+        std::cin >> address;
+    }
+
+    return address.empty() ? RCSAddress::multicast() : RCSAddress::unicast(address);
+}
+
+void printDiscoveryInProgress()
+{
+    std::cout << "Discovery in progress, press '1' to stop." << std::endl;
+}
+
+void discoverResource()
+{
+    auto onResourceDiscovered = [](
+            const RCSRemoteResourceObject::Ptr& discoveredResource)
+    {
+        std::cout << "onResourceDiscovered callback :: " << std::endl;
+
+        std::cout << "uri : " << discoveredResource->getUri() << std::endl;
+        std::cout << "host address : " << discoveredResource->getAddress() << std::endl;
+
+        g_discoveredResources.push_back(discoveredResource);
+
+        printDiscoveryInProgress();
+    };
+
+    auto resourceType = selectResourceType();
+    auto address = inputAddress();
+
+    printDiscoveryInProgress();
+
+    auto discoveryTask = RCSDiscoveryManager::getInstance()->discoverResourceByType(address,
+            resourceType, onResourceDiscovered);
+
+    while (processUserInput() != 1);
+
+    discoveryTask->cancel();
+}
+
+void runResourceControl()
+{
+    static std::vector<MenuItem> resourceMenuItems {
+        DECLARE_MENU(startMonitoring),
+        DECLARE_MENU(stopMonitoring),
+        DECLARE_MENU(getRemoteAttributes),
+        DECLARE_MENU(setRemoteAttributes),
+        DECLARE_MENU(getWithInterface),
+        DECLARE_MENU(setWithInterface),
+        DECLARE_MENU(startCachingWithoutCallback),
+        DECLARE_MENU(startCachingWithCallback),
+        DECLARE_MENU(getResourceCacheState),
+        DECLARE_MENU(getCachedAttributes),
+        DECLARE_MENU(getCachedAttribute),
+        DECLARE_MENU(stopCaching),
+    };
+
+    handleItems(resourceMenuItems);
+}
+
+void runResourceSelection()
+{
+    handleItems(g_discoveredResources);
+
+    g_currentRun = runResourceControl;
+}
+
+void runDiscovery()
+{
+    static std::vector<MenuItem> discoveryMenuItems {
+        DECLARE_MENU(discoverResource),
+    };
+
+    handleItems(discoveryMenuItems);
+
+    if (g_discoveredResources.empty())
+    {
+        throw std::runtime_error("No resource found!");
+    }
+
+    g_currentRun = runResourceSelection;
+}
+
+void configurePlatform()
+{
+    PlatformConfig config
+    {
+        OC::ServiceType::InProc, ModeType::Client, "0.0.0.0", 0, OC::QualityOfService::LowQos
+    };
+    OCPlatform::Configure(config);
+}
+
+int main()
+{
+    configurePlatform();
+
+    g_currentRun = runDiscovery;
+
+    while (true)
+    {
+        try
+        {
+            g_currentRun();
+        }
+        catch (const std::exception& e)
+        {
+            std::cout << e.what() << std::endl;
+        }
+        catch (const CloseApp&)
+        {
+            break;
+        }
+    }
+
+    std::cout << "Stopping the client" << std::endl;
+
+    return 0;
+}