npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

remote-sync

v1.0.3

Published

A cross-platform LFTP wrapper for automating file synchronization.

Downloads

15

Readme

Remote Sync

A cross-platform LFTP wrapper for automating file synchronization.

NPM

Documentation | Repository

Features

  • Leverage the power of LFTP to transfer files to/from remote host(s).
  • Logically organize LFTP operations into a workflow that is easily revisable.
  • For speed, open a persistent connection to a designated host and execute your commands in series.
  • Define separate settings (host|user|password) for independent operations that can be executed (a)synchronously.
  • Create a conditional chain of operations where you create the condition for further execution.
  • Use RemoteSync as a general purpose LFTP client.

Dependency

You'll need to have LFTP installed on your machine as its the child process RemoteSync wraps. I chose LFTP as my FTP(S) client because its easy to work with, comes preinstalled on most Unix-based OS distributions and has a nice port to Windows. If you don't already have LFTP installed (Windows) use a package management tool to get the latest version:

Windows (Chocolatey)

C:\> choco install lftp

OSX (Homebrew)

sudo brew install lftp

Linux

sudo apt-get install lftp
sudo yum install lftp

Configuration

Constructor Object

{
  operations : [{},{},..,{}],   // Array of operation objects. See below. 
  lftp_settings : {             // OPTIONAL: LFTP settings. See LFTP man page.
    'setting':'value'
  },
  user : 'user',                // User name for host. Default: ''
  pw : 'password',              // Password for host. Default: ''
  protocol : 'ftp',             // Protocol (Everything LFTP supports) Default: ftp
  host : 'some.host.com',       // Host name. Default: ''
  port : '21',                  // Port number. Default: ''
  persistent : false,           // Persistent connection. Default: false
  sync : true,                  // Synchronously execute operations. Default: true
  exit : false,                 // If persistent, close connection after operations finish. Default: false
  debug : true,                 // Pass debug flag to LFTP for verbose logging. Default: false
  stdio : stdio                 // OPTIONAL: Override stdio configuration of child process. This is overridden
                                // by operation object's stdio property.
}

Operation Object

{
    operation : 'download',     // Operation name. Something that relates to the command.
    command : 'lftp command',   // The LFTP command to run. Refer to man page.
    user : 'user',              // OPTIONAL: User name. If !persistent, overrides constructor value.
    pw : 'password',            // OPTIONAL: Password. If !persistent, overrides constructor value.
    protocol : 'ftp',           // OPTIONAL: Protocol. If !persistent, overrides constructor value.
    host : 'some.host.com',     // OPTIONAL: Host name. If !persistent, overrides constructor value.
    port : '21',                // OPTIONAL: Port number. If !persistent, overrides constructor value.
    settings : {                // OPTIONAL: Do stuff based on configuration.
        sync : fn(child),       // OPTIONAL: If !persistent and sync = true, call fn(child) on finish.
        stdio : stdio           // OPTIONAL: Override stdio configuration of child process. This overrides
                                // constructor object's stdio property.
    }
}

stdio Object

// https://nodejs.org/api/child_process.html#child_process_options_stdio
{
    stdio_config : {stdio:[]},  // See above link for custom configuration.
    stdout : data => fn(data),  // Custom behavior for child's stdout event.
    stderr : data => fn(data),  // Custom behavior for child's stderr event.
    close : code => fn(code),   // Custom behavior for child's close event.
    error : error => fn(error)  // Custom behavior for child's error event.
}

Examples

Fancy level 0: The following example will use a minimal configuration to demonstrate basic functionality. Open a non-persistent connection to ftp.host.com, execute operation 1 and exit.

// client.js
const RemoteSync = require('remote-sync');
const config = {
    operations : [
        {
            operation : 'List',
            command : 'nlist files'
        }
    ],
    user : 'kurt',
    pw : 'foobar',
    host : 'ftp.host.com'
};
const client = new RemoteSync(config);
client.perform(); // Returns a remote listing of files at ftp.host.com/files/

