-
Notifications
You must be signed in to change notification settings - Fork 8
/
index.js
157 lines (129 loc) · 5.24 KB
/
index.js
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
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
'use strict'
const fs = require('fs')
const path = require('path')
const child_process = require('child_process')
const stringifyFiles = require('./lib/stringifyFiles')
const createFilesObj = require('./lib/createFilesObj')
const createSeedObj = require('./lib/createSeedObj')
const hashSeedObj = require('./lib/hashSeedObj')
const writeSeedScript = require('./lib/writeSeedScript')
const replaceHtml = require('./lib/replaceHtml')
const writeNewHtml = require('./lib/writeNewHtml')
const uncommentingEJS = require('./lib/uncommentingEJS')
let startBots
/**
* @param {Object} options
* siteUrl: String (required)
* assetsPath: Array (required)
* assetsRoute: Array (required)
* routes: Object (required)
* userCount: Number (optional - defaults to 10)
* wfPath: String (optional - defaults to '/wfPath')
* wfRoute: String (optional - defaults to '/wfRoute')
* seedScript: String (optional - defaults to 'wf-seed.js')
* statusBar: Boolean (optional - defaults to true)
* devMode: Boolean (option - defaults to true)
*
* @param {string} serverRoot - path to root folder
*/
function WebFlight (options, serverRoot) {
Object.keys(options).forEach((key) => {
this[key] = options[key]
})
const fileNamesArr = Object.keys(this.routes).map((file) => {
return path.basename(this.routes[file])
})
// defaults
this.wfPath = options.wfPath || path.join(serverRoot, '/wfPath')
this.wfRoute = options.wfRoute || '/wfRoute'
this.seedScript = options.seedScript || path.join(this.wfPath, 'js/wf-seed.js')
this.userCount = options.userCount || 5
this.statusBar = options.statusBar // defaults to "true" (undefined)
this.devMode = options.devMode // defaults to "true" (undefined)
// non-configurables
this.count = 0
this.active = false
this.fileNames = fileNamesArr
this.htmlOutput = fileNamesArr.map((file) => `${this.wfPath}/wf-${file}`)
this.prepCount = Math.floor(this.userCount * 0.75)
this.stopCount = Math.floor(this.userCount * 0.50)
// TODO: existsSync is deprecated, need alternative
if (!fs.existsSync(this.wfPath)) {
fs.mkdirSync(this.wfPath)
fs.mkdirSync(path.join(this.wfPath, 'js'))
}
this.jsOutputDL = fileNamesArr.map((file) => { // non-configurable
if (path.extname(this.routes[file]) === '.html') {
file = path.basename(this.routes[file], '.html')
return `${this.wfPath}/js/${file}-download.js`
} else if (path.extname(this.routes[file]) === '.ejs') {
file = path.basename(this.routes[file], '.ejs')
return `${this.wfPath}/js/${file}-download.js`
}
})
if (!this.siteUrl) showError('siteUrl')
if (!this.assetsPath) showError('assetsPath')
if (!this.assetsRoute) showError('assetsRoute')
if (!this.routes) showError('routes')
if (!options) showError('options')
}
WebFlight.prototype.init = function () {
// TODO: Add 'commentingEJS' back into init
const htmlFiles = Object.keys(this.routes).map((route) => {
return this.routes[route]
})
const htmlStrings = stringifyFiles(htmlFiles)
const filesObj = createFilesObj(this.assetsPath, this.assetsRoute)
const seedObj = createSeedObj(htmlStrings, filesObj)
hashSeedObj(seedObj)
.then(writeSeedScript.bind(null, this.seedScript, this.siteUrl, this.stopCount))
.then(replaceHtml.bind(null, htmlStrings, this.statusBar))
.then(uncommentingEJS.bind(null))
.then(writeNewHtml.bind(null, this.htmlOutput))
}
WebFlight.prototype.redirect = function (req, res, next) {
const destination = req.originalUrl
if (this.routes[destination]) {
res.sendFile(`/${this.wfPath}/wf-${path.basename(this.routes[destination])}`)
} else {
next()
}
}
WebFlight.prototype.start = function () {
// TODO: check if these already exist
child_process.exec('export DISPLAY=\'0:99\'')
child_process.exec('Xvfb :99 -screen 0 1024x768x24 > /dev/null 2>&1 &')
if (typeof this.devMode === 'undefined') startBots = require('./lib/startBotsDevMode')
else startBots = require('./lib/startBots')
startBots(this.seedScript)
// if devMode is false, create screen for Xvfb to run
if (!this.devMode) {
child_process.exec('export DISPLAY=\'0:99\'')
child_process.exec('Xvfb :99 -screen 0 1024x768x24 > /dev/null 2>&1 &')
}
startBots(this.seedScript)
this.active = true
}
WebFlight.prototype.watch = function (req, res, next) {
const destination = req.originalUrl
// keep count of users on page, decay after 10 seconds
if (path.extname(destination) === '.html' || path.extname(destination) === '') {
++this.count
setTimeout(function () { --this.count }.bind(this), 20000)
}
// bots check how many current users
if (destination === '/count.check.4wf') return res.send({count: this.count})
if (destination === '/bots.no.longer.seeding.4wf') {
this.active = false
console.log('bots ending redirect')
}
// check when to start and redirect
if (!this.active && this.count > this.prepCount) this.start()
if (this.count > this.userCount) return this.redirect(req, res, next)
next()
}
function showError (input) {
if (input === 'options') console.error('Error: You must enter an options object')
else console.log(`Error: WebFlight options object requires "${input}" property`)
}
module.exports = WebFlight