How do I watchify multiple targets in Gulp? - stream

I am using browserify to listen to compile multiple files into multiple targets, like so (using this trick):
gulp.task('js', function () {
var bundler = through2.obj(function (file, enc, next) {
browserify(file.path).bundle(function(err, res) {
file.contents = res;
next(null, file);
});
});
return gulp.src(['foo.js', 'bar.js'])
.pipe(bundler)
.pipe(uglify())
// Other pipes
.pipe(gulp.dest('./compiled'));
});
How can I combine this through2 usage with watchify? The common advice about using vinyl-source-stream does not work for me. I want to generate two files (compiled/foo.js and compiled/bar.js). I don't want to combine the files into one.

I figured out how to combine through2 and watchify. The trick is to not call next() on updates:
var bundler = through.obj(function (file, enc, next) {
var b = watchify(browserify(file.path))
b.on('update', function () {
gutil.log('Updated', gutil.colors.magenta(file.path));
b.bundle(function (err, res) {
file.contents = res;
// Do not call next!
});
b.on('log', gutil.log);
}
b.bundle(function (err, res) {
file.contents = res;
next(null, file);
});
});

Related

Content.once is not a function

I try to push a file to the IPFS, and I have converted to the Buffer. I got this error " content.once is not a function".
I am using this library in node.
var Buffer = require('buffer/').Buffer;
const doc = new jsPDF();
doc.fromHTML('test',10,10);
var covnertedBuffer = Buffer.from(doc.output('arraybuffer');
Then, I take the convertedBuffer and pass it to the IPFS api.
Any idea?
Updated test:
I have successfully pushed a file to the IPFS via the API with this code below.
const filename = '/home/administrator/Downloads/5HP8LWKHLV.pdf';
this.ipfsApi = ipfsApi('localhost', '5001');
let readablestream = fs.createReadStream(filename);
readablestream.on('readable', () => {
let result = readablestream.read();
console.log(result);
if (result) {
this.ipfsApi.files.add(result, function(err, files) {
if (err) {
res.json('err');
console.log(err);
}
res.json(files);
});
}
});
But, when I get the arrayBuffer from the doc.output and convert to the Buffer object and push to the IPFS and it failed. Please see below.
var _buffer = Buffer.from(req.buffer);
console.log('Converted to buffer:' + _buffer);
this.ipfsApi = ipfsApi('localhost', '5001');
this.ipfsApi.files.add(_buffer, function(err, files) {
if (!err) {
res.status(500);
console.log(err);
} else {
res.json(files);
res.status(200);
}
});
Thank you
Adding Buffer.from(your_buffer) to your buffer before doing ipfs push works.
ipfs.files.add(Buffer.from(put_your_buffer_here), (error, result) => {
if(error) {
console.error(error)
return
}
console.log("upload is successful");
});

How to upload file in angular 2

This is the function I am using to upload file but is is giving me the error : Length is undefined. what I have to change in this code. where to give path of file to upload.
fileChange(event) {
let fileList: FileList = event.target.files;
if(fileList) {
let file: File = fileList[0];
let formData:FormData = new FormData();
formData.append('uploadFile', file, file.name);
let headers = new Headers();
/** No need to include Content-Type in Angular 4 */
headers.append('Content-Type', 'multipart/form-data');
headers.append('Accept', 'application/json');
let options = new RequestOptions({ headers: headers });
this.http.post(`assets/Files/info.txt`, formData, options)
.map(res => res.json())
.catch(error => Observable.throw(error))
.subscribe(
data => console.log(fileList),
error => console.log(error)
)
}
}
you need to use xhr request to transfer files
fileChange(event: EventTarget) {
let eventObj: MSInputMethodContext = <MSInputMethodContext> event;
let target: HTMLInputElement = <HTMLInputElement> eventObj.target;
let files: FileList = target.files;
if(files) {
let file: File = files[0];
this.upload(file)
}
}
public upload(filedata: File) {
let url = 'your url'
if (typeof filedata != 'undefined') {
return new Promise((resolve, reject) => {
let formData: any = new FormData();
let xhr = new XMLHttpRequest();
formData.append('icondata', filedata, filedata.name);
xhr.open('POST', url, true);
xhr.setRequestHeader('Authorization', 'JWT ' + localStorage.getItem('id_token'));
xhr.send(formData);
xhr.onreadystatechange = function () {
if (xhr.readyState == XMLHttpRequest.DONE) {
resolve(JSON.parse(xhr.responseText));
}
}
});
}
}
I understand that this is not the functionality you want to have but with no backend you can not upload files to be persistent, they should be stored somewhere. If you just wanna manipulate file names for instance, skip the express part in my answer. I personally used this code which I altered to upload multiple files.
In your Component :
import {FormArray, FormBuilder, FormControl, FormGroup} from "#angular/forms";
declare FormBuilder in the constructor:
constructor (private http: Http, private fb: FormBuilder) {}
in ngOnInit() set a variable as follows :
this.myForm = this.fb.group({chosenfiles: this.fb.array([])});
this is the code for the upload method :
// invoke the upload to server method
// TODO
// Should be in a service (injectable)
upload() {
const formData: any = new FormData();
const files: Array<File> = this.filesToUpload;
//console.log(files);
const chosenf = <FormArray> this.myForm.controls["chosenfiles"];
// iterate over the number of files
for(let i =0; i < files.length; i++){
formData.append("uploads[]", files[i], files[i]['name']);
// store file name in an array
chosenf.push(new FormControl(files[i]['name']));
}
this.http.post('http://localhost:3003/api/upload', formData)
.map(files => files.json())
.subscribe(files => console.log('upload completed, files are : ', files));
}
the method responsible for the file change :
fileChangeEvent(fileInput: any) {
this.filesToUpload = <Array<File>>fileInput.target.files;
const formData: any = new FormData();
const files: Array<File> = this.filesToUpload;
console.log(files);
const chosenf = <FormArray> this.myForm.controls["chosenfiles"];
// iterate over the number of files
for(let i =0; i < files.length; i++){
formData.append("uploads[]", files[i], files[i]['name']);
// store file name in an array
chosenf.push(new FormControl(files[i]['name']));
}
}
Template is something like this
<input id="cin" name="cin" type="file" (change)="fileChangeEvent($event)" placeholder="Upload ..." multiple/>
Notice multiple responsible for allowing multiple selections
The express API which will handle the request uses multer after an npm install
var multer = require('multer');
var path = require('path');
specify a static directory which will hold the files
// specify the folder
app.use(express.static(path.join(__dirname, 'uploads')));
As specified by multer
PS: I did not investigate multer, as soon as i got it working, i moved to another task but feel free to remove unnecessary code.
var storage = multer.diskStorage({
// destination
destination: function (req, file, cb) {
cb(null, './uploads/')
},
filename: function (req, file, cb) {
cb(null, file.originalname);
}
});
var upload = multer({ storage: storage });
And finally the endpoint
app.post("/api/upload", upload.array("uploads[]", 12), function (req, res) {
console.log('files', req.files);
res.send(req.files);
});

How to prevent multiple instances in Electron

I do not know if this is possible but I might as well give it a chance and ask.
I'm doing an Electron app and I'd like to know if it is possible to have no more than a single instance at a time.
I have found this gist but I'm not sure hot to use it. Can someone shed some light of share a better idea ?
var preventMultipleInstances = function(window) {
var socket = (process.platform === 'win32') ? '\\\\.\\pipe\\myapp-sock' : path.join(os.tmpdir(), 'myapp.sock');
net.connect({path: socket}, function () {
var errorMessage = 'Another instance of ' + pjson.productName + ' is already running. Only one instance of the app can be open at a time.'
dialog.showMessageBox(window, {'type': 'error', message: errorMessage, buttons: ['OK']}, function() {
window.destroy()
})
}).on('error', function (err) {
if (process.platform !== 'win32') {
// try to unlink older socket if it exists, if it doesn't,
// ignore ENOENT errors
try {
fs.unlinkSync(socket);
} catch (e) {
if (e.code !== 'ENOENT') {
throw e;
}
}
}
net.createServer(function (connection) {}).listen(socket);;
});
}
There is a new API now: requestSingleInstanceLock
const { app } = require('electron')
let myWindow = null
const gotTheLock = app.requestSingleInstanceLock()
if (!gotTheLock) {
app.quit()
} else {
app.on('second-instance', (event, commandLine, workingDirectory) => {
// Someone tried to run a second instance, we should focus our window.
if (myWindow) {
if (myWindow.isMinimized()) myWindow.restore()
myWindow.focus()
}
})
// Create myWindow, load the rest of the app, etc...
app.on('ready', () => {
})
}
Use the makeSingleInstance function in the app module, there's even an example in the docs.
In Case you need the code.
let mainWindow = null;
//to make singleton instance
const isSecondInstance = app.makeSingleInstance((commandLine, workingDirectory) => {
// Someone tried to run a second instance, we should focus our window.
if (mainWindow) {
if (mainWindow.isMinimized()) mainWindow.restore()
mainWindow.focus()
}
})
if (isSecondInstance) {
app.quit()
}

Where should I put completer.complete() in this series of Future functions?

My function have to create a directory, and copy the entire folder hierarchy from another directory to this new one. All of the operation are done asynchronously, but I want this function to return a Future that when I call the .then(result) on it, will have done all of the asynchronously work.
But I don't know where exactly I should put my completer.complete() to achieve that.
Future<Directory> createCopyDirectory(Directory directoryToCreate){
Completer<Directory> completer = new Completer<Directory>();
completer.complete(
directoryToCreate.create().then((directory){
Directory contentToCopy = new Directory(globalPathOfDirectoryToCopy);
List<Future> creatingContent = new List<Future>();
contentToCopy.list(recursive:true, followLinks:false).forEach((f){
if (f is File){
File fileToCreate = new File(f.path.replaceFirst('pages', userID));
creatingContent.add(fileToCreate.create(recursive:true).then((_){
f.readAsString().then((fileContent){
fileToCreate.writeAsString(fileContent);
});
}));
}
});
return Future.wait(creatingContent).then((_){ return directoryToCreate;});
})
);
return completer.future;
}
I precise that my function work like expected, But if I try to access directly the content I should have created in this function, like in the then() call, Dart bring me an expection like I have not created the content. So the completer.complete() is surely badly placed and call then() before the content has been created.
I have tried with the completer.complete() on the ending Future.wait(creatingContent) or by replacing return directoryToCreate by completer.complete(directoryToCreate) but the result is the same.
I am a bit confused on the way to build a proper Future based function in this kind of situation.
You shouldn't need a Completer here.
Future<Directory> createCopyDirectory(Directory directoryToCreate) {
return directoryToCreate.create().then((directory) {
String userID = split(userDirectory.path).last;
Directory contentToCopy = new Directory(globalPathOfDirectoryToCopy);
List<Future> creatingContent = new List<Future>();
return contentToCopy
.list(recursive: true, followLinks: false)
.forEach((File f) {
if (f is File) {
File fileToCreate = new File(f.path.replaceFirst('pages', userID));
creatingContent.add(fileToCreate.create(recursive: true).then((_) {
return f.readAsString().then((fileContent) {
return fileToCreate.writeAsString(fileContent);
});
}));
}
}).then((_) {
return Future.wait(creatingContent).then((_) {
return directoryToCreate;
});
});
});
}
Just to demonstrate how you could use the Completer:
Future<Directory> createCopyDirectory(Directory directoryToCreate) {
Completer<Directory> completer = new Completer<Directory>();
directoryToCreate.create().then((directory) {
String userID = split(userDirectory.path).last;
Directory contentToCopy = new Directory(globalPathOfDirectoryToCopy);
List<Future> creatingContent = new List<Future>();
contentToCopy.list(recursive: true, followLinks: false).forEach((f) {
if (f is File) {
File fileToCreate = new File(f.path.replaceFirst('pages', userID));
creatingContent.add(fileToCreate.create(recursive: true).then((_) {
return f.readAsString().then((fileContent) {
return fileToCreate.writeAsString(fileContent);
});
}));
}
}).then((_) => Future
.wait(creatingContent)
.then((_) => completer.complete(directoryToCreate)));
});
return completer.future;
}

How to return a FileContent with FileReader from function in PhoneGap iOS?

If, for example, i will that fileReader must return a content value of file, i get back only empty string. Global variable for me impossible to use, only local. Is it possible?
What do i wrong?
Edit:
function onDeviceReady() {
console.log("==> DEVICE READY");
window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, onFSSuccess, fileErrorMSG);
}
function onFSSuccess(fs) {
fileSystem = fs;
}
function readlocalFile(fileName) {
var core = "";
fileSystem.root.getFile(fileName, {create: false}, function(f) {
f.file(function(e) {
var reader = new FileReader();
reader.onloadend = function(evt) {
var res = $.parseJSON(evt.target.result);
core = res;
};
reader.readAsText(e);
});//f.file()
}, fileErrorMSG);
return core;
}
function loadDefaultCore(url) {
if (url) {
var myCore = readlocalFile(url);
console.log(myCore); // **output - empty string!!!!!!!!**
} else {
alert('can not load default core');
}
}
Thanks!
Well there a bunch of things to consider. In brief:
First, to read a file you need to get the file system.
Second, on success you need to get the file entry using the file system.
Third, on success read the file using the file entry.
The three have to be chained via the functions callbacks.
You are getting empty as you file is not being read.
I follow the chain an after the onFSSuccess function the chain is broken, the readLocalFile function is not being called, just add it after you assign your file system to the fileSystem variable which I assume is a global variable. Or call your function loadDefaultCore, I am not sure which one you really want to call first.
It will help you if you add more console log messages in each function so you can actually debug the problem easily.
Also, did you have your document even listener attached to the device ready function?
Any messages, errors warnings in the console?
From the phonegap file api, follow this and you will be safe. Check the doc for the phonegap version you are working on.
http://docs.phonegap.com/en/2.4.0/cordova_file_file.md.html#FileReader
<script type="text/javascript" charset="utf-8">
// Wait for Cordova to load //function onLoad() { document.addEventListener("deviceready", onDeviceReady, false); }
// Cordova is ready //function onDeviceReady() { window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, gotFS, fail); }
function gotFS(fileSystem) { fileSystem.root.getFile("readme.txt", null, gotFileEntry, fail); }
function gotFileEntry(fileEntry) { fileEntry.file(gotFile, fail); }
function gotFile(file){ readDataUrl(file); readAsText(file); }
function readDataUrl(file) { var reader = new FileReader(); reader.onloadend = function(evt) { console.log("Read as data URL"); console.log(evt.target.result); }; reader.readAsDataURL(file); }
function readAsText(file) { var reader = new FileReader(); reader.onloadend = function(evt) { console.log("Read as text"); console.log(evt.target.result); }; reader.readAsText(file); }
function fail(evt) { console.log(evt.target.error.code); }
</script>

Resources