From c76fe52ead667118e5eb99aadc6fb4d0a6bf5197 Mon Sep 17 00:00:00 2001 From: Jon Terje Tvergrov Kalvatn Date: Wed, 31 Oct 2018 14:30:29 +0100 Subject: [PATCH] livescore history recover kotlin conversion --- pom.xml | 9 +- .../history/recover/HistoryRecoveryTool.kt | 106 +++++ .../sportradar/history/recover/Loader.kt | 363 ++++++++++++++ .../history/recover/RecoveryTask.kt | 21 + .../sportradar/history/recover/Saver.kt | 447 ++++++++++++++++++ .../sportradar/history/recover/model/Event.kt | 24 + .../sportradar/history/recover/model/Flag.kt | 7 + .../history/recover/model/LSFSRequest.kt | 16 + .../sportradar/history/recover/model/Match.kt | 61 +++ .../history/recover/model/MatchExtra.kt | 35 ++ .../history/recover/model/Player.kt | 7 + .../history/recover/model/Position.kt | 7 + .../history/recover/model/ScoutEvent.kt | 17 + .../history/recover/util/QueryUtil.kt | 29 ++ .../history/recover/util/RequestUtil.kt | 29 ++ src/main/resources/conf/general.properties | 2 + .../resources/conf/general.properties.@env@ | 9 + src/main/resources/log4j.xml | 34 ++ 18 files changed, 1221 insertions(+), 2 deletions(-) create mode 100644 src/main/kotlin/sportradar/history/recover/HistoryRecoveryTool.kt create mode 100644 src/main/kotlin/sportradar/history/recover/Loader.kt create mode 100644 src/main/kotlin/sportradar/history/recover/RecoveryTask.kt create mode 100644 src/main/kotlin/sportradar/history/recover/Saver.kt create mode 100644 src/main/kotlin/sportradar/history/recover/model/Event.kt create mode 100644 src/main/kotlin/sportradar/history/recover/model/Flag.kt create mode 100644 src/main/kotlin/sportradar/history/recover/model/LSFSRequest.kt create mode 100644 src/main/kotlin/sportradar/history/recover/model/Match.kt create mode 100644 src/main/kotlin/sportradar/history/recover/model/MatchExtra.kt create mode 100644 src/main/kotlin/sportradar/history/recover/model/Player.kt create mode 100644 src/main/kotlin/sportradar/history/recover/model/Position.kt create mode 100644 src/main/kotlin/sportradar/history/recover/model/ScoutEvent.kt create mode 100644 src/main/kotlin/sportradar/history/recover/util/QueryUtil.kt create mode 100644 src/main/kotlin/sportradar/history/recover/util/RequestUtil.kt create mode 100644 src/main/resources/conf/general.properties create mode 100644 src/main/resources/conf/general.properties.@env@ create mode 100644 src/main/resources/log4j.xml diff --git a/pom.xml b/pom.xml index 39b28cd..6d3fb39 100644 --- a/pom.xml +++ b/pom.xml @@ -16,8 +16,8 @@ official 1.0.0 4.12 - 10 - ${java.version} + 1.8 + ${java.version} ${java.version} @@ -44,6 +44,11 @@ 0.11.2 + + com.sportradar + sportradar-common + 2.0.1 + org.jetbrains.kotlin kotlin-test-junit diff --git a/src/main/kotlin/sportradar/history/recover/HistoryRecoveryTool.kt b/src/main/kotlin/sportradar/history/recover/HistoryRecoveryTool.kt new file mode 100644 index 0000000..aa29326 --- /dev/null +++ b/src/main/kotlin/sportradar/history/recover/HistoryRecoveryTool.kt @@ -0,0 +1,106 @@ +package sportradar.history.recover + +import com.betradar.database.HistoryDB +import com.betradar.database.SystemDB +import com.betradar.util.LogUtil +import org.apache.log4j.Logger +import sportradar.history.recover.util.RequestUtil +import sportradar.kotlin.workshop.examples._14LambdaWithReceiver.use +import java.sql.SQLException +import java.time.Instant +import java.time.LocalDateTime +import java.time.ZoneId + + +/** + * converted from https://gitlab.sportradar.ag/livescore/common/tree/master/src/main/java/com/oddsarbitrage/livescore/history/recover + * using mostly intellij's convert java file to kotlin ctrl + alt + shift + k + * @author j.kalvatn + */ +class HistoryRecoveryTool { + private val loader: Loader = Loader() + private val saver: Saver = Saver() + private val log = Logger.getLogger(HistoryRecoveryTool::class.java) + + + fun runHBLRecovery() { + // 3299, 212, 3468, 3469, 688, 95, 4473,16956 + val allStarGame = RecoveryTask( + tournamentId = 3299, + fromDate = LocalDateTime.of(2017, 2, 3, 0, 0).atZone(ZoneId.systemDefault()).toInstant(), + toDate = Instant.now() + ) +// val dhbPokal = RecoveryTask( +// tournamentId = 212, +// fromDate = LocalDateTime.of(2017, 8, 18, 0, 0).atZone(ZoneId.systemDefault()).toInstant(), +// toDate = Instant.now() +// ) + + + runRecoveryTasks(listOf(allStarGame)) + } + + private fun runRecoveryTasks(tasks: List) { + try { + HistoryDB.instance().borrowConnection().use { historyConn -> + SystemDB.instance().borrowConnection().use { writeConn -> + for (task in tasks) { + log.info(task) + val tournamentId = task.tournamentId + val fromDate = task.fromDate + val toDate = task.toDate + + val matches = loader.loadMatches(historyConn, fromDate, toDate, tournamentId) + val matchIds = matches.keys + + val matchExtras = loader.loadMatchExtra(historyConn, matchIds) + val scoutEvents = loader.loadScoutEvents(historyConn, matchIds) + val events = loader.loadEvents(historyConn, matchIds) + + val eventIds = events.keys + val flags = loader.loadEventFlags(historyConn, eventIds) + val players = loader.loadEventPlayers(historyConn, eventIds) + val positions = loader.loadEventPositions(historyConn, eventIds) + + with(log) { + info(String.format("livescore_match : %d", matches.size)) + info(String.format("livescore_match_extra : %d", matchExtras.size)) + info(String.format("livescore_scoutevent : %d", scoutEvents.size)) + info(String.format("livescore_event_top_backup : %d", events.size)) + info(String.format("livescore_event_top_flag : %d", flags.size)) + info(String.format("livescore_event_top_player : %d", players.size)) + info(String.format("livescore_event_top_position : %d", positions.size)) + } + + with(saver) { + saveMatches(writeConn, matches) + saveMatchExtras(writeConn, matchExtras) + saveScoutEvents(writeConn, scoutEvents) + saveEvents(writeConn, events) + saveFlags(writeConn, flags) + savePlayers(writeConn, players) + savePositions(writeConn, positions) + + } + + log.info(String.format("generating requests for %d matches", matchIds.size)) + val requests = matchIds + .map { matchId -> RequestUtil.createMatchRequest(5704, matchId) } + saver.saveRequests(writeConn, requests) + } + } + } + } catch (e: SQLException) { + log.error(e, e) + } + + } + +} + +fun main(args: Array) { + LogUtil.setRootAppender(); + val historyRecoveryTool = HistoryRecoveryTool() + historyRecoveryTool.runHBLRecovery() +} + diff --git a/src/main/kotlin/sportradar/history/recover/Loader.kt b/src/main/kotlin/sportradar/history/recover/Loader.kt new file mode 100644 index 0000000..a38240c --- /dev/null +++ b/src/main/kotlin/sportradar/history/recover/Loader.kt @@ -0,0 +1,363 @@ +package sportradar.history.recover + +import org.apache.log4j.Logger +import sportradar.history.recover.model.* +import sportradar.history.recover.util.QueryUtil +import sportradar.kotlin.workshop.examples._14LambdaWithReceiver.use +import java.sql.Connection +import java.sql.SQLException +import java.sql.Timestamp +import java.time.Instant +import java.util.* + +internal class Loader { + + fun loadMatches( + conn: Connection, fromDate: Instant, toDate: Instant, tournamentId: Int? + ): Map { + log.info( + String.format( + "loading livescore_match for tournament %d between %s -> %s", + tournamentId, fromDate, toDate + ) + ) + + val matches = HashMap() + + try { + conn.prepareStatement(QUERY_MATCHES).use { ps -> + ps.setTimestamp(1, Timestamp.from(fromDate)) + ps.setTimestamp(2, Timestamp.from(toDate)) + ps.setInt(3, tournamentId!!) + ps.executeQuery().use { rs -> + while (rs.next()) { + val matchId = rs.getLong("matchid") + + val match = Match( + matchid = matchId, + betradarmatchid = rs.getLong("betradarmatchid"), + sportid = rs.getInt("sportid"), + realcategoryid = rs.getInt("realcategoryid"), + tournamentid = rs.getInt("tournamentid"), + teamidhome = rs.getInt("teamidhome"), + teamidaway = rs.getInt("teamidaway"), + dateofmatch = rs.getTimestamp("dateofmatch"), + isStarted = rs.getBoolean("started"), + currentperiod = rs.getInt("currentperiod"), + currentperiod_time = rs.getTimestamp("currentperiod_time"), + isEnded = rs.getBoolean("ended"), + winner = rs.getInt("winner"), + score = rs.getString("score"), + period1 = rs.getString("period1"), + period2 = rs.getString("period2"), + period3 = rs.getString("period3"), + period4 = rs.getString("period4"), + period5 = rs.getString("period5"), + period6 = rs.getString("period6"), + period7 = rs.getString("period7"), + period8 = rs.getString("period8"), + period9 = rs.getString("period9"), + period10 = rs.getString("period10"), + period11 = rs.getString("period11"), + period12 = rs.getString("period12"), + period13 = rs.getString("period13"), + normaltime = rs.getString("normaltime"), + extra1 = rs.getString("extra1"), + extra2 = rs.getString("extra2"), + overtime = rs.getString("overtime"), + penalties = rs.getString("penalties"), + isCancelled = rs.getBoolean("cancelled"), + isPostponed = rs.getBoolean("postponed"), + isAbandoned = rs.getBoolean("abandoned"), + status = rs.getInt("status"), + isHas_injuries = rs.getBoolean("has_injuries"), + comment = rs.getString("comment"), + lastgoal_time = rs.getTimestamp("lastgoal_time"), + lastgoal_team = rs.getInt("lastgoal_team"), + manualdate = rs.getInt("manualdate"), + isHidden = rs.getBoolean("hidden"), + lastupdate = rs.getTimestamp("lastupdate"), + isPublish = rs.getBoolean("publish"), + lineups_status = rs.getInt("lineups_status"), + isFormations_status = rs.getBoolean("formations_status"), + isIsontv = rs.getBoolean("isontv"), + isOnly_result = rs.getBoolean("only_result"), + isMulticast = rs.getBoolean("multicast"), + livetableid = rs.getInt("livetableid"), + stage = rs.getInt("stage"), + isFds_notes_checked = rs.getBoolean("fds_notes_checked"), + scoutmatch = rs.getInt("scoutmatch"), + lineup_manager_status = rs.getInt("lineup_manager_status"), + lineup_team_official_status = rs.getInt("lineup_team_official_status") + ) + matches[matchId] = match + } + } + } + } catch (e: SQLException) { + log.error("error loading matches", e) + } + + return matches + } + + fun loadMatchExtra(conn: Connection, matchIds: Set): Map { + log.info(String.format("loading livescore_match_extra for %d matches", matchIds.size)) + + if (matchIds.isEmpty()) { + return emptyMap() + } + + val matchExtras = HashMap() + + val sql = String.format(QUERY_MATCH_EXTRA, QueryUtil.createPlaceHolders(matchIds)) + + try { + conn.prepareStatement(sql).use { ps -> + var i = 1 + for (matchId in matchIds) { + ps.setLong(i++, matchId) + } + ps.executeQuery().use { rs -> + while (rs.next()) { + val matchId = rs.getLong("matchid") + val matchExtra = MatchExtra( + matchid = rs.getLong("matchid"), + seasonid = rs.getInt("seasonid"), + isIsontv_internal = rs.getBoolean("isontv_internal"), + first_leg = rs.getString("1st_leg"), + visibility_change = rs.getTimestamp("visibility_change"), + stadiumid = rs.getInt("stadiumid"), + startingtime_changestatus = rs.getInt("startingtime_changestatus"), + first_leg_matchid = rs.getLong("1st_leg_matchid"), + isShirtnumbers = rs.getBoolean("shirtnumbers"), + isInternal_test_match = rs.getBoolean("internal_test_match"), + current_server = rs.getInt("current_server"), + current_game_points = rs.getString("current_game_points"), + match_seconds = rs.getInt("match_seconds"), + match_start = rs.getInt("match_start"), + start_type = rs.getInt("start_type"), + tiebreak_scores = rs.getString("tiebreak_scores"), + conditions = rs.getString("conditions"), + isDeeper_coverage = rs.getBoolean("deeper_coverage"), + isBallspotting = rs.getBoolean("ballspotting"), + isTactical_lineup = rs.getBoolean("tactical_lineup"), + time_info = rs.getString("time_info"), + suspension_status = rs.getString("suspension_status"), + isScout_connection = rs.getBoolean("scout_connection"), + coverage_level = rs.getInt("coverage_level"), + isManually_hidden = rs.getBoolean("manually_hidden"), + isMedia_coverage = rs.getBoolean("media_coverage"), + isUnavailable = rs.getBoolean("unavailable"), + isOfficial_data_locked = rs.getBoolean("official_data_locked"), + current_period_seconds_left = rs.getInt("current_period_seconds_left") + ) + + matchExtras[matchId] = matchExtra + } + } + } + } catch (e: SQLException) { + log.error("error loading match extras", e) + } + + return matchExtras + } + + fun loadScoutEvents(conn: Connection, matchIds: Set): Map { + log.info(String.format("loading livescore_scoutevent for %d matches", matchIds.size)) + + if (matchIds.isEmpty()) { + return emptyMap() + } + + val events = HashMap() + val sql = String.format(QUERY_SCOUT_EVENTS, QueryUtil.createPlaceHolders(matchIds)) + try { + conn.prepareStatement(sql).use { ps -> + var i = 1 + for (matchId in matchIds) { + ps.setLong(i++, matchId) + } + ps.executeQuery().use { rs -> + while (rs.next()) { + val id = rs.getString("id") + val event = ScoutEvent( + id = id, + matchid = rs.getLong("matchid"), + eventtype = rs.getInt("eventtype"), + time = rs.getInt("time"), + param1 = rs.getString("param1"), + param2 = rs.getString("param2"), + param3 = rs.getString("param3"), + param4 = rs.getString("param4"), + text = rs.getString("text"), + eventdate = rs.getTimestamp("eventdate"), + injurytime = rs.getInt("injurytime") + ) + events[id] = event + } + } + } + } catch (e: SQLException) { + log.error("error loading scout events", e) + } + + return events + } + + fun loadEvents(conn: Connection, matchIds: Set): Map { + log.info(String.format("loading livescore_event_top_backup for %d matches", matchIds.size)) + if (matchIds.isEmpty()) { + return emptyMap() + } + + val eventIds = HashMap() + val sql = String.format(QUERY_EVENTS, QueryUtil.createPlaceHolders(matchIds)) + try { + conn.prepareStatement(sql).use { ps -> + var i = 1 + for (matchId in matchIds) { + ps.setLong(i++, matchId) + } + ps.executeQuery().use { rs -> + while (rs.next()) { + val eventId = rs.getLong("id") + val event = Event( + id = eventId, + sourceId = rs.getInt("sourceid"), + matchId = rs.getLong("matchid"), + eventType = rs.getInt("eventtype"), + time = rs.getInt("time"), + matchTime = rs.getInt("matchtime"), + param1 = rs.getString("param1"), + param2 = rs.getString("param2"), + param3 = rs.getString("param3"), + param4 = rs.getString("param4"), + param5 = rs.getString("param5"), + text = rs.getString("text"), + eventDate = rs.getTimestamp("eventdate"), + updateDate = rs.getTimestamp("updatedate"), + isDisabled = rs.getBoolean("disabled"), + injuryTime = rs.getInt("injurytime"), + injuryMatchTime = rs.getInt("injurymatchtime"), + scoutEventId = rs.getLong("scouteventid") + ) + eventIds[eventId] = event + } + } + } + } catch (e: SQLException) { + log.error("error loading events", e) + } + + return eventIds + } + + fun loadEventFlags(conn: Connection, eventIds: Set): List { + log.info(String.format("loading livescore_event_top_flag for %d events", eventIds.size)) + if (eventIds.isEmpty()) { + return emptyList() + } + + val flags = ArrayList() + val sql = String.format(QUERY_EVENT_FLAGS, QueryUtil.createPlaceHolders(eventIds)) + try { + conn.prepareStatement(sql).use { ps -> + var i = 1 + for (eventId in eventIds) { + ps.setLong(i++, eventId) + } + ps.executeQuery().use { rs -> + while (rs.next()) { + val flag = Flag( + eventId = rs.getLong("eventid"), + flagType = rs.getInt("flagtype") + ) + flags.add(flag) + } + } + } + } catch (e: SQLException) { + log.error("error loading event flags", e) + } + + return flags + } + + fun loadEventPlayers(conn: Connection, eventIds: Set): List { + log.info(String.format("loading livescore_event_top_player for %d events", eventIds.size)) + if (eventIds.isEmpty()) { + return emptyList() + } + + val players = ArrayList() + val sql = String.format(QUERY_EVENT_PLAYERS, QueryUtil.createPlaceHolders(eventIds)) + try { + conn.prepareStatement(sql).use { ps -> + var i = 1 + for (eventId in eventIds) { + ps.setLong(i++, eventId) + } + ps.executeQuery().use { rs -> + while (rs.next()) { + val player = Player( + eventId = rs.getLong("eventid"), + playerId = rs.getInt("playerid"), + number = rs.getInt("number") + ) + players.add(player) + } + } + } + } catch (e: SQLException) { + log.error("error loading event players", e) + } + + return players + } + + fun loadEventPositions(conn: Connection, eventIds: Set): List { + log.info(String.format("loading livescore_event_top_position for %d events", eventIds.size)) + if (eventIds.isEmpty()) { + return emptyList() + } + + val positions = ArrayList() + val sql = String.format(QUERY_EVENT_POSITIONS, QueryUtil.createPlaceHolders(eventIds)) + try { + conn.prepareStatement(sql).use { ps -> + var i = 1 + for (eventId in eventIds) { + ps.setLong(i++, eventId) + } + ps.executeQuery().use { rs -> + while (rs.next()) { + val position = Position( + eventId = rs.getLong("eventid"), + posX = rs.getInt("posx"), + posY = rs.getInt("posy") + ) + positions.add(position) + } + } + } + } catch (e: SQLException) { + log.error("error loading event positions", e) + } + + return positions + } + + companion object { + private val log = Logger.getLogger(Loader::class.java) + private const val QUERY_MATCHES = + "select * from livescore_match lm where lm.dateofmatch BETWEEN ? and ? and lm.tournamentid = ?" + private const val QUERY_MATCH_EXTRA = "select * from livescore_match_extra lme where lme.matchid in (%s)" + private const val QUERY_EVENTS = "select * from livescore_event_top_backup e where e.matchid in (%s)" + private const val QUERY_SCOUT_EVENTS = "select * from livescore_scoutevent e where e.matchid in (%s)" + private const val QUERY_EVENT_FLAGS = "select * from livescore_event_top_flag f where f.eventid in (%s)" + private const val QUERY_EVENT_PLAYERS = "select * from livescore_event_top_player p where p.eventid in (%s)" + private const val QUERY_EVENT_POSITIONS = "select * from livescore_event_top_position p where p.eventid in (%s)" + } +} diff --git a/src/main/kotlin/sportradar/history/recover/RecoveryTask.kt b/src/main/kotlin/sportradar/history/recover/RecoveryTask.kt new file mode 100644 index 0000000..1611ee9 --- /dev/null +++ b/src/main/kotlin/sportradar/history/recover/RecoveryTask.kt @@ -0,0 +1,21 @@ +package sportradar.history.recover + +import com.google.common.base.MoreObjects + +import java.time.Instant + +data class RecoveryTask( + val tournamentId: Int, + val fromDate: Instant, + val toDate: Instant +) { + + + override fun toString(): String { + return MoreObjects.toStringHelper(this) + .add("tournamentId", tournamentId) + .add("fromDate", fromDate) + .add("toDate", toDate) + .toString() + } +} diff --git a/src/main/kotlin/sportradar/history/recover/Saver.kt b/src/main/kotlin/sportradar/history/recover/Saver.kt new file mode 100644 index 0000000..413bf17 --- /dev/null +++ b/src/main/kotlin/sportradar/history/recover/Saver.kt @@ -0,0 +1,447 @@ +package sportradar.history.recover + +import org.apache.log4j.Logger +import sportradar.history.recover.model.* +import sportradar.history.recover.util.QueryUtil +import sportradar.kotlin.workshop.examples._14LambdaWithReceiver.use +import java.sql.Connection +import java.sql.SQLException +import java.util.* + +internal class Saver { + + fun saveMatches(conn: Connection, matches: Map) { + log.info(String.format("saving %d livescore_match rows", matches.keys.size)) + if (matches.isEmpty()) { + return + } + val fields = Arrays.asList( + "matchid", + "betradarmatchid", + "sportid", + "realcategoryid", + "tournamentid", + "teamidhome", + "teamidaway", + "dateofmatch", + "started", + "currentperiod", + "currentperiod_time", + "ended", + "winner", + "score", + "period1", + "period2", + "period3", + "period4", + "period5", + "period6", + "period7", + "period8", + "period9", + "period10", + "period11", + "period12", + "period13", + "normaltime", + "extra1", + "extra2", + "overtime", + "penalties", + "cancelled", + "postponed", + "abandoned", + "status", + "has_injuries", + "comment", + "lastgoal_time", + "lastgoal_team", + "manualdate", + "hidden", + "lastupdate", + "publish", + "lineups_status", + "formations_status", + "isontv", + "only_result", + "multicast", + "livetableid", + "Stage", + "fds_notes_checked", + "scoutmatch", + "lineup_manager_status", + "lineup_team_official_status" + ) + val sql = QueryUtil.createInsertQuery("livescore_match", fields) + + try { + conn.prepareStatement(sql).use { ps -> + for ((_, match) in matches) { + var i = 1 + ps.setLong(i++, match.matchid) + ps.setLong(i++, match.betradarmatchid) + ps.setInt(i++, match.sportid) + ps.setInt(i++, match.realcategoryid) + ps.setInt(i++, match.tournamentid) + ps.setInt(i++, match.teamidhome) + ps.setInt(i++, match.teamidaway) + ps.setTimestamp(i++, match.dateofmatch) + ps.setBoolean(i++, match.isStarted) + ps.setInt(i++, match.currentperiod) + ps.setTimestamp(i++, match.currentperiod_time) + ps.setBoolean(i++, match.isEnded) + ps.setInt(i++, match.winner) + ps.setString(i++, match.score) + ps.setString(i++, match.period1) + ps.setString(i++, match.period2) + ps.setString(i++, match.period3) + ps.setString(i++, match.period4) + ps.setString(i++, match.period5) + ps.setString(i++, match.period6) + ps.setString(i++, match.period7) + ps.setString(i++, match.period8) + ps.setString(i++, match.period9) + ps.setString(i++, match.period10) + ps.setString(i++, match.period11) + ps.setString(i++, match.period12) + ps.setString(i++, match.period13) + ps.setString(i++, match.normaltime) + ps.setString(i++, match.extra1) + ps.setString(i++, match.extra2) + ps.setString(i++, match.overtime) + ps.setString(i++, match.penalties) + ps.setBoolean(i++, match.isCancelled) + ps.setBoolean(i++, match.isPostponed) + ps.setBoolean(i++, match.isAbandoned) + ps.setInt(i++, match.status) + ps.setBoolean(i++, match.isHas_injuries) + ps.setString(i++, match.comment) + ps.setTimestamp(i++, match.lastgoal_time) + ps.setInt(i++, match.lastgoal_team) + ps.setInt(i++, match.manualdate) + ps.setBoolean(i++, match.isHidden) + ps.setTimestamp(i++, match.lastupdate) + ps.setBoolean(i++, match.isPublish) + ps.setInt(i++, match.lineups_status) + ps.setBoolean(i++, match.isFormations_status) + ps.setBoolean(i++, match.isIsontv) + ps.setBoolean(i++, match.isOnly_result) + ps.setBoolean(i++, match.isMulticast) + ps.setInt(i++, match.livetableid) + ps.setInt(i++, match.stage) + ps.setBoolean(i++, match.isFds_notes_checked) + ps.setInt(i++, match.scoutmatch) + ps.setInt(i++, match.lineup_manager_status) + ps.setInt(i, match.lineup_team_official_status) + ps.addBatch() + } + log.info(QueryUtil.psBatchUpdateToString(ps.executeBatch())) + } + } catch (e: SQLException) { + log.error("error inserting matches", e) + } + + } + + fun saveMatchExtras(conn: Connection, matchExtras: Map) { + log.info(String.format("saving %d livescore_match_extra rows", matchExtras.keys.size)) + if (matchExtras.isEmpty()) { + return + } + val fields = Arrays.asList( + "matchid", + "seasonid", + "isontv_internal", + "1st_leg", + "visibility_change", + "stadiumid", + "startingtime_changestatus", + "1st_leg_matchid", + "shirtnumbers", + "internal_test_match", + "current_server", + "current_game_points", + "match_seconds", + "match_start", + "start_type", + "tiebreak_scores", + "conditions", + "deeper_coverage", + "ballspotting", + "tactical_lineup", + "time_info", + "suspension_status", + "scout_connection", + "coverage_level", + "manually_hidden", + "media_coverage", + "unavailable", + "official_data_locked", + "current_period_seconds_left" + ) + val sql = QueryUtil.createInsertQuery("livescore_match_extra", fields) + + try { + conn.prepareStatement(sql).use { ps -> + for ((_, matchExtra) in matchExtras) { + var i = 1 + ps.setLong(i++, matchExtra.matchid) + ps.setInt(i++, matchExtra.seasonid) + ps.setBoolean(i++, matchExtra.isIsontv_internal) + ps.setString(i++, matchExtra.first_leg) + ps.setTimestamp(i++, matchExtra.visibility_change) + ps.setInt(i++, matchExtra.stadiumid) + ps.setInt(i++, matchExtra.startingtime_changestatus) + ps.setLong(i++, matchExtra.first_leg_matchid) + ps.setBoolean(i++, matchExtra.isShirtnumbers) + ps.setBoolean(i++, matchExtra.isInternal_test_match) + ps.setInt(i++, matchExtra.current_server) + ps.setString(i++, matchExtra.current_game_points) + ps.setInt(i++, matchExtra.match_seconds) + ps.setInt(i++, matchExtra.match_start) + ps.setInt(i++, matchExtra.start_type) + ps.setString(i++, matchExtra.tiebreak_scores) + ps.setString(i++, matchExtra.conditions) + ps.setBoolean(i++, matchExtra.isDeeper_coverage) + ps.setBoolean(i++, matchExtra.isBallspotting) + ps.setBoolean(i++, matchExtra.isTactical_lineup) + ps.setString(i++, matchExtra.time_info) + ps.setString(i++, matchExtra.suspension_status) + ps.setBoolean(i++, matchExtra.isScout_connection) + ps.setInt(i++, matchExtra.coverage_level) + ps.setBoolean(i++, matchExtra.isManually_hidden) + ps.setBoolean(i++, matchExtra.isMedia_coverage) + ps.setBoolean(i++, matchExtra.isUnavailable) + ps.setBoolean(i++, matchExtra.isOfficial_data_locked) + ps.setInt(i, matchExtra.current_period_seconds_left) + ps.addBatch() + } + log.info(QueryUtil.psBatchUpdateToString(ps.executeBatch())) + } + } catch (e: SQLException) { + log.error("error inserting match extras", e) + } + + } + + fun saveEvents(conn: Connection, events: Map) { + log.info(String.format("saving %d livescore_event_top_backup rows", events.keys.size)) + if (events.isEmpty()) { + return + } + val fields = Arrays.asList( + "id", + "sourceid", + "matchid", + "eventtype", + "time", + "matchtime", + "param1", + "param2", + "param3", + "param4", + "param5", + "text", + "eventdate", + "updatedate", + "disabled", + "injurytime", + "injurymatchtime", + "scouteventid" + ) + val sql = QueryUtil.createInsertQuery("livescore_event_top_backup", fields) + + try { + conn.prepareStatement(sql).use { ps -> + for ((_, event) in events) { + var i = 1 + ps.setLong(i++, event.id) + ps.setInt(i++, event.sourceId) + ps.setLong(i++, event.matchId) + ps.setInt(i++, event.eventType) + ps.setInt(i++, event.time) + ps.setInt(i++, event.matchTime) + ps.setString(i++, event.param1) + ps.setString(i++, event.param2) + ps.setString(i++, event.param3) + ps.setString(i++, event.param4) + ps.setString(i++, event.param5) + ps.setString(i++, event.text) + ps.setTimestamp(i++, event.eventDate) + ps.setTimestamp(i++, event.updateDate) + ps.setBoolean(i++, event.isDisabled) + ps.setInt(i++, event.injuryTime) + ps.setInt(i++, event.injuryMatchTime) + ps.setLong(i, event.scoutEventId) + ps.addBatch() + } + log.info(QueryUtil.psBatchUpdateToString(ps.executeBatch())) + } + } catch (e: SQLException) { + log.error("error inserting events", e) + } + + } + + fun saveScoutEvents(conn: Connection, events: Map) { + log.info(String.format("saving %d livescore_scoutevent rows", events.keys.size)) + if (events.isEmpty()) { + return + } + val fields = Arrays.asList( + "id", + "matchid", + "eventtype", + "time", + "param1", + "param2", + "param3", + "param4", + "text", + "eventdate", + "injurytime" + ) + val sql = QueryUtil.createInsertQuery("livescore_scoutevent", fields) + + try { + conn.prepareStatement(sql).use { ps -> + for ((_, event) in events) { + var i = 1 + ps.setString(i++, event.id) + ps.setLong(i++, event.matchid) + ps.setInt(i++, event.eventtype) + ps.setInt(i++, event.time) + ps.setString(i++, event.param1) + ps.setString(i++, event.param2) + ps.setString(i++, event.param3) + ps.setString(i++, event.param4) + ps.setString(i++, event.text) + ps.setTimestamp(i++, event.eventdate) + ps.setInt(i, event.injurytime) + ps.addBatch() + } + log.info(QueryUtil.psBatchUpdateToString(ps.executeBatch())) + } + } catch (e: SQLException) { + log.error("error inserting scout events", e) + } + + } + + fun saveFlags(conn: Connection, flags: List) { + log.info(String.format("saving %d livescore_event_top_flag rows", flags.size)) + if (flags.isEmpty()) { + return + } + val fields = Arrays.asList("eventid", "flagtype") + val sql = QueryUtil.createInsertQuery("livescore_event_top_flag", fields) + + try { + conn.prepareStatement(sql).use { ps -> + for (flag in flags) { + var i = 1 + ps.setLong(i++, flag.eventId) + ps.setInt(i, flag.flagType) + ps.addBatch() + } + log.info(QueryUtil.psBatchUpdateToString(ps.executeBatch())) + } + } catch (e: SQLException) { + log.error("error inserting flags", e) + } + + } + + fun savePlayers(conn: Connection, players: List) { + log.info(String.format("saving %d livescore_event_top_player rows", players.size)) + if (players.isEmpty()) { + return + } + val fields = Arrays.asList("eventid", "playerid", "number") + val sql = QueryUtil.createInsertQuery("livescore_event_top_player", fields) + + try { + conn.prepareStatement(sql).use { ps -> + for (player in players) { + var i = 1 + ps.setLong(i++, player.eventId) + ps.setInt(i++, player.playerId) + ps.setInt(i, player.number) + ps.addBatch() + } + log.info(QueryUtil.psBatchUpdateToString(ps.executeBatch())) + } + } catch (e: SQLException) { + log.error("error inserting players", e) + } + + } + + fun savePositions(conn: Connection, positions: List) { + log.info(String.format("saving %d livescore_event_top_position rows", positions.size)) + if (positions.isEmpty()) { + return + } + val fields = Arrays.asList("eventid", "posx", "posy") + val sql = QueryUtil.createInsertQuery("livescore_event_top_position", fields) + + try { + conn.prepareStatement(sql).use { ps -> + for (position in positions) { + var i = 1 + ps.setLong(i++, position.eventId) + ps.setInt(i++, position.posX) + ps.setInt(i, position.posY) + ps.addBatch() + } + log.info(QueryUtil.psBatchUpdateToString(ps.executeBatch())) + } + } catch (e: SQLException) { + log.error("error inserting positions", e) + } + + } + + fun saveRequests(conn: Connection, requests: List) { + log.info(String.format("saving %d livescore_filesender_requests rows", requests.size)) + if (requests.isEmpty()) { + return + } + val fields = Arrays.asList( + "requestedat", + "userid", + "`from`", + "`to`", + "target_type", + "target_details", + "recipientid", + "matchids" + ) + val sql = QueryUtil.createInsertQuery("livescore_filesender_requests", fields) + try { + conn.prepareStatement(sql).use { ps -> + for (request in requests) { + var i = 1 + ps.setTimestamp(i++, request.requestedat) + ps.setInt(i++, request.userid) + ps.setString(i++, request.from) + ps.setString(i++, request.to) + ps.setInt(i++, request.target_type) + ps.setString(i++, request.target_details) + ps.setInt(i++, request.recipientid) + ps.setString(i, request.matchids) + ps.addBatch() + } + log.info(QueryUtil.psBatchUpdateToString(ps.executeBatch())) + + } + } catch (e: SQLException) { + log.error("error inserting requests", e) + } + + } + + companion object { + private val log = Logger.getLogger(Saver::class.java) + } +} diff --git a/src/main/kotlin/sportradar/history/recover/model/Event.kt b/src/main/kotlin/sportradar/history/recover/model/Event.kt new file mode 100644 index 0000000..b206c8c --- /dev/null +++ b/src/main/kotlin/sportradar/history/recover/model/Event.kt @@ -0,0 +1,24 @@ +package sportradar.history.recover.model + +import java.sql.Timestamp + +data class Event( + val id: Long, + val sourceId: Int, + val matchId: Long, + val eventType: Int, + val time: Int, + val matchTime: Int, + val param1: String?, + val param2: String?, + val param3: String?, + val param4: String?, + val param5: String?, + val text: String?, + val eventDate: Timestamp?, + val updateDate: Timestamp?, + val isDisabled: Boolean, + val injuryTime: Int, + val injuryMatchTime: Int, + val scoutEventId: Long +) diff --git a/src/main/kotlin/sportradar/history/recover/model/Flag.kt b/src/main/kotlin/sportradar/history/recover/model/Flag.kt new file mode 100644 index 0000000..3681981 --- /dev/null +++ b/src/main/kotlin/sportradar/history/recover/model/Flag.kt @@ -0,0 +1,7 @@ +package sportradar.history.recover.model + +data class Flag( + val eventId: Long, + val flagType: Int +) + diff --git a/src/main/kotlin/sportradar/history/recover/model/LSFSRequest.kt b/src/main/kotlin/sportradar/history/recover/model/LSFSRequest.kt new file mode 100644 index 0000000..804b9bd --- /dev/null +++ b/src/main/kotlin/sportradar/history/recover/model/LSFSRequest.kt @@ -0,0 +1,16 @@ +package sportradar.history.recover.model + +import java.sql.Timestamp + +data class LSFSRequest( + val requestedat: Timestamp, + val userid: Int, + val from: String = "", + val to: String = "", + val target_type: Int, + val target_details: String, + val recipientid: Int, + + val matchids: String +) + diff --git a/src/main/kotlin/sportradar/history/recover/model/Match.kt b/src/main/kotlin/sportradar/history/recover/model/Match.kt new file mode 100644 index 0000000..085f594 --- /dev/null +++ b/src/main/kotlin/sportradar/history/recover/model/Match.kt @@ -0,0 +1,61 @@ +package sportradar.history.recover.model + +import java.sql.Timestamp + +data class Match( + val matchid: Long, + val betradarmatchid: Long, + val sportid: Int, + val realcategoryid: Int, + val tournamentid: Int, + val teamidhome: Int, + val teamidaway: Int, + val dateofmatch: Timestamp?, + val isStarted: Boolean, + val currentperiod: Int, + val currentperiod_time: Timestamp?, + val isEnded: Boolean, + val winner: Int, + val score: String?, + val period1: String?, + val period2: String?, + val period3: String?, + val period4: String?, + val period5: String?, + val period6: String?, + val period7: String?, + val period8: String?, + val period9: String?, + val period10: String?, + val period11: String?, + val period12: String?, + val period13: String?, + val normaltime: String?, + val extra1: String?, + val extra2: String?, + val overtime: String?, + val penalties: String?, + val isCancelled: Boolean, + val isPostponed: Boolean, + val isAbandoned: Boolean, + val status: Int, + val isHas_injuries: Boolean, + val comment: String?, + val lastgoal_time: Timestamp?, + val lastgoal_team: Int, + val manualdate: Int, // 0, 1, 255 ??? + val isHidden: Boolean, + val lastupdate: Timestamp?, + val isPublish: Boolean, + val lineups_status: Int, + val isFormations_status: Boolean, + val isIsontv: Boolean, + val isOnly_result: Boolean, + val isMulticast: Boolean, + val livetableid: Int, + val stage: Int, + val isFds_notes_checked: Boolean, + val scoutmatch: Int, // 0, 1, 2 + val lineup_manager_status: Int, // 0, 1, 2 + val lineup_team_official_status: Int // 0, 1, 2 +) diff --git a/src/main/kotlin/sportradar/history/recover/model/MatchExtra.kt b/src/main/kotlin/sportradar/history/recover/model/MatchExtra.kt new file mode 100644 index 0000000..5ba73da --- /dev/null +++ b/src/main/kotlin/sportradar/history/recover/model/MatchExtra.kt @@ -0,0 +1,35 @@ +package sportradar.history.recover.model + +import java.sql.Timestamp + +data class MatchExtra( + val matchid: Long, + val seasonid: Int, + val isIsontv_internal: Boolean, + val first_leg: String?, + val visibility_change: Timestamp?, + val stadiumid: Int, + val startingtime_changestatus: Int, + val first_leg_matchid: Long, + val isShirtnumbers: Boolean, + val isInternal_test_match: Boolean, + val current_server: Int, // 0, 1, 2 + val current_game_points: String?, + val match_seconds: Int, + val match_start: Int, + val start_type: Int, + val tiebreak_scores: String?, + val conditions: String?, + val isDeeper_coverage: Boolean, + val isBallspotting: Boolean, + val isTactical_lineup: Boolean, + val time_info: String?, + val suspension_status: String?, + val isScout_connection: Boolean, + val coverage_level: Int, // 0, 1, 2, 3, 4 + val isManually_hidden: Boolean, + val isMedia_coverage: Boolean, + val isUnavailable: Boolean, + val isOfficial_data_locked: Boolean, + val current_period_seconds_left: Int +) diff --git a/src/main/kotlin/sportradar/history/recover/model/Player.kt b/src/main/kotlin/sportradar/history/recover/model/Player.kt new file mode 100644 index 0000000..2ce568d --- /dev/null +++ b/src/main/kotlin/sportradar/history/recover/model/Player.kt @@ -0,0 +1,7 @@ +package sportradar.history.recover.model + +data class Player( + val eventId: Long, + val playerId: Int, + val number: Int +) diff --git a/src/main/kotlin/sportradar/history/recover/model/Position.kt b/src/main/kotlin/sportradar/history/recover/model/Position.kt new file mode 100644 index 0000000..0acf2db --- /dev/null +++ b/src/main/kotlin/sportradar/history/recover/model/Position.kt @@ -0,0 +1,7 @@ +package sportradar.history.recover.model + +data class Position( + val eventId: Long, + val posX: Int, + val posY: Int +) diff --git a/src/main/kotlin/sportradar/history/recover/model/ScoutEvent.kt b/src/main/kotlin/sportradar/history/recover/model/ScoutEvent.kt new file mode 100644 index 0000000..68956d4 --- /dev/null +++ b/src/main/kotlin/sportradar/history/recover/model/ScoutEvent.kt @@ -0,0 +1,17 @@ +package sportradar.history.recover.model + +import java.sql.Timestamp + +data class ScoutEvent( + val id: String?, + val matchid: Long, + val eventtype: Int, + val time: Int, + val param1: String?, + val param2: String?, + val param3: String?, + val param4: String?, + val text: String?, + val eventdate: Timestamp?, + val injurytime: Int +) diff --git a/src/main/kotlin/sportradar/history/recover/util/QueryUtil.kt b/src/main/kotlin/sportradar/history/recover/util/QueryUtil.kt new file mode 100644 index 0000000..de0053c --- /dev/null +++ b/src/main/kotlin/sportradar/history/recover/util/QueryUtil.kt @@ -0,0 +1,29 @@ +package sportradar.history.recover.util + +import java.sql.PreparedStatement +import java.util.* + +object QueryUtil { + + fun createPlaceHolders(coll: Collection<*>): String { + return Collections.nCopies(coll.size, "?").joinToString(",") + } + + fun createInsertQuery(tablename: String, fields: Collection): String { + return String.format( + "insert ignore into %s (%s) VALUES (%s)", + tablename, fields.joinToString(","), createPlaceHolders(fields) + ) + } + + fun psToString(ps: PreparedStatement): String { + val s = ps.toString() + return s.substring(s.indexOf(':')) + } + + fun psBatchUpdateToString(batchResult: IntArray): String { + val total = batchResult.size + val countUpdated = Arrays.stream(batchResult).boxed().filter { i -> i > 0 }.count() + return String.format("%d inserted of %d total", countUpdated, total) + } +} diff --git a/src/main/kotlin/sportradar/history/recover/util/RequestUtil.kt b/src/main/kotlin/sportradar/history/recover/util/RequestUtil.kt new file mode 100644 index 0000000..9eba5ac --- /dev/null +++ b/src/main/kotlin/sportradar/history/recover/util/RequestUtil.kt @@ -0,0 +1,29 @@ +package sportradar.history.recover.util + +import sportradar.history.recover.model.LSFSRequest +import java.sql.Timestamp +import java.time.Instant + +object RequestUtil { + + fun createMatchRequest(filesenderId: Int, matchId: Long): LSFSRequest { +// return LSFSRequest.newLSFSRequest() +// .userid(2586) +// .recipientid(filesenderId) +// .requestedat(Timestamp.from(Instant.now())) +// .from("") +// .to("") +// .target_type(2) +// .target_details(String.format("update-%d", matchId)) +// .matchids(matchId.toString()) +// .build() + return LSFSRequest( + userid = 2586, + recipientid = filesenderId, + requestedat = Timestamp.from(Instant.now()), + target_type = 2, + target_details = "update-$matchId", + matchids = matchId.toString() + ) + } +} diff --git a/src/main/resources/conf/general.properties b/src/main/resources/conf/general.properties new file mode 100644 index 0000000..c98d414 --- /dev/null +++ b/src/main/resources/conf/general.properties @@ -0,0 +1,2 @@ +Environment = @env@ + diff --git a/src/main/resources/conf/general.properties.@env@ b/src/main/resources/conf/general.properties.@env@ new file mode 100644 index 0000000..4c3c51e --- /dev/null +++ b/src/main/resources/conf/general.properties.@env@ @@ -0,0 +1,9 @@ + +MySqlDatabaseURL = jdbc:mysql://SELECT_URL:3306/odds +MySqlSystemUserName = +MySqlSystemPassword = + + +backupdatabaseURL = jdbc:mysql://HISTORY_URL:3306/backup +backupdatabaseUsername = +backupdatabasePassword = diff --git a/src/main/resources/log4j.xml b/src/main/resources/log4j.xml new file mode 100644 index 0000000..1726638 --- /dev/null +++ b/src/main/resources/log4j.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +