tftp
Version:
Streaming TFTP client and server
168 lines (148 loc) • 4.04 kB
JavaScript
var fs = require ("fs");
var path = require ("path");
var GetStream = require ("./streams/client/get-stream");
var PutStream = require ("./streams/client/put-stream");
var normalizeFilename = require ("./normalize-filename");
var createOptions = require ("./create-options");
var errors = require ("./protocol/errors");
var Client = module.exports = function (options){
this._options = createOptions (options);
};
Client.prototype.createGetStream = function (remote, options){
remote = normalizeFilename (remote);
return new GetStream (remote, this._options, options);
};
Client.prototype.createPutStream = function (remote, options){
remote = normalizeFilename (remote);
return new PutStream (remote, this._options, options);
};
Client.prototype.get = function (remote, local, options, cb){
remote = normalizeFilename (remote);
var argsLength = arguments.length;
if (argsLength === 2){
cb = local;
local = path.basename (remote);
}else if (argsLength === 3){
if (typeof local === "object"){
cb = options;
options = local;
local = path.basename (remote);
}else if (typeof local === "string"){
cb = options;
options = {};
}
}
var me = this;
//Check if local is a dir to prevent from starting a new request
fs.stat (local, function (error, stats){
if (error){
if (error.code !== "ENOENT") return cb (error);
}else if (stats.isDirectory ()){
return cb (new Error ("The local file is a directory"));
}
var wsError;
var open = false;
var destroy = null;
var gs = new GetStream (remote, me._options, options)
.on ("error", function (error){
if (open){
ws.on ("close", function (){
fs.unlink (local, function (){
cb (error);
});
});
ws.destroy ();
}else{
destroy = error;
}
})
.on ("abort", function (){
fs.unlink (local, function (){
cb (wsError);
});
});
var ws = fs.createWriteStream (local)
.on ("error", function (error){
wsError = error;
gs.abort (errors.EIO.message);
})
.on ("open", function (){
if (destroy){
ws.on ("close", function (){
fs.unlink (local, function (){
cb (destroy);
});
});
ws.destroy ();
}else{
open = true;
}
})
.on ("finish", function (){
cb ();
});
gs.pipe (ws);
});
};
Client.prototype.put = function (local, remote, options, cb){
var argsLength = arguments.length;
if (argsLength === 2){
cb = remote;
remote = path.basename (local);
options = {};
}else if (argsLength === 3){
if (typeof remote === "object"){
cb = options;
options = remote;
remote = path.basename (local);
}else if (typeof remote === "string"){
cb = options;
options = {};
}
}
remote = normalizeFilename (remote);
var me = this;
//Check if local is a dir or doesn't exist to prevent from starting a new
//request
fs.stat (local, function (error, stats){
if (error) return cb (error);
if (stats.isDirectory ()){
return cb (new Error ("The local file is a directory"));
}
var rsError;
var closed = false;
var rs = fs.createReadStream (local)
.on ("error", function (error){
rsError = error;
ps.abort (errors.EIO.message);
})
.on ("close", function (){
closed = true;
});
options = {
highWaterMark: options.highWaterMark,
userExtensions: options.userExtensions,
size: stats.size
};
var ps = new PutStream (remote, me._options, options)
.on ("error", function (error){
if (closed){
//Empty origin file
cb (error);
}else{
rs.on ("close", function (){
cb (error);
});
rs.destroy ();
}
})
.on ("abort", function (){
cb (rsError);
})
.on ("finish", function (){
cb ();
});
rs.pipe (ps);
});
};
;