Use GLTF-transform merge command - node js script - node.js

I want to use the gltf-transform command "merge" in my script and wrote something like this to merge two or more gltf files.
const { merge } = require('#gltf-transform/cli');
const fileA = '/model_path/fileA.gltf';
const fileB = '/model_path/fileB.gltf';
merge(fileA, fileB, output.gltf, false);
But nothing happened. No output file or console log. So I dont know where to continue my little journey.
Would be great when someone has a clue.
An alternative was...
const command = "gltf-transform merge("+fileA+", "+fileB+", output.gltf, false)";
exec(command, (error, stdout, stderr) => {
if (error) {
console.log(`error: ${error.message}`);
return;
}
if (stderr) {
console.log(`stderr: ${stderr}`);
return;
}
console.log(`stdout: ${stdout}`);
});
... but didnt work either and looks needless.

The #gltf-transform/cli package you're importing isn't really designed for programmatic usage; it's just a CLI. Code meant for programmatic use is in the /functions, /core, and /extensions packages.
If you'd like to implement something similar in JavaScript, I would try this instead:
import { Document, NodeIO } from '#gltf-transform/core';
const io = new NodeIO();
const inputDocument1 = io.read('./model_path/fileA.gltf');
const inputDocument2 = io.read('./model_path/fileB.gltf');
const outputDocument = new Document()
.merge(inputDocument1)
.merge(inputDocument2);
// Optional: Merge binary resources to a single buffer.
const buffer = doc.getRoot().listBuffers()[0];
doc.getRoot().listAccessors().forEach((a) => a.setBuffer(buffer));
doc.getRoot().listBuffers().forEach((b, index) => index > 0 ? b.dispose() : null);
io.write('./model_path/output.gltf', outputDocument);
This will create a single glTF file containing two scenes. If you wanted to merge the contents of both files into a single scene that would require moving some nodes around with the Scene API.

you can use gltf-transform/cli by using spawn.
// you should run `node #gltf-transform/cli/bin/cli.js`
const gltf_transform_cli_path = `your project's node_modules dir path${path.sep}#gltf-transform${path.sep}cli${path.sep}bin${path.sep}cli.js`
const normPath = path.normalize(gltf_transform_cli_path);
const command = `node ${normPath} merge ${fileA} ${fileB} output.gltf false`
const result = spawn(command)
and plus,
if you're going to use texture compressing using ktx(etc1s, usatc),
you've got to install ktx on your local.

Related

Slash command registers command from wrong folder discord.js14

I'm tired of trying to solve this. First off, here is my deployment code
const { REST, Routes } = require('discord.js');
const fs = require('node:fs');
const { client_id } = require('./config.json')
const commands = [];
// Grab all the command files from the commands directory you created earlier
const commandFiles = fs.readdirSync('./slashCommands').filter(file => file.endsWith('.js'));
// Grab the SlashCommandBuilder#toJSON() output of each command's data for deployment
for (const file of commandFiles) {
const command = require(`./slashCommands/${file}`);
commands.push(command.data.toJSON());
}
// Construct and prepare an instance of the REST module
const rest = new REST({ version: '10' }).setToken(process.env.TOKEN);
// and deploy your commands!
(async () => {
try {
console.log(`Started refreshing ${commands.length} application (/) commands.`);
// The put method is used to fully refresh all commands in the guild with the current set
const data = await rest.put(
Routes.applicationCommands(client_id),
{ body: commands },
);
console.log(`Successfully reloaded ${data.length} application (/) commands.`);
} catch (error) {
// And of course, make sure you catch and log any errors!
console.error(error);
}
})();
It is supposed to get the command from the "slashCommand" folder. So I run 'node deploy-commands.js' and it works.
The problem is when I do the slash command '/ping', I get this error:
/home/runner/Nocinel/commands/ping.js:8
message.reply('🏓 **Ball is going over the net...**').then(m => { m.edit(`**🏓 Pong!\n:stopwatch: Uptime: ${Math.round(message.client.uptime / 60000)} minutes\n:sparkling_heart: Websocket Heartbeat: ${message.client.ws.ping}ms\n:round_pushpin: Rountrip Latency: ${m.createdTimestamp - message.createdTimestamp}ms**`) });
^
TypeError: m.edit is not a function
at /home/runner/Nocinel/commands/ping.js:8:73
repl process died unexpectedly: exit status 1
Now this error indicates that I am running a command from my "command" folder rather than my "slashCommand" folder. Which doesnt make sense because I explicitly coded it to only get commands from the "slash command folder"
I have restarted, deleted, waited for an hour, and tested it multiple times, it always gives the same disappointing result. I see absolutely nothing wrong with my code.
There is no problem with registring comannd (deploy-comannds.js is only registring comannds not using making them work). Problem have to be in your index.js you have to handle interaction comannds to your folder slashComannds. Registring comannds was sucessfull.
Documentation:
https://discordjs.guide/creating-your-bot/command-handling.html#loading-command-files

