How do I write data to stdin of child_process in Firefox Add-on SDK? - firefox-addon

The child_process Add-on SDK docs state that the child_process module implements the node.js child_process API. So, I'm trying to spawn a sub-process and write data to it as described in the node.js docs section covering the spawn method:
var child_process = require("sdk/system/child_process");
var doiuse = child_process.spawn("/usr/local/bin/doiuse");
doiuse.stdin.write(data);
But I get this error:
TypeError: doiuse.stdin.write is not a function
So, how do I write to a child process in the Firefox Add-on SDK?

In the #jetpack IRC channel, it was suggested to use code like the child_process tests. So, I got it working with:
const { emit } = require('sdk/event/core');
const { spawn } = require('sdk/system/child_process');
var proc = spawn("/bin/cat");
emit(proc.stdin, 'data', "Hello from Add-on code");
emit(proc.stdin, 'end');

Related

Firebase Functions iOS Returns Error Not Found

I have built and deployed the default 'Hello World' firebase functions, however when I try and call it the error message is 'NOT FOUND'. Any help would be greatly appreciated. Thanks
Swift Code
func cloudRequest(){
functions.httpsCallable("testFunction").call("") {(result, error) in
if let error = error as? NSError{
switch FunctionsErrorCode(rawValue: error.code) {
case .internal:
print("Internal error \(error.localizedDescription)")
default:
print("Error \(error.localizedDescription)")
}
}
print("Running result condition")
if error == nil{
print(result?.data)
}
}
}
The code for the function deployed in GCP eu west 2 is
exports.helloWorld = (req, res) => {
let message = req.query.message || req.body.message || 'Hello World!';
res.status(200).send(message);
};
check whether the function name is correct
To call a function running in any location other than the default us-central1, you must set the appropriate value at initialization. For example, on Android you would initialize with getInstance(FirebaseApp app, String region).
Ex, lets assume europe-west3 where your function deployed; to call this function
functions('europe-west3').httpsCallable('testFunction')(/* ... */)
Useful ref:
https://firebase.google.com/docs/functions/callable#initialize_the_client_sdk
As per the updated code, it seems that the target Firebase Function is called helloWorld, not testFunction. Moreover, it is located in region europe-west2. Actually, it also seems like you are using Cloud Functions instead of Firebase Functions.
Notice that a Firebase project has a GCP counterpart, therefore a Firebase Function appears in both projects but a GCP project does not necessarily have a Firebase project linked to it. You will find more information on this in the documentation.
If you intend to call the Cloud Function from iOS, I suggest you move to Firebase Functions, where you will be able to use the Firebase SDK to trigger the function (what you intended to do).
Firebase library
Use these instructions to learn how to properly write a Firebase Functions and how to deploy it. You should have something like this:
'use strict';
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
exports.helloWorld = functions.region('europe-west2').https.onRequest((req, res) => {
let message = req.query.message || req.body.message || 'Hello World!';
res.status(200).send(message);
});
Notice that the region is specified when creating the function, otherwise it would be created in us-central1.
After that, it will be possible to reach the function using Firebase from you iOS app.
lazy var functions = Functions.functions(region:"europe-west2")
functions.httpsCallable("helloWorld").call() { (result, error) in
// code
}
This method forces you to deploy a Firebase Function on a Firebase project, it does not work on a GCP-only project.
HTTP Trigger
If you intend to keep using GCP, you can access your deployed functions using their HTTP trigger. In this case it would be something like the following but with the correct project ID:
https://europe-west2-PROJECT_ID.cloudfunctions.net/helloWorld
This method also works using a Firebase Function.

Nodejs child_process spawn calling python script with sleep

I'm testing on nodejs child_process module to read the stdout from my python script. However, I noticed when my python emit message between every second. The nodejs callback can only collect the stdout at the end of the python script ends.
Python Script
import time
for i in range(0,5):
····print i
····time.sleep(0.5)
and the nodejs script is
var cp = require('child_process');
var spw = cp.spawn('python', ['tql.py']),
str = "";
spw.stdout.on('data', function (data) {
str+= data;
console.log(data);
});
spw.on('close', function (code) {
console.log(str);
});
spw.stderr.on('data', function (data) {
console.log('stderr: ' + data);
});
Instead of emit message each second, my program only calls the callback when the python script ends. Is there anything I need to know in order to achieve my goal?

