Skip to content
Permalink
Browse files

feat(backup): backup current wallet on login

  • Loading branch information...
korhaliv committed May 15, 2019
1 parent 58aa759 commit c1a1757fbb9203594c4c24bd54eefe777d6698eb
@@ -6,7 +6,7 @@ import delay from '@zap/utils/delay'
import * as api from './gdriveApi'

/**
*Creates google drive api connection
* Creates google drive api connection
* @param {*} { clientId, authRedirectUrl, scope, tokens }
* @returns {Object} returns {drive, accessTokens} object. `drive` represent google drive api instance
*/
@@ -51,7 +51,6 @@ async function createClient({ clientId, authRedirectUrl, scope, tokens }) {
}

let { drive, accessTokens } = await createConnection({ clientId, authRedirectUrl, scope, tokens })
// mainLog.info('tokensReceived1')
postTokensReceived(accessTokens)

/**
@@ -68,12 +67,12 @@ async function createClient({ clientId, authRedirectUrl, scope, tokens }) {
}

/**
* Checks if connection is health and client is ready to process requests
* Checks if connection is healthy and client is ready to process requests
* @returns `true` if client is ready to interact with API `false` otherwise
*/
async function testConnection() {
try {
await api.listFiles(drive)
await api.listFiles(drive, { pageSize: 1 })
return true
} catch (e) {
return false
@@ -14,12 +14,25 @@ class BackupService extends EventEmitter {
super()
}

/**
* Cleans up current login. Should be called as a cleanup or before calling `login` with another credentials
*
* @memberof BackupService
*/
async logout() {
const { drive } = this
drive && drive.removeAllListeners('tokensReceived')
this.drive = null
}

/**
* Setups gdrive service for usage. This method must be called before calling any other methods
*
* @param {Object} tokens google api compliant token desc
* `{access_token,expiry_date,refresh_token,scope,token_type}`
* @returns
* @memberof BackupService
*/
async login(tokens) {
const { redirectUrl, clientId, scope } = config.backup.gdrive
const { drive } = this
@@ -33,20 +46,41 @@ class BackupService extends EventEmitter {
mainLog.info('forwardEvent')
forwardEvent(this.drive, 'tokensReceived', this)
}

return true
}

/**
* Checks if client is setup for interactions. Also tests tokens for validity
*
* @returns
* @memberof BackupService
*/
async isLoggedIn() {
const { drive } = this
return await drive.testConnection()
return drive && (await drive.testConnection())
}

/**
* Returns current access tokens
*
* @returns {Object} current tokens object or null if not logged in
* @memberof BackupService
*/
getTokens() {
const { drive } = this
return drive.getTokens()
return drive && drive.getTokens()
}

getBackupId() {
throw new Error('Not implemented')
}
getBackupId() {}

/**
* Loads backup for the specified wallet
*
* @param {string} walletId
* @returns {Buffer} wallet backup as a `Buffer`
* @memberof BackupService
*/
async loadBackup(walletId) {
const { drive, getBackupId } = this
const fileId = getBackupId(walletId)
@@ -57,6 +91,15 @@ class BackupService extends EventEmitter {
return null
}

/**
* Saves specified backup
*
* @param {string} walletId desired file name
* @param {string} fileId google drive fileID
* @param {Buffer} backup `Buffer` with backup data
* @returns {string} google drive fileID
* @memberof BackupService
*/
async saveBackup(walletId, fileId, backup) {
const backupExists = async () => {
try {
@@ -67,17 +110,27 @@ class BackupService extends EventEmitter {
}
}
const { drive } = this
// if fileId is provded and backup exists - update it
if (fileId && (await backupExists())) {
await drive.updateFromBuffer(fileId, backup)
return fileId
if (drive) {
// if fileId is provded and backup exists - update it
if (fileId && (await backupExists())) {
await drive.updateFromBuffer(fileId, backup)
return fileId
} else {
// create new file
const { id } = await drive.uploadFromBuffer(walletId, backup)
return id
}
} else {
// create new file
const { id } = await drive.uploadFromBuffer(walletId, backup)
return id
mainLog.warn('Attempting to call saveBackup in logged-out state')
}
}

/**
* Provider name
*
* @readonly
* @memberof BackupService
*/
get name() {
return 'gdrive'
}
@@ -3,10 +3,11 @@ import { mainLog } from '@zap/utils/log'
import getBackupService from './serviceFactory'

export default function createBackupService(mainWindow) {
// helper func to send messages to the renderer process
const send = (msg, params) => mainWindow.webContents.send(msg, params)

ipcMain.on('initBackupService', async (event, { walletId, tokens, provider }) => {
mainLog.info('Initializing backup service powered by: %o', provider)
mainLog.info('Initializing backup service powered by: %s for wallet: %s', provider, walletId)

const backupService = getBackupService(provider)
if (backupService) {
@@ -34,6 +34,7 @@ function App({
fetchPeers,
fetchTransactions,
setModals,
backupCurrentWallet,
}) {
/**
* App scheduler / polling service setup. Add new app-wide polls here
@@ -75,9 +76,16 @@ function App({
fetchActivityHistory()
// fetch node info.
fetchPeers()
backupCurrentWallet()
// Update autopilot node scores.
updateAutopilotNodeScores()
}, [fetchActivityHistory, fetchPeers, setIsWalletOpen, updateAutopilotNodeScores])
}, [
backupCurrentWallet,
fetchActivityHistory,
fetchPeers,
setIsWalletOpen,
updateAutopilotNodeScores,
])

// Open the pay form when a payment link is used.
useEffect(() => {
@@ -101,6 +109,7 @@ function App({
}

App.propTypes = {
backupCurrentWallet: PropTypes.func.isRequired,
fetchActivityHistory: PropTypes.func.isRequired,
fetchPeers: PropTypes.func.isRequired,
fetchTransactions: PropTypes.func.isRequired,
@@ -6,6 +6,7 @@ import { fetchActivityHistory } from 'reducers/activity'
import { fetchTransactions } from 'reducers/transaction'
import { appSelectors } from 'reducers/app'
import { setModals, modalSelectors } from 'reducers/modal'
import { backupCurrentWallet } from 'reducers/backup'
import App from 'components/App'

const mapStateToProps = state => ({
@@ -21,6 +22,7 @@ const mapDispatchToProps = {
setIsWalletOpen,
fetchTransactions,
setModals,
backupCurrentWallet,
}

export default connect(
@@ -69,7 +69,7 @@ export const backupCurrentWallet = backup => async (dispatch, getState) => {
}
return null
}

// returns binary representation of channel backups as a buffer
const getBackupBuff = backupData =>
backupData && backupData.multi_chan_backup && backupData.multi_chan_backup.multi_chan_backup

@@ -27,14 +27,6 @@ class ZapGrpc extends EventEmitter {
activeSubscriptions: {},
}

static SUBSCRIPTIONS = [
'subscribeInvoices',
'subscribeChannelGraph',
'subscribeTransactions',
'subscribeGetInfo',
'subscribeChannelBackups',
]

constructor() {
super()

@@ -30,6 +30,12 @@ async function getInfo(payload = {}) {
return infoData
}

/**
* Checks whether specified method is present in gRPC interface
*
* @param {string} method
* @returns true if specified method exists withing service
*/
function hasMethod(method) {
return Boolean(this.service[method])
}
@@ -85,12 +85,11 @@ function subscribeTransactions() {
return call
}
/**
* Call lnd grpc subscribeTransactions method and emit events on updates to the stream
* Call lnd grpc subscribeChannelBackups method and emit events on updates to the stream
* @return {Call} Grpc Call
*/
function subscribeChannelBackups() {
if (this.service.subscribeChannelBackups) {
grpcLog.info('subscribeChannelBackups')
const call = this.service.subscribeChannelBackups({})
call.on('data', data => {
grpcLog.debug('CHANNEL BACKUP: %o', data)

0 comments on commit c1a1757

Please sign in to comment.
You can’t perform that action at this time.