فهرست منبع

refactor(core): use wry RPC API (#1327)

Lucas Fernandes Nogueira 4 سال پیش
والد
کامیت
b0c1009098

+ 2 - 2
api/src/cli.ts

@@ -1,4 +1,4 @@
-import { invoke } from './tauri'
+import { invokeTauriCommand } from './helpers/tauri'
 
 export interface ArgMatch {
   /**
@@ -27,7 +27,7 @@ export interface CliMatches {
  * gets the CLI matches
  */
 async function getMatches(): Promise<CliMatches> {
-  return invoke<CliMatches>({
+  return invokeTauriCommand<CliMatches>({
     __tauriModule: 'Cli',
     message: {
       cmd: 'cliMatches'

+ 3 - 3
api/src/dialog.ts

@@ -1,4 +1,4 @@
-import { invoke } from './tauri'
+import { invokeTauriCommand } from './helpers/tauri'
 
 export interface DialogFilter {
   name: string
@@ -34,7 +34,7 @@ async function open(
     Object.freeze(options)
   }
 
-  return invoke<string | string[]>({
+  return invokeTauriCommand<string | string[]>({
     __tauriModule: 'Dialog',
     mainThread: true,
     message: {
@@ -57,7 +57,7 @@ async function save(options: SaveDialogOptions = {}): Promise<string> {
     Object.freeze(options)
   }
 
-  return invoke<string>({
+  return invokeTauriCommand<string>({
     __tauriModule: 'Dialog',
     mainThread: true,
     message: {

+ 11 - 11
api/src/fs.ts

@@ -1,4 +1,4 @@
-import { invoke } from './tauri'
+import { invokeTauriCommand } from './helpers/tauri'
 
 export enum BaseDirectory {
   Audio = 1,
@@ -61,7 +61,7 @@ async function readTextFile(
   filePath: string,
   options: FsOptions = {}
 ): Promise<string> {
-  return invoke<string>({
+  return invokeTauriCommand<string>({
     __tauriModule: 'Fs',
     message: {
       cmd: 'readTextFile',
@@ -83,7 +83,7 @@ async function readBinaryFile(
   filePath: string,
   options: FsOptions = {}
 ): Promise<number[]> {
-  return invoke<number[]>({
+  return invokeTauriCommand<number[]>({
     __tauriModule: 'Fs',
     message: {
       cmd: 'readBinaryFile',
@@ -114,7 +114,7 @@ async function writeFile(
     Object.freeze(file)
   }
 
-  return invoke({
+  return invokeTauriCommand({
     __tauriModule: 'Fs',
     message: {
       cmd: 'writeFile',
@@ -179,7 +179,7 @@ async function writeBinaryFile(
     Object.freeze(file)
   }
 
-  return invoke({
+  return invokeTauriCommand({
     __tauriModule: 'Fs',
     message: {
       cmd: 'writeBinaryFile',
@@ -203,7 +203,7 @@ async function readDir(
   dir: string,
   options: FsDirOptions = {}
 ): Promise<FileEntry[]> {
-  return invoke({
+  return invokeTauriCommand({
     __tauriModule: 'Fs',
     message: {
       cmd: 'readDir',
@@ -228,7 +228,7 @@ async function createDir(
   dir: string,
   options: FsDirOptions = {}
 ): Promise<void> {
-  return invoke({
+  return invokeTauriCommand({
     __tauriModule: 'Fs',
     message: {
       cmd: 'createDir',
@@ -252,7 +252,7 @@ async function removeDir(
   dir: string,
   options: FsDirOptions = {}
 ): Promise<void> {
-  return invoke({
+  return invokeTauriCommand({
     __tauriModule: 'Fs',
     message: {
       cmd: 'removeDir',
@@ -276,7 +276,7 @@ async function copyFile(
   destination: string,
   options: FsOptions = {}
 ): Promise<void> {
-  return invoke({
+  return invokeTauriCommand({
     __tauriModule: 'Fs',
     message: {
       cmd: 'copyFile',
@@ -299,7 +299,7 @@ async function removeFile(
   file: string,
   options: FsOptions = {}
 ): Promise<void> {
-  return invoke({
+  return invokeTauriCommand({
     __tauriModule: 'Fs',
     message: {
       cmd: 'removeFile',
@@ -323,7 +323,7 @@ async function renameFile(
   newPath: string,
   options: FsOptions = {}
 ): Promise<void> {
-  return invoke({
+  return invokeTauriCommand({
     __tauriModule: 'Fs',
     message: {
       cmd: 'renameFile',

+ 7 - 6
api/src/globalShortcut.ts

@@ -1,4 +1,5 @@
-import { invoke, transformCallback } from './tauri'
+import { invokeTauriCommand } from './helpers/tauri'
+import { transformCallback } from './tauri'
 
 /**
  * Register a global shortcut
@@ -9,7 +10,7 @@ async function register(
   shortcut: string,
   handler: (shortcut: string) => void
 ): Promise<void> {
-  return invoke({
+  return invokeTauriCommand({
     __tauriModule: 'GlobalShortcut',
     message: {
       cmd: 'register',
@@ -28,7 +29,7 @@ async function registerAll(
   shortcuts: string[],
   handler: (shortcut: string) => void
 ): Promise<void> {
-  return invoke({
+  return invokeTauriCommand({
     __tauriModule: 'GlobalShortcut',
     message: {
       cmd: 'registerAll',
@@ -45,7 +46,7 @@ async function registerAll(
  * @return {Promise<boolean>} promise resolving to the state
  */
 async function isRegistered(shortcut: string): Promise<boolean> {
-  return invoke({
+  return invokeTauriCommand({
     __tauriModule: 'GlobalShortcut',
     message: {
       cmd: 'isRegistered',
@@ -59,7 +60,7 @@ async function isRegistered(shortcut: string): Promise<boolean> {
  * @param shortcut shortcut definition, modifiers and key separated by "+" e.g. CmdOrControl+Q
  */
 async function unregister(shortcut: string): Promise<void> {
-  return invoke({
+  return invokeTauriCommand({
     __tauriModule: 'GlobalShortcut',
     message: {
       cmd: 'unregister',
@@ -72,7 +73,7 @@ async function unregister(shortcut: string): Promise<void> {
  * Unregisters all shortcuts registered by the application.
  */
 async function unregisterAll(): Promise<void> {
-  return invoke({
+  return invokeTauriCommand({
     __tauriModule: 'GlobalShortcut',
     message: {
       cmd: 'unregisterAll'

+ 4 - 3
api/src/helpers/event.ts

@@ -1,4 +1,5 @@
-import { invoke, transformCallback } from '../tauri'
+import { invokeTauriCommand } from './tauri'
+import { transformCallback } from '../tauri'
 
 export interface Event<T> {
   type: string
@@ -12,7 +13,7 @@ async function _listen<T>(
   handler: EventCallback<T>,
   once: boolean
 ): Promise<void> {
-  await invoke({
+  await invokeTauriCommand({
     __tauriModule: 'Event',
     message: {
       cmd: 'listen',
@@ -60,7 +61,7 @@ async function emit(
   windowLabel?: string,
   payload?: string
 ): Promise<void> {
-  await invoke({
+  await invokeTauriCommand({
     __tauriModule: 'Event',
     message: {
       cmd: 'emit',

+ 22 - 0
api/src/helpers/tauri.ts

@@ -0,0 +1,22 @@
+import { invoke } from '../tauri'
+
+export type TauriModule = 'Fs' |
+  'Window' |
+  'Shell' |
+  'Event' |
+  'Internal' |
+  'Dialog' |
+  'Cli' |
+  'Notification' |
+  'Http' |
+  'GlobalShortcut'
+
+export interface TauriCommand {
+  __tauriModule: TauriModule
+  mainThread?: boolean
+  [key: string]: unknown
+}
+
+export async function invokeTauriCommand<T>(command: TauriCommand): Promise<T> {
+  return invoke('tauri', command)
+}

+ 4 - 4
api/src/http.ts

@@ -1,4 +1,4 @@
-import { invoke } from './tauri'
+import { invokeTauriCommand } from './helpers/tauri'
 
 export interface ClientOptions {
   maxRedirections: boolean
@@ -80,7 +80,7 @@ export class Client {
    * drops the client instance
    */
   async drop(): Promise<void> {
-    return invoke({
+    return invokeTauriCommand({
       __tauriModule: 'Http',
       message: {
         cmd: 'dropClient',
@@ -97,7 +97,7 @@ export class Client {
    * @return promise resolving to the response
    */
   async request<T>(options: HttpOptions): Promise<Response<T>> {
-    return invoke({
+    return invokeTauriCommand({
       __tauriModule: 'Http',
       message: {
         cmd: 'httpRequest',
@@ -201,7 +201,7 @@ export class Client {
 }
 
 async function getClient(options?: ClientOptions): Promise<Client> {
-  return invoke<number>({
+  return invokeTauriCommand<number>({
     __tauriModule: 'Http',
     message: {
       cmd: 'createClient',

+ 2 - 2
api/src/notification.ts

@@ -1,4 +1,4 @@
-import { invoke } from './tauri'
+import { invokeTauriCommand } from './helpers/tauri'
 
 export interface Options {
   title: string
@@ -13,7 +13,7 @@ async function isPermissionGranted(): Promise<boolean | null> {
   if (window.Notification.permission !== 'default') {
     return Promise.resolve(window.Notification.permission === 'granted')
   }
-  return invoke({
+  return invokeTauriCommand({
     __tauriModule: 'Notification',
     message: {
       cmd: 'isNotificationPermissionGranted'

+ 20 - 20
api/src/path.ts

@@ -1,4 +1,4 @@
-import { invoke } from './tauri'
+import { invokeTauriCommand } from './helpers/tauri'
 import { BaseDirectory } from './fs'
 
 /**
@@ -7,7 +7,7 @@ import { BaseDirectory } from './fs'
  * @return {Promise<string>}
  */
 async function appDir(): Promise<string> {
-  return invoke<string>({
+  return invokeTauriCommand<string>({
     __tauriModule: 'Fs',
     message: {
       cmd: 'resolvePath',
@@ -23,7 +23,7 @@ async function appDir(): Promise<string> {
  * @return {Promise<string>}
  */
 async function audioDir(): Promise<string> {
-  return invoke<string>({
+  return invokeTauriCommand<string>({
     __tauriModule: 'Fs',
     message: {
       cmd: 'resolvePath',
@@ -39,7 +39,7 @@ async function audioDir(): Promise<string> {
  * @return {Promise<string>}
  */
 async function cacheDir(): Promise<string> {
-  return invoke<string>({
+  return invokeTauriCommand<string>({
     __tauriModule: 'Fs',
     message: {
       cmd: 'resolvePath',
@@ -55,7 +55,7 @@ async function cacheDir(): Promise<string> {
  * @return {Promise<string>}
  */
 async function configDir(): Promise<string> {
-  return invoke<string>({
+  return invokeTauriCommand<string>({
     __tauriModule: 'Fs',
     message: {
       cmd: 'resolvePath',
@@ -71,7 +71,7 @@ async function configDir(): Promise<string> {
  * @return {Promise<string>}
  */
 async function dataDir(): Promise<string> {
-  return invoke<string>({
+  return invokeTauriCommand<string>({
     __tauriModule: 'Fs',
     message: {
       cmd: 'resolvePath',
@@ -87,7 +87,7 @@ async function dataDir(): Promise<string> {
  * @return {Promise<string>}
  */
 async function desktopDir(): Promise<string> {
-  return invoke<string>({
+  return invokeTauriCommand<string>({
     __tauriModule: 'Fs',
     message: {
       cmd: 'resolvePath',
@@ -103,7 +103,7 @@ async function desktopDir(): Promise<string> {
  * @return {Promise<string>}
  */
 async function documentDir(): Promise<string> {
-  return invoke<string>({
+  return invokeTauriCommand<string>({
     __tauriModule: 'Fs',
     message: {
       cmd: 'resolvePath',
@@ -119,7 +119,7 @@ async function documentDir(): Promise<string> {
  * @return {Promise<string>}
  */
 async function downloadDir(): Promise<string> {
-  return invoke<string>({
+  return invokeTauriCommand<string>({
     __tauriModule: 'Fs',
     message: {
       cmd: 'resolvePath',
@@ -135,7 +135,7 @@ async function downloadDir(): Promise<string> {
  * @return {Promise<string>}
  */
 async function executableDir(): Promise<string> {
-  return invoke<string>({
+  return invokeTauriCommand<string>({
     __tauriModule: 'Fs',
     message: {
       cmd: 'resolvePath',
@@ -151,7 +151,7 @@ async function executableDir(): Promise<string> {
  * @return {Promise<string>}
  */
 async function fontDir(): Promise<string> {
-  return invoke<string>({
+  return invokeTauriCommand<string>({
     __tauriModule: 'Fs',
     message: {
       cmd: 'resolvePath',
@@ -167,7 +167,7 @@ async function fontDir(): Promise<string> {
  * @return {Promise<string>}
  */
 async function homeDir(): Promise<string> {
-  return invoke<string>({
+  return invokeTauriCommand<string>({
     __tauriModule: 'Fs',
     message: {
       cmd: 'resolvePath',
@@ -183,7 +183,7 @@ async function homeDir(): Promise<string> {
  * @return {Promise<string>}
  */
 async function localDataDir(): Promise<string> {
-  return invoke<string>({
+  return invokeTauriCommand<string>({
     __tauriModule: 'Fs',
     message: {
       cmd: 'resolvePath',
@@ -199,7 +199,7 @@ async function localDataDir(): Promise<string> {
  * @return {Promise<string>}
  */
 async function pictureDir(): Promise<string> {
-  return invoke<string>({
+  return invokeTauriCommand<string>({
     __tauriModule: 'Fs',
     message: {
       cmd: 'resolvePath',
@@ -215,7 +215,7 @@ async function pictureDir(): Promise<string> {
  * @return {Promise<string>}
  */
 async function publicDir(): Promise<string> {
-  return invoke<string>({
+  return invokeTauriCommand<string>({
     __tauriModule: 'Fs',
     message: {
       cmd: 'resolvePath',
@@ -231,7 +231,7 @@ async function publicDir(): Promise<string> {
  * @return {Promise<string>}
  */
 async function resourceDir(): Promise<string> {
-  return invoke<string>({
+  return invokeTauriCommand<string>({
     __tauriModule: 'Fs',
     message: {
       cmd: 'resolvePath',
@@ -247,7 +247,7 @@ async function resourceDir(): Promise<string> {
  * @return {Promise<string>}
  */
 async function runtimeDir(): Promise<string> {
-  return invoke<string>({
+  return invokeTauriCommand<string>({
     __tauriModule: 'Fs',
     message: {
       cmd: 'resolvePath',
@@ -263,7 +263,7 @@ async function runtimeDir(): Promise<string> {
  * @return {Promise<string>}
  */
 async function templateDir(): Promise<string> {
-  return invoke<string>({
+  return invokeTauriCommand<string>({
     __tauriModule: 'Fs',
     message: {
       cmd: 'resolvePath',
@@ -279,7 +279,7 @@ async function templateDir(): Promise<string> {
  * @return {Promise<string>}
  */
 async function videoDir(): Promise<string> {
-  return invoke<string>({
+  return invokeTauriCommand<string>({
     __tauriModule: 'Fs',
     message: {
       cmd: 'resolvePath',
@@ -298,7 +298,7 @@ async function resolvePath(
   path: string,
   directory: BaseDirectory
 ): Promise<string> {
-  return invoke<string>({
+  return invokeTauriCommand<string>({
     __tauriModule: 'Fs',
     message: {
       cmd: 'resolvePath',

+ 3 - 3
api/src/shell.ts

@@ -1,4 +1,4 @@
-import { invoke } from './tauri'
+import { invokeTauriCommand } from './helpers/tauri'
 
 /**
  * spawns a process
@@ -15,7 +15,7 @@ async function execute(
     Object.freeze(args)
   }
 
-  return invoke<string>({
+  return invokeTauriCommand<string>({
     __tauriModule: 'Shell',
     message: {
       cmd: 'execute',
@@ -31,7 +31,7 @@ async function execute(
  * @param url the URL to open
  */
 async function open(url: string): Promise<void> {
-  return invoke({
+  return invokeTauriCommand({
     __tauriModule: 'Shell',
     message: {
       cmd: 'open',

+ 11 - 12
api/src/tauri.ts

@@ -1,7 +1,9 @@
 declare global {
   // eslint-disable-next-line @typescript-eslint/no-unused-vars
   interface Window {
-    __TAURI_INVOKE_HANDLER__: (command: { [key: string]: unknown }) => void
+    rpc: {
+      notify: (command: string, args?: { [key: string]: unknown }) => void
+    }
   }
 }
 
@@ -49,6 +51,11 @@ function transformCallback(
   return identifier
 }
 
+export interface InvokeArgs {
+  mainThread?: boolean
+  [key: string]: unknown
+}
+
 /**
  * sends a message to the backend
  *
@@ -57,8 +64,8 @@ function transformCallback(
  * @return {Promise<T>} Promise resolving or rejecting to the backend response
  */
 async function invoke<T>(
-  cmd: string | { [key: string]: unknown },
-  args: { [key: string]: unknown } = {}
+  cmd: string,
+  args: InvokeArgs = {}
 ): Promise<T> {
   return new Promise((resolve, reject) => {
     const callback = transformCallback((e) => {
@@ -70,15 +77,7 @@ async function invoke<T>(
       Reflect.deleteProperty(window, callback)
     }, true)
 
-    if (typeof cmd === 'string') {
-      args.cmd = cmd
-    } else if (typeof cmd === 'object') {
-      args = cmd
-    } else {
-      return reject(new Error('Invalid argument type.'))
-    }
-
-    window.__TAURI_INVOKE_HANDLER__({
+    window.rpc.notify(cmd, {
       callback,
       error,
       ...args

+ 23 - 25
api/src/window.ts

@@ -1,4 +1,4 @@
-import { invoke } from './tauri'
+import { invokeTauriCommand } from './helpers/tauri'
 import { EventCallback, emit, listen, once } from './helpers/event'
 
 interface WindowDef {
@@ -90,14 +90,12 @@ class WebviewWindowHandle {
     }
     return false
   }
-
-  _emitTauriEvent(event: string): void {}
 }
 
 class WebviewWindow extends WebviewWindowHandle {
   constructor(label: string, options: WindowOptions = {}) {
     super(label)
-    invoke({
+    invokeTauriCommand({
       __tauriModule: 'Window',
       message: {
         cmd: 'createWebview',
@@ -131,7 +129,7 @@ class WindowManager {
    * Updates the window resizable flag.
    */
   async setResizable(resizable: boolean): Promise<void> {
-    return invoke({
+    return invokeTauriCommand({
       __tauriModule: 'Window',
       message: {
         cmd: 'setResizable',
@@ -146,7 +144,7 @@ class WindowManager {
    * @param title the new title
    */
   async setTitle(title: string): Promise<void> {
-    return invoke({
+    return invokeTauriCommand({
       __tauriModule: 'Window',
       message: {
         cmd: 'setTitle',
@@ -159,7 +157,7 @@ class WindowManager {
    * Maximizes the window.
    */
   async maximize(): Promise<void> {
-    return invoke({
+    return invokeTauriCommand({
       __tauriModule: 'Window',
       message: {
         cmd: 'maximize'
@@ -171,7 +169,7 @@ class WindowManager {
    * Unmaximizes the window.
    */
   async unmaximize(): Promise<void> {
-    return invoke({
+    return invokeTauriCommand({
       __tauriModule: 'Window',
       message: {
         cmd: 'unmaximize'
@@ -183,7 +181,7 @@ class WindowManager {
    * Minimizes the window.
    */
   async minimize(): Promise<void> {
-    return invoke({
+    return invokeTauriCommand({
       __tauriModule: 'Window',
       message: {
         cmd: 'minimize'
@@ -195,7 +193,7 @@ class WindowManager {
    * Unminimizes the window.
    */
   async unminimize(): Promise<void> {
-    return invoke({
+    return invokeTauriCommand({
       __tauriModule: 'Window',
       message: {
         cmd: 'unminimize'
@@ -207,7 +205,7 @@ class WindowManager {
    * Sets the window visibility to true.
    */
   async show(): Promise<void> {
-    return invoke({
+    return invokeTauriCommand({
       __tauriModule: 'Window',
       message: {
         cmd: 'show'
@@ -219,7 +217,7 @@ class WindowManager {
    * Sets the window visibility to false.
    */
   async hide(): Promise<void> {
-    return invoke({
+    return invokeTauriCommand({
       __tauriModule: 'Window',
       message: {
         cmd: 'hide'
@@ -231,7 +229,7 @@ class WindowManager {
    * Closes the window.
    */
   async close(): Promise<void> {
-    return invoke({
+    return invokeTauriCommand({
       __tauriModule: 'Window',
       message: {
         cmd: 'close'
@@ -245,7 +243,7 @@ class WindowManager {
    * @param {boolean} decorations whether the window should have borders and bars
    */
   async setDecorations(decorations: boolean): Promise<void> {
-    return invoke({
+    return invokeTauriCommand({
       __tauriModule: 'Window',
       message: {
         cmd: 'setDecorations',
@@ -260,7 +258,7 @@ class WindowManager {
    * @param {boolean} alwaysOnTop whether the window should always be on top of other windows or not
    */
   async setAlwaysOnTop(alwaysOnTop: boolean): Promise<void> {
-    return invoke({
+    return invokeTauriCommand({
       __tauriModule: 'Window',
       message: {
         cmd: 'setAlwaysOnTop',
@@ -275,7 +273,7 @@ class WindowManager {
    * @param {number} width the new window width
    */
   async setWidth(width: number): Promise<void> {
-    return invoke({
+    return invokeTauriCommand({
       __tauriModule: 'Window',
       message: {
         cmd: 'setWidth',
@@ -290,7 +288,7 @@ class WindowManager {
    * @param {number} height the new window height
    */
   async setHeight(height: number): Promise<void> {
-    return invoke({
+    return invokeTauriCommand({
       __tauriModule: 'Window',
       message: {
         cmd: 'setHeight',
@@ -306,7 +304,7 @@ class WindowManager {
    * @param {number} height the new window height
    */
   async resize(width: number, height: number): Promise<void> {
-    return invoke({
+    return invokeTauriCommand({
       __tauriModule: 'Window',
       message: {
         cmd: 'resize',
@@ -323,7 +321,7 @@ class WindowManager {
    * @param {number} minHeight the new window min height
    */
   async setMinSize(minWidth: number, minHeight: number): Promise<void> {
-    return invoke({
+    return invokeTauriCommand({
       __tauriModule: 'Window',
       message: {
         cmd: 'setMinSize',
@@ -340,7 +338,7 @@ class WindowManager {
    * @param {number} maxHeight the new window max height
    */
   async setMaxSize(maxWidth: number, maxHeight: number): Promise<void> {
-    return invoke({
+    return invokeTauriCommand({
       __tauriModule: 'Window',
       message: {
         cmd: 'setMaxSize',
@@ -356,7 +354,7 @@ class WindowManager {
    * @param {number} x the new window x position
    */
   async setX(x: number): Promise<void> {
-    return invoke({
+    return invokeTauriCommand({
       __tauriModule: 'Window',
       message: {
         cmd: 'setX',
@@ -371,7 +369,7 @@ class WindowManager {
    * @param {number} y the new window y position
    */
   async setY(y: number): Promise<void> {
-    return invoke({
+    return invokeTauriCommand({
       __tauriModule: 'Window',
       message: {
         cmd: 'setY',
@@ -387,7 +385,7 @@ class WindowManager {
    * @param {number} y the new window y position
    */
   async setPosition(x: number, y: number): Promise<void> {
-    return invoke({
+    return invokeTauriCommand({
       __tauriModule: 'Window',
       message: {
         cmd: 'setPosition',
@@ -403,7 +401,7 @@ class WindowManager {
    * @param {boolean} fullscreen whether the window should go to fullscreen or not
    */
   async setFullscreen(fullscreen: boolean): Promise<void> {
-    return invoke({
+    return invokeTauriCommand({
       __tauriModule: 'Window',
       message: {
         cmd: 'setFullscreen',
@@ -418,7 +416,7 @@ class WindowManager {
    * @param {string | number[]} icon icon bytes or path to the icon file
    */
   async setIcon(icon: 'string' | number[]): Promise<void> {
-    return invoke({
+    return invokeTauriCommand({
       __tauriModule: 'Window',
       message: {
         cmd: 'setIcon',

+ 12 - 10
cli/core/src/templates/tauri.js

@@ -124,8 +124,9 @@ if (!String.prototype.startsWith) {
         return reject(new Error("Invalid argument type."));
       }
 
-      if (window.__TAURI_INVOKE_HANDLER__) {
-        window.__TAURI_INVOKE_HANDLER__(
+      if (window.rpc) {
+        window.rpc.notify(
+          cmd,
           _objectSpread(
             {
               callback: callback,
@@ -136,7 +137,8 @@ if (!String.prototype.startsWith) {
         );
       } else {
         window.addEventListener("DOMContentLoaded", function () {
-          window.__TAURI_INVOKE_HANDLER__(
+          window.rpc.notify(
+            cmd,
             _objectSpread(
               {
                 callback: callback,
@@ -165,7 +167,7 @@ if (!String.prototype.startsWith) {
               target.href.startsWith("http") &&
               target.target === "_blank"
             ) {
-              window.__TAURI__.invoke({
+              window.__TAURI__.invoke('tauri', {
                 __tauriModule: "Shell",
                 message: {
                   cmd: "open",
@@ -198,7 +200,7 @@ if (!String.prototype.startsWith) {
     );
   }
 
-  window.__TAURI__.invoke({
+  window.__TAURI__.invoke('tauri', {
     __tauriModule: "Event",
     message: {
       cmd: "listen",
@@ -219,7 +221,7 @@ if (!String.prototype.startsWith) {
     if (window.Notification.permission !== "default") {
       return Promise.resolve(window.Notification.permission === "granted");
     }
-    return window.__TAURI__.invoke({
+    return window.__TAURI__.invoke('tauri', {
       __tauriModule: "Notification",
       message: {
         cmd: "isNotificationPermissionGranted",
@@ -235,7 +237,7 @@ if (!String.prototype.startsWith) {
 
   function requestPermission() {
     return window.__TAURI__
-      .invoke({
+      .invoke('tauri', {
         __tauriModule: "Notification",
         mainThread: true,
         message: {
@@ -255,7 +257,7 @@ if (!String.prototype.startsWith) {
 
     isPermissionGranted().then(function (permission) {
       if (permission) {
-        return window.__TAURI__.invoke({
+        return window.__TAURI__.invoke('tauri', {
           __tauriModule: "Notification",
           message: {
             cmd: "notification",
@@ -304,7 +306,7 @@ if (!String.prototype.startsWith) {
   });
 
   window.alert = function (message) {
-    window.__TAURI__.invoke({
+    window.__TAURI__.invoke('tauri', {
       __tauriModule: "Dialog",
       mainThread: true,
       message: {
@@ -315,7 +317,7 @@ if (!String.prototype.startsWith) {
   };
 
   window.confirm = function (message) {
-    return window.__TAURI__.invoke({
+    return window.__TAURI__.invoke('tauri', {
       __tauriModule: "Dialog",
       mainThread: true,
       message: {

+ 1 - 3
cli/tauri.js/test/jest/fixtures/app/dist/index.html

@@ -136,9 +136,7 @@
       })
 
       setTimeout(function () {
-        window.__TAURI_INVOKE_HANDLER__({
-          cmd: 'exit'
-        })
+        window.rpc.notify('exit')
       }, 15000)
     </script>
   </body>

+ 0 - 8
cli/tauri.js/test/jest/fixtures/app/src-tauri/src/cmd.rs

@@ -1,8 +0,0 @@
-#[derive(serde::Deserialize)]
-#[serde(tag = "cmd", rename_all = "camelCase")]
-pub enum Cmd {
-  // your custom commands
-  // multiple arguments are allowed
-  // note that rename_all = "camelCase": you need to use "myCustomCommand" on JS
-  Exit {},
-}

+ 3 - 15
cli/tauri.js/test/jest/fixtures/app/src-tauri/src/main.rs

@@ -1,5 +1,3 @@
-mod cmd;
-
 use tauri::ApplicationDispatcherExt;
 
 #[derive(tauri::FromTauriContext)]
@@ -21,19 +19,9 @@ fn main() {
         .current_webview()
         .eval("window.onTauriInit && window.onTauriInit()");
     })
-    .invoke_handler(|webview_manager, arg| async move {
-      use cmd::Cmd::*;
-      match serde_json::from_str(&arg) {
-        Err(e) => Err(e.into()),
-        Ok(command) => {
-          match command {
-            // definitions for your custom commands from Cmd here
-            Exit {} => {
-              // TODO dispatcher.terminate();
-            }
-          }
-          Ok(())
-        }
+    .invoke_handler(|webview_manager, command, _arg| async move {
+      if &command == "exit" {
+        webview_manager.close().unwrap();
       }
     })
     .build()

+ 4 - 11
tauri-macros/src/command.rs

@@ -133,17 +133,10 @@ pub fn generate_handler(item: proc_macro::TokenStream) -> TokenStream {
   });
 
   quote! {
-    |webview_manager, arg| async move {
-      let dispatch: ::std::result::Result<::tauri::DispatchInstructions, ::serde_json::Error> =
-      ::serde_json::from_str(&arg);
-      match dispatch {
-        Err(e) => Err(e.into()),
-        Ok(dispatch) => {
-          match dispatch.cmd.as_str() {
-            #(stringify!(#fn_names) => #fn_wrappers(webview_manager, dispatch.args).await,)*
-            _ => Err(tauri::Error::UnknownApi(None)),
-          }
-        }
+    |webview_manager, command, arg| async move {
+      match command.as_str() {
+        #(stringify!(#fn_names) => #fn_wrappers(webview_manager, arg).await,)*
+        _ => Err(tauri::Error::UnknownApi(None)),
       }
     }
   }

+ 1 - 1
tauri/Cargo.toml

@@ -31,7 +31,7 @@ thiserror = "1.0.24"
 once_cell = "1.7.0"
 tauri-api = { version = "0.7.5", path = "../tauri-api" }
 tauri-macros = { version = "0.1", path = "../tauri-macros" }
-wry = { git = "https://github.com/tauri-apps/wry", rev = "a607d6aba95e6ee0d9620394b7ee0092527095dc" }
+wry = { git = "https://github.com/tauri-apps/wry", rev = "729fdc182eaf4af44d822dfc9396deb3f5f5810a" }
 rand = "0.8"
 
 [build-dependencies]

+ 8 - 2
tauri/examples/api/src-tauri/Cargo.lock

@@ -1285,6 +1285,12 @@ dependencies = [
  "hashbrown",
 ]
 
+[[package]]
+name = "infer"
+version = "0.3.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "34ad0755c42f65a1374dcd0aae07e03dfefc911eceb3f409d2b4a888189447e6"
+
 [[package]]
 name = "instant"
 version = "0.1.9"
@@ -3547,7 +3553,7 @@ dependencies = [
 [[package]]
 name = "wry"
 version = "0.5.1"
-source = "git+https://github.com/tauri-apps/wry?rev=a607d6aba95e6ee0d9620394b7ee0092527095dc#a607d6aba95e6ee0d9620394b7ee0092527095dc"
+source = "git+https://github.com/tauri-apps/wry?rev=729fdc182eaf4af44d822dfc9396deb3f5f5810a#729fdc182eaf4af44d822dfc9396deb3f5f5810a"
 dependencies = [
  "cairo-rs",
  "cocoa",
@@ -3558,8 +3564,8 @@ dependencies = [
  "glib",
  "gtk",
  "image",
+ "infer",
  "libc",
- "mime_guess",
  "objc",
  "objc_id",
  "once_cell",

+ 29 - 19
tauri/examples/helloworld/public/__tauri.js

@@ -103,7 +103,7 @@ if (!String.prototype.startsWith) {
     return identifier;
   };
 
-  window.__TAURI__.invoke = function invoke(args) {
+  window.__TAURI__.invoke = function invoke(cmd, args = {}) {
     var _this = this;
 
     return new Promise(function (resolve, reject) {
@@ -116,8 +116,17 @@ if (!String.prototype.startsWith) {
         delete window[callback];
       }, true);
 
-      if (window.__TAURI_INVOKE_HANDLER__) {
-        window.__TAURI_INVOKE_HANDLER__(
+      if (typeof cmd === "string") {
+        args.cmd = cmd;
+      } else if (typeof cmd === "object") {
+        args = cmd;
+      } else {
+        return reject(new Error("Invalid argument type."));
+      }
+
+      if (window.rpc) {
+        window.rpc.notify(
+          cmd,
           _objectSpread(
             {
               callback: callback,
@@ -128,7 +137,8 @@ if (!String.prototype.startsWith) {
         );
       } else {
         window.addEventListener("DOMContentLoaded", function () {
-          window.__TAURI_INVOKE_HANDLER__(
+          window.rpc.notify(
+            cmd,
             _objectSpread(
               {
                 callback: callback,
@@ -157,7 +167,7 @@ if (!String.prototype.startsWith) {
               target.href.startsWith("http") &&
               target.target === "_blank"
             ) {
-              window.__TAURI__.invoke({
+              window.__TAURI__.invoke('tauri', {
                 __tauriModule: "Shell",
                 message: {
                   cmd: "open",
@@ -190,19 +200,19 @@ if (!String.prototype.startsWith) {
     );
   }
 
-  window.__TAURI__.invoke({
-    __tauriModule: 'Event',
+  window.__TAURI__.invoke('tauri', {
+    __tauriModule: "Event",
     message: {
-      cmd: 'listen',
-      event: 'tauri://window-created',
+      cmd: "listen",
+      event: "tauri://window-created",
       handler: window.__TAURI__.transformCallback(function (event) {
         if (event.payload) {
-          var windowLabel = event.payload.label
-          window.__TAURI__.__windows.push({ label: windowLabel })
+          var windowLabel = event.payload.label;
+          window.__TAURI__.__windows.push({ label: windowLabel });
         }
-      })
-    }
-  })
+      }),
+    },
+  });
 
   let permissionSettable = false;
   let permissionValue = "default";
@@ -211,7 +221,7 @@ if (!String.prototype.startsWith) {
     if (window.Notification.permission !== "default") {
       return Promise.resolve(window.Notification.permission === "granted");
     }
-    return window.__TAURI__.invoke({
+    return window.__TAURI__.invoke('tauri', {
       __tauriModule: "Notification",
       message: {
         cmd: "isNotificationPermissionGranted",
@@ -227,7 +237,7 @@ if (!String.prototype.startsWith) {
 
   function requestPermission() {
     return window.__TAURI__
-      .invoke({
+      .invoke('tauri', {
         __tauriModule: "Notification",
         mainThread: true,
         message: {
@@ -247,7 +257,7 @@ if (!String.prototype.startsWith) {
 
     isPermissionGranted().then(function (permission) {
       if (permission) {
-        return window.__TAURI__.invoke({
+        return window.__TAURI__.invoke('tauri', {
           __tauriModule: "Notification",
           message: {
             cmd: "notification",
@@ -296,7 +306,7 @@ if (!String.prototype.startsWith) {
   });
 
   window.alert = function (message) {
-    window.__TAURI__.invoke({
+    window.__TAURI__.invoke('tauri', {
       __tauriModule: "Dialog",
       mainThread: true,
       message: {
@@ -307,7 +317,7 @@ if (!String.prototype.startsWith) {
   };
 
   window.confirm = function (message) {
-    return window.__TAURI__.invoke({
+    return window.__TAURI__.invoke('tauri', {
       __tauriModule: "Dialog",
       mainThread: true,
       message: {

+ 8 - 2
tauri/examples/helloworld/src-tauri/Cargo.lock

@@ -1242,6 +1242,12 @@ dependencies = [
  "hashbrown",
 ]
 
+[[package]]
+name = "infer"
+version = "0.3.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "34ad0755c42f65a1374dcd0aae07e03dfefc911eceb3f409d2b4a888189447e6"
+
 [[package]]
 name = "instant"
 version = "0.1.9"
@@ -3461,7 +3467,7 @@ dependencies = [
 [[package]]
 name = "wry"
 version = "0.5.1"
-source = "git+https://github.com/tauri-apps/wry?rev=a607d6aba95e6ee0d9620394b7ee0092527095dc#a607d6aba95e6ee0d9620394b7ee0092527095dc"
+source = "git+https://github.com/tauri-apps/wry?rev=729fdc182eaf4af44d822dfc9396deb3f5f5810a#729fdc182eaf4af44d822dfc9396deb3f5f5810a"
 dependencies = [
  "cairo-rs",
  "cocoa",
@@ -3472,8 +3478,8 @@ dependencies = [
  "glib",
  "gtk",
  "image",
+ "infer",
  "libc",
- "mime_guess",
  "objc",
  "objc_id",
  "once_cell",

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 0 - 0
tauri/examples/multiwindow/dist/__tauri.js


+ 8 - 2
tauri/examples/multiwindow/src-tauri/Cargo.lock

@@ -1240,6 +1240,12 @@ dependencies = [
  "hashbrown",
 ]
 
+[[package]]
+name = "infer"
+version = "0.3.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "34ad0755c42f65a1374dcd0aae07e03dfefc911eceb3f409d2b4a888189447e6"
+
 [[package]]
 name = "instant"
 version = "0.1.9"
@@ -3459,7 +3465,7 @@ dependencies = [
 [[package]]
 name = "wry"
 version = "0.5.1"
-source = "git+https://github.com/tauri-apps/wry?rev=a607d6aba95e6ee0d9620394b7ee0092527095dc#a607d6aba95e6ee0d9620394b7ee0092527095dc"
+source = "git+https://github.com/tauri-apps/wry?rev=729fdc182eaf4af44d822dfc9396deb3f5f5810a#729fdc182eaf4af44d822dfc9396deb3f5f5810a"
 dependencies = [
  "cairo-rs",
  "cocoa",
@@ -3470,8 +3476,8 @@ dependencies = [
  "glib",
  "gtk",
  "image",
+ "infer",
  "libc",
- "mime_guess",
  "objc",
  "objc_id",
  "once_cell",

+ 13 - 21
tauri/src/app.rs

@@ -1,5 +1,5 @@
 use futures::future::BoxFuture;
-use serde::{Deserialize, Serialize};
+use serde::Serialize;
 use serde_json::Value as JsonValue;
 use tauri_api::{config::Config, private::AsTauriContext};
 
@@ -15,12 +15,12 @@ mod webview_manager;
 pub use crate::api::config::WindowUrl;
 use crate::flavors::Wry;
 pub use webview::{
-  wry::WryApplication, ApplicationDispatcherExt, ApplicationExt, Callback, CustomProtocol, Icon,
-  Message, WebviewBuilderExt,
+  wry::WryApplication, ApplicationDispatcherExt, ApplicationExt, CustomProtocol, Icon, Message,
+  RpcRequest, WebviewBuilderExt, WebviewRpcHandler,
 };
 pub use webview_manager::{WebviewDispatcher, WebviewManager};
 
-type InvokeHandler<A> = dyn Fn(WebviewManager<A>, String) -> BoxFuture<'static, crate::Result<InvokeResponse>>
+type InvokeHandler<A> = dyn Fn(WebviewManager<A>, String, JsonValue) -> BoxFuture<'static, crate::Result<InvokeResponse>>
   + Send
   + Sync;
 type Setup<A> = dyn Fn(WebviewManager<A>) -> BoxFuture<'static, ()> + Send + Sync;
@@ -63,15 +63,6 @@ impl<T: Serialize> From<T> for InvokeResponse {
   }
 }
 
-#[derive(Deserialize)]
-#[allow(missing_docs)]
-#[serde(tag = "cmd", rename_all = "camelCase")]
-pub struct DispatchInstructions {
-  pub cmd: String,
-  #[serde(flatten)]
-  pub args: JsonValue,
-}
-
 /// The application runner.
 pub struct App<A: ApplicationExt> {
   /// The JS message handler.
@@ -116,10 +107,11 @@ impl<A: ApplicationExt + 'static> App<A> {
   pub(crate) async fn run_invoke_handler(
     &self,
     dispatcher: &WebviewManager<A>,
+    command: String,
     arg: &JsonValue,
   ) -> crate::Result<Option<InvokeResponse>> {
     if let Some(ref invoke_handler) = self.invoke_handler {
-      let fut = invoke_handler(dispatcher.clone(), arg.to_string());
+      let fut = invoke_handler(dispatcher.clone(), command, arg.clone());
       fut.await.map(Some)
     } else {
       Ok(None)
@@ -142,7 +134,7 @@ trait WebviewInitializer<A: ApplicationExt> {
     webview: Webview<A>,
   ) -> crate::Result<(
     <A as ApplicationExt>::WebviewBuilder,
-    Vec<Callback<A::Dispatcher>>,
+    Option<WebviewRpcHandler<A::Dispatcher>>,
     Option<CustomProtocol>,
   )>;
 
@@ -161,7 +153,7 @@ impl<A: ApplicationExt + 'static> WebviewInitializer<A> for Arc<App<A>> {
     webview: Webview<A>,
   ) -> crate::Result<(
     <A as ApplicationExt>::WebviewBuilder,
-    Vec<Callback<A::Dispatcher>>,
+    Option<WebviewRpcHandler<A::Dispatcher>>,
     Option<CustomProtocol>,
   )> {
     let webview_manager = WebviewManager::new(
@@ -229,13 +221,13 @@ impl<A: ApplicationExt + 'static, C: AsTauriContext> AppBuilder<C, A> {
   /// Defines the JS message handler callback.
   pub fn invoke_handler<
     T: futures::Future<Output = crate::Result<InvokeResponse>> + Send + Sync + 'static,
-    F: Fn(WebviewManager<A>, String) -> T + Send + Sync + 'static,
+    F: Fn(WebviewManager<A>, String, JsonValue) -> T + Send + Sync + 'static,
   >(
     mut self,
     invoke_handler: F,
   ) -> Self {
-    self.invoke_handler = Some(Box::new(move |webview_manager, arg| {
-      Box::pin(invoke_handler(webview_manager, arg))
+    self.invoke_handler = Some(Box::new(move |webview_manager, command, args| {
+      Box::pin(invoke_handler(webview_manager, command, args))
     }));
     self
   }
@@ -319,10 +311,10 @@ fn run<A: ApplicationExt + 'static>(mut application: App<A>) -> crate::Result<()
       application.dispatchers.clone(),
       webview_label.to_string(),
     );
-    let (webview_builder, callbacks, custom_protocol) =
+    let (webview_builder, rpc_handler, custom_protocol) =
       crate::async_runtime::block_on(application.init_webview(webview))?;
 
-    let dispatcher = webview_app.create_webview(webview_builder, callbacks, custom_protocol)?;
+    let dispatcher = webview_app.create_webview(webview_builder, rpc_handler, custom_protocol)?;
     crate::async_runtime::block_on(application.on_webview_created(
       webview_label,
       dispatcher,

+ 40 - 25
tauri/src/app/utils.rs

@@ -11,8 +11,8 @@ use crate::{
 };
 
 use super::{
-  webview::{Callback, CustomProtocol, WebviewBuilderExtPrivate},
-  App, Context, Webview, WebviewManager,
+  webview::{CustomProtocol, WebviewBuilderExtPrivate, WebviewRpcHandler},
+  App, Context, RpcRequest, Webview, WebviewManager,
 };
 
 use serde::Deserialize;
@@ -84,11 +84,11 @@ pub(super) fn initialization_script(
     r#"
       {tauri_initialization_script}
       {event_initialization_script}
-      if (window.__TAURI_INVOKE_HANDLER__) {{
-        window.__TAURI__.invoke({{ cmd: "__initialized" }})
+      if (window.rpc) {{
+        window.__TAURI__.invoke("__initialized")
       }} else {{
         window.addEventListener('DOMContentLoaded', function () {{
-          window.__TAURI__.invoke({{ cmd: "__initialized" }})
+          window.__TAURI__.invoke("__initialized")
         }})
       }}
       {plugin_initialization_script}
@@ -140,7 +140,7 @@ fn event_initialization_script() -> String {
 
 pub(super) type BuiltWebview<A> = (
   <A as ApplicationExt>::WebviewBuilder,
-  Vec<Callback<<A as ApplicationExt>::Dispatcher>>,
+  Option<WebviewRpcHandler<<A as ApplicationExt>::Dispatcher>>,
   Option<CustomProtocol>,
 );
 
@@ -164,7 +164,7 @@ pub(super) fn build_webview<A: ApplicationExt + 'static>(
     WindowUrl::App => true,
     WindowUrl::Custom(url) => &url[0..8] == "tauri://",
   };
-  let (webview_builder, callbacks, custom_protocol) = if is_local {
+  let (webview_builder, rpc_handler, custom_protocol) = if is_local {
     let mut webview_builder = webview.builder.url(webview_url)
         .initialization_script(&initialization_script(plugin_initialization_script, &context.tauri_script))
         .initialization_script(&format!(
@@ -184,10 +184,17 @@ pub(super) fn build_webview<A: ApplicationExt + 'static>(
     }
 
     let webview_manager_ = webview_manager.clone();
-    let tauri_invoke_handler = crate::Callback::<A::Dispatcher> {
-      name: "__TAURI_INVOKE_HANDLER__".to_string(),
-      function: Box::new(move |_, arg| {
-        let arg = arg.into_iter().next().unwrap_or(JsonValue::Null);
+    let rpc_handler: Box<dyn Fn(<A as ApplicationExt>::Dispatcher, RpcRequest) + Send> =
+      Box::new(move |_, request: RpcRequest| {
+        let command = request.command.clone();
+        let arg = request
+          .params
+          .unwrap()
+          .as_array_mut()
+          .unwrap()
+          .first_mut()
+          .unwrap_or(&mut JsonValue::Null)
+          .take();
         let webview_manager = webview_manager_.clone();
         match serde_json::from_value::<Message>(arg) {
           Ok(message) => {
@@ -199,7 +206,12 @@ pub(super) fn build_webview<A: ApplicationExt + 'static>(
               crate::async_runtime::block_on(async move {
                 execute_promise(
                   &webview_manager,
-                  on_message(application, webview_manager.clone(), message),
+                  on_message(
+                    application,
+                    webview_manager.clone(),
+                    command.clone(),
+                    message,
+                  ),
                   callback,
                   error,
                 )
@@ -209,7 +221,7 @@ pub(super) fn build_webview<A: ApplicationExt + 'static>(
               crate::async_runtime::spawn(async move {
                 execute_promise(
                   &webview_manager,
-                  on_message(application, webview_manager.clone(), message),
+                  on_message(application, webview_manager.clone(), command, message),
                   callback,
                   error,
                 )
@@ -229,8 +241,7 @@ pub(super) fn build_webview<A: ApplicationExt + 'static>(
             }
           }
         }
-      }),
-    };
+      });
     let assets = context.assets;
     let custom_protocol = CustomProtocol {
       name: "tauri".into(),
@@ -268,16 +279,12 @@ pub(super) fn build_webview<A: ApplicationExt + 'static>(
         }
       }),
     };
-    (
-      webview_builder,
-      vec![tauri_invoke_handler],
-      Some(custom_protocol),
-    )
+    (webview_builder, Some(rpc_handler), Some(custom_protocol))
   } else {
-    (webview.builder.url(webview_url), Vec::new(), None)
+    (webview.builder.url(webview_url), None, None)
   };
 
-  Ok((webview_builder, callbacks, custom_protocol))
+  Ok((webview_builder, rpc_handler, custom_protocol))
 }
 
 /// Asynchronously executes the given task
@@ -313,9 +320,10 @@ async fn execute_promise<
 async fn on_message<A: ApplicationExt + 'static>(
   application: Arc<App<A>>,
   webview_manager: WebviewManager<A>,
+  command: String,
   message: Message,
 ) -> crate::Result<InvokeResponse> {
-  if message.inner == serde_json::json!({ "cmd":"__initialized" }) {
+  if &command == "__initialized" {
     application.run_setup(&webview_manager).await;
     crate::plugin::ready(A::plugin_store(), &webview_manager).await;
     Ok(().into())
@@ -330,7 +338,7 @@ async fn on_message<A: ApplicationExt + 'static>(
       .await
     } else {
       let mut response = match application
-        .run_invoke_handler(&webview_manager, &message.inner)
+        .run_invoke_handler(&webview_manager, command.clone(), &message.inner)
         .await
       {
         Ok(value) => {
@@ -343,7 +351,14 @@ async fn on_message<A: ApplicationExt + 'static>(
         Err(e) => Err(e),
       };
       if let Err(crate::Error::UnknownApi(_)) = response {
-        match crate::plugin::extend_api(A::plugin_store(), &webview_manager, &message.inner).await {
+        match crate::plugin::extend_api(
+          A::plugin_store(),
+          &webview_manager,
+          command,
+          &message.inner,
+        )
+        .await
+        {
           Ok(value) => {
             // If value is None, that means that no plugin matched the command
             // and the UnknownApi error should be sent to the webview

+ 11 - 8
tauri/src/app/webview.rs

@@ -157,14 +157,17 @@ pub trait WebviewBuilderExt: Sized {
   fn finish(self) -> crate::Result<Self::Webview>;
 }
 
-/// Binds the given callback to a global variable on the window object.
-pub struct Callback<D> {
-  /// Function name to bind.
-  pub name: String,
-  /// Function callback handler.
-  pub function: Box<dyn FnMut(D, Vec<JsonValue>) + Send>,
+/// Rpc request.
+pub struct RpcRequest {
+  /// RPC command.
+  pub command: String,
+  /// Params.
+  pub params: Option<JsonValue>,
 }
 
+/// Rpc handler.
+pub type WebviewRpcHandler<D> = Box<dyn Fn(D, RpcRequest) + Send>;
+
 /// Uses a custom handler to resolve file requests
 pub struct CustomProtocol {
   /// Name of the protocol
@@ -185,7 +188,7 @@ pub trait ApplicationDispatcherExt: Clone + Send + Sync + Sized {
   fn create_webview(
     &self,
     webview_builder: Self::WebviewBuilder,
-    callbacks: Vec<Callback<Self>>,
+    rpc_handler: Option<WebviewRpcHandler<Self>>,
     custom_protocol: Option<CustomProtocol>,
   ) -> crate::Result<Self>;
 
@@ -278,7 +281,7 @@ pub trait ApplicationExt: Sized {
   fn create_webview(
     &mut self,
     webview_builder: Self::WebviewBuilder,
-    callbacks: Vec<Callback<Self::Dispatcher>>,
+    rpc_handler: Option<WebviewRpcHandler<Self::Dispatcher>>,
     custom_protocol: Option<CustomProtocol>,
   ) -> crate::Result<Self::Dispatcher>;
 

+ 38 - 34
tauri/src/app/webview/wry.rs

@@ -1,6 +1,6 @@
 use super::{
-  ApplicationDispatcherExt, ApplicationExt, Callback, CustomProtocol, Icon, WebviewBuilderExt,
-  WebviewBuilderExtPrivate, WindowConfig,
+  ApplicationDispatcherExt, ApplicationExt, CustomProtocol, Icon, RpcRequest, WebviewBuilderExt,
+  WebviewBuilderExtPrivate, WebviewRpcHandler, WindowConfig,
 };
 
 use once_cell::sync::Lazy;
@@ -177,6 +177,15 @@ impl WebviewBuilderExt for wry::Attributes {
   }
 }
 
+impl From<wry::RpcRequest> for RpcRequest {
+  fn from(request: wry::RpcRequest) -> Self {
+    Self {
+      command: request.method,
+      params: request.params,
+    }
+  }
+}
+
 #[derive(Clone)]
 pub struct WryDispatcher(
   Arc<Mutex<wry::WindowProxy>>,
@@ -189,25 +198,22 @@ impl ApplicationDispatcherExt for WryDispatcher {
   fn create_webview(
     &self,
     attributes: Self::WebviewBuilder,
-    callbacks: Vec<Callback<Self>>,
+    rpc_handler: Option<WebviewRpcHandler<Self>>,
     custom_protocol: Option<CustomProtocol>,
   ) -> crate::Result<Self> {
-    let mut wry_callbacks = Vec::new();
     let app_dispatcher = self.1.clone();
-    for mut callback in callbacks {
-      let app_dispatcher = app_dispatcher.clone();
-      let callback = wry::Callback {
-        name: callback.name.to_string(),
-        function: Box::new(move |dispatcher, _, req| {
-          (callback.function)(
-            Self(Arc::new(Mutex::new(dispatcher)), app_dispatcher.clone()),
-            req,
+
+    let wry_rpc_handler = Box::new(
+      move |dispatcher: wry::WindowProxy, request: wry::RpcRequest| {
+        if let Some(handler) = &rpc_handler {
+          handler(
+            WryDispatcher(Arc::new(Mutex::new(dispatcher)), app_dispatcher.clone()),
+            request.into(),
           );
-          Ok(())
-        }),
-      };
-      wry_callbacks.push(callback);
-    }
+        }
+        None
+      },
+    );
 
     let window_dispatcher = self
       .1
@@ -215,7 +221,7 @@ impl ApplicationDispatcherExt for WryDispatcher {
       .unwrap()
       .add_window_with_configs(
         attributes,
-        Some(wry_callbacks),
+        Some(wry_rpc_handler),
         custom_protocol.map(|p| wry::CustomProtocol {
           name: p.name.clone(),
           handler: Box::new(move |a| (*p.handler)(a).map_err(|_| wry::Error::InitScriptError)),
@@ -449,31 +455,29 @@ impl ApplicationExt for WryApplication {
   fn create_webview(
     &mut self,
     webview_builder: Self::WebviewBuilder,
-    callbacks: Vec<Callback<Self::Dispatcher>>,
+    rpc_handler: Option<WebviewRpcHandler<Self::Dispatcher>>,
     custom_protocol: Option<CustomProtocol>,
   ) -> crate::Result<Self::Dispatcher> {
-    let mut wry_callbacks = Vec::new();
     let app_dispatcher = Arc::new(Mutex::new(self.inner.application_proxy()));
-    for mut callback in callbacks {
-      let app_dispatcher = app_dispatcher.clone();
-      let callback = wry::Callback {
-        name: callback.name.to_string(),
-        function: Box::new(move |dispatcher, _, req| {
-          (callback.function)(
-            WryDispatcher(Arc::new(Mutex::new(dispatcher)), app_dispatcher.clone()),
-            req,
+
+    let app_dispatcher_ = app_dispatcher.clone();
+    let wry_rpc_handler = Box::new(
+      move |dispatcher: wry::WindowProxy, request: wry::RpcRequest| {
+        if let Some(handler) = &rpc_handler {
+          handler(
+            WryDispatcher(Arc::new(Mutex::new(dispatcher)), app_dispatcher_.clone()),
+            request.into(),
           );
-          Ok(())
-        }),
-      };
-      wry_callbacks.push(callback);
-    }
+        }
+        None
+      },
+    );
 
     let dispatcher = self
       .inner
       .add_window_with_configs(
         webview_builder.finish()?,
-        Some(wry_callbacks),
+        Some(wry_rpc_handler),
         custom_protocol.map(|p| wry::CustomProtocol {
           name: p.name.clone(),
           handler: Box::new(move |a| (*p.handler)(a).map_err(|_| wry::Error::InitScriptError)),

+ 2 - 2
tauri/src/app/webview_manager.rs

@@ -250,12 +250,12 @@ impl<A: ApplicationExt + 'static> WebviewManager<A> {
       .lock()
       .await
       .push(label.to_string());
-    let (webview_builder, callbacks, custom_protocol) =
+    let (webview_builder, rpc_handler, custom_protocol) =
       self.application.init_webview(webview).await?;
 
     let window_dispatcher = self.current_webview().await?.dispatcher.create_webview(
       webview_builder,
-      callbacks,
+      rpc_handler,
       custom_protocol,
     )?;
     let webview_manager = Self::new(

+ 1 - 1
tauri/src/endpoints/file_system.rs

@@ -374,7 +374,7 @@ mod test {
   //       .resizable(true)
   //       .debug(true)
   //       .user_data(())
-  //       .invoke_handler(|_wv, _arg| Ok(()))
+  //       .invoke_handler(|_wv, _command, _arg| Ok(()))
   //       .content(Content::Html(content))
   //       .build()?,
   //   )

+ 6 - 1
tauri/src/plugin.rs

@@ -39,6 +39,7 @@ pub trait Plugin<A: ApplicationExt + 'static>: Send + Sync {
   async fn extend_api(
     &mut self,
     webview_manager: WebviewManager<A>,
+    command: String,
     payload: &JsonValue,
   ) -> crate::Result<JsonValue> {
     Err(crate::Error::UnknownApi(None))
@@ -123,11 +124,15 @@ pub(crate) async fn ready<A: ApplicationExt + 'static>(
 pub(crate) async fn extend_api<A: ApplicationExt + 'static>(
   store: &PluginStore<A>,
   webview_manager: &crate::WebviewManager<A>,
+  command: String,
   arg: &JsonValue,
 ) -> crate::Result<Option<JsonValue>> {
   let mut plugins = store.lock().await;
   for ext in plugins.iter_mut() {
-    match ext.extend_api(webview_manager.clone(), arg).await {
+    match ext
+      .extend_api(webview_manager.clone(), command.clone(), arg)
+      .await
+    {
       Ok(value) => {
         return Ok(Some(value));
       }

برخی فایل ها در این مقایسه diff نمایش داده نمی شوند زیرا تعداد فایل ها بسیار زیاد است