What i'm trying to do here is to broadcast a file to other clients connected to the server via websocket/binaryjs using a binaryjs client/server system.
The problem comes with large files (or maybe is totally random?!?!). The client stops sending data to the server giving an error.
This is the first time i try something like this and i'm pretty new to socket programming so i might be missing something.... or everything.
Here is the client
<html>
<head>
<script src="http://cdn.binaryjs.com/0/binary.js" type="text/javascript" language="javascript"></script>
<script src="http://code.jquery.com/jquery-latest.min.js" type="text/javascript" language="javascript"></script>
<script>
$(document).ready(start);
function upload(e){
var file = e.target.files[0];
var chunkSize = 1024 * 1024; //1mb in this case but the problem seems to be uneffected by the chunk size
var fileSize = file.size;
var start = 0;
var end = chunkSize;
var s = client.createStream({name: file.name, size: file.size});
while(start < fileSize) {
w = s.write(file.slice(start, end));
console.log(w);
start = end;
end = start + chunkSize;
}
/*
//the client.send way
var reader = new FileReader();
reader.onload = function(e) {
var contents = e.target.result;
client.send(contents, {name: file.name, size: file.size});
};
reader.readAsArrayBuffer(file);
*/
}
var client = new BinaryClient('ws://0.0.0.0');
function start() {
var o = $('#output');
client.on('stream', function(stream, meta){
var parts = [];
var meta = meta;
var downloaded = 0;
var element = $('<div />');
o.append(element);
stream.on('data', function(data){
downloaded += data.byteLength;
element.html(meta.name+' '+(Math.round(downloaded/meta.size*100 *100)/100)+'% ');
parts.push(data);
});
stream.on('end', function(){
var a = document.createElement("a");
a.innerHTML='download';
a.href = (window.URL || window.webkitURL).createObjectURL(new Blob(parts));
a.download = meta.name;
a.target = '_blank';
element.append(a);
});
});
}
</script>
</head>
<body>
<input type="file" id="files" name="files" />
<div id="output"></div>
<script>
document.getElementById('files').addEventListener('change', upload, false);
</script>
</body>
</html>
And then comes the server code
var BinaryServer = require('binaryjs').BinaryServer;
var server = BinaryServer({port:80});
var clients = [];
server.on('connection', function(client){
clients.push(client);
console.log(clients.length);
client.on('stream', function(stream, meta){
var s = [];
var d = 0;
for (var i=0;i<clients.length;i++) {
if (clients[i].id == client.id) {
} else {
s.push(clients[i].createStream(meta));
}
}
var name = meta;
var parts = [];
stream.on('data', function(data){
d += data.length;
console.log('data in '+d);
for (var i=0;i<s.length;i++) {
s[i].write(data);
}
});
stream.on('end', function(){
console.log('end');
for (var i=0;i<s.length;i++) {
s[i].end();
}
});
});
client.on('close', function() {
for (var i=0;i<clients.length;i++) {
if(clients[i].id == client.id) {
clients.splice(i, 1);
}
}
client.close();
});
client.on('error', function(){
console.log('error');
});
});
While uploading from the client, i get this error message at random moments (client binary.js)
WebSocket connection to 'ws://0.0.0.0/' failed: Failed to send WebSocket frame. binary.js:1341
WebSocket connection to 'ws://0.0.0.0/' failed: Failed to load Blob: error code = 3 binary.js:1341
No problem with small files (for instance it NEVER fails broadcasting a 25mb wmv). Dunno if it's just a coincidence.
Any help would be appreciated.
Related
I am using web workers for uploading larger file by creating chunks using slice but when I am sending the file in the form of formData object, it is throwing this error.when I do this in reactjs it is throwing following error
react-dom.development.js:518 Warning: React does not recognize the offClick prop on a DOM element. If you intentionally want it to appear in the DOM as a custom attribute, spell it as lowercase offclick instead. If you accidentally passed it from a parent component, remove it from the DOM element.
here is my code, where I am passing formData object to worker using postMessage, please help me to resolve this
<!DOCTYPE html>
<html>
<head>
<title>Using FileReaderSync Example</title>
<script id="worker1" type="javascript/worker">
var file = [], p = true;
function upload(blobOrFile) {
var xhr = new XMLHttpRequest();
xhr.open('POST', 'url', true);//add url to upload
xhr.onload = function(e) {
};
xhr.send(blobOrFile);
}
function process() {
for (var j = 0; j <file.length; j++) {
var blob = file[j];
const BYTES_PER_CHUNK = 1024 * 1024;
// 1MB chunk sizes.
const SIZE = blob.size;
var start = 0;
var end = BYTES_PER_CHUNK;
while (start < SIZE) {
if ('mozSlice' in blob) {
var chunk = blob.mozSlice(start, end);
} else {
var chunk = blob.slice(start, end);
}
upload(chunk);
start = end;
end = start + BYTES_PER_CHUNK;
}
p = ( j = file.length - 1) ? true : false;
self.postMessage(blob.name + " Uploaded Succesfully");
}
}
self.addEventListener('message', function(e) {
for (var j = 0; j < e.data.files.length; j++)
file.push(e.data.files[j]);
if (p) {
process()
}
})
</script>
<script>
var blob = new Blob([document.querySelector('#worker1').textContent]);
var worker = new Worker(window.URL.createObjectURL(blob));
worker.onmessage = function(e) {
alert(e.data);
};
worker.onerror =werror;
function werror(e) {
console.log('ERROR: Line ', e.lineno, ' in ', e.filename, ': ', e.message);
}
function handleFileSelect(evt) {
console.log("coming");
evt.stopPropagation();
evt.preventDefault();
let files = new FormData();
files.append('file', event.target.files );
//var files = evt.target.files;
// FileList object.
worker.postMessage({
'files' : files
});
//Sending File list to worker
// files is a FileList of File objects. List some properties.
var output = [];
for (var i = 0, f; f = files[i]; i++) {
output.push('<li><strong>', escape(f.name), '</strong> (', f.type || 'n/a', ') - ', f.size, ' bytes, last modified: ', f.lastModifiedDate ? f.lastModifiedDate.toLocaleDateString() : 'n/a', '</li>');
}
document.getElementById('list').innerHTML = '<ul>' + output.join('') + '</ul>';
}
function handleDragOver(evt) {
evt.stopPropagation();
evt.preventDefault();
evt.dataTransfer.dropEffect = 'copy';
// Explicitly show this is a copy.
}
function getd(){
document.getElementById('files').addEventListener('change', handleFileSelect, false);
}
window.addEventListener("load", getd, false);
</script>
</head>
<body>
<input type="file" id="files" name="files[]"/>
<output id="list"></output>
</body>
</html>
You do not use the worker API properly. You should have a look to this https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers
your worker file should looks like:
self.onmessage = function(e) {
// Do all the work here the postMessage the result
self.postMessage(result)
}
You "main" file is good :)
const worker = new Worker('yourWorkerFilePath')
worker.onmessage() = function(resultFormWorker) {
// treate the result here
}
worker.postMessage(file)
I have not used node.js before.
Have a .txt file with list of magnet links.
Want to write a json file with list of all files contained in these links.
var WebTorrent = require('webtorrent');
var fs = require('fs');
var client = new WebTorrent();
var array = fs.readFileSync('yop.txt').toString().split("\n");
i = 0;
while (i < array.length) {
//console.log(array[i]);
var magnetURI = array[i];
n = 0;
client.add(magnetURI, function (torrent) {
torrent.files.forEach(function (file) {
//console.log( file.name)
jsonString = JSON.stringify({'book': file.name});
fs.appendFile("data.json", jsonString, function (err) {
if (err) {console.log(err);} else { n++ }
});
if (n == torrent.files.length) {i++ }
})
})
}
when run gives the following error
Sorry for such a terrible code.
var WebTorrent = require('webtorrent')
var fs = require('fs')
var stream = fs.createWriteStream("2.txt");
var client = new WebTorrent()
var array = fs.readFileSync('yop.txt').toString().split("\n");
i = 0;
function parseMagnet (uri){
var magnetURI = uri[i]
console.log(magnetURI)
client.add(magnetURI, function (torrent) {
torrent.files.forEach(function (file) {
writeStr = (uri[i]+ '\n'+ file.name+ '\n');
stream.write(writeStr);
console.log(file.name)
});
console.log('Done !')
console.log(i)
i += 1
parseMagnet(array);
client.remove(magnetURI);
})
}
parseMagnet(array)
I am trying to stream MP3 file from a nodeJS server using BinaryJS - http://binaryjs.com/
But, when I am decoding the buffers on the client side they are seems to be overlapping, Meaning that the new chunk of data is being played few milliseconds before the previous one ended, causing the audio to lag.
is there any way to make the client wait until the current buffer is finished before starting the new one?
Server:
var BinaryServer = require('binaryjs').BinaryServer;
var fs = require('fs');
var server = BinaryServer({port: 9000});
server.on('connection', function(client){
var file = fs.createReadStream(__dirname + '/Song.mp3', {
'flags': 'r',
'bufferSize': 4 * 1024
});
});
client.send(file);
});
Client:
var client = new BinaryClient('ws://localhost:9000');
window.AudioContext = window.AudioContext || window.webkitAudioContext;
var context = new AudioContext();
client.on('stream', function (stream, meta) {
var parts = [];
var last = 0;
stream.on('data', function (data) {
var source = context.createBufferSource();
context.decodeAudioData(data, function (buf) {
source.buffer = buf;
source.connect(context.destination);
source.loop = false;
source.start(last);
last += buf.duration;
source.onended = function() {
console.log('Your audio has finished playing');
};
},
function (e) {
"Error with decoding audio data" + e.err
});
parts.push(data);
});
stream.on('end', function () {
console.log(parts);
});
});
Not sure about this, but instead of initializing last to 0, you might want to initialize it to context.currentTime.
So...I'm new to all this stuff and I'm developing an app for android with AngularJS and Ionic Framework and try to upload an audiofile I have recorded with the cordova capture Plugin like this:
// gets called from scope
$scope.captureAudio = function() {
var options = { limit: 1, duration: 10 };
$cordovaCapture.captureAudio(options).then(function(audioData) {
uploadFile(documentID, audioData);
}, function(err) {
console.log('error code: ' + err);
});
};
var uploadFile = function (document, file) {
var baseUrl = 'urltomydatabase';
var name = encodeURIComponent'test.3gpp'),
type = file[0].type,
fileReader = new FileReader(),
putRequest = new XMLHttpRequest();
$http.get(baseUrl + encodeURIComponent(document))
.success(function (data) {
putRequest.open('PUT', baseUrl + encodeURIComponent(document) + '/' + name + '?rev=' + data._rev, true);
putRequest.setRequestHeader('Content-Type', type);
fileReader.readAsArrayBuffer(file[0]);
fileReader.onload = function (readerEvent) {
putRequest.send(readerEvent);
};
putRequest.onreadystatechange = function (response) {
if (putRequest.readyState == 4) {
//success - be happy
}
};
})
.error(function () {
// failure
});
};
How the file looks in the console.log:
Playing the recorded file on the device works nice.
But everytime I upload the recording and the upload has finished, the uploaded attachment inside the document has the length '0' in the couchDB.
How the created file looks in the database after the upload:
What am I doing wrong?
EDIT: I just found out, when I upload an image, passed from this function as blob, it works well:
function upload(imageURL) {
var image = new Image();
var onload = function () {
var canvas = document.createElement("canvas");
canvas.width = this.width;
canvas.height = this.height;
var ctx = canvas.getContext("2d");
ctx.drawImage(this, 0, 0);
canvas.toBlob(function (blob) {
uploadFile(documentID, blob);
});
};
image.onload = onload;
image.src = imageURL;
}
So maybe the solution is creating a blob from the audiofile? But everytime I try it, my blob has the size of 0 bytes even before uploading it and I don't find somewhere a great explanation of how to convert a MediaFile object to blob...
It looks like your code does not send the content of your file as multipart attachment. To see what is really send to couchdb, capture the traffic with wireshark (https://www.wireshark.org/) or such.
This thread brought me to the solution, PouchDB purifies it. Now my upload function looks like this and can handle every file format
// e.g capture Audio
$scope.captureAudio = function () {
var options = {limit: 1, duration: 10};
$cordovaCapture.captureAudio(options).then(function (audioData) {
uploadFile(documentID, audioData, 'audio');
}, function (err) {
console.log('error code: ' + err);
});
};
var uploadFile = function (id, file, mediatype) {
var fileName = makeID();
if (mediatype == 'image') var name = encodeURIComponent(fileName + '.jpg');
if (mediatype == 'audio') var name = encodeURIComponent(fileName + '.3gpp');
if (mediatype == 'video') var name = encodeURIComponent(fileName + '.3gp');
db.get(id).then(function (doc) {
var path = file.fullPath;
window.resolveLocalFileSystemURL(path, function (fileEntry) {
return fileEntry.file(function (data) {
var reader = new FileReader();
reader.onloadend = function (e) {
var blob = b64toBlobAlt(e.target.result, file.type);
if (blob) {
db.putAttachment(id, name, doc._rev, blob, file.type).then(function () {
if (mediatype == 'video' || mediatype == 'image') getMedia();
if (mediatype == 'audio') $scope.audios.push(source);
});
}
};
return reader.readAsDataURL(data);
});
});
});
};
// creating the blob from the base64 string
function b64toBlobAlt(dataURI, contentType) {
var ab, byteString, i, ia;
byteString = atob(dataURI.split(',')[1]);
ab = new ArrayBuffer(byteString.length);
ia = new Uint8Array(ab);
i = 0;
while (i < byteString.length) {
ia[i] = byteString.charCodeAt(i);
i++;
}
return new Blob([ab], {
type: contentType
});
}
I'm willing to do a simple dialogue between my Arduino and a web interface.
I've been able to do this in the command line so now I'm trying to do the same with some buttons.
I've been using socket.io to manage the sockets and I can emit a socket to Arduino but when I try to emit a socket from Arduino to the server it doesn't seem to work.
Here's my code.
server.js:
var fs = require('fs');
var http = require('http');
var io = require('socket.io');
var url = require("url");
var SerialPort = require("serialport").SerialPort;
var socketServer;
var serialport;
var portName = '/dev/ttyACM0'; //change this to your Arduino port
var sendData = "";
function startServer(route,handle,debug) {
function onRequest(request, response) {
var pathname = url.parse(request.url).pathname;
console.log("Request for " + pathname + " received");
var content = route(handle,pathname,response,request,debug);
}
var httpServer = http.createServer(onRequest).listen(1337, function(){
console.log("Listening at: http://localhost:1337");
});
initSocketIO(httpServer,debug);
}
function initSocketIO(httpServer,debug) {
socketServer = io.listen(httpServer);
if(debug == false) socketServer.set('log level', 1);
socketServer.on('connection', function (socket) {
console.log("Connected");
socket.emit('onconnection', {msg:sendData});
socket.on('buttonval', function(data) {
console.log('A letter ' + data + ' was sent');
serialport.write(data);
});
socket.on('update', function(data) {
console.log('Yaaaaayaaa');
socket.emit('updateData',{msg:data.buffer});
});
socket.on('error', function(err) {
console.log(err);
});
serialListener(debug, socket);
});
}
// Listen to serial port
function serialListener(debug, socket) {
var receivedData = "";
serialport = new SerialPort(portName, {
baudrate: 9600,
dataBits: 8,
parity: 'none',
stopBits: 1,
flowControl: false
});
serialport.on('open', function(){
var buffer = "";
serialport.on('data', function(data){
var match = /\r|\n/.exec(data);
if (match) {
buffer += data;
console.log("%s", buffer);
sendData = buffer;
socket.emit('update', {msg:buffer});
buffer = "";
} else buffer += data;
});
});
}
exports.start = startServer;
index.html:
<!DOCTYPE HTML>
<html>
<head>
<style>
</style>
<script src="http://code.jquery.com/jquery-1.8.3.js"></script>
<script src="http://code.jquery.com/ui/1.9.2/jquery-ui.js"></script>
<script src="/socket.io/socket.io.js"></script>
<script>
var iosocket;
function initSocketIO() {
iosocket = io.connect();
iosocket.on('onconnection', function(value) {
initButton();
//recieve changed values by other client from server
iosocket.on('updateData', function (recievedData) {
alert(recievedData.msg);
$("#result").html(recievedData.msg);
});
});
}
function initButton(){$( "#check" ).button();}
window.onload = function() {initSocketIO();};
$(document).ready(function() {
$('#check').click(function() {
iosocket.emit('buttonval', 'S');
});
});
</script>
</head>
<body>
<div id="rData">
<h2>Data from Arduino</h2>
<div id="result"></div>
</div>
<input type="button" id="check" value="Measure"/></div>
</div>
</body>
</html>
arduino.ino:
float rP = 0;
float lP = 0;
float cP = 0;
void initMeasurement() {
Serial.println("Ready for measures");
}
void doMeasure() {
rP = 0.1;
lP = 0.2;
cP = 0.35;
}
boolean start = false;
void setup() {
// initialize serial:
Serial.begin(9600);
// init something
initMeasurement();
}
void loop() {
// Recieve data from Node and write it to a String
if (Serial.available() && !start) {
char inChar = (char)Serial.read();
if(inChar == 'S'){ // end character for led
start = true;
}
} else if (start) {
Serial.println("Measuring...");
doMeasure();
Serial.println("Results are:");
Serial.print("Rp = ");
Serial.println(rP);
Serial.print("Lp = ");
Serial.println(lP);
Serial.print("Cp = ");
Serial.println(cP);
start = false;
Serial.println("Ready again");
}
//delay(50); // give the Arduino some breathing room.
}