0z2i6v3u5t 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.devcontainer/devcontainer.json +4 -0
- package/.devcontainer/setup.sh +11 -0
- package/.dockerignore +2 -0
- package/.github/CONTRIBUTING.md +52 -0
- package/.github/FUNDING.yml +3 -0
- package/.github/ISSUE_TEMPLATE/bug_report.yml +59 -0
- package/.github/ISSUE_TEMPLATE/config.yml +5 -0
- package/.github/ISSUE_TEMPLATE/feature_request.yml +43 -0
- package/.github/dependabot.yml +17 -0
- package/.github/workflows/codeql.yml +76 -0
- package/.github/workflows/publish_docs.yml +25 -0
- package/.github/workflows/test.yml +78 -0
- package/.nvmrc +1 -0
- package/.prettierignore +1 -0
- package/.prettierrc +1 -0
- package/.vscode/launch.json +42 -0
- package/CODE_OF_CONDUCT.md +76 -0
- package/Dockerfile +17 -0
- package/LICENSE +21 -0
- package/README.md +3 -0
- package/SECURITY.md +5 -0
- package/__tests__/actions/cacheTest.ts +58 -0
- package/__tests__/actions/randomNumber.ts +26 -0
- package/__tests__/actions/recursiveAction.ts +16 -0
- package/__tests__/actions/sleepTest.ts +24 -0
- package/__tests__/actions/status.ts +17 -0
- package/__tests__/actions/swagger.ts +76 -0
- package/__tests__/actions/validationTest.ts +63 -0
- package/__tests__/cli/cli.ts +126 -0
- package/__tests__/core/api.ts +632 -0
- package/__tests__/core/cache.ts +400 -0
- package/__tests__/core/chatRoom.ts +589 -0
- package/__tests__/core/cli.ts +349 -0
- package/__tests__/core/cluster.ts +132 -0
- package/__tests__/core/config.ts +78 -0
- package/__tests__/core/errors.ts +112 -0
- package/__tests__/core/log.ts +23 -0
- package/__tests__/core/middleware.ts +427 -0
- package/__tests__/core/plugins/partialPlugin.ts +94 -0
- package/__tests__/core/plugins/withPlugin.ts +88 -0
- package/__tests__/core/plugins/withoutPlugin.ts +81 -0
- package/__tests__/core/process.ts +42 -0
- package/__tests__/core/specHelper.ts +330 -0
- package/__tests__/core/staticFile/compression.ts +99 -0
- package/__tests__/core/staticFile/staticFile.ts +180 -0
- package/__tests__/core/tasks/customQueueFunction.ts +67 -0
- package/__tests__/core/tasks/fullWorkerFlow.ts +199 -0
- package/__tests__/core/tasks/tasks.ts +605 -0
- package/__tests__/integration/browser.ts +133 -0
- package/__tests__/integration/ioredis-mock.ts +194 -0
- package/__tests__/integration/sendBuffer.ts +97 -0
- package/__tests__/integration/sendFile.ts +24 -0
- package/__tests__/integration/sharedFingerprint.ts +82 -0
- package/__tests__/integration/taskFlow.ts +110 -0
- package/__tests__/jest.ts +5 -0
- package/__tests__/modules/action.ts +103 -0
- package/__tests__/modules/config.ts +19 -0
- package/__tests__/modules/utils/ensureNoTsHeaderOrSpecFiles.ts +24 -0
- package/__tests__/servers/web/allowedRequestHosts.ts +88 -0
- package/__tests__/servers/web/enableMultiples.ts +83 -0
- package/__tests__/servers/web/fileUpload.ts +79 -0
- package/__tests__/servers/web/jsonp.ts +57 -0
- package/__tests__/servers/web/nonMultiples.ts +83 -0
- package/__tests__/servers/web/rawBody.ts +208 -0
- package/__tests__/servers/web/returnErrorCodes.ts +55 -0
- package/__tests__/servers/web/routes/deepRoutes.ts +96 -0
- package/__tests__/servers/web/routes/routes.ts +579 -0
- package/__tests__/servers/web/routes/veryDeepRoutes.ts +92 -0
- package/__tests__/servers/web/web.ts +1031 -0
- package/__tests__/servers/websocket.ts +795 -0
- package/__tests__/tasks/runAction.ts +37 -0
- package/__tests__/template.ts.example +20 -0
- package/__tests__/testCliCommands/hello.ts +44 -0
- package/__tests__/testPlugin/public/plugin.html +1 -0
- package/__tests__/testPlugin/src/actions/pluginAction.ts +14 -0
- package/__tests__/testPlugin/src/bin/hello.ts +22 -0
- package/__tests__/testPlugin/src/initializers/pluginInitializer.ts +17 -0
- package/__tests__/testPlugin/src/tasks/pluginTask.ts +15 -0
- package/__tests__/testPlugin/tsconfig.json +10 -0
- package/__tests__/utils/utils.ts +492 -0
- package/app.json +23 -0
- package/bin/deploy-docs +39 -0
- package/client/ActionheroWebsocketClient.js +277 -0
- package/docker-compose.yml +73 -0
- package/package.json +24 -0
- package/public/chat.html +194 -0
- package/public/css/cosmo.css +12 -0
- package/public/favicon.ico +0 -0
- package/public/index.html +115 -0
- package/public/javascript/.gitkeep +0 -0
- package/public/linkedSession.html +80 -0
- package/public/logo/actionhero-small.png +0 -0
- package/public/logo/actionhero.png +0 -0
- package/public/pixel.gif +0 -0
- package/public/simple.html +2 -0
- package/public/swagger.html +32 -0
- package/public/websocketLoadTest.html +322 -0
- package/src/actions/cacheTest.ts +58 -0
- package/src/actions/createChatRoom.ts +20 -0
- package/src/actions/randomNumber.ts +17 -0
- package/src/actions/recursiveAction.ts +13 -0
- package/src/actions/sendFile.ts +12 -0
- package/src/actions/sleepTest.ts +40 -0
- package/src/actions/status.ts +73 -0
- package/src/actions/swagger.ts +155 -0
- package/src/actions/validationTest.ts +36 -0
- package/src/bin/actionhero.ts +225 -0
- package/src/bin/methods/actions/list.ts +30 -0
- package/src/bin/methods/console.ts +26 -0
- package/src/bin/methods/generate/action.ts +58 -0
- package/src/bin/methods/generate/cli.ts +51 -0
- package/src/bin/methods/generate/initializer.ts +54 -0
- package/src/bin/methods/generate/plugin.ts +57 -0
- package/src/bin/methods/generate/server.ts +38 -0
- package/src/bin/methods/generate/task.ts +68 -0
- package/src/bin/methods/generate.ts +176 -0
- package/src/bin/methods/task/enqueue.ts +35 -0
- package/src/classes/action.ts +98 -0
- package/src/classes/actionProcessor.ts +463 -0
- package/src/classes/api.ts +51 -0
- package/src/classes/cli.ts +67 -0
- package/src/classes/config.ts +15 -0
- package/src/classes/connection.ts +321 -0
- package/src/classes/exceptionReporter.ts +9 -0
- package/src/classes/initializer.ts +59 -0
- package/src/classes/initializers.ts +5 -0
- package/src/classes/input.ts +9 -0
- package/src/classes/inputs.ts +34 -0
- package/src/classes/process/actionheroVersion.ts +15 -0
- package/src/classes/process/env.ts +16 -0
- package/src/classes/process/id.ts +34 -0
- package/src/classes/process/pid.ts +32 -0
- package/src/classes/process/projectRoot.ts +16 -0
- package/src/classes/process/typescript.ts +47 -0
- package/src/classes/process.ts +479 -0
- package/src/classes/server.ts +251 -0
- package/src/classes/task.ts +87 -0
- package/src/config/api.ts +107 -0
- package/src/config/errors.ts +162 -0
- package/src/config/logger.ts +113 -0
- package/src/config/plugins.ts +37 -0
- package/src/config/redis.ts +78 -0
- package/src/config/routes.ts +44 -0
- package/src/config/tasks.ts +84 -0
- package/src/config/web.ts +136 -0
- package/src/config/websocket.ts +62 -0
- package/src/index.ts +46 -0
- package/src/initializers/actions.ts +125 -0
- package/src/initializers/chatRoom.ts +214 -0
- package/src/initializers/connections.ts +124 -0
- package/src/initializers/exceptions.ts +155 -0
- package/src/initializers/params.ts +52 -0
- package/src/initializers/redis.ts +191 -0
- package/src/initializers/resque.ts +248 -0
- package/src/initializers/routes.ts +229 -0
- package/src/initializers/servers.ts +134 -0
- package/src/initializers/specHelper.ts +195 -0
- package/src/initializers/staticFile.ts +253 -0
- package/src/initializers/tasks.ts +188 -0
- package/src/modules/action.ts +89 -0
- package/src/modules/cache.ts +326 -0
- package/src/modules/chatRoom.ts +321 -0
- package/src/modules/config.ts +246 -0
- package/src/modules/log.ts +62 -0
- package/src/modules/redis.ts +93 -0
- package/src/modules/route.ts +59 -0
- package/src/modules/specHelper.ts +182 -0
- package/src/modules/task.ts +527 -0
- package/src/modules/utils/argv.ts +3 -0
- package/src/modules/utils/arrayStartingMatch.ts +21 -0
- package/src/modules/utils/arrayUnique.ts +15 -0
- package/src/modules/utils/collapseObjectToArray.ts +33 -0
- package/src/modules/utils/deepCopy.ts +3 -0
- package/src/modules/utils/ensureNoTsHeaderOrSpecFiles.ts +19 -0
- package/src/modules/utils/eventLoopDelay.ts +34 -0
- package/src/modules/utils/fileUtils.ts +119 -0
- package/src/modules/utils/filterObjectForLogging.ts +51 -0
- package/src/modules/utils/filterResponseForLogging.ts +53 -0
- package/src/modules/utils/getExternalIPAddress.ts +17 -0
- package/src/modules/utils/hashMerge.ts +63 -0
- package/src/modules/utils/isPlainObject.ts +45 -0
- package/src/modules/utils/isRunning.ts +7 -0
- package/src/modules/utils/parseCookies.ts +20 -0
- package/src/modules/utils/parseHeadersForClientAddress.ts +53 -0
- package/src/modules/utils/parseIPv6URI.ts +24 -0
- package/src/modules/utils/replaceDistWithSrc.ts +9 -0
- package/src/modules/utils/safeGlob.ts +6 -0
- package/src/modules/utils/sleep.ts +8 -0
- package/src/modules/utils/sortGlobalMiddleware.ts +17 -0
- package/src/modules/utils/sourceRelativeLinkPath.ts +29 -0
- package/src/modules/utils.ts +66 -0
- package/src/server.ts +20 -0
- package/src/servers/web.ts +894 -0
- package/src/servers/websocket.ts +304 -0
- package/src/tasks/runAction.ts +29 -0
- package/tea.yaml +9 -0
- package/templates/README.md.template +17 -0
- package/templates/action.ts.template +15 -0
- package/templates/boot.js.template +9 -0
- package/templates/cli.ts.template +15 -0
- package/templates/gitignore.template +23 -0
- package/templates/initializer.ts.template +17 -0
- package/templates/package-plugin.json.template +12 -0
- package/templates/package.json.template +45 -0
- package/templates/projectMap.txt +39 -0
- package/templates/projectServer.ts.template +20 -0
- package/templates/server.ts.template +37 -0
- package/templates/task.ts.template +16 -0
- package/templates/test/action.ts.template +13 -0
- package/templates/test/task.ts.template +20 -0
- package/tsconfig.json +11 -0
@@ -0,0 +1,32 @@
|
|
1
|
+
<html>
|
2
|
+
<head>
|
3
|
+
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
|
4
|
+
<meta http-equiv="content-language" content="en" />
|
5
|
+
<meta name="description" content="Actionhero.js" />
|
6
|
+
<link rel="icon" href="/public/favicon.ico" />
|
7
|
+
<title>Actionhero.js Swagger Documentation</title>
|
8
|
+
|
9
|
+
<link
|
10
|
+
rel="stylesheet"
|
11
|
+
type="text/css"
|
12
|
+
href="https://unpkg.com/swagger-ui-dist@3/swagger-ui.css"
|
13
|
+
/>
|
14
|
+
<script src="https://unpkg.com/swagger-ui-dist@3/swagger-ui-standalone-preset.js"></script>
|
15
|
+
<script src="https://unpkg.com/swagger-ui-dist@3/swagger-ui-bundle.js"></script>
|
16
|
+
</head>
|
17
|
+
|
18
|
+
<body>
|
19
|
+
<div class="container">
|
20
|
+
<div id="swagger-ui" />
|
21
|
+
</div>
|
22
|
+
|
23
|
+
<script type="text/javascript">
|
24
|
+
const SwaggerUI = SwaggerUIBundle({
|
25
|
+
url: "/api/swagger",
|
26
|
+
dom_id: "#swagger-ui",
|
27
|
+
presets: [SwaggerUIBundle.presets.apis, SwaggerUIStandalonePreset],
|
28
|
+
plugins: [SwaggerUIBundle.plugins.DownloadUrl],
|
29
|
+
});
|
30
|
+
</script>
|
31
|
+
</body>
|
32
|
+
</html>
|
@@ -0,0 +1,322 @@
|
|
1
|
+
<html>
|
2
|
+
<head>
|
3
|
+
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
|
4
|
+
<meta http-equiv="content-language" content="en" />
|
5
|
+
<meta name="description" content="actionhero.js" />
|
6
|
+
<title>actionhero.js WebSocket Load Test</title>
|
7
|
+
<script type="text/javascript" src="/public/javascript/ActionheroWebsocketClient.js"></script>
|
8
|
+
|
9
|
+
<style>
|
10
|
+
body {
|
11
|
+
margin: 0px;
|
12
|
+
padding: 0px;
|
13
|
+
font-family:"Trebuchet MS", Helvetica, sans-serif;
|
14
|
+
font-size: 14px;
|
15
|
+
}
|
16
|
+
|
17
|
+
#mainContainer {
|
18
|
+
height: 100%;
|
19
|
+
width: 100%;
|
20
|
+
}
|
21
|
+
|
22
|
+
#resultsContainer {
|
23
|
+
color: white;
|
24
|
+
background-color: gray;
|
25
|
+
height: 100%;
|
26
|
+
width: 300px;
|
27
|
+
text-align: left;
|
28
|
+
overflow: scroll;
|
29
|
+
float: left;
|
30
|
+
}
|
31
|
+
|
32
|
+
#optionsContainer {
|
33
|
+
background-color: orange;
|
34
|
+
height: 100%;
|
35
|
+
width: 200px;
|
36
|
+
text-align: left;
|
37
|
+
overflow: scroll;
|
38
|
+
float: left;
|
39
|
+
}
|
40
|
+
|
41
|
+
#testContainer {
|
42
|
+
background-color: lightblue;
|
43
|
+
margin-left: 500px;
|
44
|
+
height: 100%;
|
45
|
+
overflow: scroll;
|
46
|
+
}
|
47
|
+
|
48
|
+
form {
|
49
|
+
padding: 4px;
|
50
|
+
}
|
51
|
+
|
52
|
+
h1 {
|
53
|
+
color: lightgreen;
|
54
|
+
padding: 10px;
|
55
|
+
}
|
56
|
+
|
57
|
+
h2 {
|
58
|
+
color: darkgreen;
|
59
|
+
padding: 5px;
|
60
|
+
}
|
61
|
+
|
62
|
+
.smallWords {
|
63
|
+
font-style: italic;
|
64
|
+
padding: 5px;
|
65
|
+
}
|
66
|
+
|
67
|
+
.green {background-color: green;}
|
68
|
+
.red {background-color: red;}
|
69
|
+
.yellow {background-color: yellow;}
|
70
|
+
.gray {background-color: gray;}
|
71
|
+
|
72
|
+
.connection{
|
73
|
+
margin: 5px;
|
74
|
+
border: 2px solid black;
|
75
|
+
float: left;
|
76
|
+
}
|
77
|
+
</style>
|
78
|
+
|
79
|
+
<script type="text/javascript">
|
80
|
+
|
81
|
+
/////////
|
82
|
+
// APP //
|
83
|
+
/////////
|
84
|
+
|
85
|
+
var app = {};
|
86
|
+
|
87
|
+
app.defaults = function(){
|
88
|
+
return {
|
89
|
+
state: 'stopped',
|
90
|
+
clients: {},
|
91
|
+
config: {},
|
92
|
+
renderTimer: null,
|
93
|
+
stats: {
|
94
|
+
totalGood: 0,
|
95
|
+
totalBad: 0,
|
96
|
+
totalRequests: 0,
|
97
|
+
startTime: 0,
|
98
|
+
endTime: 0,
|
99
|
+
}
|
100
|
+
}
|
101
|
+
}
|
102
|
+
|
103
|
+
app.loadConfig = function(){
|
104
|
+
app.config.numClients = parseInt( document.getElementById('numClients').value );
|
105
|
+
app.config.numRequests = parseInt( document.getElementById('numRequests').value );
|
106
|
+
app.config.sleep = parseInt( document.getElementById('sleep').value );
|
107
|
+
app.config.action = document.getElementById('action').value;
|
108
|
+
app.config.params = JSON.parse(document.getElementById('params').value);
|
109
|
+
}
|
110
|
+
|
111
|
+
app.render = function(){
|
112
|
+
if(app.state === 'running'){
|
113
|
+
delta = (new Date().getTime() - app.stats.startTime) / 1000;
|
114
|
+
}else{
|
115
|
+
delta = (app.stats.endTime - app.stats.startTime) / 1000;
|
116
|
+
}
|
117
|
+
|
118
|
+
var totalTime = delta;
|
119
|
+
var reqPerSec = app.stats.totalRequests / delta;
|
120
|
+
var secPerReq = (delta / app.stats.totalRequests) * app.config.numClients;
|
121
|
+
|
122
|
+
document.getElementById('report.state').innerHTML = app.state;
|
123
|
+
document.getElementById('report.numClients').innerHTML = app.config.numClients;
|
124
|
+
document.getElementById('report.totalRequests').innerHTML = app.stats.totalRequests;
|
125
|
+
document.getElementById('report.totalTime').innerHTML = totalTime;
|
126
|
+
document.getElementById('report.totalGood').innerHTML = app.stats.totalGood;
|
127
|
+
document.getElementById('report.totalBad').innerHTML = app.stats.totalBad;
|
128
|
+
document.getElementById('report.reqPerSec').innerHTML = reqPerSec
|
129
|
+
document.getElementById('report.secPerReq').innerHTML = secPerReq
|
130
|
+
document.getElementById('report.percentGood').innerHTML = Math.round(app.stats.totalGood / (app.stats.totalGood + app.stats.totalBad) * 100)
|
131
|
+
}
|
132
|
+
|
133
|
+
app.renderLoop = function(){
|
134
|
+
app.render();
|
135
|
+
app.checkComplete();
|
136
|
+
if(app.state === 'running' || app.sate === 'stopped'){
|
137
|
+
setTimeout(function(){
|
138
|
+
app.renderLoop();
|
139
|
+
},100)
|
140
|
+
}else{
|
141
|
+
app.render();
|
142
|
+
}
|
143
|
+
}
|
144
|
+
|
145
|
+
app.checkComplete = function(){
|
146
|
+
var complete = true;
|
147
|
+
for(var i in app.clients){
|
148
|
+
var connection = app.clients[i];
|
149
|
+
if(connection.running != false){
|
150
|
+
complete = false;
|
151
|
+
break;
|
152
|
+
}
|
153
|
+
}
|
154
|
+
if(complete === true){
|
155
|
+
app.stats.endTime = new Date().getTime();
|
156
|
+
app.state = 'complete';
|
157
|
+
}
|
158
|
+
}
|
159
|
+
|
160
|
+
app.boot = function(){
|
161
|
+
app.clients = {};
|
162
|
+
for(var i in app.defaults()){
|
163
|
+
app[i] = app.defaults()[i];
|
164
|
+
}
|
165
|
+
app.loadConfig();
|
166
|
+
|
167
|
+
var rows = '';
|
168
|
+
var i = 0;
|
169
|
+
while(i < app.config.numClients){
|
170
|
+
rows += '<div class="connection" id="connection_'+i+'">';
|
171
|
+
rows += '<div id="id_'+i+'" class="gray">#'+i+'</div>';
|
172
|
+
rows += '<span id="good_'+i+'" style="color: green;">0</span>';
|
173
|
+
rows += " | "
|
174
|
+
rows += '<span id="bad_'+i+'" style="color: red;">0</span>';
|
175
|
+
rows += '</div>';
|
176
|
+
i++;
|
177
|
+
}
|
178
|
+
|
179
|
+
document.getElementById('boxes').innerHTML = rows;
|
180
|
+
|
181
|
+
var i = 0;
|
182
|
+
app.stats.startTime = new Date().getTime();
|
183
|
+
app.state = 'running';
|
184
|
+
while(i < app.config.numClients){
|
185
|
+
var c = new client(i);
|
186
|
+
c.connect();
|
187
|
+
app.clients[i] = c;
|
188
|
+
i++;
|
189
|
+
}
|
190
|
+
|
191
|
+
app.renderLoop();
|
192
|
+
|
193
|
+
return false;
|
194
|
+
}
|
195
|
+
|
196
|
+
////////////
|
197
|
+
// CLIENT //
|
198
|
+
////////////
|
199
|
+
|
200
|
+
var client = function(id){
|
201
|
+
var self = this;
|
202
|
+
self.running = null;
|
203
|
+
self.id = id;
|
204
|
+
self.goodCount = 0;
|
205
|
+
self.badCount = 0;
|
206
|
+
self.numRequests = 0;
|
207
|
+
}
|
208
|
+
|
209
|
+
client.prototype.connect = function(){
|
210
|
+
var self = this;
|
211
|
+
self.client = new ActionheroWebsocketClient();
|
212
|
+
self.client.on('connected', function(){ console.log('['+self.id+'] ' + 'connected!') })
|
213
|
+
self.client.on('disconnected', function(){ console.log('['+self.id+'] ' + 'disconnected :(') })
|
214
|
+
self.client.on('alert', function(message){ alert('['+self.id+'] ' + JSON.stringify(message) ) })
|
215
|
+
self.client.on('api', function(message){ alert('['+self.id+'] ' + JSON.stringify(message) ) })
|
216
|
+
self.client.on('welcome', function(message){ console.log('['+self.id+'] ' + JSON.stringify(message) ); })
|
217
|
+
self.client.on('say', function(message){ console.log('['+self.id+'] ' + JSON.stringify(message) ); })
|
218
|
+
self.client.connect(function(error, details){
|
219
|
+
if(error != null){
|
220
|
+
self.running = true;
|
221
|
+
console.log(error);
|
222
|
+
}else{
|
223
|
+
self.work();
|
224
|
+
}
|
225
|
+
});
|
226
|
+
}
|
227
|
+
|
228
|
+
client.prototype.work = function(){
|
229
|
+
var self = this;
|
230
|
+
document.getElementById('id_'+self.id).className = 'yellow'
|
231
|
+
self.client.action(app.config.action, app.config.params, function(data){
|
232
|
+
self.numRequests++;
|
233
|
+
app.stats.totalRequests++;
|
234
|
+
console.log('['+self.id+'] ' + JSON.stringify(data));
|
235
|
+
if(data.error == null){
|
236
|
+
self.goodCount++;
|
237
|
+
app.stats.totalGood++
|
238
|
+
}else{
|
239
|
+
self.badCount++;
|
240
|
+
app.stats.totalBad++;
|
241
|
+
}
|
242
|
+
document.getElementById('good_'+self.id).innerHTML = self.goodCount;
|
243
|
+
document.getElementById('bad_'+self.id).innerHTML = self.badCount;
|
244
|
+
if(self.numRequests >= app.config.numRequests){
|
245
|
+
// done!
|
246
|
+
if(self.badCount == 0){
|
247
|
+
document.getElementById('id_'+self.id).className = 'green';
|
248
|
+
}else{
|
249
|
+
document.getElementById('id_'+self.id).className = 'red';
|
250
|
+
}
|
251
|
+
self.running = false;
|
252
|
+
self.client.disconnect();
|
253
|
+
setTimeout(function(){
|
254
|
+
self.client.removeAllListeners('connected');
|
255
|
+
self.client.removeAllListeners('disconnected');
|
256
|
+
self.client.removeAllListeners('alert');
|
257
|
+
self.client.removeAllListeners('api');
|
258
|
+
self.client.removeAllListeners('welcome');
|
259
|
+
self.client.removeAllListeners('say');
|
260
|
+
},100);
|
261
|
+
}else{
|
262
|
+
setTimeout(function(){
|
263
|
+
self.work();
|
264
|
+
}, sleep)
|
265
|
+
}
|
266
|
+
});
|
267
|
+
}
|
268
|
+
|
269
|
+
</script>
|
270
|
+
|
271
|
+
</head>
|
272
|
+
|
273
|
+
<body>
|
274
|
+
<div id="mainContainer">
|
275
|
+
|
276
|
+
<div id="resultsContainer">
|
277
|
+
<h1>actionhero websocket load test</h1>
|
278
|
+
<p class="smallWords">Check the console for logs.<br />Be sure to update your ulimts!</p>
|
279
|
+
<ul id="results">
|
280
|
+
<li><strong>Test State</strong>: <span id="report.state"></span></li>
|
281
|
+
<li><strong>Connections</strong>: <span id="report.numClients"></span></li>
|
282
|
+
<li><strong>Total Requests</strong>: <span id="report.totalRequests"></span></li>
|
283
|
+
<li><strong>Total Time</strong>: <span id="report.totalTime"></span></li>
|
284
|
+
<li><strong>Total Good</strong>: <span id="report.totalGood"></span></li>
|
285
|
+
<li><strong>Total Bad</strong>: <span id="report.totalBad"></span></li>
|
286
|
+
<li><strong>Req/Sec</strong>: <span id="report.reqPerSec"></span></li>
|
287
|
+
<li><strong>Sec/Rec</strong>: <span id="report.secPerReq"></span></li>
|
288
|
+
<li><strong>% Good</strong>: <span id="report.percentGood"></span></li>
|
289
|
+
</ul>
|
290
|
+
</div>
|
291
|
+
|
292
|
+
<div id='optionsContainer'>
|
293
|
+
<h2>Options</h2>
|
294
|
+
|
295
|
+
<form id="form" action="#">
|
296
|
+
<label>Number of Clients:</label><br>
|
297
|
+
<input type="text" name="numClients" id="numClients" value="100"><br><br>
|
298
|
+
|
299
|
+
<label>Number of Requests:</label><br>
|
300
|
+
<input type="text" name="numRequests" id="numRequests" value="10"><br><br>
|
301
|
+
|
302
|
+
<label>Action:</label><br>
|
303
|
+
<input type="text" name="action" id="action" value="randomNumber"><br><br>
|
304
|
+
|
305
|
+
<label>Params (json):</label><br>
|
306
|
+
<input type="text" name="params" id="params" value='{"key": "key", "value": "value"}'><br><br>
|
307
|
+
|
308
|
+
<label>Sleep (ms):</label><br>
|
309
|
+
<input type="text" name="sleep" id="sleep" value="10"><br><br>
|
310
|
+
|
311
|
+
<button onclick="return app.boot()">Go!</button>
|
312
|
+
</form>
|
313
|
+
</div>
|
314
|
+
|
315
|
+
<div id='testContainer'>
|
316
|
+
<h2>Results</h2>
|
317
|
+
<div id='boxes'></div>
|
318
|
+
</div>
|
319
|
+
|
320
|
+
</div>
|
321
|
+
</body>
|
322
|
+
</html>
|
@@ -0,0 +1,58 @@
|
|
1
|
+
import { cache, Action, ParamsFrom } from "./../index";
|
2
|
+
|
3
|
+
export class CacheTest extends Action {
|
4
|
+
name = "cacheTest";
|
5
|
+
description = "I will test the internal cache functions of the API";
|
6
|
+
inputs = {
|
7
|
+
key: {
|
8
|
+
required: true as true,
|
9
|
+
formatter: this.stringFormatter,
|
10
|
+
validator: this.stringValidator,
|
11
|
+
},
|
12
|
+
|
13
|
+
value: {
|
14
|
+
required: true as true,
|
15
|
+
formatter: this.stringFormatter,
|
16
|
+
validator: this.stringValidator,
|
17
|
+
},
|
18
|
+
};
|
19
|
+
|
20
|
+
outputExample = {
|
21
|
+
cacheTestResults: {
|
22
|
+
saveResp: true,
|
23
|
+
sizeResp: 1,
|
24
|
+
loadResp: {
|
25
|
+
key: "cacheTest_key",
|
26
|
+
value: "value",
|
27
|
+
createdAt: 1420953269716,
|
28
|
+
},
|
29
|
+
deleteResp: true,
|
30
|
+
},
|
31
|
+
};
|
32
|
+
|
33
|
+
stringFormatter(s: unknown) {
|
34
|
+
return String(s);
|
35
|
+
}
|
36
|
+
|
37
|
+
stringValidator(s: string) {
|
38
|
+
if (s.length < 3) {
|
39
|
+
return "inputs should be at least 3 letters long";
|
40
|
+
} else {
|
41
|
+
return true;
|
42
|
+
}
|
43
|
+
}
|
44
|
+
|
45
|
+
async run({ params }: { params: ParamsFrom<CacheTest> }) {
|
46
|
+
const key = `cacheTest_${params.key}`;
|
47
|
+
const value = params.value;
|
48
|
+
|
49
|
+
return {
|
50
|
+
cacheTestResults: {
|
51
|
+
saveResp: await cache.save(key, value, 5000),
|
52
|
+
sizeResp: await cache.size(),
|
53
|
+
loadResp: await cache.load(key),
|
54
|
+
deleteResp: await cache.destroy(key),
|
55
|
+
},
|
56
|
+
};
|
57
|
+
}
|
58
|
+
}
|
@@ -0,0 +1,20 @@
|
|
1
|
+
import { chatRoom, Action, ParamsFrom } from "./../index";
|
2
|
+
|
3
|
+
export class CreateChatRoom extends Action {
|
4
|
+
name = "createChatRoom";
|
5
|
+
description = "I will create a chatroom with the given name";
|
6
|
+
inputs = {
|
7
|
+
name: { required: true as true },
|
8
|
+
};
|
9
|
+
|
10
|
+
async run({ params }: { params: ParamsFrom<CreateChatRoom> }) {
|
11
|
+
let didCreate = false;
|
12
|
+
|
13
|
+
if (!(await chatRoom.exists(params.name))) {
|
14
|
+
await chatRoom.add(params.name);
|
15
|
+
didCreate = true;
|
16
|
+
}
|
17
|
+
|
18
|
+
return { name: params.name, didCreate };
|
19
|
+
}
|
20
|
+
}
|
@@ -0,0 +1,17 @@
|
|
1
|
+
import { Action } from "./../index";
|
2
|
+
|
3
|
+
export class RandomNumber extends Action {
|
4
|
+
name = "randomNumber";
|
5
|
+
description = "I am an API method which will generate a random number";
|
6
|
+
outputExample = {
|
7
|
+
randomNumber: 0.123,
|
8
|
+
stringRandomNumber: "Your random number is 0.123",
|
9
|
+
};
|
10
|
+
|
11
|
+
async run() {
|
12
|
+
const randomNumber = Math.random();
|
13
|
+
const stringRandomNumber = `Your random number is ${randomNumber}`;
|
14
|
+
|
15
|
+
return { randomNumber, stringRandomNumber };
|
16
|
+
}
|
17
|
+
}
|
@@ -0,0 +1,13 @@
|
|
1
|
+
import { Action, action } from "./../index";
|
2
|
+
|
3
|
+
export class RecursiveAction extends Action {
|
4
|
+
name = "recursiveAction";
|
5
|
+
description = "I am an action that runs another action";
|
6
|
+
outputExample = {};
|
7
|
+
|
8
|
+
async run() {
|
9
|
+
const localResponse = { local: true };
|
10
|
+
const actionResponse = await action.run("randomNumber");
|
11
|
+
return Object.assign(actionResponse, localResponse);
|
12
|
+
}
|
13
|
+
}
|
@@ -0,0 +1,12 @@
|
|
1
|
+
import { Action, Connection } from "../index";
|
2
|
+
|
3
|
+
export class SendFile extends Action {
|
4
|
+
name = "sendFile";
|
5
|
+
description = "I send a file though an action";
|
6
|
+
outputExample = {};
|
7
|
+
|
8
|
+
async run(data: { connection: Connection; toRender: boolean }) {
|
9
|
+
await data.connection.sendFile("logo/actionhero.png");
|
10
|
+
data.toRender = false;
|
11
|
+
}
|
12
|
+
}
|
@@ -0,0 +1,40 @@
|
|
1
|
+
import { Action } from "./../index";
|
2
|
+
|
3
|
+
function sleep(time: number): Promise<void> {
|
4
|
+
return new Promise((resolve) => {
|
5
|
+
setTimeout(resolve, time);
|
6
|
+
});
|
7
|
+
}
|
8
|
+
|
9
|
+
export class SleepTest extends Action {
|
10
|
+
name = "sleepTest";
|
11
|
+
description = "I will sleep and then return";
|
12
|
+
inputs = {
|
13
|
+
sleepDuration: {
|
14
|
+
required: true as true,
|
15
|
+
formatter: (n: string) => {
|
16
|
+
return parseInt(n);
|
17
|
+
},
|
18
|
+
default: () => {
|
19
|
+
return 1000;
|
20
|
+
},
|
21
|
+
},
|
22
|
+
};
|
23
|
+
outputExample = {
|
24
|
+
sleepStarted: 1420953571322,
|
25
|
+
sleepEnded: 1420953572327,
|
26
|
+
sleepDelta: 1005,
|
27
|
+
sleepDuration: 1000,
|
28
|
+
};
|
29
|
+
|
30
|
+
async run({ params }: { params: { sleepDuration: number } }) {
|
31
|
+
const sleepDuration = params.sleepDuration;
|
32
|
+
const sleepStarted = new Date().getTime();
|
33
|
+
|
34
|
+
await sleep(sleepDuration);
|
35
|
+
const sleepEnded = new Date().getTime();
|
36
|
+
const sleepDelta = sleepEnded - sleepStarted;
|
37
|
+
|
38
|
+
return { sleepStarted, sleepEnded, sleepDelta, sleepDuration };
|
39
|
+
}
|
40
|
+
}
|
@@ -0,0 +1,73 @@
|
|
1
|
+
import { api, id, task, Action, actionheroVersion } from "./../index";
|
2
|
+
import { PackageJson } from "type-fest";
|
3
|
+
import * as path from "path";
|
4
|
+
import * as fs from "fs";
|
5
|
+
|
6
|
+
// These values are probably good starting points, but you should expect to tweak them for your application
|
7
|
+
const maxMemoryAlloted = process.env.maxMemoryAlloted
|
8
|
+
? parseInt(process.env.maxMemoryAlloted)
|
9
|
+
: 500;
|
10
|
+
const maxResqueQueueLength = process.env.maxResqueQueueLength
|
11
|
+
? parseInt(process.env.maxResqueQueueLength)
|
12
|
+
: 1000;
|
13
|
+
|
14
|
+
enum StatusMessages {
|
15
|
+
healthy = "Node Healthy",
|
16
|
+
unhealthy = "Node Unhealthy",
|
17
|
+
}
|
18
|
+
|
19
|
+
const packageJSON: PackageJson = JSON.parse(
|
20
|
+
fs
|
21
|
+
.readFileSync(
|
22
|
+
path.normalize(path.join(__dirname, "..", "..", "package.json")),
|
23
|
+
)
|
24
|
+
.toString(),
|
25
|
+
);
|
26
|
+
|
27
|
+
export class Status extends Action {
|
28
|
+
name = "status";
|
29
|
+
description = "I will return some basic information about the API";
|
30
|
+
outputExample = {
|
31
|
+
id: "192.168.2.11",
|
32
|
+
actionheroVersion: "9.4.1",
|
33
|
+
uptime: 10469,
|
34
|
+
};
|
35
|
+
|
36
|
+
async run() {
|
37
|
+
let nodeStatus = StatusMessages.healthy;
|
38
|
+
const problems: string[] = [];
|
39
|
+
|
40
|
+
const consumedMemoryMB =
|
41
|
+
Math.round((process.memoryUsage().heapUsed / 1024 / 1024) * 100) / 100;
|
42
|
+
if (consumedMemoryMB > maxMemoryAlloted) {
|
43
|
+
nodeStatus = StatusMessages.unhealthy;
|
44
|
+
problems.push(`Using more than ${maxMemoryAlloted} MB of RAM/HEAP`);
|
45
|
+
}
|
46
|
+
|
47
|
+
let resqueTotalQueueLength = 0;
|
48
|
+
const details = await task.details();
|
49
|
+
let length = 0;
|
50
|
+
Object.keys(details.queues).forEach((q) => {
|
51
|
+
length += details.queues[q].length;
|
52
|
+
});
|
53
|
+
resqueTotalQueueLength = length;
|
54
|
+
|
55
|
+
if (length > maxResqueQueueLength) {
|
56
|
+
nodeStatus = StatusMessages.unhealthy;
|
57
|
+
problems.push(`Resque Queues over ${maxResqueQueueLength} jobs`);
|
58
|
+
}
|
59
|
+
|
60
|
+
return {
|
61
|
+
id: id,
|
62
|
+
actionheroVersion: actionheroVersion,
|
63
|
+
name: packageJSON.name as string,
|
64
|
+
description: packageJSON.description as string,
|
65
|
+
version: packageJSON.version as string,
|
66
|
+
uptime: new Date().getTime() - api.bootTime,
|
67
|
+
consumedMemoryMB,
|
68
|
+
resqueTotalQueueLength,
|
69
|
+
nodeStatus,
|
70
|
+
problems,
|
71
|
+
};
|
72
|
+
}
|
73
|
+
}
|