Python script not executing pickle.load when called from nodejs app - javascript

I have an nodejs app which calls python script from a controller. Scripts run fine when I run from terminal directly and works fine as well when called from node app but it only stucks on this specific line model = pickle.load(open("model.pkl", "rb")). Any help would be appreciated.
predict.py
import sys
import json
import pickle
import os
def get_size(weight, height, age):
model = pickle.load(open("model.pkl", "rb"))
return model.predict([[height,weight,age,bmi]])[0]
calculated_size = get_size(69,167,26)
print(calculated_size)
sys.stdout.flush()
results.js
const scriptPath = path.dirname(require.main.filename) + '/python-scripts/predict.py';
const pythonProcess = spawn('python', [ scriptPath, 'user_inputs', JSON.stringify(results) ], {cwd: path.dirname(require.main.filename)+'/python-scripts'});
pythonProcess.stdout.on('data', async (data) => {
console.log(data.toString());
})

Fixed by changing python version in spawn:
const pythonProcess = spawn('python3', [ scriptPath, 'user_inputs', JSON.stringify(results) ], {cwd: path.dirname(require.main.filename)+'/python-scripts'});

Related

Spawn process inside process or detached it pkg builder

I dont sure what the problem here, mongod process not spawn inside program.exe that create with pkg. i test it first before compile the script can launch mongod process. after i tested it, spawn cant read pkg filesystem ( snapshot ).
const { spawn } = require('child_process');
const { parse } = require('path')
let processPath = parse(process.argv[0]);
let processDir = processPath.dir;
const args = [
'-f', `${__dirname}\\configs\\mongodb.yml`,
'--dbpath', `${processDir}\\database\\data`,
'--logpath', `${processDir}\\database\\log\\system.log`,
];
const options = {
cwd: `${processDir}\\bin`
};
const mongod = spawn('mongod', args, options);
mongod.stdout.on('data', chunk => {
console.log(chunk.toString())
});
mongod.stdout.on('error', chunk => {
console.log(chunk.toString())
});
mongod.on('spawn', () => {
console.log('success')
});
mongod.on('error', function(error) {
console.log(error)
});
Build Dir
build
build/program.exe
build/bin
build/bin/mongod.exe
build/database
build/database/data
build/database/log/system.log
Package.json pkg configurations
"bin": "dist/application.js",
"pkg": {
"targets": ["node16-win-x64"],
"outputPath": "dist/build",
"assets": [
"dist/configs/*"
]
}
Here is my solution to this issue, tested on Linux Ubuntu 22.04 LTS.
Case scenario:
I needed to include an executable file hello_world as an asset into /snapshot/project/bin/hello_world virtual path and based on some conditions execute it inside the Linux environment.
The problem:
I was getting the following error when I've been trying to execute the command via child_process.spawn:
/bin/sh: 1: /snaponshot/project/bin/hello_world: not found
So clearly my OS is trying to execute hello_world command via /bin/sh, however, the system is unable to access to /snapshot virtual filesystem, therefor not able to execute it.
The workaround:
Clearly, the main file system is unable to access the virtual file system, but we can do the opposite, by copying our executable file from the virtual file system into the main file system and executing it from there, basically, this is what I did:
//node packages
const fs = require('fs');
const os = require('os');
const path = require('path');
const {execSync, spawn} = require('child_process');
// executable file name
const executable = 'hello_world';
//file path to the asset executable file
const remoteControlFilePath = path.join(__dirname, `../bin/${executable}`);
let executableFileFullPath = remoteControlFilePath;
// avoid the workaround if the parent process in not pkg-ed version.
if (process.pkg) {
// creating a temporary folder for our executable file
const destination = fs.mkdtempSync(`${os.tmpdir()}${path.sep}`);
const destinationPath = path.join(destination, executable);
executableFileFullPath = destinationPath;
// copy the executable file into the temporary folder
fs.copyFileSync(remoteControlFilePath, destinationPath);
// on Linux systems you need to manually make the file executable
execSync(`chmod +x ${destinationPath}`);
}
// using {detached: true}, execute the command independently of its parent process
// to avoid the main parent process' failing if the child process failed as well.
const child = spawn(executableFileFullPath, {detached: true});
child.stdout.on('data', (data) => {
console.log(`child stdout:\n${data}`);
});
child.stderr.on('data', (data) => {
console.error(`child stderr:\n${data}`);
});
child.on('exit', (code, signal) => {
console.log(`child process exited with code ${code} and signal ${signal}`);
});

SSR with React : Unexpected token '<' in call to renderToString()

