-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathservice.js
153 lines (145 loc) · 5.51 KB
/
service.js
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
const axios = require('axios');
const moment = require('moment-timezone');
const DAYS = ["monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday"];
const MEALS = ["breakfast", "lunch", "hi_tea", "dinner"];
class Service {
/**
* Constructor for this service
*/
constructor() {
this.API_URL = 'https://nucleus.niituniversity.in/WebApp/StudParentDashBoard/MessMenu.aspx/GetMessMenuStudentPortal';
this.permitted_menus = ["1", "2"];
this.cache = global.cache;
}
/**
*
* @param {moment.Object} date
* @param {String} meal
*
* Fulfillment function for the Google Assistant
* Webhook.
*/
async getFulfillmentResponse(date, meal) {
/**
* Moment treats Sunday as the
* start of the week, while my convention treats
* Monday as that.
* SUN - 0 -> 6
* MON - 1 -> 0
* TUE - 2 -> 1
* WED - 3 -> 2
* THU - 4 -> 3
* FRI - 5 -> 4
* SAT - 6 -> 5
*
* Doing this as an object map implementation
* because I have something in mind about this.
*/
const DAY_MAPPING = {
0: 6,
1: 0,
2: 1,
3: 2,
4: 3,
5: 4,
6: 5
};
let day = DAY_MAPPING[moment(date).day()];
console.log(`${moment(date).day()} -> ${day}`);
const menu = await this.getMenu("1");
if (!menu) return null;
const mealArray = menu[DAYS[day]][meal];
let retval = null
if (mealArray && mealArray.length > 0) {
retval = "The mess serves ";
for (let i = 0; i < mealArray.length; i++) {
if (i < mealArray.length - 1) retval += mealArray[i] + ", ";
else retval += mealArray[i] + " ";
}
retval += `for ${meal} every ${DAYS[day]}.`;
}
return retval;
}
/**
*
* @param {String} messMenuTypeId
*
* Driver function that gets the menu from the node-cache
* if available, or fetches from upstream.
*/
async getMenu(messMenuTypeId) {
const functionTag = 'getMenu';
let menu = null;
try {
if (!messMenuTypeId) return null;
if (!this.permitted_menus.includes(messMenuTypeId)) throw new Error(`Unexpected value ${messMenuTypeId} for messMenuTypeId`);
const start = moment();
menu = this.cache.get(messMenuTypeId);
if (!menu) {
console.log(`${Service.logPrefix}: ${functionTag}: Cache miss on messMenuTypeId = ${messMenuTypeId}`);
let upstreamMenu = await this.fetchLatestMenuFromNucleus(messMenuTypeId);
if (this.cache.set(messMenuTypeId, upstreamMenu)) console.log(`${Service.logPrefix}: ${functionTag}: Populated cache for messMenuTypeId = ${messMenuTypeId}`);
return upstreamMenu;
}
console.log(`${Service.logPrefix}: ${functionTag}: Fetched menu for messMenuTypeId = ${messMenuTypeId} from cache in ${moment() - start} ms`);
return menu;
} catch (error) {
console.log(`${Service.logPrefix}: ${functionTag}: ${JSON.stringify(error, Object.getOwnPropertyNames(error))}`);
return null;
}
}
/**
*
* @param {String} messMenuTypeId
* A utility funtion to fetch the latest menu from
* Nucleus and returned a structured JSON response.
*/
async fetchLatestMenuFromNucleus(messMenuTypeId) {
/**
*
* @param {String} menuString
* A utility function to parse the dirty string
* returned by the Nucleus API into a structured
* JSON response
*/
const parseMenu = (menuString) => {
const parsedMenu = {}, menu = [];
menuString.split('$^').forEach(day => {
const meals = [];
day.split('$').forEach(meal => {
const items = [];
meal.split('\r\n').forEach(item => {
if (item) items.push(item.trim());
});
meals.push(items);
});
menu.push(meals);
});
for (let i = 0; i < DAYS.length; i++) {
let m = menu[i];
const myMeals = {};
for (let j = 0; j < MEALS.length; j++) {
myMeals[MEALS[j]] = m[j];
}
parsedMenu[DAYS[i]] = myMeals;
}
return parsedMenu;
};
const functionTag = 'fetchLatestMenuFromNucleus';
let result = null;
try {
if (!messMenuTypeId) throw new Error(`No messMenuTypeId found.`);
if (!this.permitted_menus.includes(messMenuTypeId)) throw new Error(`Unexpected value ${messMenuTypeId} for messMenuTypeId`);
const start = moment();
result = await axios.post(this.API_URL, { messMenuTypeId }, { headers: { "Content-Type": "application/json" } });
const retval = parseMenu(result.data.d);
console.log(`${Service.logPrefix}: ${functionTag}: Fetched and parsed latest menu from Nucleus in ${moment() - start} ms`);
return retval;
} catch (error) {
console.log(`${Service.logPrefix}: ${functionTag}: ${JSON.stringify(error, Object.getOwnPropertyNames(error))}`);
return null;
}
}
}
Service.logPrefix = 'Logs from Service';
module.exports = Service;