mirror of
https://github.com/xuxiaobo-bobo/boda_jsEnv.git
synced 2025-04-21 07:05:13 +08:00
373 lines
12 KiB
JavaScript
373 lines
12 KiB
JavaScript
'use strict'
|
|
|
|
var cst = require('../../../constants.js');
|
|
const chalk = require('chalk');
|
|
const path = require('path');
|
|
const fs = require('fs');
|
|
const Table = require('cli-tableau');
|
|
const pkg = require('../../../package.json')
|
|
const IOAPI = require('@pm2/js-api')
|
|
const promptly = require('promptly')
|
|
var CLIStrategy = require('./auth-strategies/CliAuth')
|
|
var WebStrategy = require('./auth-strategies/WebAuth')
|
|
const exec = require('child_process').exec
|
|
|
|
const OAUTH_CLIENT_ID_WEB = '138558311'
|
|
const OAUTH_CLIENT_ID_CLI = '0943857435'
|
|
|
|
module.exports = class PM2ioHandler {
|
|
|
|
static usePM2Client (instance) {
|
|
this.pm2 = instance
|
|
}
|
|
|
|
static strategy () {
|
|
switch (process.platform) {
|
|
case 'darwin': {
|
|
return new WebStrategy({
|
|
client_id: OAUTH_CLIENT_ID_WEB
|
|
})
|
|
}
|
|
case 'win32': {
|
|
return new WebStrategy({
|
|
client_id: OAUTH_CLIENT_ID_WEB
|
|
})
|
|
}
|
|
case 'linux': {
|
|
const isDesktop = process.env.XDG_CURRENT_DESKTOP || process.env.XDG_SESSION_DESKTOP || process.env.DISPLAY
|
|
const isSSH = process.env.SSH_TTY || process.env.SSH_CONNECTION
|
|
if (isDesktop && !isSSH) {
|
|
return new WebStrategy({
|
|
client_id: OAUTH_CLIENT_ID_WEB
|
|
})
|
|
} else {
|
|
return new CLIStrategy({
|
|
client_id: OAUTH_CLIENT_ID_CLI
|
|
})
|
|
}
|
|
}
|
|
default: {
|
|
return new CLIStrategy({
|
|
client_id: OAUTH_CLIENT_ID_CLI
|
|
})
|
|
}
|
|
}
|
|
}
|
|
|
|
static init () {
|
|
this._strategy = this.strategy()
|
|
/**
|
|
* If you are using a local backend you should give those options :
|
|
* {
|
|
* services: {
|
|
* API: 'http://localhost:3000',
|
|
* OAUTH: 'http://localhost:3100'
|
|
* }
|
|
* }
|
|
*/
|
|
this.io = new IOAPI().use(this._strategy)
|
|
}
|
|
|
|
static launch (command, opts) {
|
|
// first init the strategy and the io client
|
|
this.init()
|
|
|
|
switch (command) {
|
|
case 'connect' :
|
|
case 'login' :
|
|
case 'register' :
|
|
case undefined :
|
|
case 'authenticate' : {
|
|
this.authenticate()
|
|
break
|
|
}
|
|
case 'validate' : {
|
|
this.validateAccount(opts)
|
|
break
|
|
}
|
|
case 'help' :
|
|
case 'welcome': {
|
|
var dt = fs.readFileSync(path.join(__dirname, './pres/welcome'));
|
|
console.log(dt.toString());
|
|
return process.exit(0)
|
|
}
|
|
case 'logout': {
|
|
this._strategy.isAuthenticated().then(isConnected => {
|
|
// try to kill the agent anyway
|
|
this.pm2.killAgent(err => {})
|
|
|
|
if (isConnected === false) {
|
|
console.log(`${cst.PM2_IO_MSG} Already disconnected`)
|
|
return process.exit(0)
|
|
}
|
|
|
|
this._strategy._retrieveTokens((err, tokens) => {
|
|
if (err) {
|
|
console.log(`${cst.PM2_IO_MSG} Successfully disconnected`)
|
|
return process.exit(0)
|
|
}
|
|
this._strategy.deleteTokens(this.io).then(_ => {
|
|
console.log(`${cst.PM2_IO_MSG} Successfully disconnected`)
|
|
return process.exit(0)
|
|
}).catch(err => {
|
|
console.log(`${cst.PM2_IO_MSG_ERR} Unexpected error: ${err.message}`)
|
|
return process.exit(1)
|
|
})
|
|
})
|
|
}).catch(err => {
|
|
console.error(`${cst.PM2_IO_MSG_ERR} Failed to logout: ${err.message}`)
|
|
console.error(`${cst.PM2_IO_MSG_ERR} You can also contact us to get help: contact@pm2.io`)
|
|
})
|
|
break
|
|
}
|
|
case 'create': {
|
|
this._strategy.isAuthenticated().then(res => {
|
|
// if the user isn't authenticated, we make them do the whole flow
|
|
if (res !== true) {
|
|
this.authenticate()
|
|
} else {
|
|
this.createBucket(this.createBucketHandler.bind(this))
|
|
}
|
|
}).catch(err => {
|
|
console.error(`${cst.PM2_IO_MSG_ERR} Failed to create to the bucket: ${err.message}`)
|
|
console.error(`${cst.PM2_IO_MSG_ERR} You can also contact us to get help: contact@pm2.io`)
|
|
})
|
|
break
|
|
}
|
|
case 'web': {
|
|
this._strategy.isAuthenticated().then(res => {
|
|
// if the user isn't authenticated, we make them do the whole flow
|
|
if (res === false) {
|
|
console.error(`${cst.PM2_IO_MSG_ERR} You need to be authenticated to do that, please use: pm2 plus login`)
|
|
return process.exit(1)
|
|
}
|
|
this._strategy._retrieveTokens(() => {
|
|
return this.openUI()
|
|
})
|
|
}).catch(err => {
|
|
console.error(`${cst.PM2_IO_MSG_ERR} Failed to open the UI: ${err.message}`)
|
|
console.error(`${cst.PM2_IO_MSG_ERR} You can also contact us to get help: contact@pm2.io`)
|
|
})
|
|
break
|
|
}
|
|
default : {
|
|
console.log(`${cst.PM2_IO_MSG_ERR} Invalid command ${command}, available : login,register,validate,connect or web`)
|
|
process.exit(1)
|
|
}
|
|
}
|
|
}
|
|
|
|
static openUI () {
|
|
this.io.bucket.retrieveAll().then(res => {
|
|
const buckets = res.data
|
|
|
|
if (buckets.length === 0) {
|
|
return this.createBucket((err, bucket) => {
|
|
if (err) {
|
|
console.error(`${cst.PM2_IO_MSG_ERR} Failed to connect to the bucket: ${err.message}`)
|
|
if (bucket) {
|
|
console.error(`${cst.PM2_IO_MSG_ERR} You can retry using: pm2 plus link ${bucket.secret_id} ${bucket.public_id}`)
|
|
}
|
|
console.error(`${cst.PM2_IO_MSG_ERR} You can also contact us to get help: contact@pm2.io`)
|
|
return process.exit(0)
|
|
}
|
|
const targetURL = `https://app.pm2.io/#/bucket/${bucket._id}`
|
|
console.log(`${cst.PM2_IO_MSG} Please follow the popup or go to this URL :`, '\n', ' ', targetURL)
|
|
this.open(targetURL)
|
|
return process.exit(0)
|
|
})
|
|
}
|
|
|
|
var table = new Table({
|
|
style : {'padding-left' : 1, head : ['cyan', 'bold'], compact : true},
|
|
head : ['Bucket name', 'Plan type']
|
|
})
|
|
|
|
buckets.forEach(function(bucket) {
|
|
table.push([bucket.name, bucket.credits.offer_type])
|
|
})
|
|
console.log(table.toString())
|
|
console.log(`${cst.PM2_IO_MSG} If you don't want to open the UI to a bucket, type 'none'`)
|
|
|
|
const choices = buckets.map(bucket => bucket.name)
|
|
choices.push('none')
|
|
|
|
promptly.choose(`${cst.PM2_IO_MSG} Type the name of the bucket you want to connect to :`, choices, (err, value) => {
|
|
if (value === 'none') process.exit(0)
|
|
|
|
const bucket = buckets.find(bucket => bucket.name === value)
|
|
if (bucket === undefined) return process.exit(0)
|
|
|
|
const targetURL = `https://app.pm2.io/#/bucket/${bucket._id}`
|
|
console.log(`${cst.PM2_IO_MSG} Please follow the popup or go to this URL :`, '\n', ' ', targetURL)
|
|
this.open(targetURL)
|
|
return process.exit(0)
|
|
})
|
|
})
|
|
}
|
|
|
|
static validateAccount (token) {
|
|
this.io.auth.validEmail(token)
|
|
.then(res => {
|
|
console.log(`${cst.PM2_IO_MSG} Email succesfully validated.`)
|
|
console.log(`${cst.PM2_IO_MSG} You can now proceed and use: pm2 plus connect`)
|
|
return process.exit(0)
|
|
}).catch(err => {
|
|
if (err.status === 401) {
|
|
console.error(`${cst.PM2_IO_MSG_ERR} Invalid token`)
|
|
return process.exit(1)
|
|
} else if (err.status === 301) {
|
|
console.log(`${cst.PM2_IO_MSG} Email succesfully validated.`)
|
|
console.log(`${cst.PM2_IO_MSG} You can now proceed and use: pm2 plus connect`)
|
|
return process.exit(0)
|
|
}
|
|
const msg = err.data ? err.data.error_description || err.data.msg : err.message
|
|
console.error(`${cst.PM2_IO_MSG_ERR} Failed to validate your email: ${msg}`)
|
|
console.error(`${cst.PM2_IO_MSG_ERR} You can also contact us to get help: contact@pm2.io`)
|
|
return process.exit(1)
|
|
})
|
|
}
|
|
|
|
static createBucketHandler (err, bucket) {
|
|
if (err) {
|
|
console.trace(`${cst.PM2_IO_MSG_ERR} Failed to connect to the bucket: ${err.message}`)
|
|
if (bucket) {
|
|
console.error(`${cst.PM2_IO_MSG_ERR} You can retry using: pm2 plus link ${bucket.secret_id} ${bucket.public_id}`)
|
|
}
|
|
console.error(`${cst.PM2_IO_MSG_ERR} You can also contact us to get help: contact@pm2.io`)
|
|
return process.exit(0)
|
|
}
|
|
if (bucket === undefined) {
|
|
return process.exit(0)
|
|
}
|
|
console.log(`${cst.PM2_IO_MSG} Successfully connected to bucket ${bucket.name}`)
|
|
var targetURL = `https://app.pm2.io/#/bucket/${bucket._id}`
|
|
console.log(`${cst.PM2_IO_MSG} You can use the web interface over there: ${targetURL}`)
|
|
this.open(targetURL)
|
|
return process.exit(0)
|
|
}
|
|
|
|
static createBucket (cb) {
|
|
console.log(`${cst.PM2_IO_MSG} By default we allow you to trial PM2 Plus for 14 days without any credit card.`)
|
|
|
|
this.io.bucket.create({
|
|
name: 'PM2 Plus Monitoring'
|
|
}).then(res => {
|
|
const bucket = res.data.bucket
|
|
|
|
console.log(`${cst.PM2_IO_MSG} Successfully created the bucket`)
|
|
this.pm2.link({
|
|
public_key: bucket.public_id,
|
|
secret_key: bucket.secret_id,
|
|
pm2_version: pkg.version
|
|
}, (err) => {
|
|
if (err) {
|
|
return cb(new Error('Failed to connect your local PM2 to your bucket'), bucket)
|
|
} else {
|
|
return cb(null, bucket)
|
|
}
|
|
})
|
|
}).catch(err => {
|
|
return cb(new Error(`Failed to create a bucket: ${err.message}`))
|
|
})
|
|
}
|
|
|
|
/**
|
|
* Connect the local agent to a specific bucket
|
|
* @param {Function} cb
|
|
*/
|
|
static connectToBucket (cb) {
|
|
this.io.bucket.retrieveAll().then(res => {
|
|
const buckets = res.data
|
|
|
|
if (buckets.length === 0) {
|
|
return this.createBucket(cb)
|
|
}
|
|
|
|
var table = new Table({
|
|
style : {'padding-left' : 1, head : ['cyan', 'bold'], compact : true},
|
|
head : ['Bucket name', 'Plan type']
|
|
})
|
|
|
|
buckets.forEach(function(bucket) {
|
|
table.push([bucket.name, bucket.payment.offer_type])
|
|
})
|
|
console.log(table.toString())
|
|
console.log(`${cst.PM2_IO_MSG} If you don't want to connect to a bucket, type 'none'`)
|
|
|
|
const choices = buckets.map(bucket => bucket.name)
|
|
choices.push('none')
|
|
|
|
promptly.choose(`${cst.PM2_IO_MSG} Type the name of the bucket you want to connect to :`, choices, (err, value) => {
|
|
if (value === 'none') return cb()
|
|
|
|
const bucket = buckets.find(bucket => bucket.name === value)
|
|
if (bucket === undefined) return cb()
|
|
this.pm2.link({
|
|
public_key: bucket.public_id,
|
|
secret_key: bucket.secret_id,
|
|
pm2_version: pkg.version
|
|
}, (err) => {
|
|
return err ? cb(err) : cb(null, bucket)
|
|
})
|
|
})
|
|
})
|
|
}
|
|
|
|
/**
|
|
* Authenticate the user with either of the strategy
|
|
* @param {Function} cb
|
|
*/
|
|
static authenticate () {
|
|
this._strategy._retrieveTokens((err, tokens) => {
|
|
if (err) {
|
|
const msg = err.data ? err.data.error_description || err.data.msg : err.message
|
|
console.log(`${cst.PM2_IO_MSG_ERR} Unexpected error : ${msg}`)
|
|
return process.exit(1)
|
|
}
|
|
console.log(`${cst.PM2_IO_MSG} Successfully authenticated`)
|
|
this.io.user.retrieve().then(res => {
|
|
const user = res.data
|
|
|
|
this.io.user.retrieve().then(res => {
|
|
const tmpUser = res.data
|
|
console.log(`${cst.PM2_IO_MSG} Successfully validated`)
|
|
this.connectToBucket(this.createBucketHandler.bind(this))
|
|
})
|
|
})
|
|
})
|
|
}
|
|
|
|
static open (target, appName, callback) {
|
|
let opener
|
|
const escape = function (s) {
|
|
return s.replace(/"/g, '\\"')
|
|
}
|
|
|
|
if (typeof (appName) === 'function') {
|
|
callback = appName
|
|
appName = null
|
|
}
|
|
|
|
switch (process.platform) {
|
|
case 'darwin': {
|
|
opener = appName ? `open -a "${escape(appName)}"` : `open`
|
|
break
|
|
}
|
|
case 'win32': {
|
|
opener = appName ? `start "" ${escape(appName)}"` : `start ""`
|
|
break
|
|
}
|
|
default: {
|
|
opener = appName ? escape(appName) : `xdg-open`
|
|
break
|
|
}
|
|
}
|
|
|
|
if (process.env.SUDO_USER) {
|
|
opener = 'sudo -u ' + process.env.SUDO_USER + ' ' + opener
|
|
}
|
|
return exec(`${opener} "${escape(target)}"`, callback)
|
|
}
|
|
}
|