You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

184 lines
7.1 KiB

/**
* 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()
}
fun getTimetable(courseName: String, week: Int): TimetableCourseWeek = runBlocking {
val currentTime = System.currentTimeMillis() / 1000
var timetable = TimetableWeek()
// check if the timetable already exists and is up to date
when (timetableList.stream().filter { x -> x.meta.courseName == courseName && x.meta.week == week }.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 timetableMeta = TimetableCourseMeta(currentTime, courseName, week, courseLink.replace("week=0","week=$week"))
val jobTimetable = GlobalScope.async {
timetable = TimetableParser().getTimeTable(timetableMeta.link)
}
jobTimetable.await()
timetableList.add(TimetableCourseWeek(timetableMeta, timetable))
logger.info("added new timetable for $courseName, week $week")
}
}
return@runBlocking timetableList.stream().filter { x -> x.meta.courseName == courseName && x.meta.week == week }.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 {
val result = CourseListParser().getCourseLinks(courseListURL)
if (result != null) {
courseList = CourseList(CourseMeta(System.currentTimeMillis() / 1000, result.size), result)
}
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 {
val result = CourseListParser().getCourseLinks(courseListURL)
if (result != null) {
courseList = CourseList(CourseMeta(System.currentTimeMillis() / 1000, result.size), result)
}
}
// 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()
}
}
}

Du besuchst diese Seite mit einem veralteten IPv4-Internetzugang. Möglicherweise treten in Zukunft Probleme mit der Erreichbarkeit und Performance auf. Bitte frage deinen Internetanbieter oder Netzwerkadministrator nach IPv6-Unterstützung.
You are visiting this site with an outdated IPv4 internet access. You may experience problems with accessibility and performance in the future. Please ask your ISP or network administrator for IPv6 support.
Weitere Infos | More Information
Klicke zum schließen | Click to close