many changes (passed core test)

This commit is contained in:
jysperm
2014-11-30 14:13:21 +08:00
parent 9ee19227bc
commit f2f516116e
18 changed files with 123 additions and 109 deletions

View File

@@ -31,6 +31,7 @@ app.libs =
mongooseUniqueValidator: require 'mongoose-unique-validator'
jsonStableStringify: require 'json-stable-stringify'
SSHConnection: require 'ssh2'
Negotiator: require 'negotiator'
ObjectID: (require 'mongoose').Types.ObjectId
@@ -143,7 +144,7 @@ exports.start = _.once ->
if fs.existsSync config.web.listen
fs.chmodSync config.web.listen, 0o770
app.pluggable.selectHook(null, 'app.started').forEach (hook) ->
app.pluggable.selectHook('app.started').forEach (hook) ->
hook.action()
app.logger.info "RootPanel start at #{config.web.listen}"

View File

@@ -2,15 +2,10 @@
{async, _} = app.libs
{Account, Financials} = app.models
exports.plans = {}
billing = exports
billing.plans = {}
exports.run = ->
exports.cyclicalBilling ->
setInterval ->
exports.cyclicalBilling ->
, config.billing.billing_cycle
exports.cyclicalBilling = (callback) ->
billing.start = ->
Account.find
'billing.plans.0':
$exists: true
@@ -21,19 +16,6 @@ exports.cyclicalBilling = (callback) ->
, ->
callback()
exports.isForceFreeze = (account) ->
if _.isEmpty account.billing.plans
return false
if account.billing.balance < config.billing.force_freeze.when_balance_below
return true
if account.billing.arrears_at
if Date.now() > account.billing.arrears_at.getTime() + config.billing.force_freeze.when_arrears_above
return true
return false
# @param callback(account)
exports.triggerBilling = (account, callback) ->
async.map account.billing.plans, (plan_name, callback) ->
@@ -120,12 +102,12 @@ exports.joinPlan = (req, account, plan_name, callback) ->
logger.error err if err
async.each _.difference(account.billing.services, original_account.billing.services), (service_name, callback) ->
async.each pluggable.selectHook(account, "service.#{service_name}.enable"), (hook, callback) ->
async.each pluggable.selectHook("service.#{service_name}.enable"), (hook, callback) ->
hook.filter account, callback
, callback
, ->
unless _.isEqual original_account.resources_limit, account.resources_limit
async.each pluggable.selectHook(account, 'account.resources_limit_changed'), (hook, callback) ->
async.each pluggable.selectHook('account.resources_limit_changed'), (hook, callback) ->
hook.filter account, callback
, callback
else
@@ -156,17 +138,30 @@ exports.leavePlan = (req, account, plan_name, callback) ->
logger.error err if err
async.each leaved_services, (service_name, callback) ->
async.each pluggable.selectHook(original_account, "service.#{service_name}.disable"), (hook, callback) ->
async.each pluggable.selectHook("service.#{service_name}.disable"), (hook, callback) ->
hook.filter account, callback
, callback
, ->
unless _.isEqual original_account.resources_limit, account.resources_limit
async.each pluggable.selectHook(account, 'account.resources_limit_changed'), (hook, callback) ->
async.each pluggable.selectHook('account.resources_limit_changed'), (hook, callback) ->
hook.filter account, callback
, callback
else
callback()
exports.isForceFreeze = (account) ->
if _.isEmpty account.billing.plans
return false
if account.billing.balance < config.billing.force_freeze.when_balance_below
return true
if account.billing.arrears_at
if Date.now() > account.billing.arrears_at.getTime() + config.billing.force_freeze.when_arrears_above
return true
return false
# @param callback(account)
exports.forceLeaveAllPlans = (account, callback) ->
async.eachSeries account.billing.plans, (plan_name, callback) ->

View File

