-
Notifications
You must be signed in to change notification settings - Fork 1
/
main.coffee
219 lines (186 loc) · 6.04 KB
/
main.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
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
accesslog = require "access-log"
commandLineArgs = require "command-line-args"
fs = require "fs"
http = require "http"
https = require "https"
restService = require "rest-middleware/server"
MockableHttpServer = require("./logic").MockableHttpServer
options = [
{ name: "port", alias: "p", type: Number, defaultValue: 31337 },
{ name: "host", alias: "h", type: String, defaultValue: "0.0.0.0" },
{ name: "api-port", type: Number, defaultValue: 31338 },
{ name: "timeout", alias: "t", type: Number, defaultValue: 300 },
{ name: "ssl-key", alias: "k", type: String, defaultValue: null },
{ name: "ssl-cert", alias: "c", type: String, defaultValue: null },
]
mockableHttpServer = new MockableHttpServer()
publicServerRequestListener = (request, response) ->
accesslog(request, response)
mockableHttpServer.dispatch(request, response)
args = commandLineArgs options
console.log "Starting public server at #{args.host}:#{args.port}"
if args["ssl-key"] and args["ssl-cert"]
opts = {
key: fs.readFileSync(args["ssl-key"], "utf8"),
cert: fs.readFileSync(args["ssl-cert"], "utf8"),
}
publicServer = https.createServer opts, publicServerRequestListener
else
publicServer = http.createServer publicServerRequestListener
publicServer.listen args.port, args.host
if args.timeout > 0
publicServer.timeout = args.timeout * 1000
apiServer = restService {name: "mockableHttpServer"}
apiServer.methods {
"routes": {
docs: """
Manages the list of all known routes.
GET returns object, where key is a route ID and value is content
that was previously passed to POST /routes.
POST creates a new route, and returns new route ID.
Route"s content:
* path: string
REQUIRED. Regexp of URL to match.
* times: uint
OPTIONAL. The route will expire after these number of calls.
* method: string
OPTIONAL. Matches only specified method. If absent, all methods are
matched.
* log: true
OPTIONAL. If present, you can issue http://127.0.0.1:31337/log/{route_id}
to receive logged request.
* priority: int
REQUIRED. Priority of the route. Routes with higher priority are
processed first.
* response:
REQUIRED, conflicts with forward. This action will send predefined static
response.
code: uint. HTTP code to send.
body: string. Body of HTTP response.
* forward:
REQUIRED, conflicts with response.
Will silently relay HTTP request to specified server. And relay back
the response.
* host: string
* port: uint
* delay:
OPTIONAL, requires forward, conflicts with log.
Will delay relaying the HTTP request by specified time.
* time: uint
Example request body:
```
{
path: "^ajax$",
times: 1,
priority: 99,
log: true,
method: "POST"
response:
{
code: 500,
body: "Internal server error"
}
}
```
DELETE removes all routes.
@param {object} data: Route"s content.
""",
url: "/routes",
get: () ->
return mockableHttpServer.methodRoutesGet()
,
post: (data) ->
return mockableHttpServer.methodRoutesPost(data)
,
delete: () ->
return mockableHttpServer.methodRoutesDelete()
},
"route": {
docs: """
Manages a specific route.
* GET returns the route"s content.
POST replaces route"s content with given one.
DELETE removes the route.
@param {string} id: Route"s ID.
@param {object} data: Route"s content.
""",
url: "/route/:id",
get: (id) ->
return mockableHttpServer.methodRouteGet(id)
,
post: (id, data) ->
return mockableHttpServer.methodRoutePost(id, data)
,
delete: (id) ->
mockableHttpServer.methodRouteDelete(id)
},
"logs": {
docs: """
Manages routes with `log: true` that have responses logged.
GET returns array of IDs for such routes.
By default this is empty.
Example response body:
```
["05310fd0-701e-11e6-bf06-bd0e3cf367e9",
"07153920-701e-11e6-bf06-bd0e3cf367e9"]
```
""",
url: "/logs",
get: () ->
return mockableHttpServer.methodLogsGet()
}
"log": {
docs: """
Manages responses for routes with `log: true`.
GET returns array of logged answers for given route ID.
This is the flow:
* if there are any answers right now, they are returned.
* otherwise server will hold the request for up to given timeout. Treat this
as slow polling.
* if there are still no answers after the timeout, this will return
404 error.
This call is destructive - after a successful GET, the answers are removed
from the cache, and they won"t appear in next requests.
Returns array of objects:
* headers: object
* body: string
* method: string
url: string
Example response:
```
[
{
"headers":
{
"accept-language":"pl-PL",
},
"method":"POST",
"url":"/ajax",
"body": "..."
}
, ....
]
```
@param {string} id: Route"s ID.
@param {int} timeout: Timeout to wait for requests, in seconds.
If not given, defaults to 60 seconds.
""",
url: "/log/:id?timeout=:timeout",
get: (id, timeout) ->
return mockableHttpServer.methodLogGet(id, timeout)
}
}
console.log "Starting API server at :#{args["api-port"]}"
apiServer.start {port: args["api-port"], silent: true}
console.log ""