2017-07-10 20:03:46 +00:00
import { BaseCommand } from './base-command.js' ;
import { app } from './app.js' ;
import { _ } from 'lib/locale.js' ;
2017-07-24 19:47:01 +00:00
import { OneDriveApiNodeUtils } from './onedrive-api-node-utils.js' ;
2017-07-10 20:03:46 +00:00
import { Setting } from 'lib/models/setting.js' ;
import { BaseItem } from 'lib/models/base-item.js' ;
2017-07-17 22:43:29 +00:00
import { Synchronizer } from 'lib/synchronizer.js' ;
2017-07-24 18:01:40 +00:00
import { reg } from 'lib/registry.js' ;
2017-08-04 16:50:12 +00:00
import { cliUtils } from './cli-utils.js' ;
2017-07-24 18:01:40 +00:00
import md5 from 'md5' ;
2017-07-17 19:37:59 +00:00
const locker = require ( 'proper-lockfile' ) ;
const fs = require ( 'fs-extra' ) ;
2017-07-19 19:15:55 +00:00
const osTmpdir = require ( 'os-tmpdir' ) ;
2017-07-10 20:03:46 +00:00
class Command extends BaseCommand {
2017-07-17 18:46:09 +00:00
constructor ( ) {
super ( ) ;
this . syncTarget _ = null ;
2017-07-17 19:37:59 +00:00
this . releaseLockFn _ = null ;
2017-07-17 18:46:09 +00:00
}
2017-07-10 20:03:46 +00:00
usage ( ) {
return 'sync' ;
}
description ( ) {
2017-07-26 21:27:03 +00:00
return _ ( 'Synchronises with remote storage.' ) ;
2017-07-10 20:03:46 +00:00
}
options ( ) {
return [
2017-07-28 18:13:07 +00:00
[ '--target <target>' , _ ( 'Sync to provided target (defaults to sync.target config value)' ) ] ,
2017-07-18 18:49:47 +00:00
[ '--random-failures' , 'For debugging purposes. Do not use.' ] ,
2017-07-10 20:03:46 +00:00
] ;
}
2017-07-17 19:37:59 +00:00
static lockFile ( filePath ) {
return new Promise ( ( resolve , reject ) => {
2017-07-19 19:15:55 +00:00
locker . lock ( filePath , { stale : 1000 * 60 * 5 } , ( error , release ) => {
2017-07-17 19:37:59 +00:00
if ( error ) {
reject ( error ) ;
return ;
}
resolve ( release ) ;
} ) ;
} ) ;
}
static isLocked ( filePath ) {
return new Promise ( ( resolve , reject ) => {
locker . check ( filePath , ( error , isLocked ) => {
if ( error ) {
reject ( error ) ;
return ;
}
resolve ( isLocked ) ;
} ) ;
} ) ;
}
2017-07-10 20:03:46 +00:00
async action ( args ) {
2017-07-17 19:37:59 +00:00
this . releaseLockFn _ = null ;
2017-07-17 18:46:09 +00:00
2017-07-24 18:01:40 +00:00
// Lock is unique per profile/database
const lockFilePath = osTmpdir ( ) + '/synclock_' + md5 ( Setting . value ( 'profileDir' ) ) ;
2017-07-17 19:37:59 +00:00
if ( ! await fs . pathExists ( lockFilePath ) ) await fs . writeFile ( lockFilePath , 'synclock' ) ;
2017-07-14 19:06:01 +00:00
2017-08-04 16:50:12 +00:00
try {
if ( await Command . isLocked ( lockFilePath ) ) throw new Error ( _ ( 'Synchronisation is already in progress.' ) ) ;
2017-07-13 18:09:47 +00:00
2017-08-04 16:50:12 +00:00
this . releaseLockFn _ = await Command . lockFile ( lockFilePath ) ;
} catch ( error ) {
if ( error . code == 'ELOCKED' ) {
const msg = _ ( 'Lock file is already being hold. If you know that no synchronisation is taking place, you may delete the lock file at "%s" and resume the operation.' , error . file ) ;
this . log ( msg ) ;
return ;
}
throw error ;
}
2017-07-10 20:03:46 +00:00
2017-07-17 19:37:59 +00:00
try {
this . syncTarget _ = Setting . value ( 'sync.target' ) ;
if ( args . options . target ) this . syncTarget _ = args . options . target ;
2017-07-24 19:47:01 +00:00
2017-07-26 21:07:27 +00:00
if ( this . syncTarget _ == Setting . SYNC _TARGET _ONEDRIVE && ! reg . syncHasAuth ( this . syncTarget _ ) ) {
2017-07-24 19:47:01 +00:00
const oneDriveApiUtils = new OneDriveApiNodeUtils ( reg . oneDriveApi ( ) ) ;
const auth = await oneDriveApiUtils . oauthDance ( this ) ;
Setting . setValue ( 'sync.3.auth' , auth ? JSON . stringify ( auth ) : null ) ;
if ( ! auth ) return ;
}
2017-07-19 19:15:55 +00:00
2017-07-24 18:01:40 +00:00
let sync = await reg . synchronizer ( this . syncTarget _ ) ;
2017-07-10 20:03:46 +00:00
2017-07-17 19:37:59 +00:00
let options = {
onProgress : ( report ) => {
2017-07-17 22:43:29 +00:00
let lines = Synchronizer . reportToLines ( report ) ;
2017-08-04 16:50:12 +00:00
if ( lines . length ) cliUtils . redraw ( lines . join ( ' ' ) ) ;
2017-07-17 19:37:59 +00:00
} ,
onMessage : ( msg ) => {
2017-08-04 16:50:12 +00:00
cliUtils . redrawDone ( ) ;
2017-07-17 19:37:59 +00:00
this . log ( msg ) ;
} ,
randomFailures : args . options [ 'random-failures' ] === true ,
} ;
2017-07-26 21:27:03 +00:00
this . log ( _ ( 'Synchronisation target: %s (%s)' , Setting . enumOptionLabel ( 'sync.target' , this . syncTarget _ ) , this . syncTarget _ ) ) ;
2017-07-17 19:37:59 +00:00
2017-07-26 21:27:03 +00:00
if ( ! sync ) throw new Error ( _ ( 'Cannot initialize synchroniser.' ) ) ;
2017-07-17 19:37:59 +00:00
2017-07-26 21:27:03 +00:00
this . log ( _ ( 'Starting synchronisation...' ) ) ;
2017-07-17 19:37:59 +00:00
2017-08-19 20:56:28 +00:00
const contextKey = 'sync.' + this . syncTarget _ + '.context' ;
let context = Setting . value ( contextKey ) ;
2017-07-18 19:57:49 +00:00
context = context ? JSON . parse ( context ) : { } ;
options . context = context ;
2017-07-24 19:47:01 +00:00
try {
let newContext = await sync . start ( options ) ;
2017-08-19 20:56:28 +00:00
Setting . setValue ( contextKey , JSON . stringify ( newContext ) ) ;
2017-07-24 19:47:01 +00:00
} catch ( error ) {
if ( error . code == 'alreadyStarted' ) {
this . log ( error . message ) ;
} else {
throw error ;
}
}
2017-07-17 19:37:59 +00:00
await app ( ) . refreshCurrentFolder ( ) ;
} catch ( error ) {
2017-08-04 16:50:12 +00:00
cliUtils . redrawDone ( ) ;
2017-07-17 19:37:59 +00:00
this . releaseLockFn _ ( ) ;
this . releaseLockFn _ = null ;
throw error ;
}
2017-07-15 22:47:11 +00:00
2017-08-04 16:50:12 +00:00
cliUtils . redrawDone ( ) ;
2017-07-17 19:37:59 +00:00
this . releaseLockFn _ ( ) ;
this . releaseLockFn _ = null ;
2017-07-10 20:03:46 +00:00
}
async cancel ( ) {
2017-07-17 18:46:09 +00:00
const target = this . syncTarget _ ? this . syncTarget _ : Setting . value ( 'sync.target' ) ;
2017-08-04 16:50:12 +00:00
cliUtils . redrawDone ( ) ;
this . log ( _ ( 'Cancelling... Please wait.' ) ) ;
2017-07-26 20:09:33 +00:00
2017-07-26 21:07:27 +00:00
if ( reg . syncHasAuth ( target ) ) {
2017-07-26 20:09:33 +00:00
let sync = await reg . synchronizer ( target ) ;
if ( sync ) sync . cancel ( ) ;
} else {
if ( this . releaseLockFn _ ) this . releaseLockFn _ ( ) ;
this . releaseLockFn _ = null ;
}
2017-07-17 18:46:09 +00:00
this . syncTarget _ = null ;
2017-07-10 20:03:46 +00:00
}
}
module . exports = Command ;