From b4a08e88fd423a8eb90be271daeea6b6be28c4bb Mon Sep 17 00:00:00 2001 From: Lucas Fernandes Nogueira Date: Sat, 14 Mar 2020 11:08:13 -0300 Subject: [PATCH] feat(example) add API showcase to communication example (#511) --- cli/tauri.js/src/runner.ts | 16 +- cli/tauri.js/templates/tauri.js | 42 +--- .../communication/dist/communication.js | 29 +++ tauri/examples/communication/dist/fs.js | 46 +++++ tauri/examples/communication/dist/index.html | 60 +++--- .../communication/dist/index.tauri.html | 189 +++++++++++------- tauri/examples/communication/dist/window.js | 19 ++ 7 files changed, 265 insertions(+), 136 deletions(-) create mode 100644 tauri/examples/communication/dist/communication.js create mode 100644 tauri/examples/communication/dist/fs.js create mode 100644 tauri/examples/communication/dist/window.js diff --git a/cli/tauri.js/src/runner.ts b/cli/tauri.js/src/runner.ts index b5f2597fc..d336055e8 100644 --- a/cli/tauri.js/src/runner.ts +++ b/cli/tauri.js/src/runner.ts @@ -11,8 +11,7 @@ import logger from './helpers/logger' import onShutdown from './helpers/on-shutdown' import { spawn, spawnSync } from './helpers/spawn' import { TauriConfig } from './types/config' -// eslint-disable-next-line @typescript-eslint/no-var-requires -const getTauriConfig = require('./helpers/tauri-config') +import getTauriConfig from './helpers/tauri-config' const log = logger('app:tauri', 'green') const warn = logger('app:tauri (runner)', 'red') @@ -105,17 +104,20 @@ class Runner { path.join(tauriDir, 'build.rs'), path.join(tauriDir, 'tauri.conf.json'), ...tauriPaths - ], + ].concat(runningDevServer ? [] : [devPath]), { - ignoreInitial: true + ignoreInitial: true, + ignored: runningDevServer ? null : path.join(devPath, 'index.tauri.html') } ) .on( 'change', - debounce((path: string) => { + debounce((changedPath: string) => { (this.pid ? this.__stopCargo() : Promise.resolve()) .then(() => { - if (path.includes('tauri.conf.json')) { + const shouldTriggerRun = changedPath.includes('tauri.conf.json') || + changedPath.startsWith(devPath) + if (shouldTriggerRun) { this.run(getTauriConfig({ ctx: cfg.ctx })).catch(e => { throw e }) @@ -243,7 +245,7 @@ class Runner { }) } - if (cfg.tauri.embeddedServer.active || !cfg.tauri.inliner.active) { + if ((!cfg.ctx.dev && cfg.tauri.embeddedServer.active) || !cfg.tauri.inliner.active) { rewriteHtml(readFileSync(indexPath).toString(), domInterceptor) resolve(inlinedAssets) } else { diff --git a/cli/tauri.js/templates/tauri.js b/cli/tauri.js/templates/tauri.js index 56b336980..041be01d3 100644 --- a/cli/tauri.js/templates/tauri.js +++ b/cli/tauri.js/templates/tauri.js @@ -267,7 +267,7 @@ window.tauri = { if (_typeof(cfg) === 'object') { Object.freeze(cfg); } - this.invoke({ + return this.promisified({ cmd: 'writeFile', file: cfg.file, contents: cfg.contents @@ -282,45 +282,25 @@ window.tauri = { <% if (ctx.dev) { %> /** - * @name listFiles - * @description Get the files in a path. + * @name readDir + * @description Reads a directory * Permissions based on the app's PID owner * @param {String} path + * @param {Object} [options] + * @param {Boolean} [options.recursive] * @returns {*|Promise|Promise} */ <% } %> - listFiles: function listFiles(path) { - <% if (tauri.whitelist.listFiles === true || tauri.whitelist.all === true) { %> + readDir: function readDir(path, options) { + <% if (tauri.whitelist.readDir === true || tauri.whitelist.all === true) { %> return this.promisified({ - cmd: 'listFiles', - path: path + cmd: 'readDir', + path: path, + options: options }); <% } else { %> <% if (ctx.dev) { %> - return __whitelistWarning('listDirs') - <% } %> - return __reject() - <% } %> - }, - - <% if (ctx.dev) { %> - /** - * @name listDirs - * @description Get the directories in a path. - * Permissions based on the app's PID owner - * @param {String} path - * @returns {*|Promise|Promise} - */ - <% } %> - listDirs: function listDirs(path) { - <% if (tauri.whitelist.listDirs === true || tauri.whitelist.all === true) { %> - return this.promisified({ - cmd: 'listDirs', - path: path - }); - <% } else { %> - <% if (ctx.dev) { %> - return __whitelistWarning('listDirs') + return __whitelistWarning('readDir') <% } %> return __reject() <% } %> diff --git a/tauri/examples/communication/dist/communication.js b/tauri/examples/communication/dist/communication.js new file mode 100644 index 000000000..84e224a90 --- /dev/null +++ b/tauri/examples/communication/dist/communication.js @@ -0,0 +1,29 @@ +window.onTauriInit = function () { + window.tauri.listen('rust-event', function (res) { + document.getElementById('response').innerHTML = JSON.stringify(res) + }) +} + +document.getElementById('log').addEventListener('click', function () { + window.tauri.invoke({ + cmd: 'logOperation', + event: 'tauri-click', + payload: 'this payload is optional because we used Option in Rust' + }) +}) + +document.getElementById('request').addEventListener('click', function () { + window.tauri.promisified({ + cmd: 'performRequest', + endpoint: 'dummy endpoint arg', + body: { + id: 5, + name: 'test' + } + }).then(registerResponse).catch(registerResponse) +}) + +document.getElementById('event').addEventListener('click', function () { + window.tauri.emit('js-event', 'this is the payload string') +}) + diff --git a/tauri/examples/communication/dist/fs.js b/tauri/examples/communication/dist/fs.js new file mode 100644 index 000000000..2a44bd18f --- /dev/null +++ b/tauri/examples/communication/dist/fs.js @@ -0,0 +1,46 @@ +function arrayBufferToBase64(buffer, callback) { + var blob = new Blob([buffer], { + type: 'application/octet-binary' + }) + var reader = new FileReader() + reader.onload = function (evt) { + var dataurl = evt.target.result + callback(dataurl.substr(dataurl.indexOf(',') + 1)) + } + reader.readAsDataURL(blob) +} + +var pathInput = document.getElementById('path-to-read') + +addClickEnterHandler( + document.getElementById('read'), + pathInput, + function () { + var pathToRead = pathInput.value + var isFile = pathToRead.match(/\S+\.\S+$/g) + var promise = isFile ? window.tauri.readBinaryFile(pathToRead) : window.tauri.readDir(pathToRead) + promise.then(function (response) { + if (isFile) { + if (pathToRead.includes('.png') || pathToRead.includes('.jpg')) { + arrayBufferToBase64(new Uint8Array(response), function (base64) { + var src = 'data:image/png;base64,' + base64 + registerResponse('') + }) + } else { + var value = String.fromCharCode.apply(null, response) + registerResponse('') + var fileInput = document.getElementById('file-response') + fileInput.value = value + document.getElementById('file-save').addEventListener('click', function () { + window.tauri.writeFile({ + file: pathToRead, + contents: fileInput.value + }).catch(registerResponse) + }) + } + } else { + registerResponse(response) + } + }).catch(registerResponse) + } +) diff --git a/tauri/examples/communication/dist/index.html b/tauri/examples/communication/dist/index.html index 420b140cb..22b30d063 100644 --- a/tauri/examples/communication/dist/index.html +++ b/tauri/examples/communication/dist/index.html @@ -5,39 +5,43 @@ -
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + + + - \ No newline at end of file + diff --git a/tauri/examples/communication/dist/index.tauri.html b/tauri/examples/communication/dist/index.tauri.html index d614632d8..d26a09931 100644 --- a/tauri/examples/communication/dist/index.tauri.html +++ b/tauri/examples/communication/dist/index.tauri.html @@ -73,8 +73,29 @@ function _defineProperty(obj, key, value) { if (key in obj) { Object.definePrope function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } +/** + * @name return __whitelistWarning + * @description Present a stylish warning to the developer that their API + * call has not been whitelisted in tauri.conf.json + * @param {String} func - function name to warn + * @private + */ +var __whitelistWarning = function (func) { + console.warn('%c[Tauri] Danger \ntauri.' + func + ' not whitelisted 💣\n%c\nAdd to tauri.conf.json: \n\ntauri: \n whitelist: { \n ' + func + ': true \n\nReference: https://github.com/tauri-apps/tauri/wiki' + func, 'background: red; color: white; font-weight: 800; padding: 2px; font-size:1.5em', ' ') + return __reject() + } + + /** + * @name __reject + * @description generates a promise used to deflect un-whitelisted tauri API calls + * Its only purpose is to maintain thenable structure in client code without + * breaking the application + * * @type {Promise} + * @private + */ + var __reject = function () { return new Promise(function (_, reject) { reject(); @@ -83,11 +104,25 @@ var __reject = function () { window.tauri = { + /** + * @name invoke + * @description Calls a Tauri Core feature, such as setTitle + * @param {Object} args + */ + invoke: function invoke(args) { window.external.invoke(JSON.stringify(args)); }, + /** + * @name listen + * @description Add an event listener to Tauri backend + * @param {String} event + * @param {Function} handler + * @param {Boolean} once + */ + listen: function listen(event, handler) { var once = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false; @@ -101,17 +136,32 @@ window.tauri = { }, + /** + * @name emit + * @description Emits an evt to the Tauri back end + * @param {String} evt + * @param {Object} payload + */ + emit: function emit(evt, payload) { this.invoke({ cmd: 'emit', event: evt, - payload: payload || '' + payload: payload }); }, + /** + * @name transformCallback + * @description Registers a callback with a uid + * @param {Function} callback + * @param {Boolean} once + * @returns {*} + */ + transformCallback: function transformCallback(callback) { var once = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; var identifier = uid(); @@ -128,6 +178,13 @@ window.tauri = { }, + /** + * @name promisified + * @description Turns a request into a chainable promise + * @param {Object} args + * @returns {Promise} + */ + promisified: function promisified(args) { var _this = this; @@ -140,6 +197,14 @@ window.tauri = { }, + /** + * @name readTextFile + * @description Accesses a non-binary file on the user's filesystem + * and returns the content. Permissions based on the app's PID owner + * @param {String} path + * @returns {*|Promise|Promise} + */ + readTextFile: function readTextFile(path) { return this.promisified({ @@ -150,6 +215,14 @@ window.tauri = { }, + /** + * @name readBinaryFile + * @description Accesses a binary file on the user's filesystem + * and returns the content. Permissions based on the app's PID owner + * @param {String} path + * @returns {*|Promise|Promise} + */ + readBinaryFile: function readBinaryFile(path) { return this.promisified({ @@ -160,12 +233,21 @@ window.tauri = { }, + /** + * @name writeFile + * @description Write a file to the Local Filesystem. + * Permissions based on the app's PID owner + * @param {Object} cfg + * @param {String} cfg.file + * @param {String|Binary} cfg.contents + */ + writeFile: function writeFile(cfg) { if (_typeof(cfg) === 'object') { Object.freeze(cfg); } - this.invoke({ + return this.promisified({ cmd: 'writeFile', file: cfg.file, contents: cfg.contents @@ -174,25 +256,32 @@ window.tauri = { }, - listFiles: function listFiles(path) { + /** + * @name readDir + * @description Reads a directory + * Permissions based on the app's PID owner + * @param {String} path + * @param {Object} [options] + * @param {Boolean} [options.recursive] + * @returns {*|Promise|Promise} + */ + + readDir: function readDir(path, options) { return this.promisified({ - cmd: 'listFiles', - path: path + cmd: 'readDir', + path: path, + options: options }); }, - listDirs: function listDirs(path) { - - return this.promisified({ - cmd: 'listDirs', - path: path - }); - - }, - + /** + * @name setTitle + * @description Set the application's title + * @param {String} title + */ setTitle: function setTitle(title) { @@ -204,6 +293,12 @@ window.tauri = { }, + /** + * @name open + * @description Open an URI + * @param {String} uri + */ + open: function open(uri) { this.invoke({ @@ -214,6 +309,15 @@ window.tauri = { }, + /** + * @name execute + * @description Execute a program with arguments. + * Permissions based on the app's PID owner + * @param {String} command + * @param {String|Array} args + * @returns {*|Promise|Promise} + */ + execute: function execute(command, args) { @@ -229,21 +333,6 @@ window.tauri = { }, -bridge: function bridge(command, payload) { - - - if (_typeof(payload) === 'object') { - Object.freeze(payload); - } - - return this.promisified({ - cmd: 'bridge', - command: command, - payload: _typeof(payload) === 'object' ? [payload] : payload - }); - - }, - loadAsset: function loadAsset(assetName, assetType) { return this.promisified({ cmd: 'loadAsset', @@ -304,44 +393,4 @@ if (document.readyState === 'complete' || document.readyState === 'interactive') __openLinks() }, true) } - -
- - - -
-
- - - \ No newline at end of file +
\ No newline at end of file diff --git a/tauri/examples/communication/dist/window.js b/tauri/examples/communication/dist/window.js new file mode 100644 index 000000000..9edd9aea3 --- /dev/null +++ b/tauri/examples/communication/dist/window.js @@ -0,0 +1,19 @@ +var urlInput = document.getElementById('url') + +addClickEnterHandler( + document.getElementById('open-url'), + urlInput, + function () { + window.tauri.open(urlInput.value) + } +) + +var titleInput = document.getElementById('title') + +addClickEnterHandler( + document.getElementById('set-title'), + titleInput, + function () { + window.tauri.setTitle(titleInput.value) + } +)