Problems with converting buffer to JS object - javascript

I'm using the mosca library for a MQTT broker and this for MQTT client.
The client code looks like this:
client.on('connect', function () {
client.subscribe('presence')
var json = {
someVar: 888,
someNum: 234
}
client.publish('presence', JSON.stringify(json));
});
client.on('message', function (topic, message) {
var json = JSON.parse(message.toString())
console.log(json.someVar);
client.end();
});
The broker, where each published message is handled is here:
server.on('published', function(packet, client) {
console.log('Package received:')
console.log('Published', packet);
var stringBuf = packet.payload.toString('utf-8')
console.log('buffer to string:', stringBuf)
var stringify = JSON.stringify(packet.payload)
console.log('stringify:',stringify);
var json = JSON.parse(stringily);
}
The output for buffer to string: looks like this:
{"someVar":888,"someNum":234}
Which should be valid json. But whenever I try to access the json-object (after using JSON.parse()) it just returns undefined for the variables.
I've also tried to do
var buf = json.data;
console.log('buffer data:', but);
But that just returns a buffer array, which can't seem to convert either.
In the client function I can easily parse the string to a JS object, so I'm a bit lost as to what is happening.
Any suggestions? Thanks.

Like stdob-- said, you're trying to parse all incoming messages, example of output for your example:
Package received:
Published mqttjs_05cac308
Package received:
Published {"clientId":"mqttjs_05cac308","topic":"presence"}
Package received:
Published <Buffer 7b 22 73 6f 6d 65 56 61 72 22 3a 38 38 38 2c 22 73 6f 6d 65 4e 75 6d 22 3a 32 33 34 7d>
Package received:
Published {"clientId":"mqttjs_05cac308","topic":"presence"}
Package received:
Published mqttjs_05cac308
You can check for the topic to handle the presence message you need:
server.on('published', function (packet, client) {
if (packet.topic == 'presence') {
var stringBuf = packet.payload.toString('utf-8');
var obj = JSON.parse(stringBuf);
console.log(obj);
}
});
/* output: { someVar: 888, someNum: 234 } */

You receive an error because tries to parse all incoming messages, including service messages that do not contain the pure JSON data. Try this:
server.on('published', function(packet, client) {
console.log('Package received:')
console.log('Published', packet);
var stringBuf = packet.payload.toString('utf-8')
try {
var json = JSON.parse(stringBuf);
console.log( json );
} catch (e) {
console.log( stringBuf );
}
}

Related

S3 GetObject Returning Weird Encoding for HTML file

I am attempting to read an HTML file into a Lambda Edge function and then return it in the response body, but for some reason, I cannot get it to return the contents of the HTML file correctly.
Here is my code (simplified):
const AWS = require('aws-sdk');
const S3 = new AWS.S3({
signatureVersion: 'v4'
});
const { Body } = await S3.getObject({ Bucket: 'my-bucket', Key: 'index.html' }).promise();
console.log(Body.toString());
Instead of seeing <html... in the console log, I am seeing the dreaded question mark characters which implies (I think), bad encoding:
��Y�r#��x�`�,b�J�ٲ��NR�yIٮ�!!���"���n���޴��Is�>}�n4pF�_���de�nq�~�]� f�����v��۔*�㺮Ý� Hdž�<�! �c�5�1B��,#|Ŵ;ֶ�U����z� �Qi��j�0��V ���H���...etc
I have literally tried everything including, but not limited to:
Body.toString('utf-8');
Body.toString('ascii');
Body.toString('base64');
decoder.write(Body.toString('base64'));
and a lot more...
I think I must be missing something really obvious here as I cannot find anyone else facing the same issue. I thought it might be to do with the encryption but my other Lambda Edge function reads an image file without issues so I assume it has to be something to do with encoding that I haven't thought of.
UPDATE
I believe the issue may be related to the fact that the file is gzipped.
Here is a print of the response from S3:
{
AcceptRanges: 'bytes',
LastModified: 2023-02-17T19:44:41.000Z,
ContentLength: 1598,
ETag: 'some-key',
CacheControl: 'max-age=31536000',
ContentEncoding: 'gzip',
ContentType: 'text/html; charset=UTF-8',
ServerSideEncryption: 'AES256',
Metadata: { etag: 'some-key' },
Body: <Buffer 1f 8b 08 00 00 00 00 00 00 03 cd 59 db 72 23 b7 11 fd 15 78 f2 60 bb 2c 62 ee b7 8d c8 4a b2 d9 b2 b7 ca 4e 52 bb 79 49 d9 ae 14 06 e8 21 21 cd 0c a6 ... 1548 more bytes>
}
The issue was caused by the fact that the index.html file was gzipped. The solution to handling this is as follows:
const AWS = require('aws-sdk');
const zlib = require('zlib');
const S3 = new AWS.S3({
signatureVersion: 'v4'
});
const { Body } = await S3.getObject({ Bucket: 'my-bucket', Key: 'index.html' }).promise();
const body = zlib.unzipSync(Body).toString();
console.log(body);
However, given that this code is being deployed within a Lambda Edge function, speed is essential! With that in mind, it would/should be faster to actually utilise https.get as this will automatically unzip the contents of the file prior to returning the Buffer stream.

How to display playable Video Url from Blob

I am trying to download videos from a webDav server to my server. After that the videos should be viewable as well as playable on my client. For downloading I use the webdav library from npm.
The download of the videos works on my server, as well as the transmission of the data to my client. My Problem is, I can't play those videos on the generated website.
app.post("/someroute/api", async (req, res) => {
let result = [];
try {
const { username, password, targetUrl, data } = req.body;
const dataFull = `somedata_${data}`;
const client = createClient(targetUrl, {
username: username,
password: password,
});
const filesToDownload = await client.getDirectoryContents(`/${dataFull}`);
const downloadPromises = filesToDownload.map(async (file) => {
const fileBuffer = await client.getFileContents(file.filename);
result.push({name: file.basename, buffer: fileBuffer});
});
await Promise.all(downloadPromises);
} catch (error) {
console.error(error);
res.status(500).json({ error: "Error retrieving directory contents" });
}
console.log(result);
res.send(result);});
The result looks like this :
{ name: 'butterfly slow motion [oAI-OqTmJj4].mp4',
buffer: <Buffer 00 00 00 18 66 74 79 70 6d 70 34 32 00 00 00 00 69 73 6f 6d 6d 70 34 32 00 00 40 d7 6d 6f 6f 76 00 00 00 6c 6d 76 68 64
00 00 00 00 d8 cd f6 85 d8 cd ... 4073099 more bytes> }
On the client side I have this function to request the videos and store them in a useState.
useEffect(() => {
if (selectedData) {
getDataVideos();
}
}, [selectedData]);
const getDataVideos = async () => {
try {
const response = await fetch("/someroute/api", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
username: username,
password: password,
targetUrl: targetUrl,
data: selectedData,
}),
});
const content = await response.json();
console.log(content);
setSelectedDataVideos(content);
} catch (error) {
console.error(error);
}
};
the console.log() of the selectedDataVideos is :
Array (1) 0 Object
buffer: {type: "Buffer", data: Array}
name: "butterfly slow motion [oAI-OqTmJj4].mp4"
Later I transform the videos into a blob using this method and safe the result into a usestate
const [tempUrls, settempUrls] = useState([]);
, here a snapshot of it :
const blob = new Blob([video.buffer.data], { type: "video/mp4" });
console.log("Videoslide 2 blob")
console.log(blob)
const url = URL.createObjectURL(blob);
return {name:video.name,url:url};
The blobs are saved in a usestate const [tempUrls, settempUrls] = useState([]);
The blob itself looks like this :
[Log] Blob {size: 14484621, type: "video/mp4", slice: function,
stream: function, text: function, …}
An index the tempUrls looks finished like this :
[Log] {name: "butterfly slow motion [oAI-OqTmJj4].mp4", url:
"blob:http:// localhost:8081/ed893b3d-298f-40c4-b4c0-1c3ac688aa43"}
The space in http:// localhost is for removing the hyperlink here.
For display the video and to play it I have this :
{tempUrls.map(video =>
<div key={video.name} style={{ flex: 2, padding: "15px 20px" }}>
<video
src={video.url}
controls
type="video/mp4"
>
</video>
Only the control placeholder is displayed but I can't play the video. Also, when I open the web page in Firefox this is displayed. "No video with supported format and MIME type found". But I am not clear where exactly I made the mistake when converting. Actually I converted the array buffer to a blob of type mp4/video and then to a URL. Then saved it as object {filename, url} in a usestate and from this usestate the videos should be played/displayed.
Does anyone here possibly see the error, I've been sitting on it a bit longer without finding it. The video itself is not corrupted, ive stored it in a docker next cloud server and can play it there without problems.
Solved it by using
import { Buffer } from "buffer";
from npm to convert the arraybuffer.
let buffer = Buffer.from(item.buffer.data);
const blob = new Blob([buffer], { type: "video/mp4" });
const url = URL.createObjectURL(blob);
result.push({ name: item.name, url: url });

Reactjs: where is the file path for a file uploaded in the browser?

I'm using reactjs and chrome.
I have built a webpage where I can upload an archive file and I want to do some further work on the file.
When the archive file is 7zip, I am using this library node-7z to try to extract a single file from the it.
The official documentation in the link suggests to use it like this:
// myStream is a Readable stream
const myStream = Seven.extractFull('./archive.7z', './output/dir/', {
$progress: true
})
My code (part of it):
import sevenBin from '7zip-bin'
import Seven from 'node-7z'
const _7zOpen = async (f) => {
console.log('_7zOpen !! ', f)
// myStream is a Readable stream
const myStream = Seven.extractFull(f.path, './output/dir/', {
$progress: true
})
myStream.on('data', function (data) {
console.log(data)
})
myStream.on('progress', function (progress) {
console.log(progress)
})
}
where the input f is a file object:
_7zOpen !!
File {path: 'CE027001-120011101924-T100.7z',
name: 'CE027001-120011101924-T100.7z',
lastModified: 1599377977254,
lastModifiedDate: Sun Sep 06 2020 16:39:37 GMT+0900, webkitRelativePath: '', …}
lastModified: 1599377977254
lastModifiedDate: Sun Sep 06 2020 16:39:37 GMT+0900 {}
name: "CE027001-120011101924-T100.7z"
path: "CE027001-120011101924-T100.7z"
size: 75602083
type: "application/x-7z-compressed"
webkitRelativePath: ""
[[Prototype]]: File
It gives an error:
Unhandled Rejection (TypeError): spawn is not a function
▼ 3 stack frames were expanded.
run
node_modules/node-7z/src/lifecycle.js:74
(anonymous function)
node_modules/node-7z/src/main.js:55
extractFull
node_modules/node-7z/src/commands.js:27
▲ 3 stack frames were expanded.
_7zOpen
src/components/shared/utils/compressedFileHandler.js:56
53 |
54 |
55 | const pathTo7zip = sevenBin.path7za;
> 56 | const seven = Seven.extractFull(f.path, './output/dir/', {
| ^ 57 | $bin: pathTo7zip
58 | });
59 |
I tried another way:
const _7zOpen = async (f) => {
console.log('_7zOpen !! ', f)
const pathTo7zip = sevenBin.path7za;
const seven = Seven.extractFull(f.path, './output/dir/', {
$bin: pathTo7zip
});
}
which gives the same error message when the file is uploaded.
It could be that the f.path is not valid.
How can I find the correct path to feed to the function?

NodeJS Server - Unable to read POST request body

I'm trying to create a simple account system on a Nodejs HTTP Server.
My Server-side code:
var server=http.createServer(function(req,res){
if(req.url.startsWith("/api/")){
console.log(" - // - API CALL - // -")
switch (req.url.substr(4)) {
case '/createAccount':
if(req.method=="POST"){
const requestBody = [];
req.on('data', (chunks)=>{
requestBody.push(chunks);
console.log(chunks)
});
req.on('end', ()=>{
console.log(requestBody)
const parsedData = JSON.stringify(Buffer.concat(requestBody));
console.log(parsedData)
res.writeHead(200,{"Content-Type":"application/json","Access-Control-Allow-Origin": "*"});
res.end(JSON.stringify({'error':false}));
});
}else{
res.writeHead(405,{"Content-Type":"application/json","Access-Control-Allow-Origin": "*"});
res.end(JSON.stringify({'error':true,'statuscode':'405','errortext':'You need to send a POST request to /createAccount.'}));
}
break;
default:
res.writeHead(404,{"Content-Type":"application/json","Access-Control-Allow-Origin": "*"});
res.end(JSON.stringify({'error':true,'statuscode':'404','errortext':'This is not a valid API address.'}));
}
}else{
console.log(" - // - NORMAL WEB PAGE - // -")
res.writeHead(200,{"Content-Type":"text/html","Access-Control-Allow-Origin": "*"});
let accountstate="not logged in"
page="<html><body>This is my homepage!<br>You are "+accountstate+".</body></html>";
res.end(page);
}
});
server.listen(7000);
console.log(`Listening at http://localhost:7000`);
The request I'm sending:
fetch("http://localhost:7000/api/createAccount",{
method:"POST",
body:{
AccountName:"test",
Password:"THISSHOULDBEENCRYPTED"
}
}).then(r=>r.json()).then(r=>console.log(r))
The console output after sending the request:
- // - API CALL - // -
<Buffer 5b 6f 62 6a 65 63 74 20 4f 62 6a 65 63 74 5d>
[ <Buffer 5b 6f 62 6a 65 63 74 20 4f 62 6a 65 63 74 5d> ]
{"type":"Buffer","data":[91,111,98,106,101,99,116,32,79,98,106,101,99,116,93]}
Does anyone have an idea why this is the output and how I can read the plain request body? (Expected output: {AccountName:"test",Password:"THISSHOULDBEENCRYPTED"})
I have looked for answers on many sites, but all solutions failed in the same error.
Thanks in advance!
Here is my fixed code:
var server=http.createServer(function(req,res){
if(req.url.startsWith("/api/")){
console.log(" - // - API CALL - // -")
switch (req.url.substr(4)) {
case '/createAccount':
if(req.method=="POST"){
req.setEncoding('utf8');
const rb = [];
req.on('data', (chunks)=>{
rb.push(chunks);
});
req.on('end', ()=>{
const body=JSON.parse(rb.join(""));
console.log(body)
res.writeHead(200,{"Content-Type":"application/json","Access-Control-Allow-Origin": "*"});
res.end(JSON.stringify({'error':false,'recieved':body}));
});
}else{...}
break;
default:
...
}
}else{...}
});
server.listen(7000);
console.log(`Listening at http://localhost:7000`);
And the fixed request:
fetch("http://localhost:7000/api/createAccount",{
method:"POST",
Headers:{'Content-Type': 'application/json'},
body:JSON.stringify({
AccountName:'test',
Password:'THISSHOULDBEENCRYPTED'
})
}).then(r=>r.json()).then(r=>console.log(r))
Basically, setting the Encoding to UTF8 and sending the body as a String will fix this issue.

Nodejs: make a GET request with users parameters

I'm new in nodejs. I'm making a express server. I recive some parameter by url, and I wnat to make a request to another server with the parameters in the recived url.
var express = require("express"),
app = express(),
bodyParser = require("body-parser"),
methodOverride = require("method-override");
request = require('request');
Client = require('node-rest-client').Client;
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
app.use(methodOverride());
var router = express.Router();
app.use(router);
router.get('/get_metric_names_by_pattern', function(req, res) {
console.log('get_metric_names_by_pattern '+req.url);
console.log(req.query.pattern);
//console.log(req.parameters);
res.header('Access-Control-Allow-Origin', '*');
var client = new Client();
var salida;
console.log(req.params.name);
//Creamos la variable para los parametros
var args = {
parameters: {pattern: "OEE"}
//headers: { "test-header": "client-api" }
};
console.log(args);
console.log(args.parameters.pattern);
client.get('http:// localhost:8000/get_metric_names_by_pattern/?pattern=:pattern', req.query.pattern,
//http:// localhost:8000/get_metric_names_by_pattern/?pattern=OEE
function (data, response) {
//console.log(args.parameters.pattern);
console.log(data);
//var pattern = req.query.pattern;
//data = data.toString('utf8'); //Transformamos los datos a string para que los reconozca el navegador
//console.log(data);
salida = JSON.parse(data);
//console.log("Datos:", salida.date);
res.send(salida); //Lo enviamos al navegador
//console.log(salida);
});
});
I do recive the paramteter from the client (in this case 'OEE') but I find no way to insert that string into client.get('http:// localhost:8000/get_metric_names_by_pattern/?pattern=:pattern', req.query.pattern, .
The request should look like the commented line under that one ( //http://localhost:8000/get_metric_names_by_pattern/?pattern=OEE) and from that request I'm recibing a json, just like this :
["PanelPC0_OEE", "empacadora1.OEE", "empacadora1.OEEE", "empacadora1.OEE_Avaible", "empacadora1.OEE_Performance", "empacadora1.OEE_quality"]
The console.log look like this:
node servicio.js
Servidor corriendo en: http:// localhost:3000
get_metric_names_by_pattern /get_metric_names_by_pattern/?pattern=OEE
OEE
undefined
{ parameters: { pattern: 'OEE' } }
OEE
Buffer 5b 5d
and it should look like :
node servicio.js
Servidor corriendo en: http:// localhost:3000
get_metric_names_by_pattern /get_metric_names_by_pattern/?pattern=OEE
OEE
undefined
{ parameters: { pattern: 'OEE' } }
OEE
Buffer 5b 22 50 61 6e 65 6c 50 43 30 5f 4f 45 45 22 2c 20 22 74 65 61 6d 66 6f
6f 64 73 2e 62 6f 67 6f 74 61 2e 6d 61 72 67 61 72 69 6e 61 73 2e 65 6d 70 61 ..
.
Please, I need to know how to insert that parameter into the new url. Sorry if this post is to long or obvius. Thanks in advance
According to the documentation, to insert a parameter or argument you should use:
${param}
like this example:
var args = {
path: { "id": 120, "arg1": "hello", "arg2": "world" },
parameters: { arg1: "hello", arg2: "world" },
headers: { "test-header": "client-api" }
};
client.get("http://remote.site/rest/json/${id}/method?arg1=${arg1}&arg2=${arg2}", args,
function (data, response) {
console.log(data);
console.log(response);
});
so in your case you should try to use:
var args = {
parameters: { pattern: req.query.pattern },
};
client.get('http:// localhost:8000/get_metric_names_by_pattern/?pattern=${pattern}', args,
function(data, response){
});
although it is not pretty... the comment of #mrwillihog gave me this idea, wich actually works!
urln = 'http://localhost:8000/get_metric_names_by_pattern/?pattern='+req.query.pattern;
console.log(urln);
client.get(urln, function (data, response) { });

Categories