Fancy level 1: Add lftp_settings to the constructor object to customize the session. Open a non-persistent connection to ftp.host.com using FTPES (Explicit FTP over TLS), set parallel transfer count to 5, execute operation 1 and exit. (Read about the flags passed to mirror at LFTP.)

// client.js
const RemoteSync = require('remote-sync');
const command = 'mirror -c --only-missing <source> <dest>';
const config = {
    operations : [
        {
            operation : 'mirror directory',
            command : command
        }
    ],
    user : 'kurt',
    pw : 'foobar',
    host : 'ftp.host.com',
    lftp_settings : {
        'ftp:ssl-force':'true',
        'ftp:ssl-protect-data':'true',
        'ssl:verify-certificate':'false',
        'net:max-retries':'2',
        'net:timeout':'10',
        'net:connection-limit':'5',
        'net:reconnect-interval-base':'5',
        'net:reconnect-interval-multiplier':'1',
        'mirror:parallel-transfer-count':'5'
    }
};
const client = new RemoteSync(config);
client.perform(); // Mirror only missing files from remote source to local disk.

Fancy level 2: Create a conditional chain of operations where you create the condition for further execution. Open a non-persistent connection to ftp.host.com and execute operation 1. If operation 1's status is not 0 (success) exit the parent process, halting any further execution. If operation 1 is successful, operations 2 & 3 will be executed.

// client.js
const RemoteSync = require('remote-sync');
const mirror = 'mirror -c --only-missing <source> <dest>';
const remove = 'rm -r <source>';
const list = 'nlist files';
const config = {
    operations : [
        {
            operation : 'mirror directory',
            command : mirror,
            settings : {
                sync : child => {
                    if (child.status != 0) {
                        process.exit(1);
                    }
                }
            }
        },
        {  
            operation : 'delete directory',
            command : remove
        },
        {
            operation : 'list directory',
            command : list,
            user : 'username',
            pw : 'password',
            host : 'other.host.com'
        }
    ],
    user : 'kurt',
    pw : 'foobar',
    host : 'ftp.host.com',
    lftp_settings : settings_obj, // omitted for brevity
    sync : true
};
const client = new RemoteSync(config);
client.perform();   // Mirror only missing files from remote source to local disk.
                    // If successful, delete the remote source and get remote listing
                    // from other.host.com/files/

Fancy level 3: Open a persistent connection (persistent: true) to the designated host and perform operations in series. In this configuration a connection is established to ftp.host.com, each operation's command is executed in series followed by severing the connection (exit: true).

// client.js
const RemoteSync = require('remote-sync');
const mirror = 'mirror -c --only-missing <source> <dest>';
const upload = 'mirror -R -c --only-newer --overwrite --exclude .git/ <local> <remote>'; // reverse mirror -R
const config = {
    operations : [
        {
            operation : 'mirror directory',
            command : mirror
        },
        {  
            operation : 'upload directory',
            command : upload
        }
    ],
    user : 'kurt',
    pw : 'foobar',
    host : 'ftp.host.com',
    lftp_settings : settings_obj, // omitted for brevity
    persistent : true,
    exit : true
};
const client = new RemoteSync(config);
client.perform();   // Connection stays open until `mirror` and `upload` complete

General Purpose LFTP Client

'use strict';
const RemoteSync = require('remote-sync');
const rs = new RemoteSync({
  user : 'kurt',
  pw : 'foobar',
  host : 'ftp.host.com'
});
// Define an iterator and execute commands in series
rs[Symbol.iterator] = function* () {
    yield rs.commands('nlist files').execute();
    yield rs.commands('nlist files/completed').execute();
    yield rs.commands('nlist files').execute();
};
[...rs];

Common Commands

Mirror directory from source to dest

const mirror = 'mirror -c --only-missing <source> <dest>';

Upload directory from local to remote

const upload = 'mirror -R -c --only-newer --overwrite --exclude .git/ <local> <remote>';

Delete remote source

const remove = 'rm -r <source>';

Get remote listing source

const list = 'nlist <source>';

Cronjob

# Run client.js every 15 minutes
0/15 * * * * path/to/node path/to/client.js