1
1
require ( "dotenv" ) . config ( ) ;
2
2
3
+ // ========== Part #1. A redis client is instantiated here to fetch all of its non-expired cached information
4
+ // ========== This includes Bus services, Bus Routes, Bus Stops & Bus ETAs for pre-load rendering
5
+ // ========== and mitigate excessive load time for the web app on start
3
6
const redis = require ( "redis" ) ;
4
7
const url = require ( "url" ) ;
5
-
6
8
const redis_username = process . env . REDIS_USERNAME ;
7
9
const redis_password = process . env . REDIS_PASSWORD ;
8
-
9
10
const redis_endpoint_uri = process . env . REDIS_ENDPOINT_URI ;
10
11
const redis_db = process . env . REDIS_DB ;
11
-
12
12
const redisStr = `redis://${ redis_username } :${ redis_password } @${ redis_endpoint_uri } /${ redis_db } ` ;
13
13
const redisURL = url . parse ( redisStr ) ;
14
14
@@ -19,7 +19,7 @@ redisClient.on("connect", () => {
19
19
console . log ( "Successfully connected to Redis instance." ) ;
20
20
} ) ;
21
21
22
-
22
+ // ================== Part #2. Most variables and constants are declared here
23
23
const PORT = process . env . PORT || 3000 ;
24
24
const ORIGIN = process . env . ORIGIN || `http://localhost:${ PORT } ` ;
25
25
const LTA_API_KEY = process . env . LTA_API_KEY ;
@@ -45,6 +45,8 @@ router.use((req, res, next) => { // router middleware
45
45
next ( ) ;
46
46
} ) ;
47
47
48
+ // ================== Part #3. All server side API calls are called via the below functions and the redis Client updatse its data
49
+ // ================== storage with the API outputs in event the cache of its storage has expired (to fetch only up-to-date data)
48
50
function resolveAsyncCall ( reqOptions ) {
49
51
return new Promise ( resolve => {
50
52
request ( reqOptions , function ( err , res , body ) {
@@ -53,7 +55,6 @@ function resolveAsyncCall(reqOptions) {
53
55
} ) ;
54
56
} ) ;
55
57
}
56
-
57
58
async function asyncCall ( transportation ) {
58
59
var arr_result = [ ] ;
59
60
var offset = 0 ;
@@ -84,7 +85,6 @@ async function asyncCall(transportation) {
84
85
resolve ( arr_result ) ;
85
86
} ) ;
86
87
} ;
87
-
88
88
router . post ( "/ltaodataservice/all/:transportation" , async ( req , res ) => {
89
89
try {
90
90
let params = req . params ;
@@ -122,7 +122,6 @@ router.post("/ltaodataservice/all/:transportation", async (req, res) => {
122
122
} ) ;
123
123
}
124
124
} ) ;
125
-
126
125
router . post ( "/ltaodataservice/:transportation/:client_offset" , async ( req , res ) => {
127
126
try {
128
127
let params = req . params ;
@@ -207,14 +206,15 @@ router.post("/ltaodataservice/:transportation/:client_offset", async(req, res) =
207
206
} ) ;
208
207
}
209
208
} ) ;
210
-
211
209
router . get ( "/wake_up" , ( req , res ) => {
212
210
res . json ( { "status" :"app_is_awake" } ) ;
213
211
} ) ;
214
212
215
213
const app = express ( ) ;
216
214
app . use ( compression ( ) ) ; //use compression
217
215
216
+ // ================== Part #4. Server side socket is set up via socketio and http server below. Connection with client side must be
217
+ // ================== established before bilateral messages can be exchanged
218
218
const http = require ( "http" ) ;
219
219
const socketio = require ( "socket.io" ) ;
220
220
const server = http . createServer ( app ) ;
@@ -236,16 +236,20 @@ app.use(express.static(path.join(__dirname, "public")))
236
236
. set ( "view engine" , "html" )
237
237
. get ( "/" , ( req , res ) => res . render ( "index.html" ) )
238
238
239
- const onlineClients = new Set ( ) ;
240
- const previousBusCode = new Map ( ) ;
241
- const updateInterval = new Map ( ) ;
242
239
240
+
241
+ const onlineClients = new Set ( ) ; // Used to track the no. of connected client sockets and ids
242
+ const previousBusCode = new Map ( ) ; // Stores the latst bus stop no. ETAs requested by a client
243
+ const updateInterval = new Map ( ) ; // Stores latest intervalID of the socket tagged to its client to stop fetching data when not needed
244
+
245
+
246
+ // whenever a new user logs onto the web app a new client socket shall be established and connected
243
247
function onNewWebsocketConnection ( socket ) {
244
248
console . info ( `Server side socket[${ socket . id } ] connection established.` ) ;
245
249
246
250
// awaits for client-side to callback and confirm connection.
247
251
// echoes on the terminal every "back_to_server" message this socket sends
248
- socket . on ( "back_to_server" , msg => { // socket.id callback from client-side
252
+ socket . on ( "back_to_server" , msg => {
249
253
console . info ( `Client side socket id: ${ msg } ` ) ;
250
254
if ( msg == socket . id ) {
251
255
onlineClients . add ( socket . id ) ;
@@ -254,46 +258,42 @@ function onNewWebsocketConnection(socket) {
254
258
}
255
259
} ) ;
256
260
257
- // server side socket receives bus stop code from client side socket
261
+ // server side receives bus stop code from client side socket
258
262
socket . on ( "bus_arrivals" , bus_stop_code => {
263
+ let intervalID = updateInterval . get ( socket . id ) ;
259
264
let prevBusCode = previousBusCode . get ( socket . id ) ;
260
- let prevUpdateInterval = updateInterval . get ( socket . id ) ;
261
-
262
- console . log ( `Requesting bus stop: ${ bus_stop_code } ` ) ;
263
- console . log ( `Prev bus code: ${ prevBusCode } . Prev update interval: ${ prevUpdateInterval } ` ) ;
264
265
266
+ // when bus_stop_code is undefined it means client side has no required information
267
+ // to transfer to server side to fetch the Bus ETAs
265
268
if ( typeof bus_stop_code === "undefined" ) {
266
- if ( ( typeof prevUpdateInterval !== "undefined" ) ) {
267
- clearInterval ( prevUpdateInterval ) ;
268
- prevUpdateInterval = undefined ;
269
- updateInterval . set ( socket . id , undefined ) ;
270
-
271
- prevBusCode = undefined ;
272
- previousBusCode . set ( socket . id , undefined ) ;
273
- }
274
- } else if ( ( typeof prevBusCode === "undefined" ) || ( prevBusCode !== bus_stop_code ) ) {
275
- prevBusCode = bus_stop_code ;
276
- previousBusCode . set ( socket . id , bus_stop_code ) ;
269
+ if ( ( typeof intervalID !== "undefined" ) ) { // When user had requested for another bus stop's ETAs previously
270
+ clearInterval ( intervalID ) ;
271
+ updateInterval . set ( socket . id , undefined ) ;
277
272
278
- if ( ( typeof prevUpdateInterval !== "undefined" ) ) {
279
- clearInterval ( prevUpdateInterval ) ;
280
- updateInterval . set ( socket . id , undefined ) ;
281
- }
273
+ prevBusCode = undefined ; // When user selects another bus stop, the ETAs for the previous selection should be removed
274
+ previousBusCode . set ( socket . id , undefined ) ;
275
+ }
276
+ } else if ( ( typeof prevBusCode === "undefined" ) || ( prevBusCode !== bus_stop_code ) ) { // User has selected another bus stop
277
+ previousBusCode . set ( socket . id , bus_stop_code ) ;
282
278
283
- prevUpdateInterval = setInterval ( ( ) => {
284
- request ( {
285
- url : `${ API_ENDPOINT } /BusArrivalv2?BusStopCode=${ bus_stop_code } ` ,
286
- method : "GET" ,
287
- json : true ,
288
- headers : {
289
- "AccountKey" : LTA_API_KEY ,
290
- "accept" : "application/json"
291
- }
292
- } , ( err , res , body ) => {
293
- socket . emit ( "get_bus_arrivals_info" , JSON . stringify ( body [ "Services" ] ) ) ;
294
- } ) ;
295
- } , 10000 ) ;
296
- updateInterval . set ( socket . id , prevUpdateInterval ) ;
279
+ if ( ( typeof intervalID !== "undefined" ) ) { // To stop fetch ETAs for previous bus stop selected
280
+ clearInterval ( intervalID ) ;
281
+ updateInterval . set ( socket . id , undefined ) ;
282
+ }
283
+ intervalID = setInterval ( ( ) => {
284
+ request ( {
285
+ url : `${ API_ENDPOINT } /BusArrivalv2?BusStopCode=${ bus_stop_code } ` ,
286
+ method : "GET" ,
287
+ json : true ,
288
+ headers : {
289
+ "AccountKey" : LTA_API_KEY ,
290
+ "accept" : "application/json"
291
+ }
292
+ } , ( err , res , body ) => {
293
+ socket . emit ( "get_bus_arrivals_info" , JSON . stringify ( body [ "Services" ] ) ) ;
294
+ } ) ;
295
+ } , 10000 ) ;
296
+ updateInterval . set ( socket . id , intervalID ) ; // update the stored interval ID
297
297
}
298
298
} ) ;
299
299
@@ -305,7 +305,6 @@ function onNewWebsocketConnection(socket) {
305
305
} ) ;
306
306
}
307
307
308
-
309
308
// will fire for every new socket connection: every user logs onto the web app
310
309
io . on ( "connection" , onNewWebsocketConnection ) ;
311
310
// broadcast here
0 commit comments