This commit is contained in:
jysperm
2015-04-06 19:41:19 +08:00
parent 076de7fac0
commit ae1c6f19ad
10 changed files with 247 additions and 194 deletions

20
.gitignore vendored
View File

@@ -1,14 +1,14 @@
/node_modules
/bower_components
/coverage-reporter.html
/npm-debug.log
/.vagrant
/package.box
/.idea
*~
.DS_Store
/config.coffee
.idea/
.vagrant/
node_modules/
bower_components/
/package.box
/npm-debug.log
/session.key
/config.coffee
/coverage-reporter.html

View File

@@ -18,10 +18,6 @@
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:/;

View File

@@ -1,157 +1,6 @@
#!/usr/bin/env coffee
{EventEmitter} = require 'events'
Root = require './core'
global.rp = global.app = module.exports = new EventEmitter()
app.libs =
_: require 'underscore'
Q: require 'q'
fs: require 'fs'
path: require 'path'
jade: require 'jade'
async: require 'async'
crypto: require 'crypto'
moment: require 'moment-timezone'
request: require 'request'
express: require 'express'
child_process: require 'child_process'
cookieParser = require 'cookie-parser'
BunyanMongo = require 'bunyan-mongo'
bodyParser = require 'body-parser'
nodemailer = require 'nodemailer'
Insight = require 'insight'
morgan = require 'morgan'
Mabolo = require 'mabolo'
bunyan = require 'bunyan'
harp = require 'harp'
{_, fs, path, express} = app.libs
if fs.existsSync "#{__dirname}/config.coffee"
config = require './config'
else
config = require './sample/core.config.coffee'
app.package = require './package'
utils = require './core/utils'
if fs.existsSync config.web.listen
fs.unlinkSync config.web.listen
insight = new Insight
# 这个代码用于向 RootPanel 开发者提交匿名的统计信息
# This code used to send anonymous usage metrics to RootPanel developers
# 您不必修改这里 You do not have to modify it
trackingCode: 'UA-49193300-7'
packageName: app.package.name
packageVersion: app.package.version
insight.track 'app.coffee'
mailer = nodemailer.createTransport config.email.account
mabolo = new Mabolo utils.mongodbUri _.extend config.mongodb,
name: config.mongodb.test
bunyanMongo = new BunyanMongo()
mabolo.connect().done (db) ->
bunyanMongo.setDB db
logger = bunyan.createLogger
name: app.package.name
streams: [
type: 'raw'
level: 'info'
stream: bunyanMongo
,
level: process.env.LOG_LEVEL ? 'debug'
stream: process.stdout
]
PlanManager = require './core/PlanManager'
NodeManager = require './core/NodeManager'
CacheManager = require './core/CacheManager'
TranslationManager = require './core/TranslationManager'
PluginManager = require './core/extends/PluginManager'
HookManager = require './core/extends/HookManager'
ComponentManager = require './core/extends/ComponentManager'
_.extend app,
plans: new PlanManager config.plans
nodes: new NodeManager config.nodes
cache: new CacheManager()
hooks: new HookManager()
components: new ComponentManager()
translations: new TranslationManager config.i18n
utils: utils
config: config
mabolo: mabolo
mailer: mailer
logger: logger
models: mabolo.models
insight: insight
express: express()
require './core/model/Account'
require './core/model/Financials'
require './core/model/CouponCode'
require './core/model/Notification'
require './core/model/SecurityLog'
require './core/model/Ticket'
require './core/model/Component'
PaymentProviderManager = require './core/extends/PaymentProviderManager'
CouponProviderManager = require './core/extends/CouponProviderManager'
NotificationManager = require './core/extends/NotificationManager'
app.extends =
notifications: new NotificationManager()
payments: new PaymentProviderManager()
coupons: new CouponProviderManager()
app.middleware = require './core/middleware'
app.getHooks = app.extends.hook.getHooks
app.applyHooks = app.extends.hook.applyHooks
app.express.use bodyParser.json()
app.express.use cookieParser()
app.express.use app.middleware.reqHelpers
app.express.use app.middleware.session()
app.express.use app.middleware.logger()
app.express.use app.middleware.csrf()
app.express.use app.middleware.authenticate
app.express.use app.middleware.renderHelpers
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 '/ticket', require './core/router/ticket'
app.express.use '/admin', require './core/router/admin'
app.express.use '/panel', require './core/router/panel'
app.plugins = new PluginManager()
app.express.use '/bower_components', express.static './bower_components'
app.express.use harp.mount './core/static'
app.express.get '/', (req, res) ->
res.redirect '/panel/'
exports.start = _.once ->
app.express.listen config.web.listen, ->
app.started = true
app.logger.info "RootPanel start at #{config.web.listen}"
app.emit 'app.started'
unless module.parent
exports.start()
Root.findConfig(__dirname).done (config) ->
global.root = new Root config

View File

@@ -4,7 +4,11 @@ redis = require 'redis'
_ = require 'underscore'
Q = require 'q'
class CacheManager
###
Public: Cache utils
You can access a global instance via `root.cache`.
###
class Cache
constructor: ({host, port, password}) ->
@redis = redis.createClient port, host,
auth_pass: password

1
core/index.coffee Normal file
View File

@@ -0,0 +1 @@
module.exports = require './root'

View File

@@ -63,7 +63,7 @@ exports.reqHelpers = (req, res, next) ->
res.createCookie = (name, value) ->
res.cookie name, value,
expires: new Date(Date.now() + config.account.cookie_time)
expires: new Date(Date.now() + config.web.cookie_time)
res.createToken = (account = req.account) ->
account.createToken('full_access', req.getClientInfo()).then (token) ->

211
core/root.coffee Normal file
View File

@@ -0,0 +1,211 @@
{EventEmitter} = require 'events'
cookieParser = require 'cookie-parser'
bodyParser = require 'body-parser'
nodemailer = require 'nodemailer'
Insight = require 'insight'
express = require 'express'
Mabolo = require 'mabolo'
morgan = require 'morgan'
path = require 'path'
harp = require 'harp'
fs = require 'q-io/fs'
_ = require 'lodash'
###
Class: Root object for control RootPanel, An instance is always available as the `root` global.
###
module.exports = class Root extends EventEmitter
###
Public: Find and load configure file.
* `rootPath` {String} e.g. `/home/rpadmin/RootPanel`
Return {String}.
###
@findConfig: (rootPath) ->
configPath = path.resolve rootPath, '../config.coffee'
defaultPath = path.resolve rootPath, '../sample/config.coffee'
fs.exists(configPath).then (exists) ->
fs.read if exists then configPath else defaultPath
# Public: Config object
config: null
# Public: Node package object
package: null
# Public: express application
express: null
# Public: nodemailer instance
mailer: null
# Public: {Mabolo} instance
mabolo: null
# Public: {Insight} instance
insight: null
# Public: global {Cache} instance
cache: null
# Public: {Account} Model
Account: null
# Public: {Financials} Model
Financials: null
# Public: {CouponCode} Model
CouponCode: null
# Public: {Notification} Model
Notification: null
# Public: {SecurityLog} Model
SecurityLog: null
# Public: {Ticket} Model
Ticket: null
# Public: {Component} Model
Component: null
# Public: global {HookRegistry} instance
hooks: null
# Public: global {ViewRegistry} instance
views: null
# Public: global {WidgetRegistry} instance
widgets: null
# Public: global {ComponentRegistry} instance
components: null
# Public: global {CouponTypeRegistry} instance
couponTypes: null
# Public: global {PaymentProviderRegistry} instance
paymentProviders: null
# Public: global {I18nManager} instance
i18n: null
# Public: global {PluginManager} instance
plugins: null
# Public: global {ServerManager} instance
servers: null
# Public: global {BillingManager} instance
billing: null
# Public: global {NotificationManager} instance
notifications: null
###
Public: Construct a RootPanel instance.
* `config` {Object} Configure object
* `package` {Object} Node package object
###
constructor: (@config, @package) ->
@package ?= require '../package'
Cache = require './cache'
HookRegistry = require './registry/hook'
ViewRegistry = require './registry/view'
WidgetRegistry = require './registry/widget'
ComponentRegistry = require './registry/component'
CouponTypeRegistry = require './registry/coupon-type'
PaymentProviderRegistry = require './registry/payment-provider'
I18nManager = require './i18n-manager'
PluginManager = require './plugin-manager'
ServerManager = require './server-manager'
BillingManager = require './billing-manager'
NotificationManager = require './notification-manager'
_.extend @,
express: express()
mailer: nodemailer.createTransport @config.email.account
mabolo: new Mabolo mongodbUri @config.mongodb
insight: new Insight
trackingCode: TRACKING_CODE
pkg: @package
cache: new Cache()
Account: require './model/account'
Financials: require './model/financials'
CouponCode: require './model/coupon-code'
Notification: require './model/notification'
SecurityLog: require './model/security-log'
Ticket: require './model/ticket'
Component: require './model/component'
hooks: new HookRegistry()
views: new ViewRegistry()
widgets: new WidgetRegistry()
components: new ComponentRegistry()
couponTypes: new CouponTypeRegistry()
paymentProviders: new PaymentProviderRegistry()
i18n: new I18nManager @config.i18n
plugins: new PluginManager @config.plugins
servers: new ServerManager @config.server
billing: new BillingManager @config.billing
notifications: new NotificationManager()
@express.use bodyParser.json()
@express.use cookieParser()
@express.use morgan 'combined'
middleware = require './middleware'
@express.use middleware.reqHelpers
@express.use middleware.session()
@express.use middleware.csrf()
@express.use middleware.authenticate
@express.use middleware.renderHelpers
@express.use '/admin', require './router/admin'
@express.use '/panel', require './router/panel'
@express.use '/ticket', require './router/ticket'
@express.use '/account', require './router/account'
@express.use '/component', require './router/component'
@express.use '/bower_components', express.static @resolve '../bower_components'
@express.use harp.mount @resolve 'static'
@express.get '/', (req, res) ->
res.redirect '/panel/'
###
Public: Run RootPanel and start web service.
Return a {Promise}.
###
start: ->
@trackUsage 'root.start'
fs.exists(@config.web.listen).then (exists) ->
fs.unlink(@config.web.listen) if exists
.then ->
Q.Promise (resolve, reject) =>
@express.listen @config.web.listen, (err) =>
return reject err if err
@emit 'started'
resolve()
###
Public: Resolve path based on core directory.
* `arguments...` {String} paths
return {String}.
###
resolve: ->
return path.resolve __dirname, arguments...
###
Public: Send usage metrics to Google Analytics.
* `path` {String} e.g. `root.start`
###
trackUsage: (path) ->
@insight.track path.split('.')...
# Private: This code used to send anonymous usage metrics to RootPanel developers.
TRACKING_CODE = 'UA-49193300-7'
mongodbUri = ({user, password, host, name}) ->
if user and password
return "mongodb://#{user}:#{password}@#{host}/#{name}"
else
return "mongodb://#{host}/#{name}"

