function Client(options) { this._options = options || {}; this.remote = {}; }
n/a
scp = function (src, dest, client, callback) { if (typeof client === 'function') { callback = client; client = new Client(); } client.on('error', callback); var parsed = client.parse(src); if (parsed.host && parsed.path) { cp2local(client, parsed, dest, callback); } else { cp2remote(client, src, dest, callback); } }
...
```js
var client = require('scp2')
```
Copy a file to the server:
```js
client.scp('file.txt', 'admin:password@example.com:/home/admin/',
function(err) {
})
```
You can also add the port to the url (default is 22):
```js
client.scp('file.txt', 'admin:password@example.com:port:/home/admin/', function(err) {
...
function Client(options) { this._options = options || {}; this.remote = {}; }
n/a
function EventEmitter() { EventEmitter.init.call(this); }
n/a
close = function () { if (this.__sftp) { this.__sftp.end(); this.__sftp = null; } if (this.__ssh) { this.__ssh.end(); this.__ssh = null; } }
...
self.emit('transfer', buf, lastCursor, length);
sftp.write(handle, buf, 0, buf.length, lastIndex, function(err) {
lastIndex += buf.length;
lastCursor += 1;
callback(err);
});
}, function(err) {
sftp.close(handle, callback);
});
} else if (typeof content === 'number') {
// content is a file descriptor
length = parseInt((attrs.size - 1) / chunkSize, 10) + 1;
var range = new Array(length);
async.eachSeries(range, function(pos, callback) {
chunkSize = Math.min(chunkSize, attrs.size - lastIndex);
...
defaults = function (options) { if (options) { this._options = options || {}; } else { return this._options; } }
...
- **defaults** `function({})`
set the default values for the remote server.
```js
client.defaults({
port: 22,
host: 'example.com',
username: 'admin',
privateKey: '....',
// password: 'password', (accepts password also)
});
```
...
download = function (src, dest, callback) { var self = this; self.sftp(function(err,sftp){ if (err) { return callback(err); } var sftp_readStream = sftp.createReadStream(src); sftp_readStream.on('error', function(err){ callback(err); }); sftp_readStream.pipe(fs.createWriteStream(dest)) .on('close',function(){ self.emit('read', src); callback(null); }) .on('error', function(err){ callback(err); }); }); }
...
function cp2local(client, src, dest, callback) {
var remote = client.parse(src);
// only works on single file now
// TODO: glob match
if (/\/$/.test(dest)) {
dest = dest + path.basename(remote.path);
}
client.download(remote.path, dest, function () {
client.close();
callback.apply(this, arguments);
});
}
exports = module.exports = global_client;
...
mkdir = function (dir, attrs, callback) { if (_.isFunction(attrs)) { callback = attrs; attrs = undefined; } if (attrs) { attrs.mode = getFolderAttr(process.platform, attrs); } var self = this; var dirs = []; var exists = false; this.sftp(function(err, sftp) { if (err) { return callback(err); } // for record log var mkdir = function(dir, callback) { self.emit('mkdir', dir); sftp.mkdir(dir, attrs, callback); }; async.until(function() { return exists; }, function(done) { // detect if the directory exists sftp.stat(dir, function(err, attr) { if (err) { dirs.push(dir); dir = path.dirname(dir); } else { exists = true; } done(); }); }, function(err) { if (err) { callback(err); } else { // just like mkdir -p async.eachSeries(dirs.reverse(), mkdir, callback); } }); }); }
...
if (err) {
return callback(err);
}
// for record log
var mkdir = function(dir, callback) {
self.emit('mkdir', dir);
sftp.mkdir(dir, attrs, callback);
};
async.until(function() {
return exists;
}, function(done) {
// detect if the directory exists
sftp.stat(dir, function(err, attr) {
...
parse = function (remote) { if (_.isString(remote)) { // username:password@host:/path/to var regex = /^([a-zA-Z0-9\-\.]+)(\:.*)?@([^:]+):([^:]+:)?(.*)?$/; var m = remote.match(regex); if (!m) return {}; var ret = { username: m[1], host: m[3], }; if (m[2]) { ret.password = m[2].slice(1); } if (m.length===6 && m[4]) { ret.port = m[4].slice(0,-1); } if (m.length===6 && m[5]) { ret.path = m[5]; } else if (m.length===5 && m[4]) { ret.path = m[4]; } this.remote = ret; return ret; } this.remote = remote; return remote; }
...
var path = require('path');
var glob = require('glob');
var async = require('async');
var Client = require('./client').Client;
var global_client = new Client();
function cp2remote(client, src, dest, callback) {
client.parse(dest);
var _upload = function(files, callback) {
var rootdir = files[0];
async.eachSeries(files, function(fpath, done) {
fs.stat(fpath, function(err, stats) {
if (err) {
...
sftp = function (callback) { if (this.__sftp) { callback(null, this.__sftp); return; } var remote = _.defaults(this.remote, this._options); if (this.__ssh) { this.__ssh.connect(remote); return; } var self = this; var ssh = new Connection(); ssh.on('connect', function() { self.emit('connect'); }); ssh.on('ready', function() { self.emit('ready'); ssh.sftp(function(err, sftp) { if (err) throw err; // save for reuse self.__sftp = sftp; callback(err, sftp); }); }); ssh.on('error', function(err) { self.emit('error', err); callback(err); }); ssh.on('end', function() { self.emit('end'); }); ssh.on('close', function() { self.emit('close'); }); ssh.on('keyboard-interactive', function(name, instructions, instructionsLang, prompts, finish) { self.emit('keyboard-interactive', name, instructions, instructionsLang, prompts, finish); }); ssh.on('change password', function(message, language, done) { self.emit('change password', message, language, done); }); ssh.on('tcp connection', function(details, accept, reject) { self.emit('tcp connection', details, accept, reject); }); ssh.connect(remote); this.__ssh = ssh; }
...
var ssh = new Connection();
ssh.on('connect', function() {
self.emit('connect');
});
ssh.on('ready', function() {
self.emit('ready');
ssh.sftp(function(err, sftp) {
if (err) throw err;
// save for reuse
self.__sftp = sftp;
callback(err, sftp);
});
});
ssh.on('error', function(err) {
...
upload = function (src, dest, callback) { dest = unixy(dest); var self = this; async.waterfall([ function(callback) { fs.stat(src, callback); }, function(stat, callback) { if (stat.isDirectory()) return callback(new Error('Can not upload a directory')); // Get the attributes of the source directory fs.stat(path.dirname(src), function(err, dirStat) { if(err) return callback(err); self.mkdir(path.dirname(dest), dirStat, function(err){ callback(err, stat) }); }); }, function(stat, callback) { fs.open(src, 'r', function(err, fd) { callback(err, stat, fd); }); }, function(stat, fd, callback) { self.write({ source: src, destination: dest, content: fd, attrs: stat }, callback); } ], function(err) { callback(err); }); }
...
- source: the source path, e.g. local/file.txt
- **upload** `function(src, dest, callback) -> callback(err)`
upload a local file to the server.
```js
client.upload('file.txt', '/home/admin/file.txt', callback)
```
- **download** `function(src, dest, callback) -> callback(err)`
download a server file to local.
...
write = function (options, callback) { var destination = options.destination; destination = unixy(destination); var attrs = options.attrs; var content = options.content; var chunkSize = options.chunkSize || 32768; var self = this; this.sftp(function(err, sftp) { if (err) { return callback(err); } var _write = function(handle) { self.emit('write', options); var length; var lastIndex = 0; var lastCursor = 0; if (Buffer.isBuffer(content)) { var contents = []; length = parseInt((content.length - 1) / chunkSize, 10) + 1; for (var i = 0 ; i < length; i++) { contents.push(content.slice(i * chunkSize, (i + 1) * chunkSize)); } async.eachSeries(contents, function(buf, callback) { self.emit('transfer', buf, lastCursor, length); sftp.write(handle, buf, 0, buf.length, lastIndex, function(err) { lastIndex += buf.length; lastCursor += 1; callback(err); }); }, function(err) { sftp.close(handle, callback); }); } else if (typeof content === 'number') { // content is a file descriptor length = parseInt((attrs.size - 1) / chunkSize, 10) + 1; var range = new Array(length); async.eachSeries(range, function(pos, callback) { chunkSize = Math.min(chunkSize, attrs.size - lastIndex); if (!chunkSize) { callback(err); return; } var buf = new Buffer(chunkSize); fs.read(content, buf, 0, chunkSize, lastIndex, function(err, byteRead, buf) { self.emit('transfer', buf, lastCursor, length); sftp.write(handle, buf, 0, buf.length, lastIndex, function(err) { lastIndex += buf.length; lastCursor += 1; callback(err); }); }); }, function(err) { sftp.close(handle, function(err) { fs.close(content, callback); }); }); } else { throw new Error('Content should be buffer or file descriptor'); } }; sftp.open(destination, 'w', attrs, function(err, handle) { if (err) { // destination is directory destination = path.join( destination, path.basename(options.source) ); destination = unixy(destination); // for emit write event options.destination = destination; sftp.open(destination, 'w', attrs, function(err, handle) { _write(handle); }); } else { _write(handle); } }); }); }
...
Make a directory on the remote server. It behaves like `mdkir -p`.
- **write** `function(options, callback) -> callback(err)`
Write content on the remote server.
```js
client.write({
destination: '/home/admin/data/file.txt',
content: 'hello world'
}, callback)
```
The options can contain:
...
function Client(options) { this._options = options || {}; this.remote = {}; }
n/a
scp = function (src, dest, client, callback) { if (typeof client === 'function') { callback = client; client = new Client(); } client.on('error', callback); var parsed = client.parse(src); if (parsed.host && parsed.path) { cp2local(client, parsed, dest, callback); } else { cp2remote(client, src, dest, callback); } }
...
```js
var client = require('scp2')
```
Copy a file to the server:
```js
client.scp('file.txt', 'admin:password@example.com:/home/admin/',
function(err) {
})
```
You can also add the port to the url (default is 22):
```js
client.scp('file.txt', 'admin:password@example.com:port:/home/admin/', function(err) {
...
function Client(options) { this._options = options || {}; this.remote = {}; }
n/a