Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions src/controllers/DelaysController.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@ const router = express.Router();
router.get("/alerts", async (req, res) => {
try {
const alerts = await AlertsUtils.getAlertsData();
res.status(200).json(alerts);
res.status(200).json({
success: true,
data: alerts,
});
} catch (error) {
console.error("Error fetching alerts:", error.message);
res.status(500).json({ error: "Failed to fetch alerts" });
Expand All @@ -32,7 +35,11 @@ router.post("/delays", async (req, res) => {
})
);

res.status(200).json(delays);
res.status(200).json({
success: true,
data: allStops,
});

} catch (error) {
res.status(500).json({ error: error.message });
}
Expand Down
5 changes: 4 additions & 1 deletion src/controllers/RouteController.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,10 @@ router.post('/route', async (req, res) => {
AnalyticsUtils.assignRouteIdsAndCache(routes);

// Send the sectioned routes as the response
res.json(sectionedRoutes);
res.status(200).json({
success: true,
data: sectionedRoutes,
});
} catch (error) {
LogUtils.logErr(error, req.body, 'Error processing route request');
res.status(500).json({ error: 'Failed to process the route request' });
Expand Down
15 changes: 12 additions & 3 deletions src/controllers/RouteReportingController.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,10 @@ router.get('/closestBus', async (req, res) => {
} = req.body;

const closestBus = await RouteReportingUtils.getClosestBus(routeId, start);
res.status(200).json(closestBus);
res.status(200).json({
success: true,
data: closestBus,
});
} catch (error) {
LogUtils.logErr(error, req.body, 'Error fetching closest bus');
res.status(500).json({ error: 'Failed to fetch closest bus' });
Expand All @@ -29,7 +32,10 @@ router.post('/reports', async (req, res) => {
} = req.body;

const report = await RouteReportingUtils.insertReport(vehicleId, congestionLevel, deviceToken, timestamp);
res.status(200).json(report);
res.status(200).json({
success: true,
data: report,
});
} catch (error) {
LogUtils.logErr(error, req.body, 'Error inserting report');
res.status(500).json({ error: 'Failed to insert report' });
Expand All @@ -40,7 +46,10 @@ router.get('/reports/:vehicleId', async (req, res) => {
try {
const { vehicleId } = req.params;
const reports = await RouteReportingUtils.fetchReportsByBus(vehicleId);
res.status(200).json(reports);
res.status(200).json({
success: true,
data: reports,
});
} catch (error) {
LogUtils.logErr(error, req.params, 'Error fetching reports by vehicleId');
res.status(500).json({ error: 'Failed to fetch reports by vehicleId' });
Expand Down
5 changes: 4 additions & 1 deletion src/controllers/StopsController.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@ const router = express.Router();
router.get("/allStops", async (req, res) => {
try {
const allStops = await AllStopUtils.getAllStops();
res.status(200).json(allStops);
res.status(200).json({
success: true,
data: allStops,
});
} catch (error) {
console.error("Error fetching all stops:", error.message);
res.status(500).json({ error: "Failed to fetch all stops" });
Expand Down
7 changes: 5 additions & 2 deletions src/controllers/TrackingController.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,11 @@ router.post("/tracking", async (req, res) => {
const trackingResponse = await RealtimeFeedUtilsV3.getTrackingResponse(
data
);

res.status(200).json(trackingResponse);

res.status(200).json({
success: true,
data: trackingResponse,
});
} catch (error) {
res.status(500).json({ error: error.message });
}
Expand Down
58 changes: 57 additions & 1 deletion src/data/notifRequests.json
Original file line number Diff line number Diff line change
@@ -1 +1,57 @@
{}
{
"t776-bFA1-slD": {
"1512": [
"d5yOxYOS8UakmiJWNFX2Nr:APA91bGb6PSrXFd4vmD7XQN3vALrZEwTWXf2z9HeEMOXrYtNj0psn5qO_-zv0VLsPpuZYdFMXi3YSkJ2FTnJV75Fc7LNw01GGJTFzf9CWf-W-f6r9c7oKsXEVfqjz8k-BkXnTTqQhG2d"
]
},
"t854-b1F57-slC": {
"1328": [
"diiwsV-LXkL-vFTrMLczKh:APA91bFVvviZuN0JvnDgawDbae2RYr2-FX3yjQrf0khhB7_7d1mhODigsCC8bZrdmdFM-Wx8yeVnSOJZnS9UACYm4VNGB0bMT_2LzYuIolKSD9xPn240pu4"
]
},
"t840-b1F59-slC": {
"1328": [
"diiwsV-LXkL-vFTrMLczKh:APA91bFVvviZuN0JvnDgawDbae2RYr2-FX3yjQrf0khhB7_7d1mhODigsCC8bZrdmdFM-Wx8yeVnSOJZnS9UACYm4VNGB0bMT_2LzYuIolKSD9xPn240pu4"
]
},
"t898-b1F57-slC": {
"1533": [
"diiwsV-LXkL-vFTrMLczKh:APA91bFVvviZuN0JvnDgawDbae2RYr2-FX3yjQrf0khhB7_7d1mhODigsCC8bZrdmdFM-Wx8yeVnSOJZnS9UACYm4VNGB0bMT_2LzYuIolKSD9xPn240pu4"
]
},
"t868-b1F59-slC": {
"1534": [
"diiwsV-LXkL-vFTrMLczKh:APA91bFVvviZuN0JvnDgawDbae2RYr2-FX3yjQrf0khhB7_7d1mhODigsCC8bZrdmdFM-Wx8yeVnSOJZnS9UACYm4VNGB0bMT_2LzYuIolKSD9xPn240pu4"
]
},
"t8CF-b1F4A-slC": {
"1343": [
"de-EtLrD6Ub1sEK8dSm1jr:APA91bEU9KIQElzFZefk6KRhQ0ADcVflRp3MHhWrLBZa8DTIHVLac1wQTVYfZ5wTRfKOWGpxFFnKWyTunYJKLOC54bP3n5YPyCyHhje7skYx4y673pJXcbI"
]
},
"t908-b1F59-slC": {},
"t91C-b1F57-slC": {},
"t930-b1F59-slC": {},
"t960-b1F4B-slC": {},
"tC-b1F57-slC": {},
"t20-b1F59-slC": {},
"t13-b1F4B-slC": {},
"t14-b1F59-slC": {},
"t28-b1F57-slC": {},
"t31-b1F4B-slC": {
"1531": [
"de-EtLrD6Ub1sEK8dSm1jr:APA91bEU9KIQElzFZefk6KRhQ0ADcVflRp3MHhWrLBZa8DTIHVLac1wQTVYfZ5wTRfKOWGpxFFnKWyTunYJKLOC54bP3n5YPyCyHhje7skYx4y673pJXcbI"
]
},
"t7D0-b1F4B-slD": {},
"t7DC-b1F57-slD": {},
"t7DA-b1F5B-slD": {},
"t804-b1F57-slD": {},
"t7DF-b1F44-slD": {},
"t898-b1F4B-slD": {},
"t86D-b1F44-slD": {},
"t8A4-b1F57-slD": {},
"t898-b1F57-slD": {},
"t8C0-b1F57-slD": {},
"t8C9-b1F4B-slD": {}
}
23 changes: 13 additions & 10 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,32 +16,35 @@ import RealtimeFeedUtilsV3 from "./utils/RealtimeFeedUtilsV3.js";

import admin from "firebase-admin";
import swaggerUi from "swagger-ui-express";
import swaggerDoc from "./swagger.json" with { type: "json" };
import fs from "fs";
const swaggerDoc = JSON.parse(
fs.readFileSync(new URL("./swagger.json", import.meta.url))
);

import AlertsUtils from "./utils/AlertsUtils.js";
import AllStopUtils from "./utils/AllStopUtils.js";
import GTFSUtils from "./utils/GTFSUtils.js";


const app = express();
const port = process.env.PORT;

app.use(express.json());

app.use('/api/v1/', delayRoutes);
app.use("/api/v1/", delayRoutes);

app.use('/api/v3/', routeRoutes);
app.use("/api/v3/", routeRoutes);

app.use('/api/v3/', trackingRoutes);
app.use("/api/v3/", trackingRoutes);

app.use('/api/v2/', searchRoutes);
app.use("/api/v3/", searchRoutes);

app.use('/api/v1/', stopsRoutes);
app.use("/api/v1/", stopsRoutes);

app.use('/api/v1/', notifRoutes);
app.use("/api/v1/", notifRoutes);

app.use('/api/v1/', reportingRoutes);
app.use("/api/v1/", reportingRoutes);

app.use('/api/v1/', ecosystemRoutes);
app.use("/api/v1/", ecosystemRoutes);

// Setup Swagger docs
app.use("/api-docs", swaggerUi.serve, swaggerUi.setup(swaggerDoc));
Expand Down
80 changes: 57 additions & 23 deletions src/utils/NotificationUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { fileURLToPath } from "url";
import fs from "fs";
import path from "path";
import RealtimeFeedUtilsV3 from "./RealtimeFeedUtilsV3.js";
import LogUtils from "./LogUtils.js";

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
Expand Down Expand Up @@ -59,54 +60,86 @@ function deleteDelayNotification(tripID, stopID, deviceToken) {

function sendNotifications() {
const rtfData = RealtimeFeedUtilsV3.getRTFData();

if (!rtfData) {
// no real-time data available yet
return;
}


const tokensToDelete = [];

for (const id in rtfData) {
if (id in notifRequests) {
for (const stopID in notifRequests[id]) {
if (stopID in rtfData[id]["stopUpdates"]) {
for (const deviceToken of notifRequests[id][stopID]) {
sendNotification(
deviceToken,
`The bus on ${rtfData[id]["routeId"]} is delayed`,
"testBody"
);
//only send a notification if there is a delay
if (rtfData[id]["stopUpdates"][stopID] > 0) {
for (const deviceToken of notifRequests[id][stopID]) {
const notifData = {
title: "Delay Notification",
body: `The bus on ${rtfData[id]["routeId"]} is delayed`,
};

sendNotification(deviceToken, notifData);

tokensToDelete.push({ id, stopID, deviceToken });
}
}
}
}
}
}

for (const { id, stopID, deviceToken } of tokensToDelete) {
if (
notifRequests[id] &&
notifRequests[id][stopID] &&
Array.isArray(notifRequests[id][stopID])
) {
notifRequests[id][stopID] = notifRequests[id][stopID].filter(
(token) => token !== deviceToken
);
if (notifRequests[id][stopID].length === 0) {
delete notifRequests[id][stopID];
}
}
}

saveNotifs();
}

function sendNotification(deviceToken, data, notification) {
async function sendNotification(deviceToken, notif) {
const message = {
data: {
data,
notification,
},
token: deviceToken,
notification: {
title: notif.title,
body: notif.body,
},
};

if (!message.token) {
throw new Error("Invalid device token");
}
getMessaging()
.send(message)
.then((response) => {
console.log(response);
});

try {
const response = await getMessaging()
.send(message)
.then((response) => {
LogUtils.log({ message: response });
console.log(response);
});

console.log("Notification sent successfully:", response);
} catch (error) {
console.error("Error sending notification:", error.code, error.message);
}
}

function waitForDeparture(deviceToken, startTime) {
const startDate = new Date(parseInt(startTime) * 1000 - 60000 * 10);

const notifData = {
data: "You should board your bus in 10 minutes",
notification: "Bording Reminder",
body: "You should board your bus in 10 minutes",
title: "Bording Reminder",
};

const job = schedule.scheduleJob(startDate, () => {
Expand All @@ -121,13 +154,14 @@ function waitForDeparture(deviceToken, startTime) {
}

function cancelDeparture(deviceToken, startTime) {
const startDate = new Date(parseInt(startTime) * 1000 - 60000 * 10);
let startDate = new Date(parseInt(startTime) * 1000 - 60000 * 10);
startDate = startDate.toString();

if (deviceToken in departures) {
if (startDate in departures[deviceToken]) {
if (departures[deviceToken][startDate]) {
departures[deviceToken][startDate].cancel();
console.log("Job canceled.");
LogUtils.log({ message: "job canceled" });
}
}
}
Expand Down
12 changes: 0 additions & 12 deletions src/utils/RealtimeFeedUtilsV3.js
Original file line number Diff line number Diff line change
Expand Up @@ -146,15 +146,13 @@ function getVehicleData() {
*
*/
async function getTrackingResponse(requestData) {
LogUtils.log({ message: "getTrackingResponse: entering function" });
const vehicles = getVehicleData();

const trackingInformation = requestData
.map((data) => {
const { routeId, tripId } = data;
const vehicleData = getVehicleInformation(routeId, tripId, vehicles);
if (!vehicleData) {
LogUtils.log({ message: "getVehicleResponse: noData", vehicleData });
return null;
}
return vehicleData;
Expand Down Expand Up @@ -203,22 +201,12 @@ function getVehicleInformation(routeId, tripId, vehicles) {
// vehicles param ensures the vehicle tracking information doesn't update in
// the middle of execution
if (!routeId || !tripId || !vehicles) {
LogUtils.log({
category: "getVehicleInformation NULL",
routeId,
tripId,
});
return null;
}
const vehicleData = Object.values(vehicles).find(
(v) => v.routeId === routeId && v.tripId === tripId
);
if (!vehicleData) {
LogUtils.log({
category: "getVehicleInformation no data",
routeId,
tripId,
});
return {
case: "noData",
latitude: 0,
Expand Down