broken pipe in nodejs CLI: terminal output is hidden

When I run a little node program and I break the output through a pipe, the bash terminal output remains hidden and I'm forced to run reset (which works every time). How should I restore correctly after a broken pipe to avoid going through reset?
The program:
const { unmarshall } = require("#aws-sdk/util-dynamodb");
const fs = require('fs');
(async () => {
const input = fs.readFileSync(process.argv[2], 'utf-8');
const records = JSON.parse(input);
if (records.Items) {
records.Items = records.Items.map((a) => unmarshall(a));
}
process.stdout.on('error', function( err ) {
if (err.code === 'EPIPE') {
process.exit(0);
}
});
process.stdout.write(JSON.stringify(records, undefined, 2));
})();
And when I run this program like this and exit from less via a q keystroke, subsequent terminal output is hidden (after exiting the JS program and breaking the pipe). Output is restored via reset:
node example.js dynamo_output.json | less
# no terminal output is visible
$ reset
# output is restored
This appears to work:
const fs = require('fs');
const writeStdoutSync = (str) => {
fs.writeSync(process.stdout.fd, str);
}

Why am I getting a NOENT using Node core module 'fs'

This a repeat question (not yet answered) but I have revised and tightened up the code. And, I have included the specific example. I am sorry to keep beating this drum, but I need help.
This is a Node API. I need to read and write JSON data. I am using the Node core module 'fs', not the npm package by the same name (or fs-extra). I have extracted the particular area of concern onto a standalone module that is shown here:
'use strict';
/*==================================================
This service GETs the list of ids to the json data files
to be processed, from a json file with the id 'ids.json'.
It returns and exports idsList (an array holding the ids of the json data files)
It also calls putIdsCleared to clear the 'ids.json' file for the next batch of processing
==================================================*/
// node modules
const fs = require('fs');
const config = require('config');
const scheme = config.get('json.scheme')
const jsonPath = config.get('json.path');
const url = `${scheme}${jsonPath}/`;
const idsID = 'ids.json';
const uri = `${url}${idsID}`;
let idsList = [];
const getList = async (uri) => {
await fs.readFile(uri, 'utf8', (err, data) => {
if (err) {
return(console.log( new Error(err.message) ));
}
return jsonData = JSON.parse(data);
})
}
// The idea is to get the empty array written back to 'ids.json' before returning to 'process.js'
const clearList = async (uri) => {
let data = JSON.stringify({'ids': []});
await fs.writeFile(uri, data, (err) => {
if (err) {
return (console.log( new Error(err.message) ));
}
return;
})
}
getList(uri);
clearList(uri)
console.log('end of idsList',idsList);
module.exports = idsList;
Here is the console output from the execution of the module:
Error: ENOENT: no such file or directory, open 'File:///Users/doug5solas/sandbox/libertyMutual/server/api/ids.json'
at ReadFileContext.fs.readFile [as callback]
(/Users/doug5solas/sandbox/libertyMutual/server/.playground/ids.js:24:33)
at FSReqWrap.readFileAfterOpen [as oncomplete] (fs.js:235:13)
Error: ENOENT: no such file or directory, open 'File:///Users/doug5solas/sandbox/libertyMutual/server/api/ids.json'
at fs.writeFile
(/Users/doug5solas/sandbox/libertyMutual/server/.playground/ids.js:36:34)
at fs.js:1167:7
at FSReqWrap.oncomplete (fs.js:141:20)
I am being told there is no such file or directory. However I can copy the uri (as shown in the error message)
File:///Users/doug5solas/sandbox/libertyMutual/server/api/ids.json
into the search bar of my browser and this is what is returned to me:
{
"ids": [
"5sM5YLnnNMN_1540338527220.json",
"5sM5YLnnNMN_1540389571029.json",
"6tN6ZMooONO_1540389269289.json"
]
}
This result is the expected result. I do not "get" why I can get the data manually but I cannot get it programmatically, using the same uri. What am I missing? Help appreciated.
Your File URI is in the wrong format.
It shouldn't contain the File:// protocol (that's a browser-specific thing).
I'd imagine you want C://Users/doug5solas/sandbox/libertyMutual/server/api/ids.json.
I solved the problem by going to readFileSync. I don't like it but it works and it is only one read.

