Light Node.js script to send large files P2P

In this article you will find two lightweight Node.js scripts that will allow you to send very large files from one computer to another peer-to-peer (P2P). There is a lot of different scenarious when they can be usefull: for example if your file is too big to be send via RDP protocol (as it has limit at 2Gb per file).

Prerequisites:

What you need:

  • You need Node.JS interpreter to be installed on both computers (you can download it from here): server (from which you will load file) and client (from where you will load it);
  • Ability to open ports on server machine;
  • Ability to reach server from client (firewall should no break off connection).

How does it works?

There is two scripts:

  • Server side script – reads specified file from computer and sends it to client, when client requests it;
  • Client side – sends requests to server and downloads file to current folder;

Server.js side script

To execute server side script open terminal (command line), go to folder where you saved file and write: node node server.js --path pathToFile, change pathToFile with path to file that you would like to send to client. Path to file can be absolute or relative.

By default script will use 8000 port, if you would like to use another one, change it in the script (4 line).

const fs = require('fs');
const path = require('path');

const port = 8000;

;(() => {
	const filePathI = process.argv.indexOf('--path');
	if(filePathI == -1){
      console.log('Please call script with --path arg.');
      process.exit();
   }

	const filepath = process.argv[filePathI + 1];

	if(!fs.existsSync(filepath)){ console.log(`File does not exists!`); process.exit(); }
	const stats = fs.statSync(filepath);

	if(stats.isDirectory()){
      console.log(`File is Directory. You could not transfer directories with this script`);
      process.exit();
   }

	console.log(`You are about to transfer file: '${filepath}'`);
	console.log(`File size is ${Math.round(stats.size/1024/1024*100)/100} Mb`)

	const server = require('http').createServer();
	server.on('request', (req, res) => {
		if(req.url == '/info'){
			console.log(`Send information on file`);
			res.end(JSON.stringify({path: filepath, pathDesc: path.parse(filepath), stats}));
		} else if(req.url == '/file'){
			console.log(`Start tranfering of file`);

			const src = fs.createReadStream(filepath);
			src.pipe(res);
			src.on('end', () => {
				console.log("Transfer successfully");
				process.exit();
			});
		}
	});

	server.on('error', (e) => {
      console.error(e);
      process.exit();
   })
	server.listen(port);
})()

Client.js side script

Now is the time to load file to client machine:

  1. Save client.js file to some place on machine;
  2. Open file and change server variable, put yours machine address and port that server.js is using (by default 8000 port will be used);
  3. Open terminal and navigate to the folder from step 1;
  4. Execute node client.js. Script will start loading process. After loading process you should see message Loading is finished, if so everything is OK and you successfully load file. If You see some other message something wrong happened.

 const fs = require('fs');
 const http = require('http');
 const url = require('url');
 const path = require('path');
 
 var server = 'http://serverAddress:8000/'
 
 const getInfo = ()=>{
   return new Promise((resolve, reject) => {
     console.log(`-- Request information about the file from server`)
     http.get(url.resolve(server, '/info'), (res) => {
       let rawData = '';
       res.on('data', (chunk) => { rawData += chunk; });
       res.on('end', () => {
         try {
           return resolve(JSON.parse(rawData))
         } catch (e) {
             return reject(e);
         }
       });
     }).on("error", (err) => {
       return reject(err);
     });
   })
 }
 
 function processBar(fullsize, loaded) {
   var bars = 20;
   var loadBars = Math.round(bars * (loaded / fullsize));
   var remainBars = bars - loadBars;
 
   console.log(`[${'='.repeat(loadBars)}>${'.'.repeat(remainBars)}] ${Math.round(loaded/1024/1024*100)/100}/${Math.round(fullsize/1024/1024*100)/100}Mb`);
 }
 
 const loadFile = (info) => {
   return new Promise((resolve, reject) => {
     console.log(`-- Start file loading`)
     var pathParsed = path.parse(info.path)
     console.log(`File name is '${info.pathDesc.base}'`)
 
     if(fs.existsSync(info.pathDesc.base)){
       return reject(`Such file already exists in current folder`);
     }
 
     console.log(`File size is ${Math.round(info.stats.size/1024/1024*100)/100} Mb`)
 
     processBar(info.stats.size, 0)
 
     http.get(url.resolve(server, '/file'), (resp) => {
       var file = fs.createWriteStream('./'+info.pathDesc.base)
       var getSize = 0;
       resp.pipe(file);
       resp.on('data', chunk => {
         getSize += chunk.length
         processBar(info.stats.size, getSize)
       })
       resp.on('end', () => {
         console.log("\nLoading is finished");
         return resolve();
       });
     }).on("error", (err) => {
       return reject(err.message);
     });
   })
 }
 
 getInfo().then((info) => loadFile(info))
 .catch(e => {
   console.log(`Error in processing, stop of script execution:`)
   console.error(e)
 })

Good luck!