Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F3509330
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
7 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/native/cpp/CommonCpp/grpc/GRPCStreamHostObject.cpp b/native/cpp/CommonCpp/grpc/GRPCStreamHostObject.cpp
index 32a549c58..6f8ba2765 100644
--- a/native/cpp/CommonCpp/grpc/GRPCStreamHostObject.cpp
+++ b/native/cpp/CommonCpp/grpc/GRPCStreamHostObject.cpp
@@ -1,187 +1,187 @@
#include "GRPCStreamHostObject.h"
#include "../NativeModules/InternalModules/GlobalNetworkSingleton.h"
#include "../NativeModules/InternalModules/SocketStatus.h"
using namespace facebook;
GRPCStreamHostObject::GRPCStreamHostObject(
jsi::Runtime &rt,
std::shared_ptr<react::CallInvoker> jsInvoker)
- : readyState{0},
+ : readyState{SocketStatus::CONNECTING},
onopen{},
onmessage{},
onclose{},
send{jsi::Function::createFromHostFunction(
rt,
jsi::PropNameID::forUtf8(rt, "send"),
1,
[](jsi::Runtime &rt,
const jsi::Value &thisVal,
const jsi::Value *args,
size_t count) {
auto payload{args->asString(rt).utf8(rt)};
comm::GlobalNetworkSingleton::instance.scheduleOrRun(
[=](comm::NetworkModule &networkModule) {
std::vector<std::string> blobHashes{};
networkModule.send(
"sessionID-placeholder",
"toDeviceID-placeholder",
payload,
blobHashes);
});
return jsi::Value::undefined();
})},
close{jsi::Function::createFromHostFunction(
rt,
jsi::PropNameID::forUtf8(rt, "close"),
0,
[](jsi::Runtime &rt,
const jsi::Value &thisVal,
const jsi::Value *args,
size_t count) {
comm::GlobalNetworkSingleton::instance.scheduleOrRun(
[=](comm::NetworkModule &networkModule) {
networkModule.closeGetStream();
});
return jsi::Value::undefined();
})},
jsInvoker{jsInvoker} {
auto onReadDoneCallback = [this, &rt](std::string data) {
this->jsInvoker->invokeAsync([this, &rt, data]() {
if (this->onmessage.isNull()) {
return;
}
auto msgObject = jsi::Object(rt);
msgObject.setProperty(rt, "data", jsi::String::createFromUtf8(rt, data));
this->onmessage.asObject(rt).asFunction(rt).call(rt, msgObject, 1);
});
};
auto onOpenCallback = [this, &rt]() {
this->jsInvoker->invokeAsync([this, &rt]() {
if (this->onopen.isNull()) {
return;
}
this->onopen.asObject(rt).asFunction(rt).call(
rt, jsi::Value::undefined(), 0);
});
};
auto onCloseCallback = [this, &rt]() {
this->jsInvoker->invokeAsync([this, &rt]() {
if (this->onclose.isNull()) {
return;
}
this->onclose.asObject(rt).asFunction(rt).call(
rt, jsi::Value::undefined(), 0);
});
};
// We pass the following lambda to the `NetworkModule` on the "network"
// thread with a reference to `this` bound in. This allows us to directly
// modify the value of `readyState` in a synchronous manner.
auto setReadyStateCallback = [this](SocketStatus newSocketStatus) {
if (!this) {
// This handles the case where `GRPCStreamHostObj` may have been freed
// by the JS garbage collector and `this` is no longer a valid reference.
return;
}
this->readyState = newSocketStatus;
};
// The reason we're queueing up the `.get()` call on the JS event loop is
// to handle the case of an `.onopen` callback being set right after a
// call to `openSocket(...)`.
//
// This isn't an issue with the existing `WebSocket` approach because the
// socket will not actually open until the block of JS--which includes the
// setting of the `.onopen` callback--finishes executing.
// See the following for background: https://stackoverflow.com/a/49211579.
//
// Without wrapping the `scheduleOrRun(...)` in an `invokeAsync(...)`,
// it is possible for the gRPC `Get()` stream to open before the `.onopen`
// callback has been properly set. We queue the `get()` call on the JS
// event loop to guarantee that the `.onopen` callback is set before the
// socket can possibly open. This mimics the existing `WebSocket` behavior.
this->jsInvoker->invokeAsync([=]() {
comm::GlobalNetworkSingleton::instance.scheduleOrRun(
[=](comm::NetworkModule &networkModule) {
// The callbacks are set after the call to `.get()` because they
// need to be passed to the `ClientGetReadReactor` object, which is
// only constructed after a call to `.get()`.
networkModule.initializeNetworkModule(
"userId-placeholder", "deviceToken-placeholder", "localhost");
networkModule.get("sessionID-placeholder");
networkModule.setOnReadDoneCallback(onReadDoneCallback);
networkModule.setOnOpenCallback(onOpenCallback);
networkModule.setOnCloseCallback(onCloseCallback);
networkModule.assignSetReadyStateCallback(setReadyStateCallback);
});
});
}
std::vector<jsi::PropNameID>
GRPCStreamHostObject::getPropertyNames(jsi::Runtime &rt) {
std::vector<jsi::PropNameID> names;
names.reserve(6);
names.push_back(jsi::PropNameID::forUtf8(rt, std::string{"readyState"}));
names.push_back(jsi::PropNameID::forUtf8(rt, std::string{"onopen"}));
names.push_back(jsi::PropNameID::forUtf8(rt, std::string{"onmessage"}));
names.push_back(jsi::PropNameID::forUtf8(rt, std::string{"onclose"}));
names.push_back(jsi::PropNameID::forUtf8(rt, std::string{"close"}));
names.push_back(jsi::PropNameID::forUtf8(rt, std::string{"send"}));
return names;
}
jsi::Value
GRPCStreamHostObject::get(jsi::Runtime &runtime, const jsi::PropNameID &name) {
auto propName = name.utf8(runtime);
if (propName == "readyState") {
return jsi::Value(this->readyState);
}
if (propName == "send") {
return this->send.asObject(runtime).asFunction(runtime);
}
if (propName == "close") {
return this->close.asObject(runtime).asFunction(runtime);
}
if (propName == "onopen") {
return this->onopen.isNull()
? jsi::Value::null()
: this->onopen.asObject(runtime).asFunction(runtime);
}
if (propName == "onmessage") {
return this->onmessage.isNull()
? jsi::Value::null()
: this->onmessage.asObject(runtime).asFunction(runtime);
}
if (propName == "onclose") {
return this->onclose.isNull()
? jsi::Value::null()
: this->onclose.asObject(runtime).asFunction(runtime);
}
return jsi::Value::undefined();
}
void GRPCStreamHostObject::set(
jsi::Runtime &runtime,
const jsi::PropNameID &name,
const jsi::Value &value) {
auto propName = name.utf8(runtime);
if (propName == "onopen" && value.isObject() &&
value.asObject(runtime).isFunction(runtime)) {
this->onopen = value.asObject(runtime).asFunction(runtime);
} else if (
propName == "onmessage" && value.isObject() &&
value.asObject(runtime).isFunction(runtime)) {
this->onmessage = value.asObject(runtime).asFunction(runtime);
} else if (
propName == "onclose" && value.isObject() &&
value.asObject(runtime).isFunction(runtime)) {
this->onclose = value.asObject(runtime).asFunction(runtime);
}
}
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Mon, Dec 23, 3:33 AM (15 h, 52 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2690290
Default Alt Text
(7 KB)
Attached To
Mode
rCOMM Comm
Attached
Detach File
Event Timeline
Log In to Comment