Если я понять, что вы после этого, то вам нужно иметь некоторые способ общения между мирами Javascript и C++. Кроме того, я думаю, что если вы хотите использовать объект, реализующий этот интерфейс на C++, то для его компиляции и запуска должна быть конкретная реализация интерфейса на C++. Тогда эта реализация интерфейса вызовет Javascript.
Чтобы сделать это, вы могли бы использовать EM_ASM_* macros в классе, который реализует интерфейс:
class OsHttpImplementation : public OsHttp {
public:
~OsHttp()
{
EM_ASM({
// Cleanup anything in Javascript context
});
}
void request(const std::string & verb, const std::string & url, const std::string & body, const std::unordered_map<std::string, std::string> & headers, const std::shared_ptr<HttpCallback> & callback)
{
// Probably a good idea to save any shared pointers as members in C++
// so the objects they point to survive as long as you need them
int returnValue = EM_ASM_INT_V({
// Example ways of accessing data from C++
var verb = Pointer_stringify($0);
var url = Pointer_stringify($1);
var body = Pointer_stringify($2);
var callbackFunctionPointer = $3;
// Something here that makes an HTTP request, creates any objects, etc.
return 0;
}, verb.c_str(), url.c_str(), body.c_str(), callback.get());
}
};
Если вы хотите есть на самом деле является объектом в JavaScript, который соответствует объекту в C++, вы, возможно, придется немного ручного управления в Javascript для создания/хранения/удаления объектов на каком-то заводе. В частности, им нужно будет хранить их где-нибудь, чтобы C++ мог получить доступ к правильному через какой-то ключ. Указатель на «это» может быть удобно для этого:
class OsHttpImplementation : public OsHttp {
public:
OsHttp()
{
EM_ASM_V({
var thisPointer = $0;
OsHttpFactory.construct(thisPointer);
}, this);
}
~OsHttp()
{
EM_ASM({
var thisPointer = $0;
OsHttpFactory.destruct(thisPointer);
}, this);
}
void request(const std::string & verb, const std::string & url, const std::string & body, const std::unordered_map<std::string, std::string> & headers, const std::shared_ptr<HttpCallback> & callback)
{
int returnValue = EM_ASM_INT_V({
var thisPointer = $0;
OsHttpFactory.get(thisPointer).request($1, $2, $3, $4);
}, this, verb.c_str(), url.c_str(), body.c_str(), callback.get());
}
};
У вас есть много свободы на реализацию OsHttpFactory в JavaScript. Вы не упомянули, если вы хотите, чтобы это в браузере, но если вы делаете, и используете XMLHttpRequests, вы могли бы иметь что-то вроде
(function(context) {
var store = {}
function OsHttp() {
this.request = null;
}
OsHttp.prototype.request = function(verb, url, body, callbackPointer) {
var request = this.request = new XMLHttpRequest();
request.onreadystatechange = function() {
if (request.readyState == 4) {
// Might need other arguments if you want to pass something back to C++
Module.Runtime.dynCall('v', callbackPointer, []);
}
});
this.request.open(verb, url, true);
this.request.send();
};
OsHttp.prototype.cleanup = function() {
// Do something to cleanup in-progress requests etc.
}
context.OsHttpFactory = {
construct: function(thisPointer) {
store[thisPointer] = new OsHttp();
},
destruct: function(thisPointer) {
store[thisPointer].cleanup();
delete store[thisPointer];
},
get: function(thisPointer) {
return store[thisPointer];
}
};
})(window);
Тогда в C++ вы можете использовать его в качестве стандартного класса:
// Run constructors
auto osHttp = new OsHttpImplementation();
// Make request
osHttp->request(....);
// Run destructors, and remove object from the Javascript store
delete osHttp;
Должен сказать, все это немного издевательствует!
Спасибо @MichalCharemza, это отличный совет! –