From db57059727592538f48f7029b8ba2a4b7c4157a5 Mon Sep 17 00:00:00 2001 From: Seil0 Date: Mon, 21 Oct 2019 18:46:21 +0200 Subject: [PATCH] version 1.1.6 * API version 1.1.4 * added /health, returns 200 (OK, for status checks) * moved status code to a separate class * added status.mosad.xyz reporting --- build.gradle | 2 +- .../mosad/thecitadelofricks/APIController.kt | 96 +++---------- .../controller/CacheController.kt | 3 +- .../controller/CachetAPIController.kt | 71 +++++++--- .../controller/StatusController.kt | 127 ++++++++++++++++++ 5 files changed, 205 insertions(+), 94 deletions(-) create mode 100644 src/main/kotlin/org/mosad/thecitadelofricks/controller/StatusController.kt diff --git a/build.gradle b/build.gradle index 5b1e63b..03447cb 100644 --- a/build.gradle +++ b/build.gradle @@ -48,4 +48,4 @@ compileTestKotlin { } group 'org.mosad' -version '1.1.5' +version '1.1.6' diff --git a/src/main/kotlin/org/mosad/thecitadelofricks/APIController.kt b/src/main/kotlin/org/mosad/thecitadelofricks/APIController.kt index 24afc5c..f4de91e 100644 --- a/src/main/kotlin/org/mosad/thecitadelofricks/APIController.kt +++ b/src/main/kotlin/org/mosad/thecitadelofricks/APIController.kt @@ -28,14 +28,15 @@ import org.mosad.thecitadelofricks.controller.CacheController.Companion.getLesso 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.mosad.thecitadelofricks.controller.StatusController.Companion.getStatus +import org.mosad.thecitadelofricks.controller.StatusController.Companion.updateMensaMenuRequests +import org.mosad.thecitadelofricks.controller.StatusController.Companion.updateTimetableRequests +import org.mosad.thecitadelofricks.controller.StatusController.Companion.updateTotalRequests import org.slf4j.Logger import org.slf4j.LoggerFactory import org.springframework.web.bind.annotation.RequestMapping import org.springframework.web.bind.annotation.RequestParam import org.springframework.web.bind.annotation.RestController -import java.net.HttpURLConnection -import java.net.URL import java.time.LocalDateTime import java.util.* import kotlin.collections.ArrayList @@ -45,13 +46,11 @@ class APIController { private val logger: Logger = LoggerFactory.getLogger(APIController::class.java) - private val apiVersion = "1.1.3" - private val softwareVersion = "1.1.5" - private val startTime = System.currentTimeMillis() / 1000 - - var totalRequests = 0 - private var mensaMenuRequests = 0 - private var timetableRequests = ArrayList() + companion object { + const val apiVersion = "1.1.4" + const val softwareVersion = "1.1.6" + val startTime = System.currentTimeMillis() / 1000 + } init { CacheController() // initialize the CacheController @@ -67,15 +66,15 @@ class APIController { @RequestMapping("/courseList") fun courseList(): CourseList { logger.info("courseList request at ${LocalDateTime.now()}!") - totalRequests++ + updateTotalRequests() return courseList } @RequestMapping("/mensamenu") fun mensamenu(): MensaMenu { logger.info("mensamenu request at ${LocalDateTime.now()}!") - mensaMenuRequests++ - totalRequests++ + updateTotalRequests() + updateMensaMenuRequests() return mensaMenu } @@ -85,8 +84,8 @@ class APIController { @RequestParam(value = "week", defaultValue = "0") week: Int ): TimetableCourseWeek { logger.info("timetable request at ${LocalDateTime.now()}!") + updateTotalRequests() updateTimetableRequests(courseName) - totalRequests++ return getTimetable(courseName, week) } @@ -96,7 +95,7 @@ class APIController { @RequestParam(value = "week", defaultValue = "0") week: Int ): HashSet { logger.info("lessonSubjectList request at ${LocalDateTime.now()}!") - totalRequests++ + updateTotalRequests() return getLessonSubjectList(courseName, week) } @@ -107,75 +106,20 @@ class APIController { @RequestParam(value = "week", defaultValue = "0") week: Int ): ArrayList { logger.info("lesson request at ${LocalDateTime.now()}!") - totalRequests++ + updateTotalRequests() return getLesson(courseName, lessonSubject, week) } @RequestMapping("/status") fun status(): Status { + logger.info("status request at ${LocalDateTime.now()}!") return getStatus() } - // non direct api functions - - /** - * if a timetable is requested update the request counter - */ - private fun updateTimetableRequests(courseName: String) { - when (timetableRequests.stream().filter { x -> x.courseName == courseName }.findAny().orElse(null)) { - null -> timetableRequests.add(TimetableCounter(courseName, 0)) - } - 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++ -// }, { -// -// }) - } - - 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 - - var hsoCode = 999 - var swfrCode = 999 - logger.info("status request at ${LocalDateTime.now()}!") - - try { - val hsoURL = URL("https://www.hs-offenburg.de/") - val swfrURL = URL("https://www.swfr.de/") - - var connection = hsoURL.openConnection() as HttpURLConnection - connection.requestMethod = "HEAD" - - connection.connectTimeout = 15000 - hsoCode = connection.responseCode - - connection = swfrURL.openConnection() as HttpURLConnection - connection.connectTimeout = 15000 - swfrCode = connection.responseCode - } catch (e: Exception) { - logger.error("Error while fetching url response codes!", e) - } - - return Status( - LocalDateTime.now(), - "$days days, $hours:$minutes", - apiVersion, - softwareVersion, - totalRequests, - mensaMenuRequests, - timetableRequests, - timetableList.size, - Date(courseList.meta.updateTime * 1000), - Date(mensaMenu.meta.updateTime * 1000), - hsoCode, - swfrCode - ) + @RequestMapping("/health") + fun health(): Int { + logger.info("health request at ${LocalDateTime.now()}!") + return 200 } } \ No newline at end of file diff --git a/src/main/kotlin/org/mosad/thecitadelofricks/controller/CacheController.kt b/src/main/kotlin/org/mosad/thecitadelofricks/controller/CacheController.kt index 9d6b65a..6ebfc86 100644 --- a/src/main/kotlin/org/mosad/thecitadelofricks/controller/CacheController.kt +++ b/src/main/kotlin/org/mosad/thecitadelofricks/controller/CacheController.kt @@ -48,7 +48,6 @@ class CacheController { init { initUpdates() scheduledUpdates() - //CachetAPIController.postTotalRequests(5) } // cache objects @@ -269,7 +268,7 @@ class CacheController { // post to status.mosad.xyz every hour Timer().scheduleAtFixedRate(initDelay1h, 3600000) { - // TODO + CachetAPIController.postTotalRequests() } } diff --git a/src/main/kotlin/org/mosad/thecitadelofricks/controller/CachetAPIController.kt b/src/main/kotlin/org/mosad/thecitadelofricks/controller/CachetAPIController.kt index 2161b18..888966f 100644 --- a/src/main/kotlin/org/mosad/thecitadelofricks/controller/CachetAPIController.kt +++ b/src/main/kotlin/org/mosad/thecitadelofricks/controller/CachetAPIController.kt @@ -1,34 +1,75 @@ +/** + * 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.controller +import org.mosad.thecitadelofricks.controller.StatusController.Companion.getTotalRequests import org.slf4j.Logger import org.slf4j.LoggerFactory +import java.io.BufferedReader +import java.io.IOException +import java.io.InputStreamReader 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) + private const val baseURL = "https://status.mosad.xyz" + private const val apiKey = "" //TODO - fun postTotalRequests(totalRequests: Int) { - logger.info("sending post request ...") + private var oldTotalRequests = 0 - val currentTime = System.currentTimeMillis() / 1000 - val data = mapOf(Pair("value", totalRequests.toString()), Pair("timestamp", currentTime.toString())) + fun postTotalRequests() { + try { + val url = URL("$baseURL/api/v1/metrics/1/points") + val jsonInputString = "{\"value\": ${getTotalRequests() -oldTotalRequests}, \"timestamp\": \"${(System.currentTimeMillis() / 1000)}\"}" + oldTotalRequests = getTotalRequests() - 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 con = url.openConnection() as HttpURLConnection + con.requestMethod = "POST" + con.setRequestProperty("Content-Type", "application/json; utf-8") + con.setRequestProperty("Accept", "application/json") + con.setRequestProperty("X-Cachet-Token", apiKey) + con.doOutput = true - val writer = OutputStreamWriter(connection.outputStream) - writer.write(data.toString()) - writer.flush() - writer.close() + val os = con.outputStream + val input = jsonInputString.toByteArray(charset("utf-8")) + os.write(input, 0, input.size) + + val br = BufferedReader(InputStreamReader(con.inputStream, "utf-8")) + val response = StringBuilder() + var responseLine: String? + + while (br.readLine().also { responseLine = it } != null) { + response.append(responseLine!!.trim { it <= ' ' }) + } + logger.info(response.toString()) + + } catch (e1: IOException) { + e1.printStackTrace() + } } } diff --git a/src/main/kotlin/org/mosad/thecitadelofricks/controller/StatusController.kt b/src/main/kotlin/org/mosad/thecitadelofricks/controller/StatusController.kt new file mode 100644 index 0000000..60dfb7a --- /dev/null +++ b/src/main/kotlin/org/mosad/thecitadelofricks/controller/StatusController.kt @@ -0,0 +1,127 @@ +/** + * 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.controller + +import org.mosad.thecitadelofricks.APIController.Companion.apiVersion +import org.mosad.thecitadelofricks.APIController.Companion.softwareVersion +import org.mosad.thecitadelofricks.APIController.Companion.startTime +import org.mosad.thecitadelofricks.Status +import org.mosad.thecitadelofricks.TimetableCounter +import org.slf4j.Logger +import org.slf4j.LoggerFactory +import java.net.HttpURLConnection +import java.net.URL +import java.time.LocalDateTime +import java.util.* +import kotlin.collections.ArrayList + +class StatusController { + + companion object { + private val logger: Logger = LoggerFactory.getLogger(StatusController::class.java) + + private var totalRequests = 0 + private var mensaMenuRequests = 0 + private var timetableRequests = ArrayList() + + fun updateTotalRequests() { + totalRequests++ + } + + fun updateMensaMenuRequests() { + mensaMenuRequests++ + } + + /** + * if a timetable is requested update the request counter + */ + fun updateTimetableRequests(courseName: String) { + when (timetableRequests.stream().filter { x -> x.courseName == courseName }.findAny().orElse(null)) { + null -> timetableRequests.add(TimetableCounter(courseName, 0)) + } + 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++ +// }, { +// +// }) + } + + fun getTotalRequests(): Int { + return totalRequests + } + + fun getMensaMenuRequests(): Int { + return mensaMenuRequests + } + + fun getTimetableRequests(): ArrayList { + return timetableRequests + } + + 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 + + var hsoCode = 999 + var swfrCode = 999 + + try { + val hsoURL = URL("https://www.hs-offenburg.de/") + val swfrURL = URL("https://www.swfr.de/") + + var connection = hsoURL.openConnection() as HttpURLConnection + connection.requestMethod = "HEAD" + + connection.connectTimeout = 15000 + hsoCode = connection.responseCode + + connection = swfrURL.openConnection() as HttpURLConnection + connection.connectTimeout = 15000 + swfrCode = connection.responseCode + } catch (e: Exception) { + logger.error("Error while fetching url response codes!", e) + } + + return Status( + LocalDateTime.now(), + "$days days, $hours:$minutes", + apiVersion, + softwareVersion, + getTotalRequests(), + getMensaMenuRequests(), + getTimetableRequests(), + CacheController.timetableList.size, + Date(CacheController.courseList.meta.updateTime * 1000), + Date(CacheController.mensaMenu.meta.updateTime * 1000), + hsoCode, + swfrCode + ) + } + + } +} \ No newline at end of file