Where is my Electron App located - node.js

I have an electron app, that also operates on files in the same directory. These are not files the user selects, or files bundled inside the electron application, but I do need to reference them
for example:
/Users/test/Documents/myapp.app
/Users/test/Documents/example.zip
I need to know where that application is located, e.g.:
/Users/test/Documents
But instead when test.app is ran I get:
/Users/test/Documents/myapp.app/Contents/Resources/app/
Resulting in errors when it tries to access /Users/test/Documents/myapp.app/Contents/Resources/app/test.zip, or if I use a relative path, /test.zip.
How would I reliably access example.zip in this scenario? Note that I cannot bundle it with my app, it's being placed there by somebody else, so moving it is not an option, and it's a file I'm expecting to be there.

A friend and I looked up how Atom does it and arrived at this solution:
function getAppRoot() {
if ( process.platform === 'win32' ) {
return path.join( app.getAppPath(), '/../../../' );
} else {
return path.join( app.getAppPath(), '/../../../../' );
}
}

I think either app.getPath('exe') or process.execPath is what you are looking for. They both give you the path of the currently used executable.
Edit: Look at the docs for app.getPath() to get the paths of all the different folder (e.g. home, appdata, documents, etc.)

Where are you running the Electron App? If it is running under 'Documents' (I am assuming Windows), you can pass in the documents to app.getPath like so: app.getPath('documents').
If you are calling this from the render process, you might have to import remote and do the following if you are in a render process remote.app.getPath('documents');.
This electron doc will be better at explaining the path options you can pass in.

