/** * TheCitadelofRicks * * Copyright 2019 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * */ package org.mosad.thecitadelofricks import kotlinx.coroutines.* import org.mosad.thecitadelofricks.hsoparser.CourseListParser import org.mosad.thecitadelofricks.hsoparser.MensaParser import org.mosad.thecitadelofricks.hsoparser.TimetableParser import org.springframework.web.bind.annotation.RequestMapping import org.springframework.web.bind.annotation.RequestParam import org.springframework.web.bind.annotation.RestController import java.util.ArrayList @RestController class APIController { private val mensaLink = "https://www.swfr.de/de/essen-trinken/speiseplaene/mensa-offenburg/" private val mensaName = "Offenburg" private var coursesLinkList = ArrayList() private var coursesLastUpdate: Long = 0 private var timetableList = ArrayList() // this list contains all timetables private var mensaCurrentWeek = MensaWeek() private var mensaNextWeek = MensaWeek() private var mensaLastUpdate: Long = 0 init { initUpdates() } @RequestMapping("/courses") fun courses(): CoursesList { println("courses request at " + System.currentTimeMillis() / 1000 + "!") updateCoursesAsync() // check if we need to update and perform the update if so return CoursesList(CoursesMeta(coursesLinkList.size, coursesLastUpdate), coursesLinkList) } @RequestMapping("/mensamenu") fun mensamenu(): Mensa { println("mensamenu request at " + System.currentTimeMillis() / 1000 + "!") updateMensa() // check if we need to update and perform the update if so return Mensa(MensaMeta(mensaName, mensaLastUpdate), mensaCurrentWeek, mensaNextWeek) } @RequestMapping("/timetable") fun timetable(@RequestParam(value = "courseName", defaultValue = "AI4") courseName: String): TimetableCourse { println("timetable request at " + System.currentTimeMillis() / 1000 + "!") updateTimetableCourse(courseName) // check if we need to update and perform the update if so return timetableList.stream().filter { x -> x.meta.courseName == courseName }.findAny().orElse(null) } /** * checks if we need to update the courses list and if so does it async * during the update process the old data will be returned for a API request * update if the last update was 24 hours ago */ private fun updateCoursesAsync() = GlobalScope.launch { val currentTime = System.currentTimeMillis() / 1000 if ((currentTime - coursesLastUpdate) > 86400) { coursesLinkList = CourseListParser().getCourseLinks() coursesLastUpdate = currentTime println("updated courses successful at " + System.currentTimeMillis() / 1000) } else { println("courses are up to date!") } } /** * this function checks if we need to update the mensa menu list and if so does it * during the update process the old data will be returned for a API request * update if the last update was 6 hours ago */ private fun updateMensa() = GlobalScope.launch { val currentTime = System.currentTimeMillis() / 1000 if ((currentTime - coursesLastUpdate) > 21600) { mensaCurrentWeek = MensaParser().getMensaMenu(mensaLink) mensaNextWeek = MensaParser().getMensaMenu(MensaParser().getMenuLinkNextWeek(mensaLink)) mensaLastUpdate = currentTime println("updated mensamenu successful at " + System.currentTimeMillis() / 1000) } else { println("mensamenu is up to date!") } } /** * this function checks if we need to update the timetable for a given course and if so does it * during the update process the old data will be returned for a API request * update if the last update was 6 hours ago */ private fun updateTimetableCourse(courseName: String) = runBlocking { val currentTime = System.currentTimeMillis() / 1000 var currentWeek = TimetableWeek() var nextWeek = TimetableWeek() // check if the timetable already exists and is up to date val result = timetableList.stream().filter { x -> x.meta.courseName == courseName }.findAny().orElse(null) when { // there is no such course yet, create one result == null -> { val courseLink = coursesLinkList.stream().filter { x -> x.courseName == courseName }.findFirst().orElse(null).courseLink val timetableMeta = TimetableMeta(courseName, courseLink, currentTime) val jobCurrent = GlobalScope.async { currentWeek = TimetableParser().getTimeTable(courseLink) } val jobNext = GlobalScope.async { nextWeek = TimetableParser().getTimeTable(courseLink.replace("week=0","week=1")) } jobCurrent.await() jobNext.await() timetableList.add(TimetableCourse(timetableMeta, currentWeek, nextWeek)) } // update (currentTime - result.meta.time) > 21600 -> { val index = timetableList.indexOf(result) println("update $courseName wit index: $index") GlobalScope.async { val courseLink = coursesLinkList.stream().filter { x -> x.courseName == courseName }.findFirst().orElse(null).courseLink timetableList[index].currentWeek = TimetableParser().getTimeTable(courseLink) timetableList[index].nextWeek = TimetableParser().getTimeTable(courseLink.replace("week=0","week=1")) timetableList[index].meta.time = currentTime } } else -> println("timetable for $courseName is up to date") } } private fun initUpdates() = runBlocking { // get all courses on startup val jobCourseUpdate = GlobalScope.async{ coursesLinkList = CourseListParser().getCourseLinks() coursesLastUpdate = System.currentTimeMillis() / 1000 } // get the current and next weeks mensa menus val jobCurrentMensa = GlobalScope.async{ mensaCurrentWeek = MensaParser().getMensaMenu(mensaLink) } val jobNextMensa = GlobalScope.async{ mensaCurrentWeek = MensaParser().getMensaMenu(mensaLink) mensaLastUpdate = System.currentTimeMillis() / 1000 } jobCourseUpdate.await() jobCurrentMensa.await() jobNextMensa.await() } }