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
|
import { yellow } from 'colors';
import * as dotenv from 'dotenv';
import * as mobileDetect from 'mobile-detect';
import * as path from 'path';
import { logExecution } from './ActionUtilities';
import AssistantManager from './ApiManagers/AssistantManager';
import FlashcardManager from './ApiManagers/FlashcardManager';
import DataVizManager from './ApiManagers/DataVizManager';
import DeleteManager from './ApiManagers/DeleteManager';
import DownloadManager from './ApiManagers/DownloadManager';
import FireflyManager from './ApiManagers/FireflyManager';
import GeneralGoogleManager from './ApiManagers/GeneralGoogleManager';
import SessionManager from './ApiManagers/SessionManager';
import UploadManager from './ApiManagers/UploadManager';
import UserManager from './ApiManagers/UserManager';
import UtilManager from './ApiManagers/UtilManager';
import { DashSessionAgent } from './DashSession/DashSessionAgent';
import { AppliedSessionAgent } from './DashSession/Session/agents/applied_session_agent';
import { DashStats } from './DashStats';
import { DashUploadUtils } from './DashUploadUtils';
import { Logger } from './ProcessFactory';
import RouteManager, { Method, PublicHandler } from './RouteManager';
import RouteSubscriber from './RouteSubscriber';
import { AdminPrivileges, resolvedPorts } from './SocketData';
import { GoogleCredentialsLoader, SSL } from './apis/google/CredentialsLoader';
import { GoogleApiServerUtils } from './apis/google/GoogleApiServerUtils';
import { Database } from './database';
import initializeServer from './server_Initialization';
// import GooglePhotosManager from './ApiManagers/GooglePhotosManager';
dotenv.config();
export const onWindows = process.platform === 'win32';
export let sessionAgent: AppliedSessionAgent;
/**
* These are the functions run before the server starts
* listening. Anything that must be complete
* before clients can access the server should be run or awaited here.
*/
async function preliminaryFunctions() {
// Utils.TraceConsoleLog();
await DashUploadUtils.buildFileDirectories();
await Logger.initialize();
await GoogleCredentialsLoader.loadCredentials();
SSL.loadCredentials();
GoogleApiServerUtils.processProjectCredentials();
if (process.env.DB !== 'MEM') {
await logExecution({
startMessage: 'attempting to initialize mongodb connection',
endMessage: 'connection outcome determined',
action: Database.tryInitializeConnection,
});
}
}
/**
* Either clustered together as an API manager
* or individually referenced below, by the completion
* of this function's execution, all routes will
* be registered on the server
* @param router the instance of the route manager
* that will manage the registration of new routes
* with the server
*/
function routeSetter({ addSupervisedRoute, logRegistrationOutcome }: RouteManager) {
const managers = [
new SessionManager(),
new UserManager(),
new UploadManager(),
new DownloadManager(),
new DeleteManager(),
new UtilManager(),
new GeneralGoogleManager(),
/* new GooglePhotosManager(), */ new DataVizManager(),
new AssistantManager(),
new FlashcardManager(),
new FireflyManager(),
];
// initialize API Managers
console.log(yellow('\nregistering server routes...'));
managers.forEach(manager => manager.register(addSupervisedRoute));
/**
* Accessing root index redirects to home
*/
addSupervisedRoute({
method: Method.GET,
subscription: '/',
secureHandler: ({ res }) => res.redirect('/home'),
});
addSupervisedRoute({
method: Method.GET,
subscription: '/serverHeartbeat',
secureHandler: ({ res }) => res.send(true),
});
addSupervisedRoute({
method: Method.GET,
subscription: '/stats',
secureHandler: ({ res }) => DashStats.handleStats(res),
});
addSupervisedRoute({
method: Method.GET,
subscription: '/statsview',
secureHandler: ({ res }) => DashStats.handleStatsView(res),
});
addSupervisedRoute({
method: Method.GET,
subscription: '/resolvedPorts',
secureHandler: ({ res }) => res.send(resolvedPorts),
publicHandler: ({ res }) => res.send(resolvedPorts),
});
const serve: PublicHandler = ({ req, res }) => {
const detector = new mobileDetect(req.headers['user-agent'] || '');
const filename = detector.mobile() !== null ? 'mobile/image.html' : 'index.html';
res.sendFile(path.join(__dirname, '../../deploy/' + filename));
};
/**
* Serves a simple password input box for any
*/
addSupervisedRoute({
method: Method.GET,
subscription: new RouteSubscriber('admin').add('previous_target'),
secureHandler: ({ res, isRelease }) => {
const { PASSWORD } = process.env;
if (!(isRelease && PASSWORD)) {
res.redirect('/home');
} else res.render('admin.pug', { title: 'Enter Administrator Password' });
},
});
addSupervisedRoute({
method: Method.POST,
subscription: new RouteSubscriber('admin').add('previous_target'),
secureHandler: async ({ req, res, isRelease, user: { id } }) => {
const { PASSWORD } = process.env;
if (!(isRelease && PASSWORD)) {
res.redirect('/home');
} else {
const { password } = req.body;
const { previous_target: previousTarget } = req.params;
let redirect: string;
if (password === PASSWORD) {
AdminPrivileges.set(id, true);
redirect = `/${previousTarget.replace(':', '/')}`;
} else {
redirect = `/admin/${previousTarget}`;
}
res.redirect(redirect);
}
},
});
addSupervisedRoute({
method: Method.GET,
subscription: ['/home', new RouteSubscriber('doc').add('docId')],
secureHandler: serve,
publicHandler: ({ req, res, ...remaining }) => {
const { originalUrl: target } = req;
const docAccess = target.startsWith('/doc/');
// since this is the public handler, there's no meaning of '/home' to speak of
// since there's no user logged in, so the only viable operation
// for a guest is to look at a shared document
if (docAccess) {
serve({ req, res, ...remaining });
} else {
res.redirect('/login');
}
},
});
logRegistrationOutcome();
}
/**
* This function can be used in two different ways. If not in release mode,
* this is simply the logic that is invoked to start the server. In release mode,
* however, this becomes the logic invoked by a single worker thread spawned by
* the main monitor (master) thread.
*/
export async function launchServer() {
await logExecution({
startMessage: '\nstarting execution of preliminary functions',
endMessage: 'completed preliminary functions\n',
action: preliminaryFunctions,
});
await initializeServer(routeSetter);
}
/**
* If you're in development mode, you won't need to run a session.
* The session spawns off new server processes each time an error is encountered, and doesn't
* log the output of the server process, so it's not ideal for development.
* So, the 'else' clause is exactly what we've always run when executing npm start.
*/
(Database.Instance as Database.Database).doConnect();
if (process.env.MONITORED) {
(sessionAgent = new DashSessionAgent()).launch();
} else {
launchServer();
}
|