merge origin

This commit is contained in:
Nova
2019-02-10 13:07:31 +08:00
16 changed files with 143 additions and 90 deletions

19
ConfigBasic.js Normal file
View File

@@ -0,0 +1,19 @@
module.exports={
protocol:'http',
host:'localhost',
port:undefined,
// 如果使用 https 协议,必须填写以下内容,或在命令行参数中设置:
// sslKey: '/etc/letsencrypt/live/bittic.org/privkey.pem', // ssl key file,
// sslCert: '/etc/letsencrypt/live/bittic.org/cert.pem', // ssl cert file,
// sslCA: '../SSL/ca_bundle.crt', // ssl ca file,
deploy:{
host:'', // 待部署到的主机
port:'22', // 带部署到的主机的 SSH 端口
root:'/home/tic/node.console.web', // 待部署到的目录路径
dist:'dist', // 待部署到的文件夹
user:'tic', // 登录用户名
password:'', // 登录用户密码
key:`${process.env.HOME}/.ssh/id_rsa`, // 登录用户私钥文件
},
}

View File

@@ -1,9 +0,0 @@
module.exports={
protocol:'http',
host:'localhost',
port:undefined,
// 如果使用 https 协议,必须填写以下内容,或在命令行参数中设置:
// sslKey: '/etc/letsencrypt/live/bittic.org/privkey.pem', // ssl key file,
// sslCert: '/etc/letsencrypt/live/bittic.org/cert.pem', // ssl cert file,
// sslCA: '../SSL/ca_bundle.crt', // ssl ca file,
}

View File

@@ -7,12 +7,17 @@ npm install
### Compiles and hot-reloads for development
```
npm run serve
npm run dev
```
### Compiles and minifies for production
```
npm run build
npm run dist
```
### Compiles and minifies for production
```
npm run deploy -- -H 待部署主机的IP或域名 -r 待部署主机上的路径 -u 用户名 -p 密码
```
### Run your tests

View File

