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