reworked the CacheController Class
	
		
			
	
		
	
	
		
	
		
			All checks were successful
		
		
	
	
		
			
				
	
				continuous-integration/drone/push Build is passing
				
			
		
		
	
	
				
					
				
			
		
			All checks were successful
		
		
	
	continuous-integration/drone/push Build is passing
				
			This commit is contained in:
		| @ -22,9 +22,13 @@ | ||||
|  | ||||
| package org.mosad.thecitadelofricks | ||||
|  | ||||
| import org.mosad.thecitadelofricks.CacheController.Companion.courseList | ||||
| import org.mosad.thecitadelofricks.CacheController.Companion.mensaMenu | ||||
| import org.mosad.thecitadelofricks.CacheController.Companion.timetableList | ||||
| import org.mosad.thecitadelofricks.controller.CacheController | ||||
| import org.mosad.thecitadelofricks.controller.CacheController.Companion.courseList | ||||
| import org.mosad.thecitadelofricks.controller.CacheController.Companion.getLesson | ||||
| import org.mosad.thecitadelofricks.controller.CacheController.Companion.getLessonSubjectList | ||||
| import org.mosad.thecitadelofricks.controller.CacheController.Companion.getTimetable | ||||
| import org.mosad.thecitadelofricks.controller.CacheController.Companion.mensaMenu | ||||
| import org.mosad.thecitadelofricks.controller.CacheController.Companion.timetableList | ||||
| import org.slf4j.Logger | ||||
| import org.slf4j.LoggerFactory | ||||
| import org.springframework.web.bind.annotation.RequestMapping | ||||
| @ -35,22 +39,25 @@ import java.net.URL | ||||
| import java.time.LocalDateTime | ||||
| import java.util.* | ||||
| import kotlin.collections.ArrayList | ||||
| import kotlin.collections.HashSet | ||||
|  | ||||
| @RestController | ||||
| class APIController { | ||||
|  | ||||
|     private val logger: Logger = LoggerFactory.getLogger(APIController::class.java) | ||||
|     private val cache = CacheController() | ||||
|  | ||||
|     private val apiVersion = "1.1.3" | ||||
|     private val softwareVersion = "1.1.5" | ||||
|     private val startTime = System.currentTimeMillis() / 1000 | ||||
|  | ||||
|     private var totalRequests = 0 | ||||
|     var totalRequests = 0 | ||||
|     private var mensaMenuRequests = 0 | ||||
|     private var timetableRequests = ArrayList<TimetableCounter>() | ||||
|  | ||||
|     init { | ||||
|         CacheController() // initialize the CacheController | ||||
|     } | ||||
|  | ||||
|     // TODO remove this with API version 1.2.0 | ||||
|     @Deprecated("courses is replaced by courseList", replaceWith = ReplaceWith("courseList()")) | ||||
|     @RequestMapping("/courses") | ||||
|     fun courses(): CourseList { | ||||
| @ -80,7 +87,7 @@ class APIController { | ||||
|         logger.info("timetable request at ${LocalDateTime.now()}!") | ||||
|         updateTimetableRequests(courseName) | ||||
|         totalRequests++ | ||||
|         return cache.getTimetable(courseName, week) | ||||
|         return getTimetable(courseName, week) | ||||
|     } | ||||
|  | ||||
|     @RequestMapping("/lessonSubjectList") | ||||
| @ -111,49 +118,6 @@ class APIController { | ||||
|  | ||||
|     // non direct api functions | ||||
|  | ||||
|     /** | ||||
|      * 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<String> { | ||||
|         val lessonSubjectList = ArrayList<String>() | ||||
|  | ||||
|         // get every lesson subject for the given week | ||||
|         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) } | ||||
|         } | ||||
|  | ||||
|         return HashSet(lessonSubjectList) | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 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<Lesson> { | ||||
|         val lessonList = ArrayList<Lesson>() | ||||
|  | ||||
|         // get all lessons from the weeks timetable | ||||
|         val flatMap = cache.getTimetable(courseName, weekIndex).timetable.days.flatMap { it.timeslots.asIterable() } | ||||
|         flatMap.forEach { | ||||
|             it.forEach { lesson -> | ||||
|                 if(lesson.lessonSubject.contains(lessonSubject)) { | ||||
|                     lessonList.add(lesson) | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             //it.stream().filter { x -> x.lessonSubject.contains(lessonSubject) }.findAny().ifPresent { x -> println("${x.lessonSubject}, ${x.lessonTeacher}") } | ||||
|         } | ||||
|  | ||||
|         return lessonList | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * if a timetable is requested update the request counter | ||||
|      */ | ||||
| @ -163,6 +127,7 @@ class APIController { | ||||
|         } | ||||
|         timetableRequests.stream().filter { x ->x.courseName == courseName }.findFirst().ifPresent { x -> x.requests++ } | ||||
|  | ||||
|         // TODO Java 11 | ||||
| //        timetableRequests.stream().filter { it.courseName == courseName }.findFirst().ifPresentOrElse({ | ||||
| //            it.requests++ | ||||
| //        }, { | ||||
|  | ||||
| @ -1,190 +0,0 @@ | ||||
| /** | ||||
|  * TheCitadelofRicks | ||||
|  * | ||||
|  * Copyright 2019  <seil0@mosad.xyz> | ||||
|  * | ||||
|  * 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.GlobalScope | ||||
| import kotlinx.coroutines.async | ||||
| import kotlinx.coroutines.launch | ||||
| import kotlinx.coroutines.runBlocking | ||||
| import org.mosad.thecitadelofricks.hsoparser.CourseListParser | ||||
| import org.mosad.thecitadelofricks.hsoparser.MensaParser | ||||
| import org.mosad.thecitadelofricks.hsoparser.TimetableParser | ||||
| import org.slf4j.Logger | ||||
| import org.slf4j.LoggerFactory | ||||
| import java.util.* | ||||
| import kotlin.collections.ArrayList | ||||
| import kotlin.concurrent.scheduleAtFixedRate | ||||
|  | ||||
| class CacheController { | ||||
|  | ||||
|     private val logger: Logger = LoggerFactory.getLogger(CacheController::class.java) | ||||
|  | ||||
|     // hso parser links (hardcoded) | ||||
|     private val courseListURL = "https://www.hs-offenburg.de/studium/vorlesungsplaene/" | ||||
|     private val mensaMenuURL = "https://www.swfr.de/de/essen-trinken/speiseplaene/mensa-offenburg/" | ||||
|     private val mensaName = "Offenburg" | ||||
|  | ||||
|     // cache objects | ||||
|     companion object{ | ||||
|  | ||||
|         lateinit var courseList: CourseList | ||||
|         lateinit var mensaMenu: MensaMenu | ||||
|  | ||||
|         var timetableList = ArrayList<TimetableCourseWeek>() // this list contains all timetables | ||||
|     } | ||||
|  | ||||
|     init { | ||||
|         initUpdates() | ||||
|         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 | ||||
|         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 -> { | ||||
|                 val courseLink = courseList.courses.stream().filter { x -> x.courseName == courseName }.findFirst().orElse(null).courseLink | ||||
|                 val timetableLink = courseLink.replace("week=0","week=$weekIndex") | ||||
|  | ||||
|                 val jobTimetable = GlobalScope.async { | ||||
|                     timetable = TimetableParser().getTimeTable(timetableLink) | ||||
|                     weekNumberYear = TimetableParser().getWeekNumberYear(timetableLink) | ||||
|                 } | ||||
|  | ||||
|                 jobTimetable.await() | ||||
|  | ||||
|                 timetableList.add(TimetableCourseWeek(TimetableCourseMeta(currentTime, courseName, weekIndex, weekNumberYear, timetableLink), timetable)) | ||||
|                 logger.info("added new timetable for $courseName, week $weekIndex") | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         return@runBlocking timetableList.stream().filter { x -> x.meta.courseName == courseName && x.meta.weekIndex == weekIndex }.findAny().orElse(null) | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * this function updates the courseList | ||||
|      * during the update process the old data will be returned for a API request | ||||
|      */ | ||||
|     private fun asyncUpdateCourseList() = GlobalScope.launch { | ||||
|         CourseListParser().getCourseLinks(courseListURL)?.let { | ||||
|             courseList = CourseList(CourseMeta(System.currentTimeMillis() / 1000, it.size), it) | ||||
|         } | ||||
|  | ||||
|         logger.info("updated courses successful at ${Date(courseList.meta.updateTime * 1000)}") | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * this function updates the mensa menu list | ||||
|      * during the update process the old data will be returned for a API request | ||||
|      */ | ||||
|     private fun asyncUpdateMensa() = GlobalScope.launch { | ||||
|         val mensaCurrentWeek = MensaParser().getMensaMenu(mensaMenuURL) | ||||
|         val mensaNextWeek = MensaParser().getMensaMenu(MensaParser().getMenuLinkNextWeek(mensaMenuURL)) | ||||
|  | ||||
|         // only update if we get valid data | ||||
|         if (mensaCurrentWeek != null && mensaNextWeek != null) { | ||||
|             mensaMenu = MensaMenu(MensaMeta(System.currentTimeMillis() / 1000, mensaName), mensaCurrentWeek, mensaNextWeek) | ||||
|         } | ||||
|  | ||||
|         logger.info("updated mensamenu successful at ${Date(mensaMenu.meta.updateTime * 1000)}") | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * this function updates all existing timetables | ||||
|      * during the update process the old data will be returned for a API request | ||||
|      */ | ||||
|     private fun asyncUpdateTimetables() = GlobalScope.launch { | ||||
|         timetableList.forEach { timetableCourse -> | ||||
|             val updateURL = timetableCourse.meta.link | ||||
|             timetableCourse.timetable = TimetableParser().getTimeTable(updateURL) | ||||
|             timetableCourse.meta.updateTime = System.currentTimeMillis() / 1000 | ||||
|         } | ||||
|         logger.info("updated ${timetableList.size} timetables successful!") | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * before the APIController is up, get the data fist | ||||
|      * runBlocking: otherwise the api would return no data to requests for a few seconds after startup | ||||
|      */ | ||||
|     private fun initUpdates() = runBlocking { | ||||
|         // get all courses on startup | ||||
|         val jobCourseUpdate = GlobalScope.async { | ||||
|             CourseListParser().getCourseLinks(courseListURL)?.let { | ||||
|                 courseList = CourseList(CourseMeta(System.currentTimeMillis() / 1000, it.size), it) | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         // get the current and next weeks mensa menus | ||||
|         val jobMensa = GlobalScope.async{ | ||||
|             val mensaCurrentWeek = MensaParser().getMensaMenu(mensaMenuURL) | ||||
|             val mensaNextWeek = MensaParser().getMensaMenu(MensaParser().getMenuLinkNextWeek(mensaMenuURL)) | ||||
|  | ||||
|             // only update if we get valid data | ||||
|             if (mensaCurrentWeek != null && mensaNextWeek != null) { | ||||
|                 mensaMenu = MensaMenu(MensaMeta(System.currentTimeMillis() / 1000, mensaName), mensaCurrentWeek, mensaNextWeek) | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         jobCourseUpdate.await() | ||||
|         jobMensa.await() | ||||
|  | ||||
|         logger.info("init updates successful") | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * doesn't account the change between winter and summer time! | ||||
|      * | ||||
|      */ | ||||
|     private fun scheduledUpdates() { | ||||
|         val currentTime = System.currentTimeMillis() | ||||
|         val initDelay24h = (86400000 - ((currentTime + 3600000) % 86400000)) + 60000 | ||||
|         val initDelay3h = (10800000 - ((currentTime + 3600000) % 10800000)) + 60000 | ||||
|         val initDelay1h = (3600000 - ((currentTime + 3600000) % 3600000)) + 60000 | ||||
|  | ||||
|         // update courseList every 24 hours (time in ms) | ||||
|         Timer().scheduleAtFixedRate(initDelay24h, 86400000) { | ||||
|             asyncUpdateCourseList() | ||||
|         } | ||||
|  | ||||
|         // update all already existing timetables every 3 hours (time in ms) | ||||
|         Timer().scheduleAtFixedRate(initDelay3h, 10800000) { | ||||
|             asyncUpdateTimetables() | ||||
|         } | ||||
|  | ||||
|         // update courses every hour (time in ms) | ||||
|         Timer().scheduleAtFixedRate(initDelay1h, 3600000) { | ||||
|             asyncUpdateMensa() | ||||
|         } | ||||
|     } | ||||
|  | ||||
| } | ||||
| @ -0,0 +1,276 @@ | ||||
| /** | ||||
|  * TheCitadelofRicks | ||||
|  * | ||||
|  * Copyright 2019  <seil0@mosad.xyz> | ||||
|  * | ||||
|  * 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.controller | ||||
|  | ||||
| import kotlinx.coroutines.GlobalScope | ||||
| import kotlinx.coroutines.async | ||||
| import kotlinx.coroutines.launch | ||||
| import kotlinx.coroutines.runBlocking | ||||
| import org.mosad.thecitadelofricks.* | ||||
| import org.mosad.thecitadelofricks.hsoparser.CourseListParser | ||||
| import org.mosad.thecitadelofricks.hsoparser.MensaParser | ||||
| import org.mosad.thecitadelofricks.hsoparser.TimetableParser | ||||
| import org.slf4j.Logger | ||||
| import org.slf4j.LoggerFactory | ||||
| import java.util.* | ||||
| import kotlin.collections.ArrayList | ||||
| import kotlin.concurrent.scheduleAtFixedRate | ||||
|  | ||||
| class CacheController { | ||||
|  | ||||
|     private val logger: Logger = LoggerFactory.getLogger(CacheController::class.java) | ||||
|  | ||||
|     // hso parser links (hardcoded) | ||||
|     private val courseListURL = "https://www.hs-offenburg.de/studium/vorlesungsplaene/" | ||||
|     private val mensaMenuURL = "https://www.swfr.de/de/essen-trinken/speiseplaene/mensa-offenburg/" | ||||
|     private val mensaName = "Offenburg" | ||||
|  | ||||
|     init { | ||||
|         initUpdates() | ||||
|         scheduledUpdates() | ||||
|         //CachetAPIController.postTotalRequests(5) | ||||
|     } | ||||
|  | ||||
|     // cache objects | ||||
|     companion object{ | ||||
|         private val logger: Logger = LoggerFactory.getLogger(CacheController::class.java) | ||||
|  | ||||
|         lateinit var courseList: CourseList | ||||
|         lateinit var mensaMenu: MensaMenu | ||||
|         var timetableList = ArrayList<TimetableCourseWeek>() // this list contains all timetables | ||||
|  | ||||
|         /** | ||||
|          * 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 | ||||
|             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 -> { | ||||
|                     val courseLink = courseList.courses.stream().filter { x -> x.courseName == courseName }.findFirst().orElse(null).courseLink | ||||
|                     val timetableLink = courseLink.replace("week=0","week=$weekIndex") | ||||
|  | ||||
|                     val jobTimetable = GlobalScope.async { | ||||
|                         timetable = TimetableParser().getTimeTable(timetableLink) | ||||
|                         weekNumberYear = TimetableParser().getWeekNumberYear(timetableLink) | ||||
|                     } | ||||
|  | ||||
|                     jobTimetable.await() | ||||
|  | ||||
|                     timetableList.add( | ||||
|                         TimetableCourseWeek( | ||||
|                             TimetableCourseMeta( | ||||
|                                 currentTime, | ||||
|                                 courseName, | ||||
|                                 weekIndex, | ||||
|                                 weekNumberYear, | ||||
|                                 timetableLink | ||||
|                             ), | ||||
|                             timetable | ||||
|                         ) | ||||
|                     ) | ||||
|                     logger.info("added new timetable for $courseName, week $weekIndex") | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             return@runBlocking timetableList.stream().filter { x -> x.meta.courseName == courseName && x.meta.weekIndex == weekIndex }.findAny().orElse(null) | ||||
|         } | ||||
|  | ||||
|         /** | ||||
|          * 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 | ||||
|          */ | ||||
|         fun getLessonSubjectList(courseName: String, weekIndex: Int): HashSet<String> = runBlocking { | ||||
|             val lessonSubjectList = ArrayList<String>() | ||||
|  | ||||
|             // get every lesson subject for the given week | ||||
|             val flatMap = 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) } | ||||
|             } | ||||
|  | ||||
|             return@runBlocking HashSet(lessonSubjectList) | ||||
|         } | ||||
|  | ||||
|         /** | ||||
|          * 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 | ||||
|          */ | ||||
|         fun getLesson(courseName: String, lessonSubject: String, weekIndex: Int): ArrayList<Lesson> { | ||||
|             val lessonList = ArrayList<Lesson>() | ||||
|  | ||||
|             // get all lessons from the weeks timetable | ||||
|             val flatMap = getTimetable(courseName, weekIndex).timetable.days.flatMap { it.timeslots.asIterable() } | ||||
|             flatMap.forEach { | ||||
|                 it.forEach { lesson -> | ||||
|                     if(lesson.lessonSubject.contains(lessonSubject)) { | ||||
|                         lessonList.add(lesson) | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|                 // TODO Java 11 | ||||
|                 //it.stream().filter { x -> x.lessonSubject.contains(lessonSubject) }.findAny().ifPresent { x -> println("${x.lessonSubject}, ${x.lessonTeacher}") } | ||||
|             } | ||||
|  | ||||
|             return lessonList | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * this function updates the courseList | ||||
|      * during the update process the old data will be returned for a API request | ||||
|      */ | ||||
|     private fun asyncUpdateCourseList() = GlobalScope.launch { | ||||
|         CourseListParser().getCourseLinks(courseListURL)?.let { | ||||
|             courseList = | ||||
|                 CourseList( | ||||
|                     CourseMeta( | ||||
|                         System.currentTimeMillis() / 1000, | ||||
|                         it.size | ||||
|                     ), it | ||||
|                 ) | ||||
|         } | ||||
|  | ||||
|         logger.info("updated courses successful at ${Date(courseList.meta.updateTime * 1000)}") | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * this function updates the mensa menu list | ||||
|      * during the update process the old data will be returned for a API request | ||||
|      */ | ||||
|     private fun asyncUpdateMensa() = GlobalScope.launch { | ||||
|         val mensaCurrentWeek = MensaParser().getMensaMenu(mensaMenuURL) | ||||
|         val mensaNextWeek = MensaParser().getMensaMenu(MensaParser().getMenuLinkNextWeek(mensaMenuURL)) | ||||
|  | ||||
|         // only update if we get valid data | ||||
|         if (mensaCurrentWeek != null && mensaNextWeek != null) { | ||||
|             mensaMenu = | ||||
|                 MensaMenu( | ||||
|                     MensaMeta( | ||||
|                         System.currentTimeMillis() / 1000, | ||||
|                         mensaName | ||||
|                     ), mensaCurrentWeek, mensaNextWeek | ||||
|                 ) | ||||
|         } | ||||
|  | ||||
|         logger.info("updated mensamenu successful at ${Date(mensaMenu.meta.updateTime * 1000)}") | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * this function updates all existing timetables | ||||
|      * during the update process the old data will be returned for a API request | ||||
|      */ | ||||
|     private fun asyncUpdateTimetables() = GlobalScope.launch { | ||||
|         timetableList.forEach { timetableCourse -> | ||||
|             val updateURL = timetableCourse.meta.link | ||||
|             timetableCourse.timetable = TimetableParser().getTimeTable(updateURL) | ||||
|             timetableCourse.meta.updateTime = System.currentTimeMillis() / 1000 | ||||
|         } | ||||
|         logger.info("updated ${timetableList.size} timetables successful!") | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * before the APIController is up, get the data fist | ||||
|      * runBlocking: otherwise the api would return no data to requests for a few seconds after startup | ||||
|      */ | ||||
|     private fun initUpdates() = runBlocking { | ||||
|         // get all courses on startup | ||||
|         val jobCourseUpdate = GlobalScope.async { | ||||
|             CourseListParser().getCourseLinks(courseListURL)?.let { | ||||
|                 courseList = | ||||
|                     CourseList( | ||||
|                         CourseMeta( | ||||
|                             System.currentTimeMillis() / 1000, | ||||
|                             it.size | ||||
|                         ), it | ||||
|                     ) | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         // get the current and next weeks mensa menus | ||||
|         val jobMensa = GlobalScope.async{ | ||||
|             val mensaCurrentWeek = MensaParser().getMensaMenu(mensaMenuURL) | ||||
|             val mensaNextWeek = MensaParser().getMensaMenu(MensaParser().getMenuLinkNextWeek(mensaMenuURL)) | ||||
|  | ||||
|             // only update if we get valid data | ||||
|             if (mensaCurrentWeek != null && mensaNextWeek != null) { | ||||
|                 mensaMenu = | ||||
|                     MensaMenu( | ||||
|                         MensaMeta( | ||||
|                             System.currentTimeMillis() / 1000, | ||||
|                             mensaName | ||||
|                         ), mensaCurrentWeek, mensaNextWeek | ||||
|                     ) | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         jobCourseUpdate.await() | ||||
|         jobMensa.await() | ||||
|  | ||||
|         logger.info("init updates successful") | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * doesn't account the change between winter and summer time! | ||||
|      * | ||||
|      */ | ||||
|     private fun scheduledUpdates() { | ||||
|         val currentTime = System.currentTimeMillis() | ||||
|         val initDelay24h = (86400000 - ((currentTime + 3600000) % 86400000)) + 60000 | ||||
|         val initDelay3h = (10800000 - ((currentTime + 3600000) % 10800000)) + 60000 | ||||
|         val initDelay1h = (3600000 - ((currentTime + 3600000) % 3600000)) + 60000 | ||||
|  | ||||
|         // update courseList every 24 hours (time in ms) | ||||
|         Timer().scheduleAtFixedRate(initDelay24h, 86400000) { | ||||
|             asyncUpdateCourseList() | ||||
|         } | ||||
|  | ||||
|         // update all already existing timetables every 3 hours (time in ms) | ||||
|         Timer().scheduleAtFixedRate(initDelay3h, 10800000) { | ||||
|             asyncUpdateTimetables() | ||||
|         } | ||||
|  | ||||
|         // update courses every hour (time in ms) | ||||
|         Timer().scheduleAtFixedRate(initDelay1h, 3600000) { | ||||
|             asyncUpdateMensa() | ||||
|         } | ||||
|  | ||||
|         // post to status.mosad.xyz every hour | ||||
|         Timer().scheduleAtFixedRate(initDelay1h, 3600000) { | ||||
|             // TODO | ||||
|         } | ||||
|     } | ||||
|  | ||||
| } | ||||
| @ -0,0 +1,36 @@ | ||||
| package org.mosad.thecitadelofricks.controller | ||||
|  | ||||
| import org.slf4j.Logger | ||||
| import org.slf4j.LoggerFactory | ||||
| import java.net.HttpURLConnection | ||||
| import java.net.URL | ||||
| import java.io.OutputStreamWriter | ||||
|  | ||||
|  | ||||
| class CachetAPIController { | ||||
|  | ||||
|      companion object { | ||||
|  | ||||
|          private val logger: Logger = LoggerFactory.getLogger(CachetAPIController::class.java) | ||||
|  | ||||
|          fun postTotalRequests(totalRequests: Int) { | ||||
|              logger.info("sending post request ...") | ||||
|  | ||||
|              val currentTime = System.currentTimeMillis() / 1000 | ||||
|              val data = mapOf(Pair("value", totalRequests.toString()), Pair("timestamp", currentTime.toString())) | ||||
|  | ||||
|              val url = URL("https://status.mosad.xyz/api/v1/metrics/1/points") | ||||
|              val connection = url.openConnection() as HttpURLConnection | ||||
|              connection.setRequestProperty("X-Cachet-Token", "h0103Wix5xhhNH5tk5KU") | ||||
|              connection.requestMethod = "POST" | ||||
|              connection.doOutput = true | ||||
|  | ||||
|              val writer = OutputStreamWriter(connection.outputStream) | ||||
|              writer.write(data.toString()) | ||||
|              writer.flush() | ||||
|              writer.close() | ||||
|          } | ||||
|  | ||||
|      } | ||||
|  | ||||
| } | ||||
		Reference in New Issue
	
	Block a user