forked from fedwiki/wiki
-
Notifications
You must be signed in to change notification settings - Fork 0
/
farm.coffee
136 lines (109 loc) · 3.67 KB
/
farm.coffee
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
###
* Federated Wiki : Node Server
*
* Copyright Ward Cunningham and other contributors
* Licensed under the MIT license.
* https://github.com/fedwiki/wiki/blob/master/LICENSE.txt
###
# **farm.coffee**
# The farm module works by putting a bouncy host based proxy
# in front of servers that it creates
path = require 'path'
http = require 'http'
server = require 'wiki-server'
_ = require('lodash')
module.exports = exports = (argv) ->
# Map incoming hosts to their wiki's port
hosts = {}
# Keep an array of servers that are currently active
runningServers = []
if argv.allowed
allowedHosts = _.split(argv.allowed, ',')
allowHost = (host) ->
hostDomain = _.split(host, ':')[0]
if _.includes(allowedHosts, hostDomain)
return true
else
return false
if argv.wikiDomains
wikiDomains = _.keys(argv.wikiDomains)
inWikiDomain = ''
allowDomain = (host) ->
hostDomain = _.split(host, ':')[0]
inWikiDomain = ''
_.each wikiDomains, (domain) ->
if _.endsWith hostDomain, domain
inWikiDomain = domain
if inWikiDomain
return true
else
return false
else
allowDomain = () -> true
allow = (host) ->
# wikiDomains and allowed should both be optional
if argv.allowed and allowHost(host)
return true
else
if argv.wikiDomains and allowDomain(host)
# host is within a defined wikiDomain
return true
else
if argv.wikiDomains or argv.allowed
# host is in the list of allowed hosts
return false
else
# neither wikiDomain or allowed are configured
return true
farmServ = http.createServer (req, res) ->
if req.headers?.host
incHost = req.headers.host
else
res.statusCode = 400
res.end('Missing host header')
return
# If the host starts with "www." treat it the same as if it didn't
if incHost[0..3] is "www."
incHost = incHost[4..]
# if we already have a port for this host, forward the request to it.
if hosts[incHost]
hosts[incHost](req, res)
else
# check that request is for an allowed host
unless allow(incHost)
res.statusCode = 400
res.end('Invalid host')
return
# Create a new options object, copy over the options used to start the
# farm, and modify them to make sense for servers spawned from the farm.
# do deep copy, needed for database configuration for instance
copy = (map) ->
clone = {}
for key, value of map
clone[key] = if typeof value == "object" then copy(value) else value
clone
newargv = copy argv
newargv.data = if argv.data
path.join(argv.data, incHost.split(':')[0])
else
path.join(argv.root, 'data', incHost.split(':')[0])
newargv.url = "http://#{incHost}"
# apply wiki domain configuration, if defined
if inWikiDomain
newargv = _.assignIn newargv, newargv.wikiDomains[inWikiDomain]
newargv.wiki_domain = inWikiDomain
# Create a new server, add it to the list of servers, and
# once it's ready send the request to it.
local = server(newargv)
hosts[incHost] = local
runningServers.push(local)
# patch in new neighbors
if argv.autoseed
neighbors = if argv.neighbors then argv.neighbors + ',' else ''
neighbors += Object.keys(hosts).join(',')
runningServers.forEach (server) ->
server.startOpts.neighbors = neighbors
local.once "owner-set", ->
local.emit 'running-serv', farmServ
hosts[incHost](req, res)
runningFarmServ = farmServ.listen(argv.port, argv.host)