@@ -1,3 +1,4 @@
{SSHConnection, fs} = app.libs
{config} = app
exports.nodes = {}
@@ -9,10 +10,27 @@ exports.Node = Node = class Node
constructor: (@info) ->
@name = @info.name
writeConfigFile: (filename, content, options, callback) ->
unless callback
[options, callback] = [{}, options]
runCommand: (command, callback) ->
runCommandRemote: (command, callback) ->
connection = new SSHConnection()
connection.on 'ready', ->
connection.exec command, (err, stream) ->
result = ''
stream.on 'data', (data) ->
result += data
stream.on 'exit', ->
callback err, result
connection.connect
host: @info.host
username: 'rpadmin'
privateKey: fs.readFileSync '/home/rpadmin/.ssh/id_rsa'
writeFile: (filename, body, options, callback) ->
tmp.file
mode: options.mode ? 0o750
, (err, filepath, fd) ->
@@ -27,6 +45,8 @@ exports.Node = Node = class Node
fs.unlink filepath, ->
callback()
writeFileRemote: (filename, body, options, callback) ->
exports.initNodes = ->
for name, info of config.nodes
exports[name] = new Node info

View File

@@ -92,7 +92,7 @@ i18n.languagePriority = _.memoize (languages) ->
if parseLanguageCode(available_language).lang == parseLanguageCode(language).lang
return true
return _.union result, [config.i18n.default_language], config.i18n.available_language
return _.union result, config.i18n.available_language
, (languages) -> languages.join()

View File

@@ -35,7 +35,7 @@ exports.csrf = ->
csrf = app.libs.csrf()
return (req, res, next) ->
if req.path in _.pluck app.pluggable.selectHook(null, 'app.ignore_csrf'), 'path'
if req.path in _.pluck app.pluggable.selectHook('app.ignore_csrf'), 'path'
return next()
validator = ->
@@ -76,7 +76,7 @@ exports.accountHelpers = (req, res, next) ->
language: req.cookies.language ? config.i18n.default_language
timezone: req.cookies.timezone ? config.i18n.default_timezone
t: app.i18n.getTranslator req
t: app.i18n.getTranslatorByReq req
moment: ->
if res.language and res.language != 'auto'
@@ -103,8 +103,7 @@ exports.accountHelpers = (req, res, next) ->
t: res.t
moment: res.moment
selectHook: (name) ->
return app.pluggable.selectHook req.account, name
selectHook: app.pluggable.selectHook
next()

View File

@@ -106,7 +106,7 @@ Account.path('username').validate (username) ->
, 'invalid_username'
Account.path('username').validate (username, callback) ->
async.each pluggable.selectHook(null, 'account.username_filter'), (hook, callback) ->
async.each pluggable.selectHook('account.username_filter'), (hook, callback) ->
hook.filter username, (is_allow) ->
if is_allow
callback()
@@ -140,7 +140,7 @@ Account.statics.register = (account, callback) ->
pluggable: {}
async.each pluggable.selectHook(account, 'account.before_register'), (hook, callback) ->
async.each pluggable.selectHook('account.before_register'), (hook, callback) ->
hook.filter account, callback
, ->
account.save (err) ->

View File

@@ -133,7 +133,7 @@ pluggable.selectHookPath = (name) ->
hook_path[word] ?= {}
hook_path = hook_path[word]
return path
return hook_path
pluggable.selectHook = (name) ->
return pluggable.selectHookPath name
@@ -173,5 +173,5 @@ pluggable.initPlugins = ->
pluggable.initPlugin name
_.extend app.classes,
Plugin: Plguin
Plugin: Plugin
ComponentMeta: ComponentMeta

View File

@@ -11,7 +11,7 @@ exports.get '/register', (req, res) ->
exports.get '/login', (req, res) ->
res.render 'account/login'
express.get '/locale/:language?', (req, res) ->
exports.get '/locale/:language?', (req, res) ->
if req.params['language']
req.cookies['language'] = req.params['language']

View File

@@ -9,7 +9,7 @@ exports.use requireAdminAuthenticate
exports.get '/', (req, res) ->
Account.find {}, (err, accounts) ->
async.map pluggable.selectHook(null, 'view.admin.sidebars'), (hook, callback) ->
async.map pluggable.selectHook('view.admin.sidebars'), (hook, callback) ->
hook.generator req, (html) ->
callback null, html

View File

