1 /*
2 * Copyright (c) Meta Platforms, Inc. and affiliates.
3 *
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
6 */
7
8 #include "ABI48_0_0SampleCxxModule.h"
9 #include <ABI48_0_0cxxreact/ABI48_0_0JsArgumentHelpers.h>
10
11 #include <glog/logging.h>
12
13 #include <memory>
14 #include <thread>
15
16 using namespace folly;
17
18 namespace ABI48_0_0facebook {
19 namespace xplat {
20 namespace samples {
21
hello()22 std::string Sample::hello() {
23 LOG(WARNING) << "glog: hello, world";
24 return "hello";
25 }
26
add(double a,double b)27 double Sample::add(double a, double b) {
28 return a + b;
29 }
30
concat(const std::string & a,const std::string & b)31 std::string Sample::concat(const std::string &a, const std::string &b) {
32 return a + b;
33 }
34
repeat(int count,const std::string & str)35 std::string Sample::repeat(int count, const std::string &str) {
36 std::string ret;
37 for (int i = 0; i < count; i++) {
38 ret += str;
39 }
40
41 return ret;
42 }
43
save(std::map<std::string,std::string> dict)44 void Sample::save(std::map<std::string, std::string> dict) {
45 state_ = std::move(dict);
46 }
47
load()48 std::map<std::string, std::string> Sample::load() {
49 return state_;
50 }
51
except()52 void Sample::except() {
53 // TODO mhorowitz #7128529: There's no way to automatically test this
54 // right now.
55 // throw std::runtime_error("oops");
56 }
57
call_later(int msec,std::function<void ()> f)58 void Sample::call_later(int msec, std::function<void()> f) {
59 std::thread t([=] {
60 std::this_thread::sleep_for(std::chrono::milliseconds(msec));
61 f();
62 });
63 t.detach();
64 }
65
twice(double n)66 double Sample::twice(double n) {
67 return n * 2;
68 }
69
SampleCxxModule(std::unique_ptr<Sample> sample)70 SampleCxxModule::SampleCxxModule(std::unique_ptr<Sample> sample)
71 : sample_(std::move(sample)) {}
72
getName()73 std::string SampleCxxModule::getName() {
74 return "Sample";
75 }
76
getConstants()77 auto SampleCxxModule::getConstants() -> std::map<std::string, folly::dynamic> {
78 return {
79 {"one", 1},
80 {"two", 2},
81 {"animal", "fox"},
82 };
83 }
84
getMethods()85 auto SampleCxxModule::getMethods() -> std::vector<Method> {
86 return {
87 Method("hello", [this] { sample_->hello(); }),
88 Method(
89 "add",
90 [this](dynamic args, Callback cb) {
91 LOG(WARNING) << "Sample: add => "
92 << sample_->add(
93 jsArgAsDouble(args, 0), jsArgAsDouble(args, 1));
94 cb({sample_->add(jsArgAsDouble(args, 0), jsArgAsDouble(args, 1))});
95 }),
96 Method(
97 "concat",
98 [this](dynamic args, Callback cb) {
99 cb({sample_->concat(
100 jsArgAsString(args, 0), jsArgAsString(args, 1))});
101 }),
102 Method(
103 "repeat",
104 [this](dynamic args, Callback cb) {
105 cb({sample_->repeat(
106 (int)jsArgAsInt(args, 0), jsArgAsString(args, 1))});
107 }),
108 Method("save", this, &SampleCxxModule::save),
109 Method("load", this, &SampleCxxModule::load),
110 Method(
111 "call_later",
112 [this](dynamic args, Callback cb) {
113 sample_->call_later((int)jsArgAsInt(args, 0), [cb] { cb({}); });
114 }),
115 Method("except", [this] { sample_->except(); }),
116 Method(
117 "twice",
118 [this](dynamic args) -> dynamic {
119 return sample_->twice(jsArgAsDouble(args, 0));
120 },
121 SyncTag),
122 Method(
123 "syncHello",
124 [this]() -> dynamic {
125 sample_->hello();
126 return nullptr;
127 },
128 SyncTag),
129 Method(
130 "addIfPositiveAsPromise",
131 [](dynamic args, Callback cb, Callback cbError) {
132 auto a = jsArgAsDouble(args, 0);
133 auto b = jsArgAsDouble(args, 1);
134 if (a < 0 || b < 0) {
135 cbError({"Negative number!"});
136 } else {
137 cb({a + b});
138 }
139 }),
140 Method(
141 "addIfPositiveAsAsync",
142 [](dynamic args, Callback cb, Callback cbError) {
143 auto a = jsArgAsDouble(args, 0);
144 auto b = jsArgAsDouble(args, 1);
145 if (a < 0 || b < 0) {
146 cbError({"Negative number!"});
147 } else {
148 cb({a + b});
149 }
150 },
151 AsyncTag),
152
153 };
154 }
155
save(folly::dynamic args)156 void SampleCxxModule::save(folly::dynamic args) {
157 std::map<std::string, std::string> m;
158 for (const auto &p : jsArgN(args, 0, &dynamic::items)) {
159 m.emplace(
160 jsArg(p.first, &dynamic::asString, "map key"),
161 jsArg(p.second, &dynamic::asString, "map value"));
162 }
163 sample_->save(std::move(m));
164 }
165
load(folly::dynamic args,Callback cb)166 void SampleCxxModule::load([[maybe_unused]] folly::dynamic args, Callback cb) {
167 dynamic d = dynamic::object;
168 for (const auto &p : sample_->load()) {
169 d.insert(p.first, p.second);
170 }
171 cb({d});
172 }
173
174 } // namespace samples
175 } // namespace xplat
176 } // namespace ABI48_0_0facebook
177
178 // By convention, the function name should be the same as the class name.
SampleCxxModule()179 ABI48_0_0facebook::xplat::module::CxxModule *SampleCxxModule() {
180 return new ABI48_0_0facebook::xplat::samples::SampleCxxModule(
181 std::make_unique<ABI48_0_0facebook::xplat::samples::Sample>());
182 }
183