-
-
Notifications
You must be signed in to change notification settings - Fork 2.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[meta] Tracking issue for Node.js/Deno standard library inspired functions to include in @tauri-apps/api
#2233
Comments
Suggestion : get complete directory tree as JSON from a given folder, along with files with their metadata |
Sorry, I forgot to mention I am accepting only function suggestion from Nodejs standard library for now. Once I am done with this, I think I will make a plugin for extended api and will accept suggestion for anything. |
It would be great to have 'net.createConnection' from the Net API so that discord-rpc can work. |
@tauri-apps/api
I added
I will try to do my best but I am not sure if this will be a drop in replacement for the NodeJS one. |
Would be nice to have a synchronous api to access to files in a way that allows open/read/write/close (as mentions here #1025) to directly read/write large files without copying them into memory: Something like https://github.com/emscripten-core/emscripten/blob/main/src/library_nodefs.js |
A synchronous api is not possible, but I will add nodejs async function |
Sorry, a bit off-topic but Is that a design decision or technically impossible?
Since electron offers sync fs it will be difficult to migrate. Are there ways to customize/extend tauri to make a sync fs available in a webworker? |
yeah it is a kinda impossible technically.
you can wrap your logic in an async function and await our api calls. (async () => {
doSomething();
let file = await fs.readFile();
doSomethingWithFile(file);
})(); |
Regarding sync function calls, I do understand the technical limitations on why promises must be used. But just in case, it is possible to emulate (though inefficiently) a blocking synchronous function in JS from an asynchronous function. This can be done as follows: const syncFunctionNotDoneSymbol = Symbol(/* named, if you prefer */);
let valueToBeReturned = syncFunctionNotDoneSymbol;
export function syncFunction() {
asyncFunctionCall().then(result => valueToBeReturned = result);
while(valueToBeReturned === syncFunctionNotDoneSymbol) {
// burn CPU cycles...
}
// Reset the value, so subsequent function calls still work.
let val = valueToBeReturned;
valueToBeReturned = syncFunctionNotDoneSymbol;
return val;
} Two important things to note on my primitive implementation above:
It would also be a good idea, if such functionality is desired, to add a disclaimer in the sync function docs where you heavily discourage their use, due to them eating CPU cycles polling for the promise. But it might serve as a simple shim for large code bases until they are ported over. |
The impossible part isn't exposing a sync api, it was the other part of the request.
This is difficult in the current design because we use message passing to communicate with the WebView, meaning Rust loads the file and passes the bytes over to the webview into JS where it is consumed. To do that without copying into memory, there would need to be a way from JavaScript to directly load a file from the filesystem through the native WebView. Browsers don't have this, and AFAIK the native WebView libraries we use don't expose some way to do this. As for your sync version of async methods, I'm not sure if we will expose pseudo sync functions. IMO it matters less to have them since all the supported browsers have |
Thank you for your thoughts and insight, but ...
excuse the heresy - this is pretty much what I can do already in a good old browser: Ask for a file, load it entirely into memory, process it and ask for a save-as dialog. This is fine for small files but let's say I'd like to process a 500MB geotiff then I'll soon hit the limitations of the browser (and tauri's). The use-case I have in mind is running an emscripten compiled WebAssembly in a web worker to process local files. As of now I can not embed the wasm directly in rust (even if I could it has some advantages being able to run it within the webview). With electron I can run it in a worker and by setting I do not dare to ask for design changes but maybe there are ways to allow more customization on the rust level to inject an API (e.g. filesystem) in the worker context bypassing tauris async command (serde) api. Being able to combine WebAssembly, workers and tauri would create really interesting opportunities. |
I agree with you, that would be a really interesting interface and I would love to see it someday soon. Electron is in a fortunate place regarding this due to controlling both the backend and a custom build of Chromium. We provide Wry by default in Tauri to support the "native" OS browser (iOS/macOS = WkWebView, Linux = webkit2gtk, Windows = webview2) which would require all those libraries to support such functionality, and then apply Tauri APIs over it. As for regarding "this is pretty much what I can do already in a good old browser", that is relatively true. Browsers will let you open a local file from a prompt, some experimental APIs will even let you do it without a prompt, if the files are in the correct directory. These types of things can likely be implemented by a Tauri plugin, but only if the underlying platform supports it. I haven't look into it at all, but if you are interested in it then the results may be fruitful. Additionally, if you did want to support a custom runtime including things like preventing copying memory when reading large files, then you can implement |
I don't see it listed as a task (or maybe I misread), but adding file permissions when writing a file (not after the fact - race condition) would help tremendously for electron apps that needed to store sensitive data (e.g. passwords, secrets) that are not readable by groups or others. Example: // mode should be configurable, just showing as an example:
File::with_options().mode(600).open("somefile.txt"); |
@zoombinis it is listed under Edit: updated the list for more transparency |
I really need the |
@Lancear we are in a code-freeze phase and there won't be any new features to Tauri v1, so any new features will land in Tauri v2 check #2060 for more info. With that said, I gotta warn you, we might not be able to exactly replicate NodeJS' Pull requests to the |
@tauri-apps/api
@tauri-apps/api
@tauri-apps/api
@tauri-apps/api
Hello, I would also like to request the ability to read a file line by line, like the following in Node : import {
createReadStream
} from 'node:fs';
import {
createInterface
} from 'node:readline';
for await (const line of createInterface({
input: createReadStream(
path,
{
flags: 'a+'
}
),
crlfDelay: Infinity
})){
// TODO something with `line`
} Not necessarily by implementing exactly the same modules and methods as long as it does the same thing. Thanks |
@KaKi87 thanks for the suggestion, it has now been implemented in the linked PR and will look like this: const lines = await readTextFileLines('file.txt', { baseDir: BaseDirectory.App });
for await (const line of lines) {
console.log(line);
} Also, since each line will be lazily read as you advance through the iterator, it makes this function perfect for performance critical apps as you can manually advance the iterator by calling |
Nice one @amrbashir |
Exactly, thanks ! |
Any updates on the |
Does the
I was looking for ways to read files without loading the entire file into memory, but found issues like #4133 and this one Any workarounds for the current version of tauri? |
If you need it that bad, then you could call an external tool (maybe |
@KaKi87 that’s great for reading files! Do you have a workaround for writing files too? |
|
Ahh, I was looking at the |
Actually, with
I hope that a streaming version of file reading/writing can be added to the tauri |
You can, using
Indeed, my proposal should work as much on Mac as it does on Linux, but different commands would for sure be required on Windows.
Of course. That, or writing Rust code. |
any plans for I find that whatever apps I write, I always end up using How quickly I can sketch up an app is significantly faster with |
@adminy We already have this, see https://tauri.app/v1/api/js/shell |
We decided to most of the JS APIs into its own plugins in https://github.com/tauri-apps/plugins-workspace, most of the APIs proposed here are already implemented there or waiting for merge. The If anything is missing or doesn't have a PR open, feel free to open an issue in that repo. |
Where's the documentation for the |
fs-extra plugin has been removed and its functionality has been integrated into |
So, concretely, where will the |
That will be implemented in |
So it will never be available in v1 ? |
Not planned atm but it can be implemented in your app:
async function readTextFileLines(
path: string
): Promise<AsyncIterableIterator<string>> {
return Promise.resolve({
path,
rid: null as number | null,
async next(): Promise<IteratorResult<string>> {
if (!this.rid) {
this.rid = await invoke<number>('read_text_file_lines', { path: this.path })
}
const [line, done] = await invoke<number>('read_text_file_lines_next', { rid: this.rid })
// an iteration is over, reset rid for next iteration
if (done) this.rid = null
return {
value: done ? '' : (line as string),
done
}
},
[Symbol.asyncIterator](): AsyncIterableIterator<string> {
return this
}
})
}
#[tauri::command]
fn read_text_file_lines<R: Runtime>(app: AppHandle<R>, path: PathBuf) -> Result<u32, std::io::Error> {
use std::io::{BufRead, BufReader};
let file = File::open(path)?;
let lines = BufReader::new(file).lines();
let rid = 0 // generate a uniuqe ID for this request
// Assuming you have a `ResourceTable` struct where you store your resources
// and you stored it inside tauri state
// by calling `app.manage(ResourceTable::new())` in the `setup` function
// grab the resource table
let mut resource_table = app.state::<ResourceTable>().inner().lock().unwrap();
// store the lines iterator inside the resource table
resource_table.insert(lines);
// return the rid
Ok(rid)
}
#[tauri::command]
fn read_text_file_lines_next<R: Runtime>(app: AppHandle<R>, rid: u32) -> Result<(Option<String>, bool), std::io::Error> {
use std::io::Lines;
// grab the resource table
let mut resource_table = app.state::<ResourceTable>().inner().lock().unwrap();
// get the stored lines iterator for this rid
let lines = resource_table.get(&rid).unwrap();
let ret = lines
.next()
.map(|l| (l.ok(), false))
.unwrap_or_else(|| {
let _ = resource_table.remove(&rid).unwrap();
(None, true)
});
Ok(ret)
} |
Most of the APIs in this issue have been implemented in If there is any missing APIs, feel free to open an issue in plugins-workspace repo. |
updates on net? |
No work has been done on |
I will be refactoring our js api and aiming to make the it more familiar to users coming from electron/js-land so it is easier to migrate.
Some of current functions will be deprecated and removed when new variants are released.
We want to gather some feedback from users and which functions they want to add from the Nodejs standard library, so comment below and I will add them to this list of new functions:
os
moduleEOL
platform()
version()
tempdir()
hostname
path
modulejoin()
normalize()
resolve()
sep
delimiter
dirname()
basename()
extname()
isAbsolute()
fs
modulecreate()
open()
close()
FsFile
classwriteFile()
writeTextFile()
readFile()
readTextFile()
copyFile()
readDir()
mkdir()
remove()
rename()
exists()
net
modulecreateConnection()
dns
moduleThe text was updated successfully, but these errors were encountered: