Line data Source code
1 : // Webthing-CPP
2 : // SPDX-FileCopyrightText: 2023-present Benno Waldhauer
3 : // SPDX-License-Identifier: MIT
4 :
5 : #pragma once
6 :
7 : #include <bw/webthing/action.hpp>
8 : #include <bw/webthing/errors.hpp>
9 : #include <bw/webthing/event.hpp>
10 : #include <bw/webthing/json.hpp>
11 : #include <bw/webthing/json_validator.hpp>
12 : #include <bw/webthing/mdns.hpp>
13 : #include <bw/webthing/property.hpp>
14 : #include <bw/webthing/server.hpp>
15 : #include <bw/webthing/thing.hpp>
16 : #include <bw/webthing/utils.hpp>
17 : #include <bw/webthing/value.hpp>
18 : #include <bw/webthing/version.hpp>
19 :
20 : namespace bw::webthing
21 : {
22 :
23 22 : inline std::shared_ptr<Thing> make_thing(std::string id, std::string title, std::vector<std::string> type, std::string description)
24 : {
25 22 : if(id == "")
26 7 : id = "uuid:" + generate_uuid();
27 22 : if(title == "")
28 10 : title = id;
29 22 : return std::make_shared<Thing>(id, title, type, description);
30 : }
31 :
32 22 : inline std::shared_ptr<Thing> make_thing(std::string id = "", std::string title = "", std::string type = "", std::string description = "")
33 : {
34 22 : std::vector<std::string> types;
35 22 : if(type != "")
36 1 : types.push_back(type);
37 44 : return make_thing(id, title, types, description);
38 22 : }
39 :
40 18 : template<class T> std::shared_ptr<Value<T>> make_value(T initial_value, typename Value<T>::ValueForwarder value_forwarder = nullptr)
41 : {
42 18 : return std::make_shared<Value<T>>(initial_value, std::move(value_forwarder));
43 : }
44 :
45 3 : template<class T> std::shared_ptr<Value<T>> make_unknown_value(typename Value<T>::ValueForwarder value_forwarder = nullptr)
46 : {
47 3 : return std::make_shared<Value<T>>(std::nullopt, std::move(value_forwarder));
48 : }
49 :
50 17 : template<class T> std::shared_ptr<Property<T>> link_property(Thing* thing, std::string name, std::shared_ptr<Value<T>> value, json metadata = json::object())
51 : {
52 51 : PropertyChangedCallback property_changed_callback = [thing](json property_status){
53 17 : thing->property_notify(property_status);
54 : };
55 17 : auto property = std::make_shared<Property<T>>(std::move(property_changed_callback), name, value, metadata);
56 17 : thing->add_property(property);
57 34 : return property;
58 17 : }
59 :
60 1 : template<class T> std::shared_ptr<Property<T>> link_property(Thing* thing, std::string name, T intial_value, json metadata = json::object())
61 : {
62 1 : return link_property(thing, name, make_value(intial_value), metadata);
63 : }
64 :
65 16 : template<class T> std::shared_ptr<Property<T>> link_property(std::shared_ptr<Thing> thing, std::string name, std::shared_ptr<Value<T>> value, json metadata = json::object())
66 : {
67 16 : return link_property(thing.get(), name, value, metadata);
68 : }
69 :
70 15 : template<class T> std::shared_ptr<Property<T>> link_property(std::shared_ptr<Thing> thing, std::string name, T intial_value, json metadata = json::object())
71 : {
72 15 : return link_property(thing, name, make_value(intial_value), metadata);
73 : }
74 :
75 6 : inline void link_event(Thing* thing, std::string name, json metadata = json::object())
76 : {
77 6 : thing->add_available_event(name, metadata);
78 6 : }
79 :
80 6 : inline void link_event(std::shared_ptr<Thing> thing, std::string name, json metadata = json::object())
81 : {
82 6 : link_event(thing.get(), name, metadata);
83 6 : }
84 :
85 8 : inline std::shared_ptr<Event> emit_event(Thing* thing, std::string name, std::optional<json> data = std::nullopt)
86 : {
87 8 : auto event = std::make_shared<Event>(thing, name, data);
88 8 : thing->add_event(event);
89 8 : return event;
90 0 : }
91 :
92 8 : inline std::shared_ptr<Event> emit_event(std::shared_ptr<Thing> thing, std::string name, std::optional<json> data = std::nullopt)
93 : {
94 8 : return emit_event(thing.get(), name, data);
95 : }
96 :
97 : inline std::shared_ptr<Event> emit_event(Thing* thing, Event&& event)
98 : {
99 : auto event_ptr = std::make_shared<Event>(event);
100 : thing->add_event(event_ptr);
101 : return event_ptr;
102 : }
103 :
104 1 : inline std::shared_ptr<Event> emit_event(std::shared_ptr<Thing> thing, Event&& event)
105 : {
106 1 : auto event_ptr = std::make_shared<Event>(event);
107 1 : thing->add_event(event_ptr);
108 1 : return event_ptr;
109 0 : }
110 :
111 5 : inline void link_action(Thing* thing, std::string action_name, json metadata,
112 : std::function<void()> perform_action = nullptr, std::function<void()> cancel_action = nullptr)
113 : {
114 10 : Thing::ActionSupplier action_supplier = [thing, action_name, perform_action, cancel_action](auto input){
115 : return std::make_shared<Action>(generate_uuid(),
116 10 : make_action_behavior(thing, perform_action, cancel_action),
117 5 : action_name, input);
118 5 : };
119 :
120 5 : thing->add_available_action(action_name, metadata, std::move(action_supplier));
121 5 : }
122 :
123 3 : inline void link_action(std::shared_ptr<Thing> thing, std::string action_name, json metadata,
124 : std::function<void()> perform_action = nullptr, std::function<void()> cancel_action = nullptr)
125 : {
126 3 : link_action(thing.get(), action_name, metadata, perform_action, cancel_action);
127 3 : }
128 :
129 1 : inline void link_action(Thing* thing, std::string action_name,
130 : std::function<void()> perform_action = nullptr, std::function<void()> cancel_action = nullptr)
131 : {
132 1 : link_action(thing, action_name, json::object(), perform_action, cancel_action);
133 1 : }
134 :
135 : inline void link_action(std::shared_ptr<Thing> thing, std::string action_name,
136 : std::function<void()> perform_action = nullptr, std::function<void()> cancel_action = nullptr)
137 : {
138 : link_action(thing.get(), action_name, perform_action, cancel_action);
139 : }
140 :
141 5 : template<class ActionImpl> void link_action(Thing* thing, std::string action_name, json metadata = json::object())
142 : {
143 : static_assert(has_perform_action<ActionImpl>::value, "ActionImpl does not have a perform_action method");
144 :
145 5 : Thing::ActionSupplier action_supplier;
146 : if constexpr(std::is_constructible_v<ActionImpl, Thing*, std::optional<json>>)
147 : {
148 6 : action_supplier = [thing](auto input){
149 3 : return std::make_shared<ActionImpl>(thing, input);
150 : };
151 : }
152 : else if constexpr(std::is_constructible_v<ActionImpl, Thing*, json>)
153 : {
154 4 : action_supplier = [thing](auto input){
155 3 : if(!input)
156 3 : throw ActionError("Input must not be empty for this Action type");
157 4 : return std::make_shared<ActionImpl>(thing, input.value_or(json()));
158 : };
159 : }
160 : else if constexpr(std::is_constructible_v<ActionImpl, Thing*>)
161 : {
162 2 : action_supplier = [thing](auto input){
163 1 : return std::make_shared<ActionImpl>(thing);
164 : };
165 : }
166 : else
167 : {
168 : throw std::runtime_error("ActionImpl does not provide a suitable constructor");
169 : }
170 :
171 5 : thing->add_available_action(action_name, metadata, std::move(action_supplier));
172 5 : }
173 :
174 4 : template<class ActionImpl> void link_action(std::shared_ptr<Thing> thing, std::string action_name, json metadata = json::object())
175 : {
176 4 : link_action<ActionImpl>(thing.get(), action_name, metadata);
177 4 : }
178 :
179 : } // bw::webthing
|