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

This commit is contained in:
Lucas Fernandes Nogueira 2021-03-06 23:19:12 -03:00 committed by GitHub
parent e7f65ebdd7
commit b0c1009098
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
30 changed files with 327 additions and 276 deletions

View File

@ -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'

View File

@ -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: {

View File

@ -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',

View File

@ -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'

View File

@ -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
api/src/helpers/tauri.ts Normal file
View File

@ -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)
}

View File

@ -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',

View File

@ -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'

View File

@ -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',

View File

@ -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',

View File

@ -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

View File

@ -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',

View File

@ -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: {

View File

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

View File

@ -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 {},
}

View File

@ -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()

View File

@ -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)),
}
}
}

View File

@ -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]

View File

@ -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",

View File

@ -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: {

View File

@ -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",

File diff suppressed because one or more lines are too long

View File

@ -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",

View File

@ -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,

View File

@ -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

View File

@ -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>;

View File

@ -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)),

View File

@ -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(

View File

@ -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()?,
// )

View File

@ -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));
}