View File

@@ -1,14 +1,18 @@
validator = require 'validator'
crypto = require 'crypto'
_ = require 'underscore'
_ = require 'lodash'
exports.rx =
username: /^[a-z][0-9a-z_]{2,23}$/
email: /^\w+([-+.]\w+)*@\w+([-+.]\w+)*$/
password: /^.+$/
domain: /^(\*\.)?[A-Za-z0-9]+(\-[A-Za-z0-9]+)*(\.[A-Za-z0-9]+(\-[A-Za-z0-9]+)*)*$/
filename: /^[A-Za-z0-9_\-\.]+$/
url: /^https?:\/\/[^\s;]*$/
validator.extend 'isUsername', (username) ->
return /^[a-z][0-9a-z_]{2,23}$/.test username
validator.extend 'isPassword', (password) ->
return /^.+$/.test password
exports.sha256 = (data) ->
if data
return crypto.createHash('sha256').update(data).digest('hex')
@@ -48,19 +52,3 @@ exports.pickErrorName = (error) ->
return "#{err.path}_exist"
return err.message
exports.formatBillingTrigger = (name, plugin_name) ->
[part1, part2] = name.split '.'
if part2
return name
else
return "#{plugin_name}.#{part1}"
exports.mongodbUri = (config) ->
{user, password, host, name} = config
if user and password
return "mongodb://#{user}:#{password}@#{host}/#{name}"
else
return "mongodb://#{host}/#{name}"

View File

@@ -54,5 +54,6 @@ RootPanel 使用 Mabolo 管理数据模型。
## 应用入口
* Routers `/core/router`: 路由
* App Entry `/app`: RootPanel 主程序的入口
* Root `/core/root` 全局对象 `root`
* App Entry `/app`: 入口点
* Tests `/core/test`: 自动测试

View File

@@ -22,6 +22,7 @@
},
"dependencies": {
"async": "^0.9.0",
"async-q": "^0.2.2",
"body-parser": "^1.9.3",
"bower": "^1.3.12",
"bunyan": "^1.2.3",
@@ -37,8 +38,8 @@
"express-session": "^1.9.2",
"get-parameter-names": "^0.2.0",
"harp": "^0.14.0",
"insight": "^0.4.3",
"jade": "^1.7.0",
"insight": "^0.5.3",
"jade": "^1.9.2",
"json-stable-stringify": "^1.0.0",
"lodash": "^3.6.0",
"mabolo": "^0.3.0-rc.1",
@@ -50,11 +51,13 @@
"negotiator": "^0.4.9",
"nodemailer": "^1.3.0",
"q": "^1.2.0",
"q-io": "^1.12.0",
"redis": "^0.12.1",
"request": "^2.48.0",
"semver": "^4.1.0",
"ssh2": "^0.3.6",
"underscore": "^1.7.0"
"underscore": "^1.7.0",
"validator": "^3.37.0"
},
"devDependencies": {
"chai": "^1.10.0",