Shaka Player Embedded
js_object_wrapper.h
Go to the documentation of this file.
1 // Copyright 2019 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #ifndef SHAKA_EMBEDDED_CORE_JS_OBJECT_WRAPPER_H_
16 #define SHAKA_EMBEDDED_CORE_JS_OBJECT_WRAPPER_H_
17 
18 #include <future>
19 #include <memory>
20 #include <string>
21 #include <type_traits>
22 #include <utility>
23 #include <vector>
24 
25 #include "shaka/async_results.h"
26 #include "shaka/error.h"
27 #include "shaka/variant.h"
29 #include "src/core/task_runner.h"
30 #include "src/mapping/convert_js.h"
31 #include "src/mapping/js_engine.h"
32 #include "src/mapping/js_utils.h"
34 #include "src/mapping/promise.h"
35 #include "src/util/macros.h"
36 
37 namespace shaka {
38 
46  public:
49 
51 
56  template <typename Ret, typename = void>
57  struct Converter {
59  using future_type = std::shared_future<variant_type>;
60 
61  static variant_type Convert(const std::string& name,
62  Handle<JsValue> result) {
63  Ret ret;
64  if (!FromJsValue(result, &ret)) {
65  return Error("Invalid return value from " + name + "().");
66  }
67 
68  return ret;
69  }
70  };
71  template <typename Dummy>
72  struct Converter<void, Dummy> {
74  using future_type = std::shared_future<variant_type>;
75 
76  static variant_type Convert(const std::string& /* name */,
77  Handle<JsValue> /* result */) {
78  return monostate();
79  }
80  };
81 
91  template <typename Ret, typename... Args>
92  typename Converter<Ret>::future_type CallMethod(const std::string& name,
93  Args&&... args) const {
94  return CallMethodCommon<Ret>(&object_, name, std::forward<Args>(args)...);
95  }
96 
106  template <typename Ret, typename... Args>
108  const std::vector<std::string>& global_path, Args&&... args) {
109  std::vector<std::string> obj_path{global_path.begin(),
110  global_path.end() - 1};
111  return CallMethodCommon<Ret>(std::move(obj_path), global_path.back(),
112  std::forward<Args>(args)...);
113  }
114 
121  template <typename T>
123  const std::vector<std::string>& global_path) {
124  auto callback = std::bind(&GetFieldRaw<T>, global_path);
126  std::move(callback));
127  }
128 
132  static Error ConvertError(Handle<JsValue> except);
133 
135  void Init(Handle<JsObject> object);
136 
137  protected:
144  Handle<JsObject> that, const std::string& name, int argc,
145  LocalVar<JsValue>* argv, LocalVar<JsValue>* result);
146 
157  const std::string& name, std::function<void(const Error&)> on_error,
158  std::function<void(Handle<JsObject> event)> handler) const;
159 
167  template <typename T>
169  const std::vector<std::string>& global_path) {
170  LocalVar<JsValue> value =
171  GetDescendant(JsEngine::Instance()->global_handle(), global_path);
172  return Converter<T>::Convert(global_path.back(), value);
173  }
174 
185  template <typename Ret, typename... Args>
186  static void CallMethodRaw(
187  std::shared_ptr<std::promise<typename Converter<Ret>::variant_type>> p,
188  variant<const Global<JsObject>*, std::vector<std::string>> that,
189  const std::string& name, Args&&... args) {
190  DCHECK(JsManagerImpl::Instance()->MainThread()->BelongsToCurrentThread());
191  LocalVar<JsObject> that_obj;
192  if (holds_alternative<const Global<JsObject>*>(that)) {
193  that_obj = *get<const Global<JsObject>*>(that);
194  } else {
195  LocalVar<JsValue> temp =
196  GetDescendant(JsEngine::Instance()->global_handle(),
197  get<std::vector<std::string>>(that));
198  if (!IsObject(temp)) {
199  p->set_value(Error("Unable to find object."));
200  return;
201  }
202  that_obj = UnsafeJsCast<JsObject>(temp);
203  }
204 
205  LocalVar<JsValue> result;
206  LocalVar<JsValue> js_args[] = {ToJsValue(args)..., JsUndefined()};
207  auto error =
208  CallMemberFunction(that_obj, name, sizeof...(args), js_args, &result);
209  if (holds_alternative<Error>(error)) {
210  p->set_value(get<Error>(error));
211  return;
212  }
213 
214  auto js_promise = Converter<Promise>::Convert(name, result);
215  if (holds_alternative<Error>(js_promise)) {
216  p->set_value(Converter<Ret>::Convert(name, result));
217  return;
218  }
219 
220  get<Promise>(js_promise)
221  .Then(
222  [p, name](Any res) {
223  LocalVar<JsValue> value = res.ToJsValue();
224  p->set_value(Converter<Ret>::Convert(name, value));
225  },
226  [p](Any except) {
227  LocalVar<JsValue> val = except.ToJsValue();
228  p->set_value(ConvertError(val));
229  });
230  }
231 
238  template <typename T>
239  using bind_forward =
241 
253  template <typename Ret, typename... Args>
255  variant<const Global<JsObject>*, std::vector<std::string>> that,
256  const std::string& name, Args&&... args) {
257  auto promise =
258  std::make_shared<std::promise<typename Converter<Ret>::variant_type>>();
260  CallMethodRaw<Ret>(promise, std::move(that), name,
261  std::forward<Args>(args)...);
262  } else {
263  auto callback =
264  std::bind(&CallMethodRaw<Ret, bind_forward<Args>...>, promise,
265  std::move(that), name, std::forward<Args>(args)...);
267  TaskPriority::Internal, name, std::move(callback));
268  }
269  return promise->get_future().share();
270  }
271 
272  Global<JsObject> object_;
273 };
274 
275 } // namespace shaka
276 
277 #endif // SHAKA_EMBEDDED_CORE_JS_OBJECT_WRAPPER_H_
Definition: any.h:31
typename AsyncResults< Ret >::variant_type variant_type
ReturnVal< JsValue > JsUndefined()
Definition: js_wrappers.cc:284
bool IsObject(Handle< JsValue > value)
Definition: js_wrappers.cc:315
bool FromJsValue(Handle< JsValue > source, T *dest)
Definition: convert_js.h:370
ReturnVal< JsValue > GetDescendant(Handle< JsObject > root, const std::vector< std::string > &names)
Definition: js_utils.cc:52
Converter< Ret >::future_type CallMethod(const std::string &name, Args &&... args) const
const char * name
static Converter< T >::future_type GetGlobalField(const std::vector< std::string > &global_path)
ReturnVal< JsValue > ToJsValue(T &&source)
Definition: convert_js.h:381
Global< JsObject > object_
static Converter< void >::variant_type CallMemberFunction(Handle< JsObject > that, const std::string &name, int argc, LocalVar< JsValue > *argv, LocalVar< JsValue > *result)
static void CallMethodRaw(std::shared_ptr< std::promise< typename Converter< Ret >::variant_type >> p, variant< const Global< JsObject > *, std::vector< std::string >> that, const std::string &name, Args &&... args)
ExceptionCode type
std::shared_future< variant_type > future_type
std::shared_future< impl::RetOf< Func > > InvokeOrSchedule(Func &&callback)
Definition: task_runner.h:192
std::shared_future< variant_type > future_type
static Converter< Ret >::future_type CallMethodCommon(variant< const Global< JsObject > *, std::vector< std::string >> that, const std::string &name, Args &&... args)
static variant_type Convert(const std::string &, Handle< JsValue >)
SHAKA_NON_COPYABLE_OR_MOVABLE_TYPE(JsObjectWrapper)
typename std::add_const< typename std::remove_reference< T >::type >::type & bind_forward
static variant_type Convert(const std::string &name, Handle< JsValue > result)
Converter< void >::variant_type AttachEventListener(const std::string &name, std::function< void(const Error &)> on_error, std::function< void(Handle< JsObject > event)> handler) const
std::shared_ptr< ThreadEvent< impl::RetOf< Func > > > AddInternalTask(TaskPriority priority, const std::string &name, Func &&callback)
Definition: task_runner.h:219
static Converter< T >::variant_type GetFieldRaw(const std::vector< std::string > &global_path)
static Converter< Ret >::future_type CallGlobalMethod(const std::vector< std::string > &global_path, Args &&... args)
ReturnVal< JsValue > ToJsValue() const override
Definition: any.cc:56
static Error ConvertError(Handle< JsValue > except)
bool BelongsToCurrentThread() const
Definition: task_runner.cc:68
bool holds_alternative(const variant< Choices... > &variant)
Definition: variant.h:449
void Init(Handle< JsObject > object)
TaskRunner * MainThread()