Open external file with Electron

I have a running Electron app and is working great so far. For context, I need to run/open a external file which is a Go-lang binary that will do some background tasks.
Basically it will act as a backend and exposing an API that the Electron app will consume.
So far this is what i get into:
I tried to open the file with the "node way" using child_process but i have fail opening the a sample txt file probably due to path issues.
The Electron API expose a open-file event but it lacks of documentation/example and i don't know if it could be useful.
That's it.
How i open an external file in Electron ?
There are a couple api's you may want to study up on and see which helps you.
fs
The fs module allows you to open files for reading and writing directly.
var fs = require('fs');
fs.readFile(p, 'utf8', function (err, data) {
if (err) return console.log(err);
// data is the contents of the text file we just read
});
path
The path module allows you to build and parse paths in a platform agnostic way.
var path = require('path');
var p = path.join(__dirname, '..', 'game.config');
shell
The shell api is an electron only api that you can use to shell execute a file at a given path, which will use the OS default application to open the file.
const {shell} = require('electron');
// Open a local file in the default app
shell.openItem('c:\\example.txt');
// Open a URL in the default way
shell.openExternal('https://github.com');
child_process
Assuming that your golang binary is an executable then you would use child_process.spawn to call it and communicate with it. This is a node api.
var path = require('path');
var spawn = require('child_process').spawn;
var child = spawn(path.join(__dirname, '..', 'mygoap.exe'), ['game.config', '--debug']);
// attach events, etc.
addon
If your golang binary isn't an executable then you will need to make a native addon wrapper.
Maybe you are looking for this ?
dialog.showOpenDialog refer to: https://www.electronjs.org/docs/api/dialog
If using electron#13.1.0, you can do like this:
const { dialog } = require('electron')
console.log(dialog.showOpenDialog({ properties: ['openFile', 'multiSelections'] }))
dialog.showOpenDialog(function(file_paths){
console.info(file_paths) // => this gives the absolute path of selected files.
})
when the above code is triggered, you can see an "open file dialog" like this (diffrent view style for win/mac/linux)
Electron allows the use of nodejs packages.
In other words, import node packages as if you were in node, e.g.:
var fs = require('fs');
To run the golang binary, you can make use of the child_process module. The documentation is thorough.
Edit: You have to solve the path differences. The open-file event is a client-side event, triggered by the window. Not what you want here.
I was also totally struggling with this issue, and almost seven years later the documentation is quite not clear what's the case with Linux.
So, on Linux it falls under Windows treatment in this regard, which means you have to look into process.argv global in the main processor, the first value in the array is the path that fired the app. The second argument, if one exist, is holding the path that requested the app to be opened. For example, here is the output for my test case:
Array(2)
0: "/opt/Blueprint/b-test"
1: "/home/husayngonzalez/2022-01-20.md"
length: 2
So, when you're creating a new window, you check for the length of process.argv and then if it was more than 1, i.e. = 2 it means you have a path that requested to be opened with your app.
Assuming you got your application packaged with the ability to process those files, and also you set the operating system to request your application to open those.
I know this doesn't exactly meet your specification, but it does cleanly separate your golang binary and Electron application.
The way I have done it is to expose the golang binary as a web service. Like this
package main
import (
"fmt"
"net/http"
)
func handler(w http.ResponseWriter, r *http.Request) {
//TODO: put your call here instead of the Fprintf
fmt.Fprintf(w, "HI there from Go Web Svc. %s", r.URL.Path[1:])
}
func main() {
http.HandleFunc("/api/someMethod", handler)
http.ListenAndServe(":8080", nil)
}
Then from Electron just make ajax calls to the web service with a javascript function. Like this (you could use jQuery, but I find this pure js works fine)
function get(url, responseType) {
return new Promise(function(resolve, reject) {
var request = new XMLHttpRequest();
request.open('GET', url);
request.responseType = responseType;
request.onload = function() {
if (request.status == 200) {
resolve(request.response);
} else {
reject(Error(request.statusText));
}
};
request.onerror = function() {
reject(Error("Network Error"));
};
request.send();
});
With that method you could do something like
get('localhost/api/somemethod', 'text')
.then(function(x){
console.log(x);
}

How to use a Windows native dll in a Mozilla Firefox 32+ add-on?

I’d like to resurrect an abandoned add-on that was created for Firefox 11. This add-on controlled a device via a native dll. With the Firefox 32 addon-api and ctx, I don’t see how to:
1) insert lengthy custom init code into bootstrap.js or harness-options.json.
2) include additional binaries into the xpi archive
3) discover or determine the executable path for use of external code within my add-on
I have a copy of the original old xpi. I can see how they put the required dll in “.\plugins\5.9.6.0000\foobar.dll”. I can see they used the “install” function in .\bootstrap.js. I’ve included some of the the original code from bootstrap.js here.
function registerPlugin()
{
var profPath = Components.classes["#mozilla.org/file/directory_service;1"].getService( Components.interfaces.nsIProperties).get("ProfD", Components.interfaces.nsIFile).path;
var wrk = Components.classes["#mozilla.org/windows-registry-key;1"]
.createInstance(Components.interfaces.nsIWindowsRegKey);
wrk.open(wrk.ROOT_KEY_CURRENT_USER, "SOFTWARE", wrk.ACCESS_ALL);
if(!wrk.hasChild("MozillaPlugins"))
wrk = wrk.createChild("MozillaPlugins", wrk.ACCESS_ALL);
else
wrk = wrk.openChild("MozillaPlugins", wrk.ACCESS_ALL);
var t1 = wrk.createChild("blueglow#hardcorps.com", wrk.ACCESS_ALL);
t1.writeStringValue("Description", "CanCan extension for BagMan");
t1.writeStringValue("ProductName", "CanCan extension for BagMan");
t1.writeStringValue("Vendor", "Hardcorps Inc.");
t1.writeStringValue("Version", "5.9.6.0000");
t1.writeStringValue("Path", profPath + "\\extensions\\blueglow#hardcorps.com\\plugins\\5.9.6.0000\\foobar.dll" );
var t2 = t1.createChild("MimeTypes", wrk.ACCESS_ALL);
t2.createChild("application/blueglow-ff-plugin", wrk.ACCESS_ALL);
t2.close();
t1.close();
wrk.close();
Components.classes['#mozilla.org/appshell/window-mediator;1']
.getService(Ci.nsIWindowMediator)
.getMostRecentWindow('navigator:browser')
.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
.getInterface(Components.interfaces.nsIWebNavigation)
.QueryInterface(Components.interfaces.nsIDocShellTreeItem)
.rootTreeItem
.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
.getInterface(Components.interfaces.nsIDOMWindow).navigator.plugins.refresh(false);
}
function install(data, reason)
{
registerPlugin();
}
Drop the dll into your addon and then use it via js-ctypes.
Here's an example on Mac, they use .dylib instead of .dll:
source: https://github.com/vasi/firefox-dock-progress/tree/master
compiled source: https://addons.mozilla.org/en-US/firefox/files/browse/185970/file/chrome/content/DockProgress.jsm

