2022-11-11 07:26:34 -06:00
|
|
|
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
|
|
|
|
/*
|
|
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
|
*/
|
|
|
|
|
2022-11-28 08:46:32 -06:00
|
|
|
#include "wasmapp.hpp"
|
|
|
|
|
Make the temporary "WASM app" work
Now I hope things are initialised in the right order and the plumbing
gets set up so that messages are passed as expected. It seems to work
most of the time.
Main changes are:
- The online WASM executable is built using the -s MODULARIZE -s
EXPORT_NAME=createOnlineModule options. This means that the WASM
runtime is not automatically initialized and the main() function
is not automatically started. Only when the createOnlineModule()
function is called is that done. Calling exported C/C++ functions
is a little bit more complicated.
- Code to actually Base64-encode strings to be executed as
JavaScript when expected is now present in wasmapp.cpp. (After
being passed through the Base64ToArrayBuffer function on the JS
side.) Whether this is actually necessary is not fully clear, but
to keep the code similar to that in the GTK, iOS, and Android
apps, this is kept as such for now. It would probably work fine to
just directly create the ArrayBuffer in the C++ (using the EM_ASM
magic).
- The COOLWSD::run() function is now run in a separate thread so
that main() can return.
- The FakeWebSocket's onopen() function is now called from
innerMain(), where the HULLO message is sent. It remains a bit
unclear if this really is the ideal place.
In the mobile apps the HULLO message is sent and the onopen()
function is called in the window.socket.onopen() function in
global.js.
But note that despite that the WASM app and the mobile apps are
largely quite similarly constructed and the FakeSocket and
FakeWebSocket plumbing is the same, there is an important
difference. In a mobile app the C++ code is what runs first, and
that then loads the HTML page into WebKit, in which the JS
runs. In the WASM app it is the other way around. The web page is
naturaly the one that is loaded and the JS code then starts
running the C++ code as WASM.
Finally, note that the whole concept that there is a separate "WASM
app" is temporary.
What we eventually want to achieve is that the COOL webpage upon
loading will connect a COOL server. As it does currently. The COOL
server runs the online and core C++ code to load a document, and
renders document tiles and sends those to the client JS code to
dispay.
The new thing will be that, if enabled, in addition to the HTML and JS
resources, the client will also download the WASM code and data
resources. Also, the document and updates to it will be downloaded
while being edited so that a copy can be kept in client memory. But
the WASM code and the downloaded document will remain unused most of
the time. Only if the connection to the COOL server breaks will the JS
start running the WASM code and the JS will talk to online code
running locally as WASM instead of to a COOL server. Obviously there
are still lots of things hanging in the air here regarding how exactly
this will work.
Signed-off-by: Tor Lillqvist <tml@collabora.com>
Change-Id: Ib1786a0b485d51797b0f2302d4296aa1ff9df5c1
2023-01-05 12:11:01 -06:00
|
|
|
#include "base64.hpp"
|
|
|
|
|
2022-11-11 07:26:34 -06:00
|
|
|
int coolwsd_server_socket_fd = -1;
|
|
|
|
|
2022-11-28 08:46:32 -06:00
|
|
|
const char* user_name;
|
Make the temporary "WASM app" work
Now I hope things are initialised in the right order and the plumbing
gets set up so that messages are passed as expected. It seems to work
most of the time.
Main changes are:
- The online WASM executable is built using the -s MODULARIZE -s
EXPORT_NAME=createOnlineModule options. This means that the WASM
runtime is not automatically initialized and the main() function
is not automatically started. Only when the createOnlineModule()
function is called is that done. Calling exported C/C++ functions
is a little bit more complicated.
- Code to actually Base64-encode strings to be executed as
JavaScript when expected is now present in wasmapp.cpp. (After
being passed through the Base64ToArrayBuffer function on the JS
side.) Whether this is actually necessary is not fully clear, but
to keep the code similar to that in the GTK, iOS, and Android
apps, this is kept as such for now. It would probably work fine to
just directly create the ArrayBuffer in the C++ (using the EM_ASM
magic).
- The COOLWSD::run() function is now run in a separate thread so
that main() can return.
- The FakeWebSocket's onopen() function is now called from
innerMain(), where the HULLO message is sent. It remains a bit
unclear if this really is the ideal place.
In the mobile apps the HULLO message is sent and the onopen()
function is called in the window.socket.onopen() function in
global.js.
But note that despite that the WASM app and the mobile apps are
largely quite similarly constructed and the FakeSocket and
FakeWebSocket plumbing is the same, there is an important
difference. In a mobile app the C++ code is what runs first, and
that then loads the HTML page into WebKit, in which the JS
runs. In the WASM app it is the other way around. The web page is
naturaly the one that is loaded and the JS code then starts
running the C++ code as WASM.
Finally, note that the whole concept that there is a separate "WASM
app" is temporary.
What we eventually want to achieve is that the COOL webpage upon
loading will connect a COOL server. As it does currently. The COOL
server runs the online and core C++ code to load a document, and
renders document tiles and sends those to the client JS code to
dispay.
The new thing will be that, if enabled, in addition to the HTML and JS
resources, the client will also download the WASM code and data
resources. Also, the document and updates to it will be downloaded
while being edited so that a copy can be kept in client memory. But
the WASM code and the downloaded document will remain unused most of
the time. Only if the connection to the COOL server breaks will the JS
start running the WASM code and the JS will talk to online code
running locally as WASM instead of to a COOL server. Obviously there
are still lots of things hanging in the air here regarding how exactly
this will work.
Signed-off-by: Tor Lillqvist <tml@collabora.com>
Change-Id: Ib1786a0b485d51797b0f2302d4296aa1ff9df5c1
2023-01-05 12:11:01 -06:00
|
|
|
const int SHOW_JS_MAXLEN = 200;
|
2022-11-28 08:46:32 -06:00
|
|
|
|
2023-01-09 07:49:21 -06:00
|
|
|
static std::string fileURL = "file:///sample.docx";
|
2022-11-28 08:46:32 -06:00
|
|
|
static COOLWSD *coolwsd = nullptr;
|
|
|
|
static int fakeClientFd;
|
|
|
|
static int closeNotificationPipeForForwardingThread[2] = {-1, -1};
|
2022-12-14 12:25:34 -06:00
|
|
|
static lok::Office * llo = NULL;
|
2022-11-28 08:46:32 -06:00
|
|
|
|
2022-11-30 09:38:39 -06:00
|
|
|
static void send2JS(const std::vector<char>& buffer)
|
|
|
|
{
|
Make the temporary "WASM app" work
Now I hope things are initialised in the right order and the plumbing
gets set up so that messages are passed as expected. It seems to work
most of the time.
Main changes are:
- The online WASM executable is built using the -s MODULARIZE -s
EXPORT_NAME=createOnlineModule options. This means that the WASM
runtime is not automatically initialized and the main() function
is not automatically started. Only when the createOnlineModule()
function is called is that done. Calling exported C/C++ functions
is a little bit more complicated.
- Code to actually Base64-encode strings to be executed as
JavaScript when expected is now present in wasmapp.cpp. (After
being passed through the Base64ToArrayBuffer function on the JS
side.) Whether this is actually necessary is not fully clear, but
to keep the code similar to that in the GTK, iOS, and Android
apps, this is kept as such for now. It would probably work fine to
just directly create the ArrayBuffer in the C++ (using the EM_ASM
magic).
- The COOLWSD::run() function is now run in a separate thread so
that main() can return.
- The FakeWebSocket's onopen() function is now called from
innerMain(), where the HULLO message is sent. It remains a bit
unclear if this really is the ideal place.
In the mobile apps the HULLO message is sent and the onopen()
function is called in the window.socket.onopen() function in
global.js.
But note that despite that the WASM app and the mobile apps are
largely quite similarly constructed and the FakeSocket and
FakeWebSocket plumbing is the same, there is an important
difference. In a mobile app the C++ code is what runs first, and
that then loads the HTML page into WebKit, in which the JS
runs. In the WASM app it is the other way around. The web page is
naturaly the one that is loaded and the JS code then starts
running the C++ code as WASM.
Finally, note that the whole concept that there is a separate "WASM
app" is temporary.
What we eventually want to achieve is that the COOL webpage upon
loading will connect a COOL server. As it does currently. The COOL
server runs the online and core C++ code to load a document, and
renders document tiles and sends those to the client JS code to
dispay.
The new thing will be that, if enabled, in addition to the HTML and JS
resources, the client will also download the WASM code and data
resources. Also, the document and updates to it will be downloaded
while being edited so that a copy can be kept in client memory. But
the WASM code and the downloaded document will remain unused most of
the time. Only if the connection to the COOL server breaks will the JS
start running the WASM code and the JS will talk to online code
running locally as WASM instead of to a COOL server. Obviously there
are still lots of things hanging in the air here regarding how exactly
this will work.
Signed-off-by: Tor Lillqvist <tml@collabora.com>
Change-Id: Ib1786a0b485d51797b0f2302d4296aa1ff9df5c1
2023-01-05 12:11:01 -06:00
|
|
|
if (buffer.size() < SHOW_JS_MAXLEN)
|
|
|
|
LOG_TRC_NOFILE("Send to JS: " << std::string(buffer.data(), buffer.size()));
|
|
|
|
else
|
|
|
|
LOG_TRC_NOFILE("Send to JS: " << std::string(buffer.data(), SHOW_JS_MAXLEN) << "...");
|
2022-11-30 09:38:39 -06:00
|
|
|
|
|
|
|
std::string js;
|
|
|
|
|
|
|
|
// Check if the message is binary. We say that any message that isn't just a single line is
|
|
|
|
// "binary" even if that strictly speaking isn't the case; for instance the commandvalues:
|
|
|
|
// message has a long bunch of non-binary JSON on multiple lines. But _onMessage() in Socket.js
|
|
|
|
// handles it fine even if such a message, too, comes in as an ArrayBuffer. (Look for the
|
|
|
|
// "textMsg = String.fromCharCode.apply(null, imgBytes);".)
|
|
|
|
|
|
|
|
const char *newline = (const char *)memchr(buffer.data(), '\n', buffer.size());
|
|
|
|
if (newline != nullptr)
|
|
|
|
{
|
|
|
|
// The data needs to be an ArrayBuffer
|
|
|
|
js = "window.TheFakeWebSocket.onmessage({'data': Base64ToArrayBuffer('";
|
Make the temporary "WASM app" work
Now I hope things are initialised in the right order and the plumbing
gets set up so that messages are passed as expected. It seems to work
most of the time.
Main changes are:
- The online WASM executable is built using the -s MODULARIZE -s
EXPORT_NAME=createOnlineModule options. This means that the WASM
runtime is not automatically initialized and the main() function
is not automatically started. Only when the createOnlineModule()
function is called is that done. Calling exported C/C++ functions
is a little bit more complicated.
- Code to actually Base64-encode strings to be executed as
JavaScript when expected is now present in wasmapp.cpp. (After
being passed through the Base64ToArrayBuffer function on the JS
side.) Whether this is actually necessary is not fully clear, but
to keep the code similar to that in the GTK, iOS, and Android
apps, this is kept as such for now. It would probably work fine to
just directly create the ArrayBuffer in the C++ (using the EM_ASM
magic).
- The COOLWSD::run() function is now run in a separate thread so
that main() can return.
- The FakeWebSocket's onopen() function is now called from
innerMain(), where the HULLO message is sent. It remains a bit
unclear if this really is the ideal place.
In the mobile apps the HULLO message is sent and the onopen()
function is called in the window.socket.onopen() function in
global.js.
But note that despite that the WASM app and the mobile apps are
largely quite similarly constructed and the FakeSocket and
FakeWebSocket plumbing is the same, there is an important
difference. In a mobile app the C++ code is what runs first, and
that then loads the HTML page into WebKit, in which the JS
runs. In the WASM app it is the other way around. The web page is
naturaly the one that is loaded and the JS code then starts
running the C++ code as WASM.
Finally, note that the whole concept that there is a separate "WASM
app" is temporary.
What we eventually want to achieve is that the COOL webpage upon
loading will connect a COOL server. As it does currently. The COOL
server runs the online and core C++ code to load a document, and
renders document tiles and sends those to the client JS code to
dispay.
The new thing will be that, if enabled, in addition to the HTML and JS
resources, the client will also download the WASM code and data
resources. Also, the document and updates to it will be downloaded
while being edited so that a copy can be kept in client memory. But
the WASM code and the downloaded document will remain unused most of
the time. Only if the connection to the COOL server breaks will the JS
start running the WASM code and the JS will talk to online code
running locally as WASM instead of to a COOL server. Obviously there
are still lots of things hanging in the air here regarding how exactly
this will work.
Signed-off-by: Tor Lillqvist <tml@collabora.com>
Change-Id: Ib1786a0b485d51797b0f2302d4296aa1ff9df5c1
2023-01-05 12:11:01 -06:00
|
|
|
js = js + macaron::Base64::Encode(std::string(buffer.data(), buffer.size()));
|
2022-11-30 09:38:39 -06:00
|
|
|
js = js + "')});";
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
const unsigned char *ubufp = (const unsigned char *)buffer.data();
|
|
|
|
std::vector<char> data;
|
|
|
|
for (size_t i = 0; i < buffer.size(); i++)
|
|
|
|
{
|
|
|
|
if (ubufp[i] < ' ' || ubufp[i] == '\'' || ubufp[i] == '\\')
|
|
|
|
{
|
|
|
|
data.push_back('\\');
|
|
|
|
data.push_back('x');
|
|
|
|
data.push_back("0123456789abcdef"[(ubufp[i] >> 4) & 0x0F]);
|
|
|
|
data.push_back("0123456789abcdef"[ubufp[i] & 0x0F]);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
data.push_back(ubufp[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
js = "window.TheFakeWebSocket.onmessage({'data': '";
|
Make the temporary "WASM app" work
Now I hope things are initialised in the right order and the plumbing
gets set up so that messages are passed as expected. It seems to work
most of the time.
Main changes are:
- The online WASM executable is built using the -s MODULARIZE -s
EXPORT_NAME=createOnlineModule options. This means that the WASM
runtime is not automatically initialized and the main() function
is not automatically started. Only when the createOnlineModule()
function is called is that done. Calling exported C/C++ functions
is a little bit more complicated.
- Code to actually Base64-encode strings to be executed as
JavaScript when expected is now present in wasmapp.cpp. (After
being passed through the Base64ToArrayBuffer function on the JS
side.) Whether this is actually necessary is not fully clear, but
to keep the code similar to that in the GTK, iOS, and Android
apps, this is kept as such for now. It would probably work fine to
just directly create the ArrayBuffer in the C++ (using the EM_ASM
magic).
- The COOLWSD::run() function is now run in a separate thread so
that main() can return.
- The FakeWebSocket's onopen() function is now called from
innerMain(), where the HULLO message is sent. It remains a bit
unclear if this really is the ideal place.
In the mobile apps the HULLO message is sent and the onopen()
function is called in the window.socket.onopen() function in
global.js.
But note that despite that the WASM app and the mobile apps are
largely quite similarly constructed and the FakeSocket and
FakeWebSocket plumbing is the same, there is an important
difference. In a mobile app the C++ code is what runs first, and
that then loads the HTML page into WebKit, in which the JS
runs. In the WASM app it is the other way around. The web page is
naturaly the one that is loaded and the JS code then starts
running the C++ code as WASM.
Finally, note that the whole concept that there is a separate "WASM
app" is temporary.
What we eventually want to achieve is that the COOL webpage upon
loading will connect a COOL server. As it does currently. The COOL
server runs the online and core C++ code to load a document, and
renders document tiles and sends those to the client JS code to
dispay.
The new thing will be that, if enabled, in addition to the HTML and JS
resources, the client will also download the WASM code and data
resources. Also, the document and updates to it will be downloaded
while being edited so that a copy can be kept in client memory. But
the WASM code and the downloaded document will remain unused most of
the time. Only if the connection to the COOL server breaks will the JS
start running the WASM code and the JS will talk to online code
running locally as WASM instead of to a COOL server. Obviously there
are still lots of things hanging in the air here regarding how exactly
this will work.
Signed-off-by: Tor Lillqvist <tml@collabora.com>
Change-Id: Ib1786a0b485d51797b0f2302d4296aa1ff9df5c1
2023-01-05 12:11:01 -06:00
|
|
|
js = js + std::string(data.data(), data.size());
|
2022-11-30 09:38:39 -06:00
|
|
|
js = js + "'});";
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string subjs = js.substr(0, std::min(std::string::size_type(SHOW_JS_MAXLEN), js.length()));
|
|
|
|
if (js.length() > SHOW_JS_MAXLEN)
|
|
|
|
subjs += "...";
|
|
|
|
|
|
|
|
LOG_TRC_NOFILE( "Evaluating JavaScript: " << subjs);
|
|
|
|
|
2022-12-28 07:43:57 -06:00
|
|
|
MAIN_THREAD_EM_ASM(eval(UTF8ToString($0)), js.c_str());
|
2022-11-30 09:38:39 -06:00
|
|
|
}
|
|
|
|
|
2022-12-14 12:25:34 -06:00
|
|
|
extern "C"
|
2022-12-05 02:38:59 -06:00
|
|
|
void handle_cool_message(const char *string_value)
|
2022-11-30 09:38:39 -06:00
|
|
|
{
|
2022-12-28 07:43:57 -06:00
|
|
|
std::cout << "================ handle_cool_message(): '" << string_value << "'" << std::endl;
|
|
|
|
|
2022-11-30 09:38:39 -06:00
|
|
|
if (strcmp(string_value, "HULLO") == 0)
|
|
|
|
{
|
|
|
|
// Now we know that the JS has started completely
|
|
|
|
|
|
|
|
// Contact the permanently (during app lifetime) listening COOLWSD server
|
|
|
|
// "public" socket
|
|
|
|
assert(coolwsd_server_socket_fd != -1);
|
|
|
|
int rc = fakeSocketConnect(fakeClientFd, coolwsd_server_socket_fd);
|
|
|
|
assert(rc != -1);
|
|
|
|
|
|
|
|
// Create a socket pair to notify the below thread when the document has been closed
|
|
|
|
fakeSocketPipe2(closeNotificationPipeForForwardingThread);
|
|
|
|
|
|
|
|
// Start another thread to read responses and forward them to the JavaScript
|
|
|
|
std::thread([]
|
|
|
|
{
|
|
|
|
Util::setThreadName("app2js");
|
|
|
|
while (true)
|
|
|
|
{
|
|
|
|
struct pollfd pollfd[2];
|
|
|
|
pollfd[0].fd = fakeClientFd;
|
|
|
|
pollfd[0].events = POLLIN;
|
|
|
|
pollfd[1].fd = closeNotificationPipeForForwardingThread[1];
|
|
|
|
pollfd[1].events = POLLIN;
|
|
|
|
if (fakeSocketPoll(pollfd, 2, -1) > 0)
|
|
|
|
{
|
|
|
|
if (pollfd[1].revents == POLLIN)
|
|
|
|
{
|
|
|
|
// The code below handling the "BYE" fake Websocket
|
|
|
|
// message has closed the other end of the
|
|
|
|
// closeNotificationPipeForForwardingThread. Let's close
|
|
|
|
// the other end too just for cleanliness, even if a
|
|
|
|
// FakeSocket as such is not a system resource so nothing
|
|
|
|
// is saved by closing it.
|
|
|
|
fakeSocketClose(closeNotificationPipeForForwardingThread[1]);
|
|
|
|
|
|
|
|
// Close our end of the fake socket connection to the
|
|
|
|
// ClientSession thread, so that it terminates
|
|
|
|
fakeSocketClose(fakeClientFd);
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (pollfd[0].revents == POLLIN)
|
|
|
|
{
|
|
|
|
int n = fakeSocketAvailableDataLength(fakeClientFd);
|
|
|
|
if (n == 0)
|
|
|
|
return;
|
|
|
|
std::vector<char> buf(n);
|
|
|
|
n = fakeSocketRead(fakeClientFd, buf.data(), n);
|
|
|
|
send2JS(buf);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
assert(false);
|
|
|
|
}).detach();
|
|
|
|
|
|
|
|
// First we simply send it the URL. This corresponds to the GET request with Upgrade to
|
|
|
|
// WebSocket.
|
|
|
|
LOG_TRC_NOFILE("Actually sending to Online:" << fileURL);
|
|
|
|
|
|
|
|
std::thread([]
|
|
|
|
{
|
|
|
|
struct pollfd pollfd;
|
|
|
|
pollfd.fd = fakeClientFd;
|
|
|
|
pollfd.events = POLLOUT;
|
|
|
|
fakeSocketPoll(&pollfd, 1, -1);
|
|
|
|
fakeSocketWrite(fakeClientFd, fileURL.c_str(), fileURL.size());
|
|
|
|
}).detach();
|
|
|
|
}
|
|
|
|
else if (strcmp(string_value, "BYE") == 0)
|
|
|
|
{
|
|
|
|
LOG_TRC_NOFILE("Document window terminating on JavaScript side. Closing our end of the socket.");
|
|
|
|
|
|
|
|
// Close one end of the socket pair, that will wake up the forwarding thread above
|
|
|
|
fakeSocketClose(closeNotificationPipeForForwardingThread[0]);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// As above
|
|
|
|
char *string_copy = strdup(string_value);
|
|
|
|
std::thread([=]
|
|
|
|
{
|
|
|
|
struct pollfd pollfd;
|
|
|
|
pollfd.fd = fakeClientFd;
|
|
|
|
pollfd.events = POLLOUT;
|
|
|
|
fakeSocketPoll(&pollfd, 1, -1);
|
|
|
|
fakeSocketWrite(fakeClientFd, string_copy, strlen(string_copy));
|
|
|
|
free(string_copy);
|
|
|
|
}).detach();
|
|
|
|
}
|
|
|
|
}
|
2022-11-28 08:46:32 -06:00
|
|
|
|
2022-12-02 01:47:48 -06:00
|
|
|
void readWASMFile(emscripten::val& contentArray, size_t nRead, const std::vector<char>& filebuf)
|
|
|
|
{
|
|
|
|
emscripten::val fileContentView = emscripten::val(emscripten::typed_memory_view(
|
|
|
|
nRead,
|
|
|
|
filebuf.data()));
|
|
|
|
emscripten::val fileContentCopy = emscripten::val::global("ArrayBuffer").new_(nRead);
|
|
|
|
emscripten::val fileContentCopyView = emscripten::val::global("Uint8Array").new_(fileContentCopy);
|
|
|
|
fileContentCopyView.call<void>("set", fileContentView);
|
|
|
|
contentArray.call<void>("push", fileContentCopyView);
|
|
|
|
}
|
|
|
|
|
|
|
|
void writeWASMFile(emscripten::val& contentArray, const std::string& rFileName)
|
|
|
|
{
|
|
|
|
emscripten::val document = emscripten::val::global("document");
|
|
|
|
emscripten::val window = emscripten::val::global("window");
|
|
|
|
emscripten::val type = emscripten::val::object();
|
|
|
|
type.set("type","application/octet-stream");
|
|
|
|
emscripten::val contentBlob = emscripten::val::global("Blob").new_(contentArray, type);
|
|
|
|
emscripten::val contentUrl = window["URL"].call<emscripten::val>("createObjectURL", contentBlob);
|
|
|
|
emscripten::val contentLink = document.call<emscripten::val>("createElement", std::string("a"));
|
|
|
|
contentLink.set("href", contentUrl);
|
|
|
|
contentLink.set("download", rFileName);
|
|
|
|
contentLink.set("style", "display:none");
|
|
|
|
emscripten::val body = document["body"];
|
|
|
|
body.call<void>("appendChild", contentLink);
|
|
|
|
contentLink.call<void>("click");
|
|
|
|
body.call<void>("removeChild", contentLink);
|
|
|
|
window["URL"].call<emscripten::val>("revokeObjectURL", contentUrl);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Copy file from online to WASM memory
|
|
|
|
void copyFileBufferToWasmMemory(const std::string& fileName, const std::vector<char>& filebuf)
|
|
|
|
{
|
|
|
|
EM_ASM(
|
|
|
|
{
|
|
|
|
FS.writeFile(UTF8ToString($0), new Uint8Array(Module.HEAPU8.buffer, $1, $2));
|
|
|
|
}, fileName.c_str(), filebuf.data(), filebuf.size());
|
|
|
|
}
|
|
|
|
|
2022-11-28 08:46:32 -06:00
|
|
|
/// Close the document.
|
|
|
|
void closeDocument()
|
2022-11-15 05:18:31 -06:00
|
|
|
{
|
2022-11-28 08:46:32 -06:00
|
|
|
// Close one end of the socket pair, that will wake up the forwarding thread that was constructed in HULLO
|
|
|
|
fakeSocketClose(closeNotificationPipeForForwardingThread[0]);
|
|
|
|
|
|
|
|
LOG_DBG("Waiting for COOLWSD to finish...");
|
|
|
|
std::unique_lock<std::mutex> lock(COOLWSD::lokit_main_mutex);
|
|
|
|
LOG_DBG("COOLWSD has finished.");
|
|
|
|
}
|
|
|
|
|
2022-12-13 04:12:59 -06:00
|
|
|
void * lok_init()
|
|
|
|
{
|
|
|
|
try {
|
|
|
|
std::string lo_path = "/instdir/program";
|
|
|
|
llo = lok::lok_cpp_init(lo_path.c_str());
|
|
|
|
if (!llo) {
|
|
|
|
std::cerr << ": Failed to initialise LibreOfficeKit" << std::endl;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
return static_cast<void*>(llo);
|
|
|
|
} catch (const std::exception & e) {
|
|
|
|
delete llo;
|
|
|
|
std::cerr << ": LibreOfficeKit threw exception (" << e.what() << ")" << std::endl;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-12-13 07:34:16 -06:00
|
|
|
int main(int, char*[])
|
2022-11-28 08:46:32 -06:00
|
|
|
{
|
2022-12-19 03:47:31 -06:00
|
|
|
std::cout << "================ Here is main()" << std::endl;
|
|
|
|
|
2022-12-13 07:51:02 -06:00
|
|
|
lok_init();
|
2022-11-28 08:46:32 -06:00
|
|
|
|
|
|
|
Log::initialize("WASM", "trace", false, false, {});
|
|
|
|
Util::setThreadName("main");
|
|
|
|
|
|
|
|
fakeSocketSetLoggingCallback([](const std::string& line)
|
|
|
|
{
|
|
|
|
LOG_TRC_NOFILE(line);
|
|
|
|
});
|
|
|
|
|
2022-12-13 07:51:02 -06:00
|
|
|
char *argv[2];
|
|
|
|
argv[0] = strdup("wasm");
|
|
|
|
argv[1] = nullptr;
|
|
|
|
Util::setThreadName("app");
|
2022-11-28 08:46:32 -06:00
|
|
|
|
|
|
|
fakeClientFd = fakeSocketSocket();
|
|
|
|
|
Make the temporary "WASM app" work
Now I hope things are initialised in the right order and the plumbing
gets set up so that messages are passed as expected. It seems to work
most of the time.
Main changes are:
- The online WASM executable is built using the -s MODULARIZE -s
EXPORT_NAME=createOnlineModule options. This means that the WASM
runtime is not automatically initialized and the main() function
is not automatically started. Only when the createOnlineModule()
function is called is that done. Calling exported C/C++ functions
is a little bit more complicated.
- Code to actually Base64-encode strings to be executed as
JavaScript when expected is now present in wasmapp.cpp. (After
being passed through the Base64ToArrayBuffer function on the JS
side.) Whether this is actually necessary is not fully clear, but
to keep the code similar to that in the GTK, iOS, and Android
apps, this is kept as such for now. It would probably work fine to
just directly create the ArrayBuffer in the C++ (using the EM_ASM
magic).
- The COOLWSD::run() function is now run in a separate thread so
that main() can return.
- The FakeWebSocket's onopen() function is now called from
innerMain(), where the HULLO message is sent. It remains a bit
unclear if this really is the ideal place.
In the mobile apps the HULLO message is sent and the onopen()
function is called in the window.socket.onopen() function in
global.js.
But note that despite that the WASM app and the mobile apps are
largely quite similarly constructed and the FakeSocket and
FakeWebSocket plumbing is the same, there is an important
difference. In a mobile app the C++ code is what runs first, and
that then loads the HTML page into WebKit, in which the JS
runs. In the WASM app it is the other way around. The web page is
naturaly the one that is loaded and the JS code then starts
running the C++ code as WASM.
Finally, note that the whole concept that there is a separate "WASM
app" is temporary.
What we eventually want to achieve is that the COOL webpage upon
loading will connect a COOL server. As it does currently. The COOL
server runs the online and core C++ code to load a document, and
renders document tiles and sends those to the client JS code to
dispay.
The new thing will be that, if enabled, in addition to the HTML and JS
resources, the client will also download the WASM code and data
resources. Also, the document and updates to it will be downloaded
while being edited so that a copy can be kept in client memory. But
the WASM code and the downloaded document will remain unused most of
the time. Only if the connection to the COOL server breaks will the JS
start running the WASM code and the JS will talk to online code
running locally as WASM instead of to a COOL server. Obviously there
are still lots of things hanging in the air here regarding how exactly
this will work.
Signed-off-by: Tor Lillqvist <tml@collabora.com>
Change-Id: Ib1786a0b485d51797b0f2302d4296aa1ff9df5c1
2023-01-05 12:11:01 -06:00
|
|
|
// We run COOOLWSD::run() in a thread of its own so that main() can return.
|
|
|
|
std::thread([&]
|
|
|
|
{
|
|
|
|
coolwsd = new COOLWSD();
|
|
|
|
coolwsd->run(1, argv);
|
|
|
|
delete coolwsd;
|
|
|
|
}).detach();
|
2022-12-13 04:12:59 -06:00
|
|
|
|
2022-12-19 03:47:31 -06:00
|
|
|
std::cout << "================ main() is returning" << std::endl;
|
2022-11-15 05:18:31 -06:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2022-11-11 07:26:34 -06:00
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
|