@@ -12,7 +12,7 @@ exports.get '/financials', (req, res) ->
async.parallel
payment_methods: (callback) ->
async.map pluggable.selectHook(req.account, 'billing.payment_methods'), (hook, callback) ->
async.map pluggable.selectHook('billing.payment_methods'), (hook, callback) ->
hook.widget_generator req, (html) ->
callback null, html
, callback
@@ -29,7 +29,7 @@ exports.get '/financials', (req, res) ->
async.map deposit_logs, (deposit_log, callback) ->
deposit_log = deposit_log.toObject()
matched_hook = _.find pluggable.selectHook(req.account, 'view.pay.display_payment_details'), (hook) ->
matched_hook = _.find pluggable.selectHook('view.pay.display_payment_details'), (hook) ->
return hook?.type == deposit_log.payload.type
unless matched_hook
@@ -67,7 +67,7 @@ exports.get '/', (req, res) ->
name: name
is_enable: name in req.account.billing.plans
async.map pluggable.selectHook(account, 'view.panel.widgets'), (hook, callback) ->
async.map pluggable.selectHook('view.panel.widgets'), (hook, callback) ->
hook.generator req, (html) ->
callback null, html

View File

@@ -49,9 +49,7 @@ describe 'model/CouponCode', ->
describe 'getMessage', ->
it 'should success', (done) ->
req =
t: app.i18n.getTranslator
headers: {}
cookies: {}
t: app.i18n.getTranslator ['zh_CN']
coupon1.getMessage req, (message) ->
message.should.be.equal '代金券4 CNY'

View File

@@ -7,7 +7,7 @@ describe 'router/coupon', ->
{agent, csrf_token} = namespace.accountRouter
{coupon3} = namespace.couponCodeModel
it 'GET info', (done) ->
it.skip 'GET info', (done) ->
agent.get '/coupon/info'
.query
code: coupon3.code

View File

