improve shadowsocks

This commit is contained in:
jysperm
2014-11-18 01:41:46 +08:00
parent fe5096c5ed
commit cc8871848d
12 changed files with 104 additions and 77 deletions

View File

@@ -45,6 +45,11 @@ exports.hooks =
# path
styles: []
admin:
# generator: function(req, callback)
sidebars: _.extend [],
global_event: true
panel:
# path
scripts: []

View File

@@ -9,9 +9,15 @@ exports.use requireAdminAuthenticate
exports.get '/', (req, res) ->
Account.find {}, (err, accounts) ->
return res.render 'admin',
accounts: accounts
coupon_code_types: _.keys config.coupons_meta
async.map pluggable.selectHook(null, 'view.admin.sidebars'), (hook, callback) ->
hook.generator req, (html) ->
callback null, html
, (err, sidebars_html) ->
res.render 'admin',
accounts: accounts
sidebars_html: sidebars_html
coupon_code_types: _.keys config.coupons_meta
exports.get '/account_details', (req, res) ->
Account.findById req.query.account_id, (err, account) ->

View File

@@ -111,6 +111,9 @@ block main
button.btn.btn-success.action-confirm-payment(type='button')= t('common.create')
prepend sidebar
for sidebar_html in sidebars_html
!= sidebar_html
.row
a.btn.btn-lg.btn-success(href='/admin/ticket/')= t('ticket.ticket_list')

View File

@@ -1,5 +1,6 @@
{_, fs} = app.libs
{pluggable, config, utils} = app
{Financials} = app.models
exports = module.exports = class ShadowSocksPlugin extends pluggable.Plugin
@NAME: 'shadowsocks'
@@ -31,6 +32,32 @@ exports.registerHook 'view.panel.widgets',
exports.render 'widget', req, result, callback
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 = {}
for name, range of time_range
logs = _.filter financials, (i) ->
return i.created_at.getTime() > Date.now() - range
traffic_result[name] = _.reduce logs, (memo, i) ->
return memo + i.payload.traffic_mb
, 0
exports.render 'admin/sidebar', req, traffic_result, callback
exports.registerHook 'app.started',
action: ->
shadowsocks.initSupervisor ->

View File

@@ -4,8 +4,10 @@
"remote_port": "Port",
"reset": "Reset",
"transfer": "Traffic",
"method": "method",
"transfer_remainder": "About __traffic__ G remainder",
"24hours_ago": "24 hours ago",
"3days_ago": "3 days ago",
"7days_ago": "7 days ago",
"30days_ago": "30 days ago"
}

View File

@@ -4,8 +4,10 @@
"remote_port": "端口",
"reset": "重置",
"transfer": "流量",
"method": "加密算法",
"transfer_remainder": "余额折合约 __traffic__ G 流量",
"24hours_ago": "过去 24 小时",
"3days_ago": "过去 3 天",
"7days_ago": "过去 7 天",
"30days_ago": "过去 30 天"
}

View File

@@ -1,4 +1,4 @@
{utils} = app
{utils, config} = app
{markdown, fs, path, express} = app.libs
{requireInService} = app.middleware
@@ -15,20 +15,19 @@ exports.post '/reset_password', (req, res) ->
$set:
'pluggable.shadowsocks.password': password
, ->
req.account.pluggable.shadowsocks.password = password
shadowsocks.updateConfigure req.account, ->
shadowsocks.updateConfigure ->
res.json {}
exports.post '/switch_method', (req, res) ->
unless req.body.method in config.plugins.shadowsocks.available_ciphers
return res.error 'invalid_method'
if req.body.method == req.account.pluggable.shadowsocks.method
return res.error 'already_in_method'
req.account.update
$set:
'pluggable.shadowsocks.method': method
'pluggable.shadowsocks.method': req.body.method
, ->
req.account.pluggable.shadowsocks.method = method
shadowsocks.updateConfigure req.account, ->
shadowsocks.updateConfigure ->
res.json {}

View File