I'm working on SSR with react but I'm encountering the following error.
Syntax error: Unexpected token '<'`
<div id="root">${ReactDOMServer.renderToString(<App />)}</div>```
^
As mentioned is here
babel-register doesn't process the file it is called from.
Therefore, I rightly declared my babel dependencies in a new file, however I'm still getting the above error.
Below is my index.js file
import babelRegister from '#babel/register';
import ignoreStyles from 'ignore-styles';
babelRegister({
ignore: [/node_modules/],
presets: ['#babel/preset-env', '#babel/preset-react'],
});
import express from 'express';
import appRender from './server.js';
const app = express();
appRender(app);
My server.js file.
import initialRenderRoutes from './routes/initialRenderRoutes.js';
import path from 'path';
const appRender = (app) => {
const __dirname = path.resolve();
app.use(express.static(path.resolve(__dirname, '../build')));
app.use('*', initialRenderRoutes);
const port = 5000;
app.listen(port, () => console.log(`Server running on port ${port}`));
};
export default appRender;
My initialController.js file
import fs from 'fs';
import ReactDOMServer from 'react-dom/server.js';
import path from 'path';
import App from '../../src/App.js';
const initialRenderController = (req, res, next) => {
console.log(path.resolve());
fs.readFile(
path.resolve('../client/build/index.html'),
'utf8',
(err, data) => {
if (err) {
console.log(err);
return res.status(500).send('Internal Server Error');
}
return res.send(
data.replace(
'<div id="root"></div>',
`<div id="root">${ReactDOMServer.renderToString(<App />)}</div>`
<<<<The problem lies here>>>>
)
);
}
);
};
export default initialRenderController;
Is it something related to babel, please help.
Try the below changes in your index.js file,
require('ignore-styles');
require('#babel/register')({
ignore: [/(node_modules)/],
presets: ['#babel/preset-env', '#babel/preset-react']
});
require('./server');
require('./initialController');
The above should work, I tested locally the below, it works perfectly fine.
My server.js
import express from 'express';
import fs from 'fs';
import path from 'path';
import React from 'react';
import ReactDOMServer from 'react-dom/server';
import App from '../App';
const app = express();
app.use('^/$', (req, res, next) => {
fs.readFile(path.resolve('./build/index.html'), 'utf-8', (err, data) => {
if (err) {
console.log(err);
return res.status(500).send("Some error occurred")
}
return res.send(data.replace('<div id="root"></div>', `<div id="root">${ReactDOMServer.renderToString(<App />)}</div>`))
})
});
app.use(express.static(path.resolve(__dirname, "..", "build")));
app.listen(5000, ()=>{
console.log("App running on port 5k")
})
index.js
require('ignore-styles');
require('#babel/register')({
ignore: [/(node_modules)/],
presets: ['#babel/preset-env', '#babel/preset-react']
});
require('./server');
I hope you have the .babelrc file with the required presets.
Update in response to comment:
Consider removing type: "module", since it will throw error when you use require. #babel/register will run files using babel on the fly. The require hook will bind itself to the node’s require and will automatically compile files at runtime. server.js using es module won't clash if you remove type: "module". The order of require matters, we require babel-register in index.js with the presets needed to recognize the syntaxes in the then-required server.js.
I believe there are two things that need to be changed. One on your initialControler.js you are using export default in a node.js file, use module.exports
module.exports vs. export default in Node.js and ES6
You should change all the imports in your node files.
You use export / export default in React and then import to pull in the files
https://www.geeksforgeeks.org/reactjs-importing-exporting/
module.exports and require to pull in the files for Node
What is the purpose of Node.js module.exports and how do you use it?
Second they moved the app.get into that renderReact.js file and then required it into their index.js file. However on your server.js file I don't see you importing in your initialController file.
From your example it looks like you should be doing something like this:
Server.js
let initialController = require('/path to this file');
initialController(app)
Yow broh don’t waste yow time reading them parchments.
All you need to do is remove any space b4 and after each ><
const val= ReactDOMServer.renderToString(<App />);
/// make sure you don’t have any sort of space
/// between them > < and yow ${}
/// is better if you store that long text into an small var, as I did to ///prevent prettier or some other 💩 to add a line break of an space
return res.send( `<div id="root">${val}</div>`);

Load local dll with node-ffi: No such file

I try to load a local .dll according the examples on stackoverflow and node-ffi documentation.
But I get the error ENOENT: no such file or directory, open '../test/user32.dll.so'. The file is there (no exception).
The extension '.so' is added automatically. Any idea what I'm doing wrong? Is this code plattform dependent? I'm on Debian.
const path = require('path');
const fs = require('fs');
const ffi = require('ffi');
function setCursor() {
const dllFile = path.join('../test', 'user32.dll');
if (!fs.existsSync(dllFile)) {
throw (new Error('dll does not exist'));
}
const user32 = ffi.Library(dllFile, {
"SetCursorPos": [
"bool", ["int32", "int32"]
]
});
console.log(user32.SetCursorPos(0, 0));
}
setCursor();
It looks like path doesn't recognize ../test as being the parent folder. I think path.join(__dirname, '..', 'test', 'user32.dll'); should get you to the right place.

how to redirect all server requests to a function in Firebase Hosting

