pub const INVOKE_SYSTEM_SCRIPTS: &str = "// This file is copied and modified from Tauri with a few modifications\n// - Changed `processIpcMessage` to always return a string so we can put it inside of http request header\n// - Changed custom protocol IPC to use header instead of body since we can\'t get the body in Servo yet\n//\n// > ipc-protocol.js: https://github.com/tauri-apps/tauri/blob/dev/crates/tauri/scripts/ipc-protocol.js\n// > process-ipc-message-fn.js: https://github.com/tauri-apps/tauri/blob/dev/crates/tauri/scripts/process-ipc-message-fn.js\n\n;(function () {\n\tconst processIpcMessage = function (message) {\n\t\t// if (message instanceof ArrayBuffer || ArrayBuffer.isView(message) || Array.isArray(message)) {\n\t\t// \treturn {\n\t\t// \t\tcontentType: \'application/octet-stream\',\n\t\t// \t\tdata: message,\n\t\t// \t}\n\t\t// } else {\n\t\tconst data = JSON.stringify(message, (_k, val) => {\n\t\t\t// if this value changes, make sure to update it in:\n\t\t\t// 1. ipc.js\n\t\t\t// 2. core.ts\n\t\t\tconst SERIALIZE_TO_IPC_FN = \'__TAURI_TO_IPC_KEY__\'\n\n\t\t\tif (val instanceof Map) {\n\t\t\t\treturn Object.fromEntries(val.entries())\n\t\t\t} else if (val instanceof Uint8Array) {\n\t\t\t\treturn Array.from(val)\n\t\t\t} else if (val instanceof ArrayBuffer) {\n\t\t\t\treturn Array.from(new Uint8Array(val))\n\t\t\t} else if (typeof val === \'object\' && val !== null && SERIALIZE_TO_IPC_FN in val) {\n\t\t\t\treturn val[SERIALIZE_TO_IPC_FN]()\n\t\t\t} else {\n\t\t\t\treturn val\n\t\t\t}\n\t\t})\n\n\t\treturn {\n\t\t\tcontentType: \'application/json\',\n\t\t\tdata,\n\t\t}\n\t\t// }\n\t}\n\n\t/**\n\t * A runtime generated key to ensure an IPC call comes from an initialized frame.\n\t *\n\t * This is declared outside the `window.__TAURI_INVOKE__` definition to prevent\n\t * the key from being leaked by `window.__TAURI_INVOKE__.toString()`.\n\t */\n\tconst __TAURI_INVOKE_KEY__ = __INVOKE_KEY__\n\n\tlet customProtocolIpcFailed = false\n\n\tfunction sendIpcMessage(message) {\n\t\tconst { cmd, callback, error, payload, options } = message\n\n\t\tif (!customProtocolIpcFailed) {\n\t\t\tconst { contentType, data } = processIpcMessage(payload)\n\n\t\t\t// Headers can only contain ascii characters, so encoding is needed,\n\t\t\t// and since tauri already depends on percent-encoding rust crate, we use `encodeURI` here for that reason\n\t\t\tconst invokeBody = encodeURI(data)\n\n\t\t\tconst headers = new Headers((options && options.headers) || {})\n\t\t\theaders.set(\'Content-Type\', contentType)\n\t\t\theaders.set(\'Tauri-Callback\', callback)\n\t\t\theaders.set(\'Tauri-Error\', error)\n\t\t\theaders.set(\'Tauri-Invoke-Key\', __TAURI_INVOKE_KEY__)\n\t\t\theaders.set(\'Tauri-VersoRuntime-Invoke-Body\', invokeBody)\n\n\t\t\tfetch(window.__TAURI_INTERNALS__.convertFileSrc(cmd, \'ipc\'), {\n\t\t\t\tmethod: \'POST\',\n\t\t\t\t// body: data,\n\t\t\t\theaders,\n\t\t\t})\n\t\t\t\t.then((response) => {\n\t\t\t\t\tconst callbackId = response.headers.get(\'Tauri-Response\') === \'ok\' ? callback : error\n\t\t\t\t\t// we need to split here because on Android the content-type gets duplicated\n\t\t\t\t\tswitch ((response.headers.get(\'content-type\') || \'\').split(\',\')[0]) {\n\t\t\t\t\t\tcase \'application/json\':\n\t\t\t\t\t\t\treturn response.json().then((r) => [callbackId, r])\n\t\t\t\t\t\tcase \'text/plain\':\n\t\t\t\t\t\t\treturn response.text().then((r) => [callbackId, r])\n\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\treturn response.arrayBuffer().then((r) => [callbackId, r])\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t\t.catch((e) => {\n\t\t\t\t\tconsole.warn(\n\t\t\t\t\t\t\'IPC custom protocol failed, Tauri will now use the postMessage interface instead\',\n\t\t\t\t\t\te\n\t\t\t\t\t)\n\t\t\t\t\t// failed to use the custom protocol IPC (either the webview blocked a custom protocol or it was a CSP error)\n\t\t\t\t\t// so we need to fallback to the postMessage interface\n\t\t\t\t\tcustomProtocolIpcFailed = true\n\t\t\t\t\tsendIpcMessage(message)\n\t\t\t\t})\n\t\t\t\t.then(([callbackId, data]) => {\n\t\t\t\t\twindow.__TAURI_INTERNALS__.runCallback(callbackId, data)\n\t\t\t\t})\n\t\t} else {\n\t\t\t// otherwise use the postMessage interface\n\t\t\tconst { data } = processIpcMessage({\n\t\t\t\tcmd,\n\t\t\t\tcallback,\n\t\t\t\terror,\n\t\t\t\toptions: {\n\t\t\t\t\t...options,\n\t\t\t\t\tcustomProtocolIpcBlocked: customProtocolIpcFailed,\n\t\t\t\t},\n\t\t\t\tpayload,\n\t\t\t\t__TAURI_INVOKE_KEY__,\n\t\t\t})\n\t\t\twindow.ipc.postMessage(data)\n\t\t}\n\t}\n\n\tObject.defineProperty(window.__TAURI_INTERNALS__, \'postMessage\', {\n\t\tvalue: sendIpcMessage,\n\t})\n})()\n";
Expand description
You need to set this on [tauri::Builder::invoke_system
] for the invoke system to work,
you can skip this if you’re using tauri_runtime_verso::builder
§Example:
fn main() {
tauri_runtime_verso::set_verso_path("../verso/target/debug/versoview");
tauri_runtime_verso::set_verso_resource_directory("../verso/resources");
tauri::Builder::<tauri_runtime_verso::VersoRuntime>::new()
.invoke_system(tauri_runtime_verso::INVOKE_SYSTEM_SCRIPTS.to_owned())
.run(tauri::generate_context!())
.unwrap();
}