ipc-protocol.js 3.2 KB

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