Trying to implement SSR with Firebase so I'm using a function to prerender each page of a React App. It's working well except the home page, so it must be either the match is wrong on the firebase redirect or possibly on the express route itself.
firebase.json
{
"firestore": {
"rules": "firestore.rules",
"indexes": "firestore.indexes.json"
},
"functions": {
"predeploy": [
"npm --prefix \"$RESOURCE_DIR\" run lint"
]
},
"hosting": {
"public": "build",
"rewrites": [
{
"source": "**",
"function": "contentServer"
}
],
"ignore": [
"firebase.json",
"**/.*",
"**/node_modules/**"
]
}
}
contentServer.js
import * as functions from 'firebase-functions';
import * as fs from 'fs';
import * as path from 'path';
import React from 'react';
import Helmet from 'react-helmet';
import { renderToString } from 'react-dom/server';
import Server from '../browser/Server.js';
const express = require('express');
const app = express();
// might be this? Also tried /**
app.get(['**'], (request, response) => {
const context = {};
const location = request.url;
console.log('Processing request for ', location);
let appCode;
try {
appCode = renderToString(<Server context={context} location={location} />);
} catch (err) {
appCode = 'with error';
}
// const appState = {
// pageTitle: 'Hello World',
// };
// const preloadedState = JSON.stringify(appState).replace(/</g, '\\u003c');
const fileName = path.join(__dirname, '../index.html');
const htmlTemplate = fs.readFileSync(fileName, 'utf8');
const head = Helmet.renderStatic();
const responseString = htmlTemplate
.replace('<div id="root"></div>', `<div id="root">${appCode}</div>`)
.replace('<title>React App</title>', `${head.title}\n${head.link}`);
return response.send(responseString);
});
export default functions.https.onRequest(app);
Curl
I run firebase serve --only functions,hosting
Then use curl to check the response:
curl http://localhost:5000 - does not render the home page - just the standard react page
curl http://localhost:5000/ - also does not work - just the standard react page.
curl http://localhost:5000/contact-us - works well and returns the contact us page, all other pages on the site work and trigger the function.
If you want redirect every single URL to your host to an express app in Cloud Functions, you will need to do the following:
Make sure there is no index.html in your public hosting folder (otherwise it will always be served with the path /).
Configure Firebase hosting in firebase.json to rewrite all urls to a function (you are currently doing this in your "hosting" block, which is good):
"rewrites": [
{
"source": "**",
"function": "contentServer"
}
]
Write a Cloud Function exported with the same name as the function in the rewrite, and attach an express app that handles the route wildcarded with *. In index.js in your functions folder, minimally:
const functions = require('firebase-functions')
const express = require('express')
const app = express()
app.get("*", (request, response) => {
response.send("OK")
})
exports.contentServer = functions.https.onRequest(app)
If you run this locally with firebase serve --only hosting,functions, every path that you send to localhost:5000 will say "OK".

Cloudkit JS && Node JS

I'm currently trying to perform server side connection to iCloud Server using the new CloudKit JS from Apple. According to the WWDC 2015 "CloudKit JS and Web Service", since CloudKit JS is a pure JS framework, you can use it in all JS environnements such as node JS.
I copied the source code of CloudKit JS from https://cdn.apple-cloudkit.com/ck/1/cloudkit.js and pasted it in a file named "cloudkit.js". Here is a demo of what I tried :
var CloudKit = require("/some/folders/cloudkit.js")
function demoPerformQuery() {
CloudKit.configure({
containers: [{
containerIdentifier: 'myContainerIdentifier',
apiToken: 'myAPIToken',
environment: 'development'
}]
})
var container = CloudKit.getDefaultContainer();
var publicDB = container.publicCloudDatabase;
publicDB.performQuery({recordType: 'Items'}).then(function(response){
// never called :-(
})
}
var express = require('express')
var app = express()
app.get("/", function(){
demoPerformQuery()
})
var server = app.listen(8080, function () {
console.log("server launched")
})
CloudKit seems to be correctly set up since all the functions are correctly called. But the callback of performQuery is never called. Why ?
Is there someone who already succeed to configure CloudKit JS in an server environnement ?
Thanks in advance
In the browser, CloudKit.js relies on XmlHttpRequest in order to fetch resources, but since CloudKit isn't an npm module you'll need a way to fetch things from your server.
npm install node-fetch
Using node-fetch, here is a tweaked version of your code that logs the resulting Items in your query:
var fetch = require('node-fetch');
var CloudKit = require("./cloudkit.js")
CloudKit.configure({
services: {
fetch: fetch
},
containers: [{
containerIdentifier: 'yourContainerIdentifier',
apiToken: 'yourAPItoken',
environment: 'development'
}]
})
var container = CloudKit.getDefaultContainer();
var publicDB = container.publicCloudDatabase;
function demoPerformQuery() {
publicDB.performQuery({recordType: 'Items'}).then(function(response){
console.log(response)
}).catch(function(error){
console.log(error)
})
}
var express = require('express')
var app = express()
app.get("/", function() {
demoPerformQuery()
})
var server = app.listen(8080, function () {
console.log("Server listen")
})
After hitting http://localhost:8080 you should see your server log the response to your query.

Categories