MotionLib  1.0.0
SamBuCa motion library
AsyncConfigController.hpp
1 /*
2 ** Copyright (C) 2022 CERN
3 **
4 ** This software is provided 'as-is', without any express or implied
5 ** warranty. In no event will the authors be held liable for any damages
6 ** arising from the use of this software.
7 **
8 ** Permission is granted to anyone to use this software for any purpose,
9 ** including commercial applications, and to alter it and redistribute it
10 ** freely, subject to the following restrictions:
11 **
12 ** 1. The origin of this software must not be misrepresented; you must not
13 ** claim that you wrote the original software. If you use this software
14 ** in a product, an acknowledgment in the product documentation would be
15 ** appreciated but is not required.
16 ** 2. Altered source versions must be plainly marked as such, and must not be
17 ** misrepresented as being the original software.
18 ** 3. This notice may not be removed or altered from any source distribution.
19 **
20 ** Created on: 2022-08-02T09:42:28
21 ** Author: Sylvain Fargier <sylvain.fargier@cern.ch>
22 */
23 
24 #ifndef ASYNCCONFIGCONTROLLER_HPP__
25 #define ASYNCCONFIGCONTROLLER_HPP__
26 
27 #include <ccut/utils.hpp>
28 #include <oatpp/core/macro/component.hpp>
29 
30 #include "FutureCoroutine.hpp"
31 #include "OatExt.hpp"
32 #include "SmcController.hpp"
33 #include "device/DeviceBase.hpp"
34 #include "device/DeviceStore.hpp"
35 
36 #include OATPP_CODEGEN_BEGIN(ApiController)
37 
38 // clang-format off
40 {
41 public:
42  explicit AsyncConfigController(OATPP_COMPONENT(std::shared_ptr<ObjectMapper>,
43  objectMapper)) :
44  SmcController(objectMapper)
45  {
46  addTag(*this, "config");
47  }
48 
49  void addParams(const std::shared_ptr<oatpp::web::server::api::Endpoint::Info>& info)
50  {
51  info->pathParams.add<String>("id")
52  .addExample("Grbl axis X", String("grbl://1/axis/X"));
53  }
54 
55  ENDPOINT_INFO(getConfigList)
56  {
57  info->summary = "get device configuration parameters";
58  info->addResponse<List<String>>(Status::CODE_200, "application/json");
59  addParams(info);
60  }
61  ENDPOINT_ASYNC("GET", "/config/{id}", getConfigList)
62  {
63  public:
64  ENDPOINT_ASYNC_INIT(getConfigList)
65  Action act() override
66  {
67  auto deviceStore(controller->deviceStore.lock());
68  if (deviceStore)
69  {
70  smc::DeviceBase::Shared device = deviceStore->getDevice(
71  ccut::urldecode(request->getPathVariable("id").getValue("")));
72 
73  auto future = device->listConfig();
74  return smc::debug::wait(future.share())
75  .callbackTo(&getConfigList::onResult);
76  }
77  return _return(controller->createResponse(Status::CODE_500, "no deviceStore"));
78  }
79 
80  Action onResult(const std::set<std::string> &value)
81  {
82  oatpp::UnorderedSet<String> ret{oatpp::UnorderedSet<String>::createShared()};
83  ret->insert(value.begin(), value.end());
84  return _return(
85  controller->createDtoResponse(Status::CODE_200, ret));
86  }
87  };
88 
89  ENDPOINT_INFO(getConfig)
90  {
91  info->summary = "get configuration parameter value";
92  info->addResponse<String>(Status::CODE_200, "application/json");
93  addParams(info);
94  info->pathParams.add<String>("name")
95  .addExample("Axis travel resolution", String("axis travel resolution"));
96  }
97  ENDPOINT_ASYNC("GET", "/config/{id}/{name}", getConfig)
98  {
99  public:
100  ENDPOINT_ASYNC_INIT(getConfig)
101  Action act() override
102  {
103  auto deviceStore(controller->deviceStore.lock());
104  if (deviceStore)
105  {
106  smc::DeviceBase::Shared device = deviceStore->getDevice(
107  ccut::urldecode(request->getPathVariable("id").getValue("")));
108  const std::string name =
109  ccut::urldecode(request->getPathVariable("name").getValue(""));
110 
111  auto future = device->getConfig(name);
112  return smc::debug::wait(future.share())
113  .callbackTo(&getConfig::onResult);
114  }
115  return _return(controller->createResponse(Status::CODE_500, "no deviceStore"));
116  }
117 
118  Action onResult(const std::string &value)
119  {
120  return _return(
121  controller->createDtoResponse(Status::CODE_200, String{value}));
122  }
123  };
124 
125  ENDPOINT_INFO(putConfig)
126  {
127  info->summary = "set a configuration parameter value";
128  info->addResponse<String>(Status::CODE_200, "application/json");
129  addParams(info);
130  info->pathParams.add<String>("name")
131  .addExample("Axis travel resolution", String("axis travel resolution"));
132  info->addConsumes<String>("application/json")
133  .addExample("sample value", String("250"));
134  }
135  ENDPOINT_ASYNC("PUT", "/config/{id}/{name}", putConfig)
136  {
137  public:
138  ENDPOINT_ASYNC_INIT(putConfig)
139  Action act() override
140  {
141  return request->readBodyToDtoAsync<String>(
142  controller->getDefaultObjectMapper())
143  .callbackTo(&putConfig::onBody);
144  }
145 
146  Action onBody(const String &value)
147  {
148  auto deviceStore(controller->deviceStore.lock());
149  if (deviceStore)
150  {
151  smc::DeviceBase::Shared device = deviceStore->getDevice(
152  ccut::urldecode(request->getPathVariable("id").getValue("")));
153  const std::string name =
154  ccut::urldecode(request->getPathVariable("name").getValue(""));
155 
156  auto future = device->setConfig(name, value.getValue(""));
157  return smc::debug::wait(future.share())
158  .next(_return(controller->createResponse(Status::CODE_200, "done")));
159  }
160  return _return(controller->createResponse(Status::CODE_500, "no deviceStore"));
161  }
162  };
163 };
164 
165 //clang-format on
166 
167 #include OATPP_CODEGEN_END(ApiController)
168 
169 
170 #endif