You can use the fs.readdir function to list all the files that are in a particular directory (could be your app's or anywhere). You can make a directory from the code to put all the new files so it would be easier for you to list them out properly to process.
const testFolder = './tests/';
const fs = require('fs');
fs.readdir(testFolder, (err, files) => {
files.forEach(file => {
console.log(file);
});
});
How do you get a list of the names of all files present in a directory in Node.js?

Related

How to add Multiple public folders in remix.run

I am currently trying to build a electron app using Remix. Thanks to this great setup here https://github.com/itsMapleLeaf/remix-electron.
My requirements is as follows.
When the user uploads an asset, I store it inside a folder xyz in the app path. For mac is /Users/xyz/Application Support/app-folder/assets. I need to show these assets as image tags in electron view. But it fails to locate these files as the public folder is set to /build/. I tried using the file:/// protocol with absolute path but that didn't work as well.
The above repo has a config to set the public folder and that works, but then app stops working as it expects to find JS assets in /build/ folder. And I am not able to dynamically set the "publicPath" value in remix.config.js.
The solution I am looking for, is to have two public folders. 1. default /build/ folder and another one from app location. So remix can serve assets from both paths.
Any help is highly appreciated.
Thank you.
You'll need to update the remix-electron source.
In main.ts, you'll see where it gets all the asset files. You can include your other folders here. Note this is done at initialization, so any dynamically added files won't be included later. You'll need to export a function that lets you add to the asset files.
let [assetFiles] = await Promise.all([
collectAssetFiles(publicFolder),
collectAssetFiles(otherPublicFolder), // add additional folders
app.whenReady(),
])
https://github.com/itsMapleLeaf/remix-electron/blob/20352cc20f976bed03ffd20354c2d011e5ebed64/src/main.ts#L55-L58
Another option is to update the serveAsset function. This is called on every request with the path. You can then check your list of public folders for the asset. This will pickup any new files added.
export async function serveAsset(
request: Electron.ProtocolRequest,
files: AssetFile[],
): Promise<Electron.ProtocolResponse | undefined> {
const url = new URL(request.url)
// TODO: try different folders for list of files to check
const file = files.find((file) => file.path === url.pathname)
if (!file) return
return {
data: await file.content(),
mimeType: mime.getType(file.path) ?? undefined,
}
}
https://github.com/itsMapleLeaf/remix-electron/blob/20352cc20f976bed03ffd20354c2d011e5ebed64/src/asset-files.ts#L24-L37

Best way to copy a directory from an external drive to a local folder with electronjs?

Just wondering if anyone has ever attempted to copy a directory from an external drive (connected via USB) to a local folder.
I am using ElectronJS so I can use my JavaScript, HTML/CSS skills to create a desktop application without utilising a C language. (i.e. C# or C++) With ElectronJS there's a lot less to worry about.
Here is the list of things I've tried so far:
basic fs.copyFile (using copyFile intially and will then loop round the directory to copy all files)
var fs = require('fs');
window.test = () => {
fs.moveSync("targetFile","destDir", function(err) {
if(err){
console.log(err);
}else{
console.log("copy complete")
}
});
}
fs.moveSync is not a function even though Visual Studio Code brought up moveSync as a suggestion when I entered fs. (ctrl + space)
using child_process functions to copy files using the command line.
Code is:
var process = require('child_process')
window.test = function(){
process.exec('ipconfig', function(err, stdout, stderr){
if(err){
console.log(err);
}else{
console.log(stdout)
}
})
}
Then bundled with browserify. Bundle.js is then imported into the html file and the test function is called on the click of a button. I'm aware the command is ipconfig for now, this was merely used to see if a command could be executed. It appears it could because I was getting process.exec is not defined.
use the node-hid node module to read and trasfer data from the external drive.
The exposed functions within this module were also reported as being undefined. And I thought about the use case longer I thought a simple copy process would suffice because external drive can be accessed like any other folder in the file explorer.
Unfortunately, all of the above have failed and I've spent the most part of the day looking for alternative modules and/or solutions.
Thanks in advance because any help to achieve this would be much appreciated.
Thanks
Patrick
The npm package fs-extra should solve your problem.
It has the move function, which
Moves a file or directory, even across devices
Ended up adding this to my preload.js for:
window.require = require;
It will work for now but is due to be depreciated.
I'll use this for now and make other updates when I have to.

how to prompt where to download zip file created with archiver in node

I am trying to create a zip file in node using the code provided from how to create a zip file in node given multiple downloadable links, as shown below:
var fs = require('fs');
var archiver = require('archiver');
var output = fs.createWriteStream('./example.zip');
var archive = archiver('zip', {
gzip: true,
zlib: { level: 9 } // Sets the compression level.
});
archive.on('error', function(err) {
throw err;
});
// pipe archive data to the output file
archive.pipe(output);
// append files
archive.file('/path/to/file0.txt', {name: 'file0-or-change-this-whatever.txt'});
archive.file('/path/to/README.md', {name: 'foobar.md'});
//
archive.finalize();
When I use this suggestion, the zip file is downloaded without any kind of prompt asking me where I would like to save the file - is there any way I can make it so that a prompt is created asking me where I would like to save the file, which is quite normal these days?
If this is absolutely not possible, would it be possible to always save the file in the downloads folder (regardless of whether on mac or windows or any other operating system)?
So there's a couple of things here. In terms of a 'prompt' or 'pop-up' you won't find anything along the lines of WinForms out of the box, there are options for the command line such as prompts You can use that as your user input.
https://www.npmjs.com/package/prompts
You'll want to use path and more specifically path.join() to combat the mac/windows/linux issue.
Do you need to use path.join in node.js?
You can run an express server and create a route that uses res.download() in which you would provide the zipped file.
https://expressjs.com/en/api.html#res.download

node.js issues with Meteor's file system

I have tried to figure out what i am missing from this puzzle between. Node.js and Meteor.js. Meteor is built on Node.js i know this. But Meteor doesn't not work properly with Node.js. Either I need to do 20 more steps to get the same result, which I don't know what they are. Or there is a serious bug between the two. Standalone Node.js runs the command below just fine. Running the same commands on Meteor cause errors or undefined results. Wish i had a why to solve this or they need to patch this so it will work the way it should work.
examples #1
var fs = require('fs');
fs.readFile('file.txt', 'utf8', function (err,data) {
if (err) {
return console.log(err);
}
console.log(data);
});
example #2
var jetpack = require('fs-jetpack');
var data = jetpack.read('file.txt');
console.log(data);
example #3
var fs = require ('fs');
var readMe = fs.readFileSync('file.txt', 'utf8');
console.log(readMe);
You shouldn't try to load files like this because you don't know what the folder structure looks like. Meteor creates builds from your project directory, both in development and production mode. This means that even though you have a file.txt in your project folder, it doesn't end up in the same place in the build (or it isn't even included in the build at all).
For example, your code tries to read the file from the development build folder .meteor/local/build/programs/server. However, this folder doesn't contain file.txt.
Solution: Store file.txt in the private folder of your project and use Assets.getText to read it. If you still want to use the functions from fs to load the file, you can retrieve the absolute path with Assets.absoluteFilePath.

Node js module mkdirp only creates half the directories

I'm trying to use mkdirp for a project, but when I feed it a var with my dir path I want created, it only creates the first half of it. I've installed the module locally with npm. I'm using Node v0.10.20 on a Raspberry Pi.
This is how it looks:
var filePath = "upload/home/pi/app/temp";
mkdirp(filePath, function(error) {
if(error) {
console.log(error);
} else {
...
}
});
I don't get an error creating the path, but it only creates "upload/home/pi", however if I run my script again, it creates the rest of the directory structure. Upload is a
directory in the current working directory which is the user home.
I emailed the author of the module who suggested that it could be because I'm using a flash drive as my medium, which in turn lies about when IO operations are complete, which I guess confuses node.js to think it has successfully written the path to disk. How should I tackle my problem? I guess I can do a check on if the directory was created, and loop that until it has, but that feels like the wrong thing to do. Any suggestions welcome.
Thanks.
Try doing this synchronously:
var filePath = "upload/home/pi/app/temp";
mkdirp(filePath)

Resources