Emscripten Javascript 接口实现

Emscripten Javascript interface implementation

我需要更多关于如何在 javascript 中实现生成 类 的 emscripten 的信息。我在 c++ 中有以下接口,但需要在 javascript 端实现它。

class OsHttp {
public:
    virtual ~OsHttp() {}

    virtual 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) = 0;
};

我知道下面的内容会让我入门,但我该如何实现构造函数等

var osHttp = {
    constructor: function(){}
    request: function(verb, url, body, headers, callback) {
        console.log('OsHttp with: ' + verb);
    }
};

var OsHttpObject = Module.OsHttp.implement(osHttp);

如果我理解您的需求,那么您需要有某种方式在 Javascript 和 C++ 世界之间进行通信。另外,我认为如果你想使用一个在 C++ 中实现这个接口的对象,那么要让它编译和运行,必须有一个在 C++ 中的接口的具体实现。这个接口的实现然后会调用 Javascript.

为此,您可以在实现接口的 class 中使用 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([=10=]);
            var url = Pointer_stringify();
            var body = Pointer_stringify();
            var callbackFunctionPointer = ;

            // 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 到 create/store/delete 对象中进行一些手动管理在某种工厂里。具体来说,它需要将它们存储在某个地方,以便 C++ 可以通过某种密钥访问正确的。指向 "this" 的指针可能会很方便:

class OsHttpImplementation : public OsHttp {
public:
    OsHttp()
    {
       EM_ASM_V({
         var thisPointer = [=11=];
         OsHttpFactory.construct(thisPointer);
       }, this);
    }

    ~OsHttp()
    {
       EM_ASM({
         var thisPointer = [=11=];
         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 = [=11=];
           OsHttpFactory.get(thisPointer).request(, , , );
        }, this, verb.c_str(), url.c_str(), body.c_str(), callback.get());
    }
};

您在 Javascript 中对 OsHttpFactory 的实现有很大的自由度。你没有提到你是否想在浏览器中使用它,但如果你这样做了,并且正在使用 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++ 中,您可以将其用作标准 class:

// Run constructors
auto osHttp = new OsHttpImplementation();

// Make request
osHttp->request(....);

// Run destructors, and remove object from the Javascript store
delete osHttp;

不得不说,这一切都有些胡闹!