merge origin
This commit is contained in:
19
ConfigBasic.js
Normal file
19
ConfigBasic.js
Normal 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`, // 登录用户私钥文件
|
||||
},
|
||||
}
|
||||
@@ -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,
|
||||
}
|
||||
@@ -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
|
||||
|
||||
65
deploy.js
65
deploy.js
@@ -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! ]')
|
||||
|
||||
13
package.json
13
package.json
@@ -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",
|
||||
|
||||
35
server.js
35
server.js
@@ -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)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -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: {
|
||||
|
||||
@@ -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: {
|
||||
|
||||
@@ -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/`
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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 || [])
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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') }}
|
||||
|
||||
Reference in New Issue
Block a user