How can I get information about the file that launched my app? - node.js

Similar to How to get the arguments for opening file with electron app but the solution there is not working for me.
Using:
OS - Windows 10
Electron - https://github.com/castlabs/electron-releases.git#v1.8.7-vmp1010
electron-builde - v20.28.3
I have a an electron app build with electron-builder, and using the latter I have specified a custom file association, .custom.
So when you double-click on a file with this extension, file.custom, the installed app opens. This file would have some data in it that the app needs, and I'd like to read this data using my app.
Is there any way that my app can detect what launched it, so that I can say "file.custom" launched me, and it's sitting at "C:\Users\Owner\Downloads\,?
The file does not appear in process.argv

You can get a reference to the file using process.argv, example:
var ipc = require('ipc');
var fs = require('fs');
// read the file and send data to the render process
ipc.on('get-file-data', function(event) {
var data = null;
if (process.platform == 'win32' && process.argv.length >= 2) {
var openFilePath = process.argv[1];
data = fs.readFileSync(openFilePath, 'utf-8');
}
event.returnValue = data;
});
source: Source

Related

How to use filesystem (fs) in angular-cli with electron-js

I have set up an angular-cli project
(# Angular / cli: 1.0.0-rc.2 node: 6.10.0 os: linux x64)
With electron js (v1.6.2)
And I need to use the filesystem to create / delete .csv files and folders, but I can not do includ in the angular component
How could you configure the angular-cli to be able to: import fs from 'fs'?
You wouldn't configure Angular-CLI to use the NodeJS fs module.
In electron you have 2 processes; main and renderer. The main process controls items such as the browserWindow, which is essentially the 'window' the user sees when they open their app, and in turn this loads the html file for the view. Here, in the main process, you import the fs module.
In the render process, you would handle actions from the view, and send them to the main process. This is where you would use IPC to communicate via events to do something with the main process. Once that event is triggered, the render process takes the event and sends it to main. Main would do something with it, and open a file for example on the desktop.
I would recommend using the electron API demo application to see clear examples of this. Here is an example of print to pdf using FS (from the demo app).
Also, here is an electron application github example written by Ray Villalobos using React, which has some similar concepts that will show you how to integrate components in your app.
Render process:
const ipc = require('electron').ipcRenderer
const printPDFBtn = document.getElementById('print-pdf')
printPDFBtn.addEventListener('click', function (event) {
ipc.send('print-to-pdf')
})
ipc.on('wrote-pdf', function (event, path) {
const message = `Wrote PDF to: ${path}`
document.getElementById('pdf-path').innerHTML = message
})
Main Process:
const fs = require('fs')
const os = require('os')
const path = require('path')
const electron = require('electron')
const BrowserWindow = electron.BrowserWindow
const ipc = electron.ipcMain
const shell = electron.shell
ipc.on('print-to-pdf', function (event) {
const pdfPath = path.join(os.tmpdir(), 'print.pdf')
const win = BrowserWindow.fromWebContents(event.sender)
// Use default printing options
win.webContents.printToPDF({}, function (error, data) {
if (error) throw error
fs.writeFile(pdfPath, data, function (error) {
if (error) {
throw error
}
shell.openExternal('file://' + pdfPath)
event.sender.send('wrote-pdf', pdfPath)
})
})
})
You can try using const fs = (<any>window).require("fs"); within the component or better still, create a service.ts provider to handle i/o operations.

Windows UWP CreateFIle2 cannot read file in ApplicationData.LocalFolder

I am trying to build UWP app in C#. My app has a native library written in C++. Whenever the app tries to read a file in ApplicationData.LocalFolder, CreateFile2 api is returning ERROR_NOT_SUPPORTED_IN_APPCONTAINER. The file exists in the path specified to this api.
This is the sequence of operation in my app.
Launch app. App creates file & writes some data
Later on based on user input app tries to read data in this file
Step 1 is working fine. App is able to create the file & write data in it. Only when app tries to access it later on, does it get this error.
I get the path to ApplicationData.LocalFolder using
Windows.Storage.ApplicationData.Current.LocalFolder.Path
This is the actual path I see in the app:
C:\Users\xxxxx\AppData\Local\Packages\ac7a11e4-c1d6-4d37-b9eb-a4b0dc8f67b8_yyjvd81p022em\LocalState\temp.txt
My code is as below:
CREATEFILE2_EXTENDED_PARAMETERS ms_param = {0};
ms_param.dwSize = sizeof(CREATEFILE2_EXTENDED_PARAMETERS);
ms_param.dwFileAttributes = FILE_ATTRIBUTE_READONLY;
ms_param.dwFileFlags = FILE_FLAG_NO_BUFFERING;
ms_param.dwSecurityQosFlags = SECURITY_DELEGATION;
ms_param.lpSecurityAttributes = NULL;
ms_param.hTemplateFile = NULL;
g_hfile = CreateFile2(filename, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, OPEN_EXISTING, &ms_param);
if (g_hfile == INVALID_HANDLE_VALUE)
{
return GetLastError();
}
I tried CreateFile2 with both OPEN_EXISTING & OPEN_ALWAYS option for dwCreationDisposition parameter, but I see the same error in either case.
I had similar issue with CreateFile2 earlier. But that was an problem with my app & I have fixed that issue. This time though the file is available within the LocalFolder, still I get the error.
The problem here is related to the dwSecurityQosFlags you've set in CREATEFILE2_EXTENDED_PARAMETERS.
When called from a Windows Store app, CreateFile2 is simplified. You can open only files or directories inside the ApplicationData.LocalFolder or Package.InstalledLocation directories. You can't open named pipes or mailslots or create encrypted files (FILE_ATTRIBUTE_ENCRYPTED).
The dwSecurityQosFlags parameter specifies SQOS information. In Windows Stroe app, we can only set it to SECURITY_ANONYMOUS. Using other flag will raise ERROR_NOT_SUPPORTED_IN_APPCONTAINER exception. This indicates that it is not supported in UWP app.
Following is the code I used to test:
StorageFolder^ localFolder = ApplicationData::Current->LocalFolder;
String^ path = localFolder->Path;
path += L"\\MyFile.txt";
CREATEFILE2_EXTENDED_PARAMETERS ms_param = { 0 };
ms_param.dwSize = sizeof(CREATEFILE2_EXTENDED_PARAMETERS);
ms_param.dwFileAttributes = FILE_ATTRIBUTE_READONLY;
ms_param.dwFileFlags = FILE_FLAG_NO_BUFFERING;
ms_param.dwSecurityQosFlags = SECURITY_ANONYMOUS;
ms_param.lpSecurityAttributes = NULL;
ms_param.hTemplateFile = NULL;
HANDLE g_hfile = CreateFile2(path->Data(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, OPEN_EXISTING, &ms_param);
DWORD error = GetLastError();
If I don't have "MyFile.txt" under LocalFolder, I will get ERROR_FILE_NOT_FOUND exception, otherwise it will be ERROR_SUCCESS.

Unable to read a saved file in heroku

I am using NodeJS on heroku.
I read a file from another server and save it into my application in the /temp directory.
Next, I read the same file to pass it on to my client.
The code that saves the file and then subsequently reads it is:
http.request(options, function (pdfResponse) {
var filename = Math.random().toString(36).slice(2) + '.pdf',
filepath = nodePath.join(process.cwd(),'temp/' + filename);
pdfResponse.on('end', function () {
fs.readFile(filepath, function (err, contents) {
//Stuff to do after reading
});
});
//Read the response and save it directly into a file
pdfResponse.pipe(fs.createWriteStream(filepath));
});
This works well on my localhost.
However, when deployed to heroku, I get the following error:
events.js:72
throw er; // Unhandled 'error' event
Error: ENOENT, open '/app/temp/nvks0626yjf0qkt9.pdf'
Process exited with status 8
State changed from up to crashed
I am using process.cwd() to ensure that the path is correctly used. But even then it did not help. As per the heroku documentation, I am free to create files in the applications directory, which I am doing. But I can't figure out why this is failing to read the file...
The error you describe there is consistent with /app/temp/ not existing. You need to create it before you start writing in it. The idea is:
var fs = require("fs");
var path = require("path");
var temp_dir = path.join(process.cwd(), 'temp/');
if (!fs.existsSync(temp_dir))
fs.mkdirSync(temp_dir);
I've used the sync version of the calls for illustrations purposes only. This code should be part of the start up code for your app (instead of being called for each request) and how you should structure it depends on your specific application.

intel XDK directory browsing

I'm trying to get a way to reach and parse all JSON file from a directory, witch inside an Intel Xdk project. All files in my case stored in '/cards' folder of the project.
I have tried to reach theme with fs.readdirSync('/cards') method, but that wasn't pointed to the location what I expected, and I haven't got luck with 'intel.xdk.webRoot' path.
With the simulator I've managed to get files, with a trick:
fs.readdirSync(intel.xdk.webRoot.replace('localhost:53862/http-services/emulator-webserver/ripple/userapp/', '')+'cards');
(intel.xdk.webRoot contains absolute path to my '/cards' folder)
and its work like a charm, but it isn't working in any real device what I'd like to build it.
I have tried it with iOS7 and Android 4.2 phones.
Please help me to use in a great way the fs.readdirSync() method, or give me some alternate solution.
Thanks and regards,
satire
You can't use nodejs api's on mobile apps. It is a bug that the XDK emulator lets you do it. The bug is fixed in the next release of XDK.
You could write a node program that scans the directory and then writes out a js file with the contents of the directory. You would run the node script on your laptop before packaging the app in the build tab. The output would look like this:
files.js:
dir = {files: ['file1.txt', 'file2.txt']}
Then use a script tag to load it:
And your js can read the dir variable. This assumes that the contents does not change while the app is running.
The location of your application's root directory will vary depending on the target platform and can also vary with the emulator and the debug containers (e.g., App Preview versus App Analyzer). Here's what I've done to locate files within the project:
// getWebPath() returns the location of index.html
// getWebRoot() returns URI pointing to index.html
function getWebPath() {
"use strict" ;
var path = window.location.pathname ;
path = path.substring( 0, path.lastIndexOf('/') ) ;
return 'file://' + path ;
}
function getWebRoot() {
"use strict" ;
var path = window.location.href ;
path = path.substring( 0, path.lastIndexOf('/') ) ;
return path ;
}
I have not been able to test this exhaustively, but it appears to be working so far. Here's an example where I'm using a Cordova media object and want it to play a file stored locally in the project. Note that I have to "special case" the iOS container:
var x = window.device && window.device.platform ;
console.log("platform = ", x) ;
if(x.match(/(ios)|(iphone)|(ipod)|(ipad)/ig)) {
var media = new Media("audio/bark.wav", mediaSuccess, mediaError, mediaStatus) ;
}
else {
var media = new Media(getWebRoot() + "/audio/bark.wav", mediaSuccess, mediaError, mediaStatus) ;
}
console.log("media.src = ", media.src) ;
media.play() ;
Not quite sure if this is what you are looking for...
You will need to use the Cordova build in the Intel XDK, here is information on building with Cordova:
https://software.intel.com/en-us/html5/articles/using-the-cordova-for-android-ios-etc-build-option
And a DirectoryReader example:
function success(entries) {
var i;
for (i=0; i<entries.length; i++) {
console.log(entries[i].name);
}
}
function fail(error) {
alert("Failed to list directory contents: " + error.code);
}
// Get a directory reader
var directoryReader = dirEntry.createReader();
// Get a list of all the entries in the directory
directoryReader.readEntries(success,fail);

Nodejs Backbone Templates

I have worked a lot with rails, requirejs and backbone and know how to use haml coffee templates in rails.
App = new Backbone.Marionette.Application()
App.addInitializer (options) ->
Backbone.history.start()
alert "yay"
$ ->
alert "yay"
App.start()
How do i do it in Node.js, I have a Node.js app and i am at a deadend with regards to how do i get a template to compile client side, i am not stuck on haml coffee, any template engine will do, jade is fine too, underscore too. Just a good starting point so that i can get on with building the backbone app in node.js.
Any Help is appreciated!
I don't suggest dragging the templates to the client and compiling them there,the right way would be to use some framework such as www.socketstream.com that offers what you want and much more. If you're against frameworks quick and dirty solution to compiling them on the server and calling them as function on the client will be :
// compile.js
var fs = require("fs")
,jade = require("jade");
exports.build = function(templatesDir) {
var js = "var Templates = {}; \n\n";
var files = fs.readdirSync(templatesDir);
var jadeFiles = files.filter(function(file) {
return file.substr(-5) === ".jade";
});
for(var i = 0; i < jadeFiles.length; ++i){
var filePath, key;
var file = jadeFiles[i];
key = file.substr(0, file.indexOf("."));
filePath = templatesDir + file;
var jadeSource = fs.readFileSync(filePath);
js += "Templates." + key + " = " + jade.compile(jadeSource, {
debug: false,
client: true
}).toString() + "; \n\n";
}
return js;
};
// On the server.js
// Compile views
var viewsPath = path.join(__dirname, 'views/');
var generatedJs = require('./compile').build(viewsPath);
var savePath = path.join(__dirname, 'public/js/lib/templates.js');
fs.writeFile(savePath, generatedJs, function (err) {
if (err) throw err;
});
// Then on the client include js/lib/templates.js and use templates like this
FactSummaryView = Backbone.View.extend({
template: Templates.issueSummary,
render: function() {
this.$el.html(this.template(this.model.toJSON()));
return this;
}
});
// Also add templates.js to nodemonignore if you're using nodemon
./public/js/lib/templates.js
/public/js/lib/templates.js
You usually don't compile the templates on the client (expect the templates are edited directly in the browser), instead they are compiled in the backend and rendered in the browser.
Compile the templates
In this step you compile the template source code to a JavaScript file that contains a render function.
You can either use haml-coffee on the command line and make a script in your build process or make use of the projects listed in the integration section of the Haml-Coffee README.
Grunt is a popular solution to run certain tasks and with Grunt-Haml you have certainly a flexible build solution for your project.
Render the templates
To render the templates with Marionette you need to make sure the template render function is available on the client. Just type the configured namespace into the developer tools to see if the template functions are registered:
If this is fine, you need to have a custom template render function:
Backbone.Marionette.Renderer.render = (template, data) ->
if JST[template]
JST[template](data)
else if _.isFunction(template)
template(data)
else
console.error 'Template %s not found', template
Now you can simply define the view template and it'll be rendered properly:
class App.Views.Login extends Backbone.Marionette.ItemView
template: 'shared/_login'

Resources