@@ -1,31 +1,55 @@
const fs = require('fs')
const path = require('path')
const ssh = new (require('node-ssh'))()
/********************* 读取命令行以及配置文件里的参数 **********************/
const commander = require('commander')
const deepmerge = require('deepmerge')
var Config={}
// 读取配置文件
try {
if (fs.existsSync('./ConfigBasic.js')) {
Config=require('./ConfigBasic.js')
console.info('ConfigBasic loaded')
}
if (fs.existsSync('./ConfigCustom.js')) { // 如果存在,覆盖掉 ConfigBasic 里的默认参数
Config=deepmerge(Config, require('./ConfigCustom.js')) // 注意objectMerge后产生了一个新的对象而不是在原来的Config里添加
console.info('ConfigCustom loaded')
}
if (fs.existsSync('./ConfigSecret.js')) { // 如果存在,覆盖掉 ConfigBasic 和 ConfigCustom 里的参数
Config=deepmerge(Config, require('./ConfigSecret.js'))
console.info('ConfigSecret loaded')
}
}catch(err){
console.error('Loading config files failed: '+err.message)
}
commander
.version('1.0', '-v, --version') // 默认是 -V。如果要 -v就要加 '-v --version'
.option('-H, --host <host>', 'domain name or ip address of the target server')
.option('-P, --port <port>', 'ssh port number of the target server')
.option('-r, --root <root>', 'root directory to deploy on the target server')
.option('-d, --dist <dist>', 'dist folder to deploy on the target server')
.option('-u, --user <user>', 'user id to login the target server')
.option('-k, --key <key>', 'user key file to login the target server')
.option('-p, --password <password>', 'user password to login the target server. You may have to enclose the password in ""')
.option('-H, --host <host>', `Host IP or domain name of the target server. Default to ${Config.deploy.host}`)
.option('-P, --port <port>', `Ssh port number of the target server. Default to ${Config.deploy.port}`)
.option('-r, --root <root>', `Path to deploy on the target server. Default to ${Config.deploy.root}`)
.option('-d, --dist <dist>', `Folder to deploy on the target server. Default to ${Config.deploy.dist}`)
.option('-u, --user <user>', `User id to login the target server. Default to ${Config.deploy.user}`)
.option('-k, --key <key>', `User private key file to login the target server. Default to ${Config.deploy.key}`)
.option('-p, --password <password>', `User password to login the target server. You may have to enclose it in "". Default to ${Config.deploy.password}`)
.parse(process.argv)
const root=commander.root // 本地的项目目录。似乎该目录必须已经存在于服务器上
const dist=commander.dist||'dist' // 新系统将发布在这个目录里。建议为dist和npm run build产生的目录一致这样既可以远程自动部署也可以直接登录服务器手动部署。
const root=commander.root||Config.deploy.root // 本地的项目目录。似乎该目录必须已经存在于服务器上
console.log(` root = ${root} `)
const dist=commander.dist||Config.deploy.dist||'dist' // 新系统将发布在这个目录里。建议为dist和npm run build产生的目录一致这样既可以远程自动部署也可以直接登录服务器手动部署。
console.log(` dist = ${dist} `)
const privateKeyFile=commander.key||Config.deploy.key||`${process.env.HOME}/.ssh/id_rsa`
console.log(` privateKeyFile = ${privateKeyFile}`)
const privateKeyFile=commander.key||`${process.env.HOME}/.ssh/id_rsa`
const connection = {
host: commander.host,
port: commander.port||22,
username: commander.user||'tic',
host: commander.host||Config.deploy.host,
port: commander.port||Config.deploy.port||22,
username: commander.user||Config.deploy.user,
privateKey: fs.existsSync(privateKeyFile)?privateKeyFile:undefined,
password: commander.password,
password: commander.password||Config.deploy.password,
tryKeyboard: true,
onKeyboardInteractive: (name, instructions, instructionsLang, prompts, finish) => { // 不起作用
if (prompts.length > 0 && prompts[0].prompt.toLowerCase().includes('password')) {
@@ -33,8 +57,9 @@ const connection = {
}
},
}
console.log(connection)
console.log(` connection = ${JSON.stringify(connection)}`)
/************************ 连接到待部署的主机,拷贝文件到指定路径 ***************/
function subDirs(path) {
const dirs = [path]
if (fs.statSync(path).isFile()) {
@@ -57,13 +82,13 @@ const necessaryPath = (path) => {
}
ssh.connect(connection).then(async () => {
console.log(`[ ${root} > mv ${dist} ${dist}-backup-${new Date().toISOString()} ... ]`)
console.log(`[ mv ${dist} ${dist}-backup-${new Date().toISOString()} ... ]`)
await ssh.execCommand(`mv ${dist} ${dist}-backup-${new Date().toISOString()}`, { cwd:root })
console.log(`[ ${root} > mkdir ${dist} ... ]`)
console.log(`[ mkdir ${dist} ... ]`)
await ssh.execCommand(`mkdir ${dist}`, { cwd:root })
const toCreate = necessaryPath('./dist')
for (const name of toCreate) {
console.log(`[ ${root} > mkdir ${dist}/${name.join('/')} ... ]`)
console.log(`[ mkdir ${dist}/${name.join('/')} ... ]`)
await ssh.execCommand(`mkdir ${dist}/${name.join('/')}`, { cwd:root })
}
@@ -77,13 +102,13 @@ ssh.connect(connection).then(async () => {
return !baseName.endsWith('.map');
},
tick: (localPath, remotePath, error) => {
console.log(`"${localPath}" ===> "${remotePath}" ... ${error || 'succeeded!'}`)
console.log(`Uploading "${localPath}" ===> "${remotePath}" ${error || 'succeeded!'}`)
err = error
},
})
ssh.dispose()
if (err) {
console.log('[ Upload failed! ]')
console.log('[ Uploaded with error! ]')
process.exit(1)
} else {
console.log('[ Uploaded successfully! ]')

View File

@@ -1,11 +1,13 @@
{
"name": "console",
"name": "tic.node.console",
"version": "0.1.0",
"private": true,
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"deploy": "node ./deploy.js -r '/home/tic/console.web.site' -u tic",
"dev": "vue-cli-service serve",
"dist": "vue-cli-service build",
"deploy": "node ./deploy.js",
"daemon:sup": "cross-env NODE_ENV=production supervisor -i data.log,node_modules,dist server.js",
"daemon": "cross-env NODE_ENV=production pm2 start server.js -n node.console.web",
"lint": "vue-cli-service lint",
"test:unit": "vue-cli-service test:unit"
},
@@ -23,7 +25,7 @@
"morgan": "^1.9.0",
"serve-favicon": "^2.4.5",
"socket.io": "^2.1.1",
"tic.crypto": "git+https://git.faronear.org/tic/tic.crypto#20181205",
"tic.crypto": "git+https://git.faronear.org/tic/tic.crypto#20190109_preview",
"vue": "^2.5.17",
"vue-axios": "^2.1.3",
"vue-i18n": "^8.1.0",
@@ -42,6 +44,7 @@
"babel-core": "7.0.0-bridge.0",
"babel-jest": "^23.0.1",
"babel-plugin-transform-imports": "^1.5.1",
"cross-env": "^5.1.3",
"node-sass": "^4.9.0",
"node-ssh": "^5.1.2",
"sass-loader": "^7.0.1",

View File

@@ -9,15 +9,15 @@ function config(){
// 读取配置文件
try {
if (fs.existsSync('./ConfigSys.js')) {
Config=require('./ConfigSys.js')
console.info('ConfigSys loaded')
if (fs.existsSync('./ConfigBasic.js')) {
Config=require('./ConfigBasic.js')
console.info('ConfigBasic loaded')
}
if (fs.existsSync('./ConfigUser.js')) { // 如果存在,覆盖掉 ConfigSys 里的默认参数
Config=deepmerge(Config, require('./ConfigUser.js')) // 注意objectMerge后产生了一个新的对象而不是在原来的Config里添加
console.info('ConfigUser loaded')
if (fs.existsSync('./ConfigCustom.js')) { // 如果存在,覆盖掉 ConfigBasic 里的默认参数
Config=deepmerge(Config, require('./ConfigCustom.js')) // 注意objectMerge后产生了一个新的对象而不是在原来的Config里添加
console.info('ConfigCustom loaded')
}
if (fs.existsSync('./ConfigSecret.js')) { // 如果存在,覆盖掉 ConfigSys 和 ConfigUser 里的参数
if (fs.existsSync('./ConfigSecret.js')) { // 如果存在,覆盖掉 ConfigBasic 和 ConfigCustom 里的参数
Config=deepmerge(Config, require('./ConfigSecret.js'))
console.info('ConfigSecret loaded')
}
@@ -28,11 +28,11 @@ try {
// 载入命令行参数
commander
.version(Config.VERSION, '-v, --version') // 默认是 -V。如果要 -v就要加 '-v --version'
.option('-H, --host <host>', 'host ip or domain name')
.option('-P, --protocol <protocol>', 'Web server protocol http|https|httpall, default to httpall')
.option('-p, --port <port>', 'Server port, default to 80|443')
.option('--sslCert <cert>', 'SSL cert file')
.option('--sslKey <key>', 'SSL privkey file')
.option('-H, --host <host>', 'Host ip or domain name. Default to ' + Config.host)
.option('-P, --protocol <protocol>', 'Web server protocol http|https|httpall|http2https. Default to ' + Config.protocol)
.option('-p, --port <port>', `Server port. Default to ${Config.port?Config.port:'80|443'}`)
.option('--sslCert <cert>', 'SSL cert file. Default to ' + Config.sslCert)
.option('--sslKey <key>', 'SSL privkey file. Default to ' + Config.sslKey)
.option('--sslCA <ca>', 'SSL ca bundle file')
.parse(process.argv)
@@ -101,14 +101,21 @@ async function init(){ /*** 设置全局对象 ***/
}else if ('httpall'===wo.Config.protocol) {
let portHttp=wo.Config.port?wo.Config.port:80 // 如果port参数已设置使用它否则默认为80
require('http').createServer(server).listen(portHttp, function(err) {
console.log('Server listening on %s://%s:%d for %s environment', 'httpall:http', wo.Config.host, portHttp, server.settings.env)
console.log('Server listening on [%s] http://%s:%d for %s environment', wo.Config.protocol, wo.Config.host, portHttp, server.settings.env)
})
let portHttps=(wo.Config.port && wo.Config.port!==80)?wo.Config.port+443:443 // 如果port参数已设置使用它+443否则默认为443
require('https').createServer({
key: fs.readFileSync(wo.Config.sslKey), cert: fs.readFileSync(wo.Config.sslCert) // , ca: [ fs.readFileSync(wo.Config.sslCA) ] // https://nodejs.org/api/tls.html#tls_tls_createserver_options_secureconnectionlistener
}, server).listen(portHttps, function(err){
console.log('Server listening on %s://%s:%d for %s environment', 'httpall:https', wo.Config.host, portHttps, server.settings.env)
console.log('Server listening on [%s] https://%s:%d for %s environment', wo.Config.protocol, wo.Config.host, portHttps, server.settings.env)
})
}else if ('http2https'===wo.Config.protocol) {
wo.Config.port = wo.Config.port || 80
require('http').createServer(express().all('*', function(ask, reply){ /* 错误的API调用进入这里。*/
reply.redirect(`https://${wo.Config.host}`)
})).listen(wo.Config.port, function(err){
console.log('Server listening on [%s] http://%s:%d for %s environment', wo.Config.protocol, wo.Config.host, wo.Config.port, server.settings.env)
})
}

View File

@@ -1,6 +1,6 @@
export default {
export default {
login: {
title: 'TIC Node Console',
title: 'TIC Console',
inputLabel: '请输入密语例如Lorem ipsum dolor sit amet, consectetur adipisicing elit. Eos, molestias, quisquam?',
loginBtn: 'Sign In',
secwordBtn: 'Create Secword',
@@ -27,12 +27,12 @@
tableNone: '暂无数据',
},
network: {
tableHeader: '当前邻居',
searchHolder: '请输入该输入的',
thIndex: '序号',
thAddress: '连接地址',
thStatus: '连接状态',
thPeerOwnerAddress: '邻居主人的账户地址',
tableHeader: 'Current neighbouring peer list',
searchHolder: 'Please input peer owner address or network url',
thIndex: 'Nr.',
thAccessPoint: 'Url',
thStatus: 'Status',
thOwnerAddress: 'Owner address',
tableNone: '暂无数据',
},
chain: {

View File

@@ -1,6 +1,6 @@
export default {
export default {
login: {
title: 'TIC Node 节点控制台',
title: 'TIC 控制台',
inputLabel: '请输入密语例如Lorem ipsum dolor sit amet, consectetur adipisicing elit. Eos, molestias, quisquam?',
loginBtn: '登录',
secwordBtn: '新密语',
@@ -27,12 +27,12 @@
tableNone: '暂无数据',
},
network: {
tableHeader: '当前邻居',
searchHolder: '请输入该输入的',
tableHeader: '当前邻居节点列表',
searchHolder: '请输入主人地址或节点网址',
thIndex: '序号',
thAddress: '连接址',
thAccessPoint: '连接址',
thOwnerAddress: '邻居主人地址',
thStatus: '连接状态',
thPeerOwnerAddress: '邻居主人的账户地址',
tableNone: '暂无数据',
},
chain: {

View File

@@ -1,5 +1,5 @@
import axios from 'axios'
import axios from 'axios'
// import app from './app'
// 控制台应当默认访问控制台所在主机(localhost 或者 window.location.hostname)的 TIC后台或者让用户在控制台启动时自己设置一个节点主机。
axios.defaults.baseURL = `http://${window.location.hostname}:6842/api/`
axios.defaults.baseURL = `${window.location.protocol}//${window.location.hostname}:${window.location.port}/api/`

View File

@@ -1,4 +1,4 @@
import axios from 'axios'
import axios from 'axios'
export default {
namespaced: true,
@@ -13,10 +13,10 @@ export default {
],
itemList: [
{
height: '1',
timestamp: '2011-11-20',
type: '0',
hash: 'null',
height: 'loading',
timestamp: 'loading',
type: 'loading',
hash: 'loading',
},
],
fetching: false,

View File

@@ -1,4 +1,4 @@
import axios from 'axios'
import axios from 'axios'
export default {
namespaced: true,
@@ -7,17 +7,17 @@ export default {
pageEntity: [5, 10, 25],
headers: [
{ text: 'network.thIndex', value: 'index', align: 'center' },
{ text: 'network.thAddress', value: 'address', align: 'center' },
{ text: 'network.thAccessPoint', value: 'accessPoint', align: 'center' },
{ text: 'network.thOwnerAddress', value: 'ownerAddress', align: 'center' },
{ text: 'network.thStatus', value: 'status', align: 'center' },
{ text: 'network.thPeerOwnerAddress', value: 'peerOwnerAddress', align: 'center' },
],
itemList: [
// {
// index: '',
// address: '',
// status: '',
// peerOwnerAddress: '',
// },
{
index: 'loading',
accessPoint: 'loading',
ownerAddress: 'loading',
status: 'loading',
},
],
fetching: false,
filter: '',
@@ -42,7 +42,8 @@ export default {
actions: {
async updateNetInfo({ state, commit }) {
let result = await axios.post('Peer/sharePeer', {})
let result = await axios.post('Peer/getPeerList', {})
commit('setPeerNumber', (result && result.data) ? result.data.length : 0)
commit('setItemList', result.data || [])

View File

@@ -12,10 +12,10 @@ export default {
],
itemList: [
{
height: '1',
timestamp: '2011-11-20',
type: '0',
hash: 'null',
height: 'loading',
timestamp: 'loading',
type: 'loading',
hash: 'loading',
},
],
fetching: false,

View File

@@ -89,10 +89,11 @@ import Vue from 'vue'
import store from '../store'
import VueSocketio from 'vue-socket.io'
import io from 'socket.io-client'
import axios from 'axios'
const { mapState, mapGetters, mapActions, mapMutations } = createNamespacedHelpers('chain')
Vue.use(VueSocketio, io(`http://${window.location.hostname}:6842`), store) // todo: luk: 整个控制台应当依赖于同一个全局的节点地址变量。
Vue.use(VueSocketio, io(axios.defaults.baseURL), store)
export default {
name: 'Chain',

View File

@@ -101,7 +101,7 @@ export default {
display: flex;
$sideWidth: 260px;
$sideWidth: 240px;
$headerHeight: 64px;
.side-menus {
&.collapsed {
@@ -109,6 +109,7 @@ export default {
}
width: $sideWidth;
min-width: 120px;
background: url('../assets/images/bg.jpg') center;
background-size: cover;
overflow-y: auto;

View File

@@ -1,4 +1,4 @@
<template>
<template>
<div class="network-page">
<div class="card-content">
<div class="app-card elevation-1">
@@ -36,9 +36,9 @@
</template>
<template slot="items" slot-scope="props">
<td>{{ props.item.index }}</td>
<td>{{ props.item.address }}</td>
<td>{{ props.item.accessPoint }}</td>
<td>{{ props.item.ownerAddress }}</td>
<td>{{ props.item.status }}</td>
<td>{{ props.item.peerOwnerAddress }}</td>
</template>
<template slot="no-results">
{{ $t('network.tableNone') }}