ipc-protocol.js 3.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. // Copyright 2019-2024 Tauri Programme within The Commons Conservancy
  2. // SPDX-License-Identifier: Apache-2.0
  3. // SPDX-License-Identifier: MIT
  4. ;(function() {
  5. /**
  6. * A runtime generated key to ensure an IPC call comes from an initialized frame.
  7. *
  8. * This is declared outside the `window.__TAURI_INVOKE__` definition to prevent
  9. * the key from being leaked by `window.__TAURI_INVOKE__.toString()`.
  10. */
  11. const __TAURI_INVOKE_KEY__ = __TEMPLATE_invoke_key__
  12. const processIpcMessage = __RAW_process_ipc_message_fn__
  13. const osName = __TEMPLATE_os_name__
  14. const fetchChannelDataCommand = __TEMPLATE_fetch_channel_data_command__
  15. const linuxIpcProtocolEnabled = __TEMPLATE_linux_ipc_protocol_enabled__
  16. let customProtocolIpcFailed = false
  17. // on Linux we only use the custom-protocol-based IPC if the linux-ipc-protocol Cargo feature is enabled
  18. // on Android we never use it because Android does not have support to reading the request body
  19. const canUseCustomProtocol =
  20. osName === 'linux' ? linuxIpcProtocolEnabled : osName !== 'android'
  21. function sendIpcMessage(message) {
  22. const { cmd, callback, error, payload, options } = message
  23. if (
  24. !customProtocolIpcFailed &&
  25. (canUseCustomProtocol || cmd === fetchChannelDataCommand)
  26. ) {
  27. const { contentType, data } = processIpcMessage(payload)
  28. fetch(window.__TAURI_INTERNALS__.convertFileSrc(cmd, 'ipc'), {
  29. method: 'POST',
  30. body: data,
  31. headers: {
  32. 'Content-Type': contentType,
  33. 'Tauri-Callback': callback,
  34. 'Tauri-Error': error,
  35. 'Tauri-Invoke-Key': __TAURI_INVOKE_KEY__,
  36. ...((options && options.headers) || {})
  37. }
  38. })
  39. .then((response) => {
  40. const cb = response.ok ? callback : error
  41. // we need to split here because on Android the content-type gets duplicated
  42. switch ((response.headers.get('content-type') || '').split(',')[0]) {
  43. case 'application/json':
  44. return response.json().then((r) => [cb, r])
  45. case 'text/plain':
  46. return response.text().then((r) => [cb, r])
  47. default:
  48. return response.arrayBuffer().then((r) => [cb, r])
  49. }
  50. })
  51. .then(([cb, data]) => {
  52. if (window[`_${cb}`]) {
  53. window[`_${cb}`](data)
  54. } else {
  55. console.warn(
  56. `[TAURI] Couldn't find callback id {cb} in window. This might happen when the app is reloaded while Rust is running an asynchronous operation.`
  57. )
  58. }
  59. })
  60. .catch(() => {
  61. // failed to use the custom protocol IPC (either the webview blocked a custom protocol or it was a CSP error)
  62. // so we need to fallback to the postMessage interface
  63. customProtocolIpcFailed = true
  64. sendIpcMessage(message)
  65. })
  66. } else {
  67. // otherwise use the postMessage interface
  68. const { data } = processIpcMessage({
  69. cmd,
  70. callback,
  71. error,
  72. options,
  73. payload,
  74. __TAURI_INVOKE_KEY__
  75. })
  76. window.ipc.postMessage(data)
  77. }
  78. }
  79. Object.defineProperty(window.__TAURI_INTERNALS__, 'postMessage', {
  80. value: sendIpcMessage
  81. })
  82. })()