diff --git a/INSTALL.md b/INSTALL.md
index 47fb424..a6bcf34 100644
--- a/INSTALL.md
+++ b/INSTALL.md
@@ -6,43 +6,15 @@
apt-get update
apt-get upgrade
- vi /etc/hostname
- vi /etc/hosts
-
apt-get install mongodb=1:2.4.9-1ubuntu2
apt-get install python g++ make nodejs git nginx redis-server supervisor
npm install coffee-script -g
- mongo
-
- use admin
- db.addUser({user: 'rpadmin', pwd: 'password', roles: ['readWriteAnyDatabase', 'userAdminAnyDatabase', 'dbAdminAnyDatabase', 'clusterAdmin']})
- use RootPanel
- db.addUser({user: 'rpadmin', pwd: 'password', roles: ['readWrite']})
-
- vi /etc/mongodb.conf
-
- auth = true
- noprealloc = true
- smallfiles = true
-
- vi /etc/redis/redis.conf
-
- requirepass password
-
- rm /etc/nginx/sites-enabled/default
-
vi /etc/nginx/sites-enabled/rpadmin
- ssl_certificate /home/rpadmin/rpvhost.crt;
- ssl_certificate_key /home/rpadmin/keys/rpvhost.key;
-
- ssl_session_cache shared:SSL:10m;
-
server {
listen 80 default_server;
- listen 443 ssl default_server;
listen [::]:80 default_server ipv6only=on;
rewrite .* $scheme://rp.rpvhost.net/#redirect redirect;
@@ -50,7 +22,6 @@
server {
listen 80;
- listen 443 ssl;
server_name rp.rpvhost.net;
@@ -67,8 +38,6 @@
useradd -m rpadmin
usermod -G rpadmin -a www-data
- mkdir -m 750 /home/rpadmin/keys
-
vi /etc/sudoers
rpadmin ALL=(ALL) NOPASSWD: ALL
@@ -99,10 +68,70 @@
redirect_stderr = true
user = rpadmin
- service nginx restart
- service mongodb restart
- service redis-server restart
- service supervisor restart
+### Optional Security Settings
+
+ mongo
+
+ use admin
+ db.addUser({user: 'rpadmin', pwd: 'password', roles: ['readWriteAnyDatabase', 'userAdminAnyDatabase', 'dbAdminAnyDatabase', 'clusterAdmin']})
+ use RootPanel
+ db.addUser({user: 'rpadmin', pwd: 'password', roles: ['readWrite']})
+
+ vi /etc/mongodb.conf
+
+ auth = true
+
+ vi /etc/redis/redis.conf
+
+ requirepass password
+
+ rm /etc/nginx/sites-enabled/default
+
+### Optional Performance Settings
+
+
+ vi /etc/hostname
+ vi /etc/hosts
+
+ vi /etc/mongodb.conf
+
+ noprealloc = true
+ smallfiles = true
+
+### Optional SSL Settings
+
+ vi /etc/nginx/sites-enabled/rpadmin
+
+ ssl_certificate /home/rpadmin/rpvhost.crt;
+ ssl_certificate_key /home/rpadmin/keys/rpvhost.key;
+
+ ssl_session_cache shared:SSL:10m;
+
+ server {
+ listen 80 default_server;
+ listen 443 ssl default_server;
+ listen [::]:80 default_server ipv6only=on;
+
+ rewrite .* $scheme://rp.rpvhost.net/#redirect redirect;
+ }
+
+ server {
+ listen 80;
+ listen 443 ssl;
+
+ server_name rp.rpvhost.net;
+
+ location ~ /\.git {
+ deny all;
+ }
+
+ location / {
+ proxy_set_header X-Real-IP $remote_addr;
+ proxy_pass http://unix:/home/rpadmin/rootpanel.sock:/;
+ }
+ }
+
+ mkdir -m 750 /home/rpadmin/keys
### Clusters
@@ -111,7 +140,7 @@
su rpadmin
mkdir ~/.ssh
- echo 'master key' >> ~/.ssh/authorized_keys
+ echo 'Master SSH Public Key' >> ~/.ssh/authorized_keys
chmod -R 700 ~/.ssh
### Plugins
@@ -180,3 +209,10 @@
# Node.js
npm install forever gulp mocha harp bower -g
+
+### Restart Services
+
+ service nginx restart
+ service mongodb restart
+ service redis-server restart
+ service supervisor restart
diff --git a/app.coffee b/app.coffee
index 0620912..183fb2b 100755
--- a/app.coffee
+++ b/app.coffee
@@ -134,6 +134,7 @@ app.express.use app.middleware.accountHelpers
app.express.set 'views', path.join(__dirname, 'core/view')
app.express.set 'view engine', 'jade'
+app.express.use '/component', require './core/router/component'
app.express.use '/account', require './core/router/account'
app.express.use '/billing', require './core/router/billing'
app.express.use '/ticket', require './core/router/ticket'
@@ -144,7 +145,7 @@ app.express.use '/panel', require './core/router/panel'
app.i18n.init()
app.interfaces.Plan.initPlans()
app.interfaces.Node.initNodes()
-app.pluggable.initPlugins()
+app.interfaces.Plugin.initPlugins()
app.express.get '/', (req, res) ->
unless res.headerSent
diff --git a/core/cache.coffee b/core/cache.coffee
index 831ccc5..f2474d5 100644
--- a/core/cache.coffee
+++ b/core/cache.coffee
@@ -3,9 +3,7 @@ getParameterNames = require 'get-parameter-names'
CounterCache = require 'counter-cache'
_ = require 'underscore'
-config = require '../config'
-
-{redis} = app
+{redis, config} = app
exports.counter = new CounterCache()
diff --git a/core/interface/ComponentType.coffee b/core/interface/ComponentType.coffee
index aec0c1a..bf1ae08 100644
--- a/core/interface/ComponentType.coffee
+++ b/core/interface/ComponentType.coffee
@@ -1,8 +1,9 @@
{_, async} = app.libs
{logger} = app
-{Node} = app.interfaces
{Account, Component} = app.models
+Node = require './Node'
+
module.exports = class ComponentType
@component_types = {}
@@ -19,29 +20,6 @@ module.exports = class ComponentType
initialize: (component, callback) ->
callback()
- populateComponent: (component) ->
- if component.toObject
- component = component.toObject()
-
- async.parallel
- account: (callback) ->
- Account.findById component.account_id, callback
-
- coworkers: (callback) ->
- async.each component.coworkers, (coworker, callback) ->
- Account.findById coworker.account_id, (err, account) ->
- callback _.extend coworker,
- account: account
- , callback
-
- , (err, result) ->
- {account, coworkers} = result
-
- callback _.extend component,
- account: account
- coworkers: coworkers
- physical_node: Node.nodes[component.physical_node]
-
# @param callback(err, component)
createComponent: (account, info, callback) ->
{name, physical_node} = info
@@ -54,18 +32,18 @@ module.exports = class ComponentType
physical_node: physical_node
dependencies: {}
, (err, component) =>
- @populateComponent component, (component) =>
- @initialize component, (err) =>
+ component.populateComponent (populated_component) =>
+ @initialize populated_component, (err) =>
return callback err if err
- Component.markAsStatus component, 'running', callback
+ component.markAsStatus 'running', callback
# @param callback(err)
destroyComponent: (component, callback) ->
- Component.markAsStatus component, 'destroying', (err) =>
+ component.markAsStatus 'destroying', (err) =>
return callback err if err
- @populateComponent component, (component) =>
+ component.populateComponent (component) =>
@destroy component, (err) =>
return callback err if err
diff --git a/core/interface/Node.coffee b/core/interface/Node.coffee
index 489dd5e..b21436e 100644
--- a/core/interface/Node.coffee
+++ b/core/interface/Node.coffee
@@ -1,3 +1,7 @@
+{_, child_process, async} = app.libs
+{config, logger} = app
+{available_plugins} = config.plugin
+
module.exports = class Node
info: null
name: null
@@ -7,15 +11,20 @@ module.exports = class Node
@initNodes: ->
for name, info of config.nodes
- @nodes[name] = new @constructor _.extend info,
+ @nodes[name] = new Node _.extend info,
name: name
@get: (name) ->
return @nodes[name]
constructor: (@info) ->
- @name = @info.name
- @master = true if @info.master
+ _.extend @, info
+
+ for component_type in @available_components
+ unless component_type in available_plugins
+ err = new Error "Node:#{@name} include unknown Component:#{component_type}"
+ logger.fatal err
+ throw err
# @param callback(err, stdout, stderr)
runCommand: (command, callback) ->
diff --git a/core/interface/Plan.coffee b/core/interface/Plan.coffee
index 40c24f4..aafd141 100644
--- a/core/interface/Plan.coffee
+++ b/core/interface/Plan.coffee
@@ -1,9 +1,14 @@
+{_} = app.libs
+{config, logger} = app
+
+{available_plugins} = config.plugin
+
module.exports = class Plan
@plans = {}
@initPlans: ->
for name, info of config.plans
- @plans[name] = new @constructor _.extend info,
+ @plans[name] = new Plan _.extend info,
name: name
@get: (name) ->
@@ -13,6 +18,11 @@ module.exports = class Plan
_.extend @, info
for component_type, info of @available_components
+ unless component_type in available_plugins
+ err = new Error "Plan:#{@name} include unknown Component:#{component_type}"
+ logger.fatal err
+ throw err
+
if info.default
unless _.isArray info.default
info.default = [info.default]
diff --git a/core/interface/Plugin.coffee b/core/interface/Plugin.coffee
index 0909575..86432e0 100644
--- a/core/interface/Plugin.coffee
+++ b/core/interface/Plugin.coffee
@@ -1,13 +1,35 @@
+{_, path, fs, jade, harp} = app.libs
+{config, logger, i18n} = app
+{available_plugins} = config.plugin
+
+pluggable = require '../pluggable'
+
module.exports = class Plugin
info: null
name: null
config: null
path: null
+ @plugins = {}
+
+ @get: (name) ->
+ return @plugins[name]
+
+ @initPlugins: ->
+ for name in available_plugins
+ Plugin.plugins[name] = require path.join __dirname, '../../plugin', name
+
constructor: (@info) ->
@name = info.name
@config = config.plugins[@name] ? {}
- @path = path.join __dirname, '../plugin', @name
+ @path = path.join __dirname, '../../plugin', @name
+
+ if info.dependencies
+ for dependence in plugin.dependencies
+ unless dependence in available_plugins
+ err = new Error "Plugin:#{@name} is Dependent on Plugin:#{dependence} but not load"
+ logger.fatal err
+ throw err
for name, payload of info.register_hooks ? {}
if payload.register_if
@@ -69,7 +91,7 @@ module.exports = class Plugin
return t.apply @, _.toArray(arguments)
render: (name, req, view_data, callback) ->
- template_path = path.join __dirname, '../plugin', @name, 'view', "#{name}.jade"
+ template_path = path.join __dirname, '../../plugin', @name, 'view', "#{name}.jade"
locals = _.extend _.clone(req.res.locals), view_data,
account: req.account
@@ -80,7 +102,7 @@ module.exports = class Plugin
callback html
renderTemplate: (name, view_data, callback) ->
- template_path = path.join __dirname, '../plugin', @name, 'view', name
+ template_path = path.join __dirname, '../../plugin', @name, 'view', name
fs.readFile template_path, (err, template_file) ->
callback _.template(template_file.toString()) view_data
diff --git a/core/model/Account.coffee b/core/model/Account.coffee
index db524af..28cb89e 100644
--- a/core/model/Account.coffee
+++ b/core/model/Account.coffee
@@ -1,11 +1,11 @@
{pluggable, utils, config, models} = app
{_, async, mongoose, mongooseUniqueValidator} = app.libs
{Financial, SecurityLog, Component} = app.models
-{Plan} = app.interfaces
+
+Plan = require '../interface/Plan'
process.nextTick ->
{Financial, SecurityLog, Component} = app.models
- {Plan} = app.interfaces
Token = mongoose.Schema
type:
@@ -88,6 +88,7 @@ Account = mongoose.Schema
pluggable:
type: Object
+ default: {}
resources_limit:
type: Object
diff --git a/core/model/Component.coffee b/core/model/Component.coffee
index 6ffde7c..42523e7 100644
--- a/core/model/Component.coffee
+++ b/core/model/Component.coffee
@@ -1,4 +1,5 @@
-{_, ObjectId, mongoose} = app.libs
+{_, ObjectId, mongoose, async} = app.libs
+{Account} = app.models
Component = mongoose.Schema
component_type:
@@ -43,10 +44,32 @@ Component = mongoose.Schema
type: String
enum: []
-Component.statics.markAsStatus = (component, status, callback) ->
- @findByIdAndUpdate component._id,
- status: status
- , callback
+Component.methods.populateComponent = (callback) ->
+ component = @toObject()
+
+ async.parallel
+ account: (callback) ->
+ Account.findById component.account_id, callback
+
+ coworkers: (callback) ->
+ async.each component.coworkers, (coworker, callback) ->
+ Account.findById coworker.account_id, (err, account) ->
+ callback _.extend coworker,
+ account: account
+ , callback
+
+ , (err, result) ->
+ {account, coworkers} = result
+
+ callback _.extend component,
+ account: account
+ coworkers: coworkers
+ component_type: ComponentType.get component.component_type
+ physical_node: Node.get component.physical_node
+
+Component.methods.markAsStatus = (status, callback) ->
+ @status = status
+ @save callback
_.extend app.models,
Component: mongoose.model 'Component', Component
diff --git a/core/pluggable.coffee b/core/pluggable.coffee
index a2a1133..51f0f47 100644
--- a/core/pluggable.coffee
+++ b/core/pluggable.coffee
@@ -1,6 +1,8 @@
{async, path, harp, jade, tmp, fs, _, child_process} = app.libs
{i18n, config, logger} = app
+Plugin = require './interface/Plugin'
+
pluggable = exports
pluggable.hooks =
@@ -28,8 +30,8 @@ pluggable.hooks =
billing:
# type
- # widget_generator: function(req, callback(html)),
- # details_message: function(req, deposit_log, callback(l_details))
+ # widgetGenerator: function(req, callback(html)),
+ # detailsMessage: function(req, deposit_log, callback(l_details))
payment_methods: []
view:
@@ -66,18 +68,3 @@ pluggable.selectHookPath = (name) ->
pluggable.selectHook = (name) ->
return pluggable.selectHookPath name
-
-pluggable.initPlugins = ->
- plugins_name = config.plugin.available_plugins
-
- for name in plugins_name
- plugin = require path.join __dirname, '../plugin', name
-
- if plugin.dependencies
- for dependence in plugin.dependencies
- unless dependence in plugins_name
- err = new Error "#{name} is Dependent on #{dependence} but not load"
- logger.fatal err
- throw err
-
- exports.plugins[name] = plugin
diff --git a/core/router/component.coffee b/core/router/component.coffee
new file mode 100644
index 0000000..ee0ba93
--- /dev/null
+++ b/core/router/component.coffee
@@ -0,0 +1,3 @@
+{_, express} = app.libs
+
+module.exports = exports = express.Router()
diff --git a/core/router/panel.coffee b/core/router/panel.coffee
index 73b6bce..0f93f15 100644
--- a/core/router/panel.coffee
+++ b/core/router/panel.coffee
@@ -13,7 +13,7 @@ exports.get '/financials', (req, res) ->
async.parallel
payment_methods: (callback) ->
async.map pluggable.selectHook('billing.payment_methods'), (hook, callback) ->
- hook.widget_generator req, (html) ->
+ hook.widgetGenerator req, (html) ->
callback null, html
, callback
@@ -29,13 +29,13 @@ exports.get '/financials', (req, res) ->
async.map deposit_logs, (deposit_log, callback) ->
deposit_log = deposit_log.toObject()
- matched_hook = _.find pluggable.selectHook('view.pay.display_payment_details'), (hook) ->
- return hook?.type == deposit_log.payload.type
+ matched_hook = _.find pluggable.selectHook('billing.payment_methods'), (hook) ->
+ return hook.type == deposit_log.payload.type
unless matched_hook
return callback null, deposit_log
- matched_hook.filter req, deposit_log, (payment_details) ->
+ matched_hook.detailsMessage req, deposit_log, (payment_details) ->
deposit_log.payment_details = payment_details
callback null, deposit_log
diff --git a/library/Mabolo.coffee b/library/Mabolo.coffee
new file mode 100644
index 0000000..bb1adac
--- /dev/null
+++ b/library/Mabolo.coffee
@@ -0,0 +1,4 @@
+module.exports = class Mabolo
+ constructor: (options) ->
+
+ model: (name) ->
diff --git a/plugin/bitcoin/bitcoin.coffee b/plugin/bitcoin/bitcoin.coffee
index 16fda6d..bf09c4b 100644
--- a/plugin/bitcoin/bitcoin.coffee
+++ b/plugin/bitcoin/bitcoin.coffee
@@ -4,7 +4,7 @@
# @param callback(address)
exports.genAddress = (bitcoin_secret, callback) ->
if config.plugins.bitcoin.coinbase_api_key == 'coinbase-simple-api-key'
- app.deprecate 'Invalid coinbase-simple-api-key'
+ logger.wran plugin: 'bitcoin', new Error 'Invalid coinbase-simple-api-key'
return callback()
request 'https://coinbase.com/api/v1/account/generate_receive_address',
diff --git a/plugin/bitcoin/index.coffee b/plugin/bitcoin/index.coffee
index c5eccd3..22b3561 100644
--- a/plugin/bitcoin/index.coffee
+++ b/plugin/bitcoin/index.coffee
@@ -1,7 +1,7 @@
{jade, path} = app.libs
{Account} = app.models
{pluggable, config, utils} = app
-{Plugin} = app.classes
+{Plugin} = app.interfaces
bitcoin = require './bitcoin'
@@ -25,16 +25,17 @@ bitcoinPlugin = module.exports = new Plugin
'billing.payment_methods':
type: 'bitcoin'
- widget_generator: (req, callback) ->
+
+ widgetGenerator: (req, callback) ->
bitcoin.getExchangeRate config.billing.currency, (rate) ->
bitcoinPlugin.render 'payment_method', req,
exchange_rate: rate
, callback
- details_message: (req, deposit_log, callback) ->
+ detailsMessage: (req, deposit_log, callback) ->
callback bitcoinPlugin.getTranslator(req) 'view.payment_details',
order_id: deposit_log.payload.order_id
- short_order_id: deposit_log.payload.order_id[0 .. 40]
+ short_order_id: deposit_log.payload.order_id[... 40]
initialize: ->
app.express.post '/bitcoin/coinbase_callback', (req, res) ->
@@ -42,10 +43,10 @@ bitcoinPlugin = module.exports = new Plugin
'pluggable.bitcoin.bitcoin_deposit_address': req.body.address
, (err, account) ->
unless account
- return res.send 400, 'Invalid Address'
+ return res.status(400).send 'Invalid Address'
unless req.query.secret == account.pluggable.bitcoin.bitcoin_secret
- return res.send 400, 'Invalid Secret'
+ return res.status(400).send 'Invalid Secret'
bitcoin.getExchangeRate config.billing.currency, (rate) ->
amount = req.body.amount / rate
diff --git a/plugin/bitcoin/locale/en.json b/plugin/bitcoin/locale/en.json
index fbad29b..d4030f9 100644
--- a/plugin/bitcoin/locale/en.json
+++ b/plugin/bitcoin/locale/en.json
@@ -3,6 +3,7 @@
"view": {
"payment_tips": "You can transfer directly to this address. system will automatically recharge for you after first confirmed. The minimum payment amount: 0.0005 BTC.",
"exchange_rate_tips": "Real-time Exchange Rates: 10 CNY = __rate10__ BTC",
- "payment_details": "Bitcoin Payment __short_order_id__"
+ "payment_details": "Bitcoin Payment __short_order_id__",
+ "no_address": "No Address"
}
}
diff --git a/plugin/bitcoin/locale/zh_CN.json b/plugin/bitcoin/locale/zh_CN.json
index 4b40c99..437e198 100644
--- a/plugin/bitcoin/locale/zh_CN.json
+++ b/plugin/bitcoin/locale/zh_CN.json
@@ -3,6 +3,7 @@
"view": {
"payment_tips": "你可以直接向该地址发送比特币。在经过一次确认后,系统会实时地,自动为你折算充值金额,最小支付金额为 0.0005 BTC.",
"exchange_rate_tips": "实时汇率:10 CNY = __rate10__ BTC",
- "payment_details": "比特币支付 __short_order_id__"
+ "payment_details": "比特币支付 __short_order_id__",
+ "no_address": "暂无地址"
}
}
diff --git a/plugin/bitcoin/view/payment_method.jade b/plugin/bitcoin/view/payment_method.jade
index 3ae8b48..e9a6b1e 100644
--- a/plugin/bitcoin/view/payment_method.jade
+++ b/plugin/bitcoin/view/payment_method.jade
@@ -2,4 +2,7 @@ div
h2= t('')
p= t('view.payment_tips')
p= t('view.exchange_rate_tips', {rate10: (exchange_rate * 10).toFixed(4)})
- pre= account.pluggable.bitcoin.bitcoin_deposit_address
+ if account.pluggable.bitcoin
+ pre= account.pluggable.bitcoin.bitcoin_deposit_address
+ else
+ pre= t('view.no_address')
diff --git a/plugin/rpvhost/index.coffee b/plugin/rpvhost/index.coffee
index 009640e..7454e64 100644
--- a/plugin/rpvhost/index.coffee
+++ b/plugin/rpvhost/index.coffee
@@ -1,6 +1,6 @@
-{jade, path, fs} = app.libs
+{path, fs} = app.libs
{pluggable, config} = app
-{Plugin} = app.classes
+{Plugin} = app.interfaces
rpvhostPlugin = module.exports = new Plugin
name: 'rpvhost'
@@ -21,10 +21,11 @@ rpvhostPlugin = module.exports = new Plugin
'billing.payment_methods':
type: 'taobao'
- widget_generator: (req, callback) ->
+
+ widgetGenerator: (req, callback) ->
rpvhostPlugin.render 'payment_method', req, {}, callback
- details_message: (req, deposit_log, callback) ->
+ detailsMessage: (req, deposit_log, callback) ->
callback rpvhostPlugin.getTranslator(req) 'view.payment_details',
order_id: deposit_log.payload.order_id