@@ -16,14 +16,14 @@ exports.initSupervisor = (callback) ->
if program_name in _.pluck program_status, 'name'
return callback()
shadowsocks_config_file = "/etc/shadowsocks/#{method}.json"
configure = exports.generateConfigure [],
method: method
ShadowsocksPlugin.writeConfigFile shadowsocks_config_file, configure, {mode: 0o755}, ->
filename = "/etc/shadowsocks/#{method}.json"
ShadowsocksPlugin.writeConfigFile filename, configure, {mode: 0o755}, ->
supervisor.writeConfig {username: 'nobody'},
program_name: program_name
command: "ssserver -c #{shadowsocks_config_file}"
command: "ssserver -c #{filename}"
name: program_name
autostart: true
autorestart: true
@@ -109,12 +109,12 @@ exports.initAccount = (account, callback) ->
child_process.exec "sudo iptables -I OUTPUT -p tcp --sport #{port}", ->
child_process.exec 'sudo iptables-save | sudo tee /etc/iptables.rules', ->
exports.updateConfigure account, ->
exports.updateConfigure ->
callback()
exports.deleteAccount = (account, callback) ->
exports.queryIptablesInfo (iptables_info) ->
{port, method} = account.pluggable.shadowsocks
{port} = account.pluggable.shadowsocks
billing_traffic = iptables_info[port].bytes - account.pluggable.shadowsocks.last_traffic_value
billing_traffic = iptables_info[port].bytes if billing_traffic < 0
@@ -136,10 +136,7 @@ exports.deleteAccount = (account, callback) ->
child_process.exec 'sudo iptables-save | sudo tee /etc/iptables.rules', callback
(callback) ->
exports.deleteAccountConfigure account, callback
(callback) ->
supervisor.updateProgram {}, {program_name: "shadowsocks-#{method}"}, callback
exports.updateConfigure callback
], ->
if amount > 0
@@ -178,60 +175,24 @@ exports.accountUsage = (account, callback) ->
callback result
exports.updateConfigure = (account, callback) ->
{port, method, password} = account.pluggable.shadowsocks
original_method = null
exports.updateConfigure = (callback) ->
async.eachSeries config.plugins.shadowsocks.available_ciphers, (method, callback) ->
shadowsocks_config_file = "/etc/shadowsocks/#{method}.json"
Account.find
'pluggable.shadowsocks.method': method
, (err, accounts) ->
users = _.map accounts, (account) ->
return account.pluggable.shadowsocks
fs.readFile shadowsocks_config_file, (err, content) ->
if port.toString() in _.keys JSON.parse(content).port_password
original_method = method
callback true
else
callback()
configure = exports.generateConfigure users,
method: method
, ->
async.series [
(callback) ->
shadowsocks_config_file = "/etc/shadowsocks/#{method}.json"
fs.readFile shadowsocks_config_file, (err, content) ->
configure = JSON.parse content
configure.port_password[port] = password
ShadowsocksPlugin.writeConfigFile shadowsocks_config_file, JSON.stringify(configure), {mode: 0o755}, ->
callback()
(callback) ->
filename = "/etc/shadowsocks/#{method}.json"
ShadowsocksPlugin.writeConfigFile filename, configure, {mode: 0o755}, ->
supervisor.updateProgram {}, {program_name: "shadowsocks-#{method}"}, ->
callback()
(callback) ->
if original_method == original_method
return callback()
account = account.toObject()
account.pluggable.shadowsocks.method = original_method
exports.deleteAccountConfigure account, ->
supervisor.updateProgram {}, {program_name: "shadowsocks-#{original_method}"}, ->
callback()
], ->
callback()
exports.deleteAccountConfigure = (account, callback) ->
{port, method} = account.pluggable.shadowsocks
shadowsocks_config_file = "/etc/shadowsocks/#{method}.json"
fs.readFile shadowsocks_config_file, (err, content) ->
configure = JSON.parse content
delete configure.port_password[port]
fs.writeFile shadowsocks_config_file, JSON.stringify(configure), ->
callback()
, ->
callback()
exports.monitoring = ->
exports.queryIptablesInfo (iptables_info) ->

View File

@@ -1,11 +1,11 @@
$ ->
$('#widget-shadowsocks .action-reset-password').click ->
$('.widget-shadowsocks .action-reset-password').click ->
if window.confirm 'Are you sure?'
$.post '/plugin/shadowsocks/reset_password/', {}
.fail (jqXHR) ->
if jqXHR.responseJSON?.error
alert jqXHR.responseJSON.error
else
alert jqXHR.statusText
.success ->
request '/plugin/shadowsocks/reset_password/', {}, ->
location.reload()
$('.widget-shadowsocks .action-switch-method').click ->
request '/plugin/shadowsocks/switch_method/',
method: $('.widget-shadowsocks .input-method').val()
, ->
alert 'Success'

View File

@@ -0,0 +1,15 @@
.row
table.table.table-hover
tbody
tr
td #{(traffic_24hours / 1000).toFixed(1)}G
td= t('24hours_ago')
tr
td #{(traffic_3days / 1000).toFixed(1)}G
td= t('3days_ago')
tr
td #{(traffic_7days / 1000).toFixed(1)}G
td= t('7days_ago')
tr
td #{(traffic_30days / 1000).toFixed(1)}G
td= t('30days_ago')

View File

@@ -13,6 +13,13 @@
input.form-control(type='text', value=account.pluggable.shadowsocks.password, disabled)
span.input-group-btn
button.btn.btn-default.action-reset-password(type='button')= t('reset')
.input-group
span.input-group-addon= t('method')
select.input-method.form-control(style='-webkit-appearance: none;')
for method in config.plugins.shadowsocks.available_ciphers
option= method
span.input-group-btn
button.btn.btn-default.action-switch-method(type='button')= t('common.change')
.col-md-6
.panel.panel-default

View File

@@ -9,7 +9,7 @@ exports.registerHook 'view.layout.menu_bar',
href: '/wiki/'
t_body: 'plugins.wiki.'
unless config.plugins.wiki.disable_default_wiki
unless config.plugins.wiki?.disable_default_wiki
wiki_path = "#{__dirname}/../../WIKI"
for category_name in fs.readdirSync(wiki_path)