Is it possible to pass command-line arguments to a new isolate from spawnUri()

When starting a new isolate with spawnUri(), is it possible to pass command line args into that new isolate?
eg: Command line:
dart.exe app.dart "Hello World"
In app.dart
#import("dart:isolate");
main() {
var options = new Options();
print(options.arguments); // prints ["Hello World"]
spawnUri("other.dart");
}
In other.dart
main() {
var options = new Options();
print(options.arguments); // prints [] when spawned from app.dart.
// Is it possible to supply
// Options from another isolate?
}
Although I can pass data into other.dart through its SendPort, the specific use I want is to use another dart app that hasn't been created with a recievePort callback (such as pub.dart, or any other command-line app).
As far as I can tell the answer is currently no, and it would be hard to simulate via message passing because the options would not be available in main().
I think there are two good feature requests here. One is to be able to pass options on spawn() so that a script can run the same from the root isolate or a spawned isolate.
The other feature, which could be used to implement the first, is a way to pass messages that are handled by libraries before main() is invoked so that objects that main() depends on can be initialized with data from the spawning isolate.
Your example doesn't call print(options.arguments); in other.dart using the current stable SDK.
However
spanUri("other.dart");
spawns an Uri. So how about spawnUri("other.dart?param=value#orViaHash"); and try if you can find the param/value pair via
print(options.executable);
print(options.script);

Resources