Strange behavior of node js spawn/exec with unzipped content

I'm trying to write a client which installs and updates packages using nodejs with mqtt. I tested all functionalities of data transfer and archiving but when I came to windows environment and actualy tried to run some scripts I came to some strange errors.
I will add some code so anyone can see exacly how I write downloaded content to disk but first I will explain behaviour.
Steps taken for each itteration:
download content from mqtt (works)
create buffer and stream from it (works)
unzip stream to disk (works)
run batch job in downloaded content (strange things happen)
run another batch job (even stranger)
Strange things: At first try spawn/exec respoonses with: error spawn cmd.exe ENOENT, but at second try (triggered by topic subscription) it goes over that stage. But the next itteration when first batch job passes second job returns Error: EBUSY: resource busy or locked, open C:\...appt#0.0.1\nssm.exe' where nssm.exe is file called from batch job
Code for downloading and extraction:
const debug = require('debug')('service-manager:functions:download')
const serviceBus = require('../helpers/mqtt-helper.js')
const stream = require('stream')
const unzip = require('unzip-stream')
module.exports = (service, to, from) => {
debug(`Downloading ${service}#${to}`)
return serviceBus.getFromBus(`service_manager/${service}/${to}`)
.then(data => {
debug(`Downloaded ${service}#${to}`)
return new Promise((resolve, reject) => {
debug(`Unzipping ${service}#${to}`)
const buffer = Buffer.from(data)
const bufferStream = new stream.PassThrough()
bufferStream.end(buffer)
bufferStream.pipe(unzip.Extract({
path: `${__dirname}/../../services/active/${service}#${to}`
})).on('finish', resolve)
}).then(() => {
debug(`Unzipped ${service}#${to}`)
})
})
}
Code used to run batch jobs:
const debug = require('debug')('service-manager:functions:runner')
const { exec } = require('child_process')
const { resolve } = require('path')
module.exports = (type, reverse) => (service, to, from) => {
return new Promise((resolve, reject) => {
debug(`Running ${type} for ${service}#${reverse ? from : to}`)
const batchFile = resolve(
`../../services/active/${service}#${reverse ? from : to}/${type}.sh`
)
exec(batchFile, (error, stdout, stderr) => {
if (error) {
return reject(error)
}
debug(`Gotten STDOUT on ${type} for ${service}#${reverse ? from : to}: ${stdout}`)
debug(`Gotten STDERR on ${type} for ${service}#${reverse ? from : to}: ${stderr}`)
return resolve()
})
})
}
It turns out that unzip-stream called finish and close event before files were written on dist which resulted in files not being accessible to run with batch script. I swaped libraries and it worked.

How To Execute Windows Shell Commands (Cmd.exe) with Node JS

I would like to
C:\>ACommandThatGetsData > save.txt
But instead of parsing and saving the data in the console, I would like to do the above command with Node.JS
How to execute a shell command with Node.JS?
Use process.execPath():
process.execPath('/path/to/executable');
Update
I should have read the documentations better.
There is a Child Process Module which allows to execute a child process. You will need either child_process.exec, child_process.execFile or child_process.spawn. All of these are similar in use, but each has its own advantages. Which of them to use depends on your needs.
You could also try the node-cmd package:
const nodeCmd = require('node-cmd');
nodeCmd.get('dir', (err, data, stderr) => console.log(data));
On newer versions of the package, the syntax changed a little:
const nodeCmd = require('node-cmd');
nodeCmd.run('dir', (err, data, stderr) => console.log(data));
I know this question is old, but it helped me get to my solution using promises.
Also see: this question & answer
const util = require('util');
const exec = util.promisify(require('child_process').exec);
async function runCommand(command) {
const { stdout, stderr, error } = await exec(command);
if(stderr){console.error('stderr:', stderr);}
if(error){console.error('error:', error);}
return stdout;
}
async function myFunction () {
// your code here building the command you wish to execute ...
const command = 'dir';
const result = await runCommand(command);
console.log("_result", result);
// your code here processing the result ...
}
// just calling myFunction() here so it runs when the file is loaded
myFunction();

Resources