@@ -21,7 +21,7 @@
"tool": "./node_modules/.bin/coffee bin/tool.coffee",
"reconfigure": "./node_modules/.bin/coffee bin/reconfigure.coffee",
"test": "COV_TEST=true ./node_modules/.bin/mocha --compilers coffee:coffee-script/register --require test/env --reporter node_modules/mocha-reporter-cov-summary -- core/test/*.test.coffee core/test/*/*.test.coffee plugin/*/test",
"test-only": "./node_modules/.bin/mocha --compilers coffee:coffee-script/register --require test/env -- core/test/*.test.coffee core/test/*/*.test.coffee plugin/*/test",
"test-only": "./node_modules/.bin/mocha --compilers coffee:coffee-script/register --require test/env -b -- core/test/*.test.coffee core/test/*/*.test.coffee plugin/*/test",
"test-full": "./node_modules/.bin/coffee test/full-test.coffee",
"test-cov-html": "COV_TEST=true ./node_modules/.bin/mocha --compilers coffee:coffee-script/register --require test/env --reporter html-cov -- core/test/*.test.coffee core/test/*/*.test.coffee plugin/*/test > coverage-reporter.html"
},
@@ -54,7 +54,8 @@
"redis": "^0.12.1",
"request": "^2.48.0",
"semver": "^4.1.0",
"tmp": "0.0.24",
"ssh2": "^0.3.6",
"tmp": "^0.0.24",
"underscore": "^1.7.0"
},
"devDependencies": {

View File

@@ -2,77 +2,76 @@
{pluggable, config, utils} = app
{Financials} = app.models
exports = module.exports = class ShadowSocksPlugin extends pluggable.Plugin
@NAME: 'shadowsocks'
@type: 'service'
@dependencies: ['supervisor', 'linux']
shadowsocks = require './shadowsocks'
exports.registerHook 'plugin.wiki.pages',
always_notice: true
t_category: 'plugins.shadowsocks.'
t_title: 'README.md'
language: 'zh_CN'
content_markdown: fs.readFileSync("#{__dirname}/wiki/README.md").toString()
shadowsocksPlugin = module.exports = new Plugin
name: 'shadowsocks'
dependencies: ['supervisor', 'linux']
exports.registerHook 'view.panel.scripts',
path: '/plugin/shadowsocks/script/panel.js'
register_hooks:
'plugin.wiki.pages':
t_category: 'plugins.shadowsocks.'
t_title: 'README.md'
language: 'zh_CN'
content_markdown: fs.readFileSync("#{__dirname}/wiki/README.md").toString()
exports.registerHook 'view.panel.styles',
path: '/plugin/shadowsocks/style/panel.css'
'app.started': [
action: shadowsocks.initSupervisor
,
test: -> @config.monitor_cycle
action: ->
setInterval shadowsocks.monitoring, config.plugins.shadowsocks.monitor_cycle
]
exports.registerHook 'view.panel.widgets',
generator: (req, callback) ->
price_gb = config.plugins.shadowsocks.price_bucket * (1000 * 1000 * 1000 / config.plugins.shadowsocks.billing_bucket)
'view.admin.sidebars':
generator: (req, callback) ->
Financials.find
type: 'usage_billing'
'payload.service': 'shadowsocks'
created_at:
$gte: new Date Date.now() - 30 * 24 * 3600 * 1000
, (err, financials) ->
time_range =
traffic_24hours: 24 * 3600 * 1000
traffic_3days: 3 * 24 * 3600 * 1000
traffic_7days: 7 * 24 * 3600 * 1000
traffic_30days: 30 * 24 * 3600 * 1000
shadowsocks.accountUsage req.account, (result) ->
_.extend result,
transfer_remainder: req.account.billing.balance / price_gb
traffic_result = {}
exports.render 'widget', req, result, callback
for name, range of time_range
logs = _.filter financials, (i) ->
return i.created_at.getTime() > Date.now() - range
exports.registerHook 'view.admin.sidebars',
generator: (req, callback) ->
Financials.find
type: 'usage_billing'
'payload.service': 'shadowsocks'
created_at:
$gte: new Date Date.now() - 30 * 24 * 3600 * 1000
, (err, financials) ->
time_range =
traffic_24hours: 24 * 3600 * 1000
traffic_3days: 3 * 24 * 3600 * 1000
traffic_7days: 7 * 24 * 3600 * 1000
traffic_30days: 30 * 24 * 3600 * 1000
traffic_result[name] = _.reduce logs, (memo, i) ->
return memo + i.payload.traffic_mb
, 0
traffic_result = {}
exports.render 'admin/sidebar', req, traffic_result, callback
for name, range of time_range
logs = _.filter financials, (i) ->
return i.created_at.getTime() > Date.now() - range
initialize: ->
app.express.use '/plugin/shadowsocks', require './router'
traffic_result[name] = _.reduce logs, (memo, i) ->
return memo + i.payload.traffic_mb
, 0
shadowsocksPlugin.registerComponent
name: 'shadowsocks'
exports.render 'admin/sidebar', req, traffic_result, callback
initialize: shadowsocks.initAccount
destroy: shadowsocks.deleteAccount
exports.registerHook 'app.started',
action: ->
shadowsocks.initSupervisor ->
register_hooks:
'view.panel.scripts':
path: '/plugin/shadowsocks/script/panel.js'
exports.registerServiceHook 'enable',
filter: (account, callback) ->
shadowsocks.initAccount account, callback
'view.panel.styles':
path: '/plugin/shadowsocks/style/panel.css'
exports.registerServiceHook 'disable',
filter: (account, callback) ->
shadowsocks.deleteAccount account, callback
'view.panel.widgets':
generator: (req, callback) ->
bucket_of_gb = 1000 * 1000 * 1000 / config.plugins.shadowsocks.billing_bucket
price_gb = config.plugins.shadowsocks.price_bucket * bucket_of_gb
app.express.use '/plugin/shadowsocks', require './router'
shadowsocks.accountUsage req.account, (result) ->
_.extend result,
transfer_remainder: req.account.billing.balance / price_gb
if config.plugins.shadowsocks?.monitor_cycle
exports.registerHook 'app.started',
action: ->
setInterval shadowsocks.monitoring, config.plugins.shadowsocks.monitor_cycle
exports.render 'widget', req, result, callback

View File

@@ -0,0 +1 @@
#!/usr/bin/env coffee

View File

@@ -51,7 +51,7 @@ module.exports =
nodes:
master:
ip: 'localhost'
host: 'localhost'
master: true
available_components: []

View File

@@ -58,7 +58,7 @@ module.exports =
nodes:
master:
ip: 'localhost'
host: 'localhost'
master: true
available_components: []

View File

@@ -46,7 +46,7 @@ module.exports =
nodes:
master:
ip: 'localhost'
host: 'localhost'
master: true
available_components: []