From 6a687eb297086d76a5791a1d0bc7173b8c4b91d8 Mon Sep 17 00:00:00 2001 From: Seil0 Date: Sat, 5 Oct 2019 17:17:26 +0200 Subject: [PATCH] added more status metrics, api version 1.1.3 (/lesson -> /lessons) * updated spring boot 2.1.8 -> 2.1.9 * closes #7 --- build.gradle | 2 +- .../mosad/thecitadelofricks/APIController.kt | 69 +++++++++++++------ .../thecitadelofricks/CacheController.kt | 18 +++-- .../org/mosad/thecitadelofricks/DataTypes.kt | 5 +- 4 files changed, 63 insertions(+), 31 deletions(-) diff --git a/build.gradle b/build.gradle index 7550213..00fd33c 100644 --- a/build.gradle +++ b/build.gradle @@ -1,7 +1,7 @@ buildscript { ext.kotlin_version = '1.3.50' - ext.spring_boot_version = '2.1.8.RELEASE' + ext.spring_boot_version = '2.1.9.RELEASE' repositories { jcenter() diff --git a/src/main/kotlin/org/mosad/thecitadelofricks/APIController.kt b/src/main/kotlin/org/mosad/thecitadelofricks/APIController.kt index 6b09f9d..67d28be 100644 --- a/src/main/kotlin/org/mosad/thecitadelofricks/APIController.kt +++ b/src/main/kotlin/org/mosad/thecitadelofricks/APIController.kt @@ -34,7 +34,6 @@ import java.net.HttpURLConnection import java.net.URL import java.time.LocalDateTime import java.util.* -import java.util.stream.Collectors import kotlin.collections.ArrayList import kotlin.collections.HashSet @@ -44,11 +43,13 @@ class APIController { private val logger: Logger = LoggerFactory.getLogger(APIController::class.java) private val cache = CacheController() - private val apiVersion = "1.1.2" - private val softwareVersion = "1.1.4" + private val apiVersion = "1.1.3" + private val softwareVersion = "1.1.5" private val startTime = System.currentTimeMillis() / 1000 - private var requestCount = 0 + private var totalRequests = 0 + private var mensaMenuRequests = 0 + private var timetableRequests = ArrayList() @Deprecated("courses is replaced by courseList", replaceWith = ReplaceWith("courseList()")) @RequestMapping("/courses") @@ -59,15 +60,16 @@ class APIController { @RequestMapping("/courseList") fun courseList(): CourseList { logger.info("courseList request at ${LocalDateTime.now()}!") - requestCount++ - return courseList + totalRequests++ + return courseList } @RequestMapping("/mensamenu") fun mensamenu(): MensaMenu { logger.info("mensamenu request at ${LocalDateTime.now()}!") - requestCount++ - return mensaMenu + mensaMenuRequests++ + totalRequests++ + return mensaMenu } @RequestMapping("/timetable") @@ -76,7 +78,8 @@ class APIController { @RequestParam(value = "week", defaultValue = "0") week: Int ): TimetableCourseWeek { logger.info("timetable request at ${LocalDateTime.now()}!") - requestCount++ + updateTimetableRequests(courseName) + totalRequests++ return cache.getTimetable(courseName, week) } @@ -86,18 +89,18 @@ class APIController { @RequestParam(value = "week", defaultValue = "0") week: Int ): HashSet { logger.info("lessonSubjectList request at ${LocalDateTime.now()}!") - requestCount++ + totalRequests++ return getLessonSubjectList(courseName, week) } - @RequestMapping("/lesson") + @RequestMapping("/lessons") fun lesson( @RequestParam(value = "courseName", defaultValue = "AI4") courseName: String, @RequestParam(value = "lessonSubject", defaultValue = "Mathematik 4") lessonSubject: String, @RequestParam(value = "week", defaultValue = "0") week: Int ): ArrayList { logger.info("lesson request at ${LocalDateTime.now()}!") - requestCount++ + totalRequests++ return getLesson(courseName, lessonSubject, week) } @@ -108,11 +111,17 @@ class APIController { // non direct api functions - private fun getLessonSubjectList(courseName: String, week: Int): HashSet { + /** + * get every explicit lesson in a week + * @param courseName the name of the course to be requested + * @param weekIndex request week number (current week = 0) + * @return a HashSet of explicit lessons for one week + */ + private fun getLessonSubjectList(courseName: String, weekIndex: Int): HashSet { val lessonSubjectList = ArrayList() // get every lesson subject for the given week - val flatMap = cache.getTimetable(courseName, week).timetable.days.flatMap { it.timeslots.asIterable() } + val flatMap = cache.getTimetable(courseName, weekIndex).timetable.days.flatMap { it.timeslots.asIterable() } flatMap.forEach { it.stream().filter { x -> x.lessonSubject.isNotEmpty() }.findAny().ifPresent { x -> lessonSubjectList.add(x.lessonSubject) } } @@ -120,11 +129,18 @@ class APIController { return HashSet(lessonSubjectList) } - private fun getLesson(courseName: String, lessonSubject: String, week: Int): ArrayList { + /** + * get every explicit lesson in a week + * @param courseName the name of the course to be requested + * @param lessonSubject the lesson subject to be requested + * @param weekIndex request week number (current week = 0) + * @return a ArrayList of every lesson with lessonSubject for one week + */ + private fun getLesson(courseName: String, lessonSubject: String, weekIndex: Int): ArrayList { val lessonList = ArrayList() // get all lessons from the weeks timetable - val flatMap = cache.getTimetable(courseName, week).timetable.days.flatMap { it.timeslots.asIterable() } + val flatMap = cache.getTimetable(courseName, weekIndex).timetable.days.flatMap { it.timeslots.asIterable() } flatMap.forEach { it.forEach { lesson -> if(lesson.lessonSubject.contains(lessonSubject)) { @@ -138,15 +154,23 @@ class APIController { return lessonList } + /** + * if a timetable is requested update the request counter + */ + private fun updateTimetableRequests(courseName: String) { + timetableRequests.stream().filter { it.courseName == courseName }.findFirst().ifPresentOrElse({ + it.requests++ + }, { + timetableRequests.add(TimetableCounter(courseName, 1)) + }) + } + private fun getStatus(): Status { val currentTime = System.currentTimeMillis() / 1000 val minutes = (currentTime - startTime) % 3600 / 60 val hours = (currentTime - startTime) % 86400 / 3600 val days = (currentTime - startTime) / 86400 - val timetableListSize = timetableList.size - val timetableListNames = timetableList.stream().map { x -> x.meta.courseName }.collect(Collectors.toList()) - var hsoCode = 999 var swfrCode = 999 logger.info("status request at ${LocalDateTime.now()}!") @@ -173,9 +197,10 @@ class APIController { "$days days, $hours:$minutes", apiVersion, softwareVersion, - requestCount, - timetableListSize, - HashSet(timetableListNames).toString(), + totalRequests, + mensaMenuRequests, + timetableRequests, + timetableList.size, Date(courseList.meta.updateTime * 1000), Date(mensaMenu.meta.updateTime * 1000), hsoCode, diff --git a/src/main/kotlin/org/mosad/thecitadelofricks/CacheController.kt b/src/main/kotlin/org/mosad/thecitadelofricks/CacheController.kt index f7a0738..213a9bc 100644 --- a/src/main/kotlin/org/mosad/thecitadelofricks/CacheController.kt +++ b/src/main/kotlin/org/mosad/thecitadelofricks/CacheController.kt @@ -58,12 +58,18 @@ class CacheController { scheduledUpdates() } + /** + * get a timetable, since they may not cached, we need to make sure it's cached, otherwise download + * @param courseName the name of the course to be requested + * @param weekIndex request week number (current week = 0) + * @return the timetable of a course (courseName) + */ fun getTimetable(courseName: String, weekIndex: Int): TimetableCourseWeek = runBlocking { val currentTime = System.currentTimeMillis() / 1000 var timetable = TimetableWeek() var weekNumberYear = 0 - // check if the timetable already exists and is up to date + // check if the timetable already exists and is up to date when (timetableList.stream().filter { x -> x.meta.courseName == courseName && x.meta.weekIndex == weekIndex }.findAny().orElse(null)) { // there is no such course yet, create one null -> { @@ -90,9 +96,8 @@ class CacheController { * during the update process the old data will be returned for a API request */ private fun asyncUpdateCourseList() = GlobalScope.launch { - val result = CourseListParser().getCourseLinks(courseListURL) - if (result != null) { - courseList = CourseList(CourseMeta(System.currentTimeMillis() / 1000, result.size), result) + CourseListParser().getCourseLinks(courseListURL)?.let { + courseList = CourseList(CourseMeta(System.currentTimeMillis() / 1000, it.size), it) } logger.info("updated courses successful at ${Date(courseList.meta.updateTime * 1000)}") @@ -134,9 +139,8 @@ class CacheController { private fun initUpdates() = runBlocking { // get all courses on startup val jobCourseUpdate = GlobalScope.async { - val result = CourseListParser().getCourseLinks(courseListURL) - if (result != null) { - courseList = CourseList(CourseMeta(System.currentTimeMillis() / 1000, result.size), result) + CourseListParser().getCourseLinks(courseListURL)?.let { + courseList = CourseList(CourseMeta(System.currentTimeMillis() / 1000, it.size), it) } } diff --git a/src/main/kotlin/org/mosad/thecitadelofricks/DataTypes.kt b/src/main/kotlin/org/mosad/thecitadelofricks/DataTypes.kt index 7a11cc4..074576e 100644 --- a/src/main/kotlin/org/mosad/thecitadelofricks/DataTypes.kt +++ b/src/main/kotlin/org/mosad/thecitadelofricks/DataTypes.kt @@ -62,14 +62,17 @@ data class TimetableCourseWeek(val meta: TimetableCourseMeta, var timetable: Tim // data classes for the status part +data class TimetableCounter(var courseName: String, var requests: Int) + data class Status( val time: LocalDateTime, val uptime: String, val apiVersion: String, val softwareVersion: String, val requestCount: Int, + val mensaMenuRequests: Int, + val timetableRequests: ArrayList, val timetableListSize: Int, - val timetableListNames: String, val coursesLastUpdate: Date, val mensaLastUpdate: Date, val hsoResponseCode: Int,