I'm trying to get a Parse server up and running locally. I'm following the readme that tells me to install parse-server and mongodb, then I run:
parse-server --appId {app_id} --masterKey {key} --databaseURI mongodb://localhost/test
When I try to hit my Parse app locally, with the url http://localhost:1337/parse, calling the foo function, I get this response in my terminal
error: Error handling request: ParseError { code: 141, message: 'Invalid function: "foo"' } code=141, message=Invalid function: "foo"
error: Invalid function: "foo" code=141, message=Invalid function: "foo"
foo is defined in main.js as:
Parse.Cloud.define('foo', function(request, resposne) {
response.success("hi");
});
It's called from my objc code as
[PFCloud callFunctionInBackground:#"foo" withParameters:nil block:^(NSString *res, NSError *error) {
if (error) {
NSLog([error description]);
} else {
NSLog(res);
}
}];
I'm also not able to call other functions in this code that I know work and are present. The issue seems to be not being able to locate the Parse server locally
Not quite sure what I'm doing wrong here, would love some help.
You need to specify a cloud function directory. For example, './cloud/main.js'
I'm not sure how to do that in command line, should be something like --cloud ./cloud/main.js
In your index.js file, it should look like this:
var api = new ParseServer({
databaseURI: 'mongodb://....',
cloud: process.env.CLOUD_CODE_MAIN || __dirname + '/cloud/main.js',
appId: process.env.APP_ID || '***',
masterKey: process.env.MASTER_KEY || '***',
serverURL: process.env.SERVER_URL || 'http://localhost:1337/parse'
});
And you can run node index.js to start server locally.
Related
Preamble
To start off, I'm not a developer; I'm just an analyst / product owner with time on their hands. While my team's actual developers have been busy finishing off projects before year-end I've been attempting to put together a very basic API server in Node.js for something we will look at next year.
I used Swagger to build an API spec and then used the Swagger code generator to get a basic Node.js server. The full code is near the bottom of this question.
The Problem
I'm coming across an issue when writing out to a log file using the fs module. I know that the ENOENT error is usually down to just specifying a path incorrectly, but the behaviour doesn't occur when I comment out the Swagger portion of the automatically generated code. (I took the logging code directly out of another tool I built in Node.js, so I'm fairly confident in that portion at least...)
When executing npm start, a few debugging items write to the console:
"Node Server Starting......
Current Directory:/mnt/c/Users/USER/Repositories/PROJECT/api
Trying to log data now!
Mock mode: disabled
PostgreSQL Pool created successfully
Your server is listening on port 3100 (http://localhost:3100)
Swagger-ui is available on http://localhost:3100/docs"
but then fs throws an ENOENT error:
events.js:174
throw er; // Unhandled 'error' event
^
Error: ENOENT: no such file or directory, open '../logs/logEvents2021-12-24.log'
Emitted 'error' event at:
at lazyFs.open (internal/fs/streams.js:277:12)
at FSReqWrap.args [as oncomplete] (fs.js:140:20)
Investigating
Now normally, from what I understand, this would just mean I've got the paths wrong. However, the file has actually been created and the first line of the log file has been written just fine
My next thought was that I must've set the fs flags incorrectly, but it was set to 'a' for append:
var logsFile = fs.createWriteStream(__logdir+"/logEvents"+dateNow()+'.log',{flags: 'a'},(err) =>{
console.error('Could not write new Log File to location: %s \nWith error description: %s',__logdir, err);
});
Removing Swagger Code
Now here's the weird bit: if I remove the Swagger code, the log files write out just fine and I don't get the fs exception!
This is the specific Swagger code:
// swaggerRouter configuration
var options = {
routing: {
controllers: path.join(__dirname, './controllers')
},
};
var expressAppConfig = oas3Tools.expressAppConfig(path.join(__dirname, '/api/openapi.yaml'), options);
var app = expressAppConfig.getApp();
// Initialize the Swagger middleware
http.createServer(app).listen(serverPort, function () {
console.info('Your server is listening on port %d (http://localhost:%d)', serverPort, serverPort);
console.info('Swagger-ui is available on http://localhost:%d/docs', serverPort);
}).on('error',console.error);
When I comment out this code, the log file writes out just fine.
The only thing I can think that might be happening is that somehow Swagger is modifying (?) the app's working directory so that fs no longer finds the same file?
Full Code
'use strict';
var path = require('path');
var fs = require('fs');
var http = require('http');
var oas3Tools = require('oas3-tools');
var serverPort = 3100;
// I am specifically tried using path.join that I found when investigating this issue, and referencing the app path, but to no avail
const __logdir = path.join(__dirname,'./logs');
//These are date and time functions I use to add timestamps to the logs
function dateNow(){
var dateNow = new Date().toISOString().slice(0,10).toString();
return dateNow
}
function rightNow(){
var timeNow = new Date().toTimeString().slice(0,8).toString();
return "["+timeNow+"] "
};
console.info("Node Server Starting......");
console.info("Current Directory: " + __dirname)
// Here I create the WriteStreams
var logsFile = fs.createWriteStream(__logdir+"/logEvents"+dateNow()+'.log',{flags: 'a'},(err) =>{
console.error('Could not write new Log File to location: %s \nWith error description: %s',__logdir, err);
});
var errorsFile = fs.createWriteStream(__logdir+"/errorEvents"+dateNow()+'.log',{flags: 'a'},(err) =>{
console.error('Could not write new Error Log File to location: %s \nWith error description: %s',__logdir, err);
});
// And create an additional console to write data out:
const Console = require('console').Console;
var logOut = new Console(logsFile,errorsFile);
console.info("Trying to log data now!") // Debugging logging
logOut.log("========== Server Startup Initiated ==========");
logOut.log(rightNow() + "Server Directory: "+ __dirname);
logOut.log(rightNow() + "Logs directory: "+__logdir);
// Here is the Swagger portion that seems to create the behaviour.
// It is unedited from the Swagger Code-Gen tool
// swaggerRouter configuration
var options = {
routing: {
controllers: path.join(__dirname, './controllers')
},
};
var expressAppConfig = oas3Tools.expressAppConfig(path.join(__dirname, '/api/openapi.yaml'), options);
var app = expressAppConfig.getApp();
// Initialize the Swagger middleware
http.createServer(app).listen(serverPort, function () {
console.info('Your server is listening on port %d (http://localhost:%d)', serverPort, serverPort);
console.info('Swagger-ui is available on http://localhost:%d/docs', serverPort);
}).on('error',console.error);
In case it helps, this is the project's file structure . I am running this project within a WSL instance in VSCode on Windows, same as I have with other projects using fs.
Is anyone able to help me understand why fs can write the first log line but then break once the Swagger code gets going? Have I done something incredibly stupid?
Appreciate the help, thanks!
Edit: Tried to fix broken images.
Found the problem with some help from a friend. The issue boiled down to a lack of understanding of how the Swagger module works in the background, so this will likely be eye-rollingly obvious to most, but keeping this post around in case anyone else comes across this down the line.
So it seems that as part of the Swagger initialisation, any scripts within the utils folder will also be executed. I would not have picked up on this if it wasn't pointed out to me that in the middle of the console output there was a reference to some PostgreSQL code, even though I had taken all reference to it out of the main index.js file.
That's when I realised that the error wasn't actually being generated from the code posted above: it was being thrown from to that folder.
So I guess the answer is don't add stuff to the utils folder, but if you do, always add a bunch of console logging...
I am using this block of code to create and write a new directory and a file.
I just started to learn nodejs
var lib = {};
lib.baseDir = path.join(__dirname,'/../.data/');
lib.create = function(dir,file,data,callback){
fs.open(lib.baseDir+dir+'/'+file+'.json', 'wx', function(err, fileDescriptor){
if(!err && fileDescriptor){
var stringData = JSON.stringify(data);
// Write to file and close it
fs.writeFile(fileDescriptor, stringData,function(err){
if(!err){
fs.close(fileDescriptor,function(err){
if(!err){
callback(false);
} else {
callback('Error closing new file');
}
});
} else {
callback('Error writing to new file'+'lib.baseDir');
}
});
} else {
callback(err);
}
});
};
but I am repeatedly getting the error
{ Error: ENOENT: no such file or directory, open 'C:\Users\Jawahr\Documents\GitHub\node-api\.data\test\newFile.json'
errno: -4058,
code: 'ENOENT',
syscall: 'open',
path: 'C:\\Users\\Jawahr\\Documents\\GitHub\\node-
api\\.data\\test\\newFile.json' }
calling this library in a index.js as
var _data = require('./lib/data');
_data.create('test','newFile', {"asdksadlk" : "asldj"} ,function(err) {
console.log('this was the error ',err);
});
I've been stuck here for a while, is it because the pathname and filename contained the part "C:" which has colon a reserved char in windows 10, if it is the problem how to solve this.
using windows 10 and NodeJs 8.6.
Can you try this -
fs.open(lib.baseDir+dir+'/'+file+'.json', 'w', function(err, fileDescriptor){
It looks like 'wx' throws an error if file exists -
'w' - Open file for writing. The file is created (if it does not exist) or truncated (if it exists).
'wx' - Like 'w' but fails if the path exists.
'w+' - Open file for reading and writing. The file is created (if it does not exist) or truncated (if it exists).
'wx+' - Like 'w+' but fails if the path exists.
Referred from here
Looks like your put non-existing or non-accessible path to your file. Look:
fs.open('/path/is/not/exists/xx.js','wx',(err,fd)=>{
if (err) {
console.log(err.message);
}
});
and got
Error: ENOENT: no such file or directory, open '/path/is/not/exists/xx.js'
In case when file is already exists you will got something like Error: EEXIST: file already exists, open '...'
And last, but not least. Instead of lib.baseDir+dir+'/'+file+'.json' better solution is use path.join(lib.baseDir,dir,file+'.json') from path module
Add a check for directory or create before fs.open
if (!fs.existsSync(dir)){
fs.mkdirSync(dir);
}
Then the rest of your code will work. as fs.open only creates file if it doesn't exist, it does not create directory
I hope you can help!
I have setup and Amazon echo applcation, the application makes a request to and AWS EC2 instance and gets JSON data as a response, this is working as expected however the use case for the final application is to connect to a private IP sending paramaters to an API to return the same JSON DATA.
for many reasons sadly I cannot share any of the endpoint information.
I need my NODE.js Application to make a request to the private IP over a VPN connection, Im currently using OPENVPN to make local requests to the endpoint.
I have looked at node packages to see if this is possible but I cannot seem to find one, except for this package here
https://www.npmjs.com/package/node-openvpn
This package is has a dependancy thats fails to download, so i got the node_module manually but Im getting an error when i try to execute the code
var openvpnmanager = require('node-openvpn');
var opts = {
host: 'xx.xx.xx.xx', // normally '127.0.0.1', will default to if undefined
port: 443, //port openvpn management console
timeout: 1500, //timeout for connection - optional, will default to 1500ms if undefined
logpath: 'log.txt' //optional write openvpn console output to file, can be relative path or absolute
};
var auth = {
user: '*******',
pass: '*******',
};
var openvpn = openvpnmanager.connect(opts)
openvpn.on('connected', function() { //will be emited on successful interfacing with openvpn instance
openvpnmanager.authorize(auth);
});
openvpn.on('console-output', function(output) { //emits console output of openvpn instance as a line
console.log(output)
});
openvpn.on('state-change', function(state) { //emits console output of openvpn state as a array
console.log(output)
});
// openvpnmanager.getLog(console.log) //get all console logs up to this point
// and finally when/if you want to
// openvpnmanager.disconnect();
openvpn.on('disconnected', function() { //emits on disconnect
openvpnmanager.destroy() //finally destroy the disconnected manager
});
this just gives me an error
Unhandled rejection TypeError: Cannot read property 'writable' of undefined
at Telnet.exec (C:\Users\user\Desktop\alexa- po\node_modules\node-openvpn\node_modules\telnet-client\lib\telnet- client.js:90:24)
If anybody has any suggetions on how to make this possible I would be very grateful.
I'm trying to use the Meteor package perak:meteor-mqtt-collection to connect to CloudMQTT, but am unsure about how to interpret the syntax for the mqttConnect function:
Collection.mqttConnect(uri, topics, options, mqttOptions)
"where mqttOptions is an object that is supplied to mqtt.connect([url],options) in the MQTT.js library for configuring the underlying options of the MQTT.js-client. See the docs."
So far my Meteor test-code looks like this:
Goals = new Meteor.Collection('dbGoals');
if (Meteor.isClient) {
Goals.insert({
topic: "goals",
message: "Hello world from Meteor Web Client",
broadcast: true
});
}
if (Meteor.isServer) {
Meteor.startup(function () {
Goals.mqttConnect("m10.cloudmqtt.com", ["goals"], {
insert: true,
raw: true
},
{ servers: [{ host: 'm10.cloudmqtt.com', port: 12310 }],
clientId:"uniqueIdforEachMqttClient",
username: "myMqttUserName",
password: "myMqttUserPass",
clean:false
});
And gets the following error:
C:\Users\user\AppData\Local\.meteor\packages\meteor-tool\1.1.10\mt-os.windows.x86_32\dev_bundle\server-lib\node_modules\fibers\future.js:245
throw(ex);
^
TypeError: Cannot call method 'replace' of null
at Object.connect (C:\Users\user\AppData\Local\.meteor\packages\perak_mqtt-collection\1.0.4\npm\node_modules\mqtt\lib\connect\index.js:62:35)
at [object Object].Mongo.Collection.mqttConnect (packages/perak_mqtt-collection/packages/perak_mqtt-collection.js:37:1)
at E:\Data\Projects\Project2016\design\sw\mqttColl\.meteor\local\build\programs\server\boot.js:249:5
at mqttColl.js:25:11
=> Exited with code: 8
=> Your application is crashing.
The line mqttColl.js:25:11 is:
Goals.mqttConnect("m10.cloudmqtt.com", "goals", {
I know the object with my servers: options works with MQTT.js running on Node and CloudMQTT, but I'm not sure that I've got the mqttConnect() function parameters entered correctly for the perak Meteor package. For starters, it seems unlikely that the MQTT broker's URL would be needed in multiple places nor that the topic goals should be in brackets, but I'm just not clear on the parameter syntax.
Any suggestions?
You should add protocol into the URL: mqtt://m10.cloudmqtt.com.
I'm trying to do something I thought would be simple. I'm using nwjs (Formerly called Node-Webkit) which if you don't know basically means I'm developing a desktop app using Chromium & Node where the DOM is in the same scope as Node. I want to offload work to a webworker so that the GUI doesn't hang when I send some text off to Ivona Cloud (using ivona-node) which is a text to speech API. The audio comes back in chunks as it's generated and gets written to an MP3. ivona-node uses fs to write the mp3 to the drive. I got it working in the dom but webworkers are needed to not hang the UI. So I have two node modules I need to use in the webworker, ivona-node and fs.
The problem is that in a webworker you can't use require. So I tried packaging ivona-node and fs with browserify (There's a package called browserify-fs for this which I used) and replacing require with importScripts(). Now I'm getting var errors in the node modules.
Note: I don't think the method of native_fs_ will work for writing the mp3 to disk in chunks (The stream) as it should be and I'm getting errors in the Ivona package as well (Actually first and foremost) that I don't know how to fix. I'm including all information to reproduce this.
Here's an error I'm getting in the console: Uncaught SyntaxError: Unexpected token var VM39 ivonabundle.js:23132
Steps to reproduce in NWJS:
npm install ivona-node
npm install browserify-fs
npm install -g browserify
Now I browserified main.js for ivona-node and index.js for browserify-fs:
browserify main.js > ivonabundle.js
browserify index.js > fsbundle.js
package.json...
{
"name": "appname",
"description": "appdescr",
"title": "apptitle",
"main": "index.html",
"window":
{
"toolbar": true,
"resizable": false,
"width": 800,
"height": 500
},
"webkit":
{
"plugin": true
}
}
index.html...
<html>
<head>
<title>apptitle</title>
</head>
<body>
<p><output id="result"></output></p>
<button onclick="startWorker()">Start Worker</button>
<button onclick="stopWorker()">Stop Worker</button>
<br><br>
<script>
var w;
function startWorker() {
if(typeof(Worker) !== "undefined") {
if(typeof(w) == "undefined") {
w = new Worker("TTMP3.worker.js");
w.postMessage(['This is some text to speak.']);
}
w.onmessage = function(event) {
document.getElementById("result").innerHTML = event.data;
};
} else {
document.getElementById("result").innerHTML = "Sorry! No Web Worker support.";
}
}
function stopWorker() {
w.terminate();
w = undefined;
}
</script>
</body>
</html>
TTMP3.worker.js...
importScripts('node_modules/browserify-fs/fsbundle.js','node_modules/ivona-node/src/ivonabundle.js');
onmessage = function T2MP3(Text2Speak)
{
postMessage(Text2Speak.data[0]);
//var fs = require('fs'),
// Ivona = require('ivona-node');
var ivona = new Ivona({
accessKey: 'xxxxxxxxxxx',
secretKey: 'xxxxxxxxxxx'
});
//ivona.listVoices()
//.on('end', function(voices) {
//console.log(voices);
//});
// ivona.createVoice(text, config)
// [string] text - the text to be spoken
// [object] config (optional) - override Ivona request via 'body' value
ivona.createVoice(Text2Speak.data[0], {
body: {
voice: {
name: 'Salli',
language: 'en-US',
gender: 'Female'
}
}
}).pipe(fs.createWriteStream('text.mp3'));
postMessage("Done");
}
There are two things that I wan to point out first:
Including node modules in a web worker
In order to include the module ivona-node I had to change a little its code. When I try to browserify it I get an error: Uncaught Error: Cannot find module '/node_modules/ivona-node/src/proxy'. Checking the bundle.js generated I notice that it doesn't include the code of the module proxy which is in the file proxy.js in the src folder of ivona-node. I can load the proxy module changing this line HttpsPA = require(__dirname + '/proxy'); by this: HttpsPA = require('./proxy');. After that ivona-node can be loaded in the client side through browserify. Then I was facing another error when trying to follow the example. Turn out that this code:
ivona.createVoice(Text2Speak.data[0], {
body: {
voice: {
name: 'Salli',
language: 'en-US',
gender: 'Female'
}
}
}).pipe(fs.createWriteStream('text.mp3'));
is no longer correct, it cause the error: Uncaught Error: Cannot pipe. Not readable. The problem here is in the module http. the module browserify has wrapped many built-in modules of npm, which mean that they are available when you use require() or use their functionality. http is one of them, but as you can reference here: strem-http, It tries to match node's api and behavior as closely as possible, but some features aren't available, since browsers don't give nearly as much control over requests. Very significant is the fact of the class http.ClientRequest, this class in nodejs environment create an OutgoingMessage that produce this statement Stream.call(this) allowing the use of the method pipe in the request, but in the browserify version when you call https.request the result is a Writable Stream, this is the call inside the ClientRequest: stream.Writable.call(self). So we have explicitly a WritableStream even with this method:
Writable.prototype.pipe = function() {
this.emit('error', new Error('Cannot pipe. Not readable.'));
};
The responsible of the above error. Now we have to use a different approach to save the data from ivona-node, which leave me to the second issue.
Create a file from a web worker
Is well know that having access to the FileSystem from a web application have many security issues, so the problem is how we can have access to the FileSystem from the web worker. One first approach is using the HTML5 FileSystem API. This approach has the inconvenient that it operate in a sandbox, so if we have in a desktop app we want to have access to the OS FileSystem. To accomplish this goal we can pass the data from the web worker to the main thread where we can use all the nodejs FileSystem functionalities. Web worker provide a functionality called Transferable Objects, you can get more info here and here that we can use to pass the data received from the module ivona-node in the web worker to the main thread and then use require('fs') in the same way that node-webkit provide us. These are the step you can follow:
install browserify
npm install -g browserify
install ivona-node
npm install ivona-node --save
go to node_modules/ivona-node/src/main.js and change this line:
HttpsPA = require(__dirname + '/proxy');
by this:
HttpsPA = require('./proxy');
create your bundle.js.
Here you have some alternatives, create a bundle.js to allow a require() or put some code in a file with some logic of what you want (you can actually include all the code of the web worker) and then create the bundle.js. In this example I will create the bundle.js only for have access to require() and use importScripts() in the web worker file
browserify -r ivona-node > ibundle.js
Put all together
Modify the code of the web worker and index.html in order to receive the data in the web worker and send it to the main thread (in index.html)
this is the code of web worker (MyWorker.js)
importScripts('ibundle.js');
var Ivona = require('ivona-node');
onmessage = function T2MP3(Text2Speak)
{
var ivona = new Ivona({
accessKey: 'xxxxxxxxxxxx',
secretKey: 'xxxxxxxxxxxx'
});
var req = ivona.createVoice(Text2Speak.data[0], {
body: {
voice: {
name: 'Salli',
language: 'en-US',
gender: 'Female'
}
}
});
req.on('data', function(chunk){
var arr = new Uint8Array(chunk);
postMessage({event: 'data', data: arr}, [arr.buffer]);
});
req.on('end', function(){
postMessage(Text2Speak.data[0]);
});
}
and index.html:
<html>
<head>
<title>apptitle</title>
</head>
<body>
<p><output id="result"></output></p>
<button onclick="startWorker()">Start Worker</button>
<button onclick="stopWorker()">Stop Worker</button>
<br><br>
<script>
var w;
var fs = require('fs');
function startWorker() {
var writer = fs.createWriteStream('text.mp3');
if(typeof(Worker) !== "undefined") {
if(typeof(w) == "undefined") {
w = new Worker("MyWorker.js");
w.postMessage(['This is some text to speak.']);
}
w.onmessage = function(event) {
var data = event.data;
if(data.event !== undefined && data.event == 'data'){
var buffer = new Buffer(data.data);
writer.write(buffer);
}
else{
writer.end();
document.getElementById("result").innerHTML = data;
}
};
} else {
document.getElementById("result").innerHTML = "Sorry! No Web Worker support.";
}
}
function stopWorker() {
w.terminate();
w = undefined;
}
</script>
</body>
</html>