694 lines
20 KiB
Go
694 lines
20 KiB
Go
package main
|
|
|
|
import (
|
|
"database/sql"
|
|
"errors"
|
|
"github.com/google/uuid"
|
|
"log"
|
|
)
|
|
|
|
func saveResponse(db *sql.DB, response Response) error {
|
|
if response.ScanProgress < 1 {
|
|
return nil
|
|
}
|
|
tx, err := db.Begin()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
commited := false
|
|
defer func(tx *sql.Tx) {
|
|
if !commited {
|
|
err := tx.Rollback()
|
|
if err != nil {
|
|
log.Fatalf("Rollback failed: %v", err)
|
|
}
|
|
}
|
|
}(tx)
|
|
|
|
// Insert or update server details
|
|
serverID, err := insertOrUpdateServer(tx, response.ServerInfo)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Insert or update favicon
|
|
faviconID, err := insertFavicon(tx, response.Favicon.PngData)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Insert a scan entry
|
|
scanID, err := insertScan(tx, response, serverID, faviconID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
var addedPlayers []AddedPlayer
|
|
// Insert players and seen players
|
|
err = insertPlayersAndSeenPlayers(tx, response.Players.Sample, scanID, &addedPlayers)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if response.ScanProgress >= 3 {
|
|
|
|
err = insertDimensions(tx, response.PlayerLoginInfo.Dimensions, scanID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Insert players and seen players
|
|
err = insertPlayersAndSeenPlayersUpdate(tx, response.PlayersInfo, scanID, &addedPlayers)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Insert plugin data sent
|
|
err = insertPluginData(tx, response.PluginDataSent, scanID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Insert feature flags and link to scan
|
|
err = insertFeatureFlags(tx, response.FeatureFlags, scanID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Insert datapacks and link to scan
|
|
err = insertDatapacks(tx, response.EnabledDatapacks, scanID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Insert registry entries
|
|
err = insertRegistryEntries(tx, response.RegistryDatas, scanID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Insert player updates and properties
|
|
err = insertPlayerUpdates(tx, response.PlayersInfo, scanID, &addedPlayers)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
err = saveUpdateTags(tx, response.Tags, scanID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
}
|
|
commited = true
|
|
return tx.Commit()
|
|
}
|
|
|
|
// Insert or update server details
|
|
func insertOrUpdateServer(tx *sql.Tx, serverInfo ServerInfo) (int, error) {
|
|
// First, try to select the server with the provided hostname, IP, and port
|
|
var serverID int
|
|
err := tx.QueryRow(
|
|
"SELECT id FROM servers WHERE hostname = ? AND ip = ? AND port = ?",
|
|
serverInfo.Hostname, serverInfo.IP, serverInfo.Port,
|
|
).Scan(&serverID)
|
|
|
|
// If the server already exists, update the details
|
|
if err == nil {
|
|
_, err := tx.Exec(
|
|
"UPDATE servers SET hostname = ?, ip = ?, port = ? WHERE id = ?",
|
|
serverInfo.Hostname, serverInfo.IP, serverInfo.Port, serverID,
|
|
)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
return serverID, nil
|
|
}
|
|
|
|
// If the server does not exist, insert a new record
|
|
if errors.Is(err, sql.ErrNoRows) {
|
|
result, err := tx.Exec(
|
|
"INSERT INTO servers (hostname, ip, port) VALUES (?, ?, ?)",
|
|
serverInfo.Hostname, serverInfo.IP, serverInfo.Port,
|
|
)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
newServerID, err := result.LastInsertId()
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
return int(newServerID), nil
|
|
}
|
|
|
|
// Return error if something went wrong during the SELECT query
|
|
return 0, err
|
|
}
|
|
|
|
// Insert favicon if not exists
|
|
func insertFavicon(tx *sql.Tx, pngData []byte) (int, error) {
|
|
if pngData == nil {
|
|
pngData = []byte{}
|
|
}
|
|
result, err := tx.Exec("INSERT INTO favicons (favicon) VALUES (?) ON DUPLICATE KEY UPDATE id = LAST_INSERT_ID(id)", pngData)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
faviconID, err := result.LastInsertId()
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
return int(faviconID), nil
|
|
}
|
|
|
|
// Insert scan data
|
|
func insertScan(tx *sql.Tx, response Response, serverID int, faviconID int) (int, error) {
|
|
result, err := tx.Exec(
|
|
`INSERT INTO scans
|
|
(server_id, progress, timestamp, favicon_id, raw_message, version, max_players, online_players, description, enforces_secure_chat,
|
|
prevents_chat_reports, compression_threshold, is_offline_mode, encryption, message, entity_id, hardcore, view_distance,
|
|
simulation_distance, reduced_debug_info, enable_respawn_screen, do_limited_crafting, dimension_type, dimension_name,
|
|
hashed_seed, game_mode, previous_game_mode, is_debug, is_flat, has_death_location, death_dimension_name, death_location_x,
|
|
death_location_y, death_location_z, portal_cooldown, server_difficulty,
|
|
server_difficulty_locked, player_slot, player_location_x, player_location_y,player_location_z,player_location_pitch,
|
|
player_location_yaw, invulnerable, flying, allow_flying, creative_mode, flying_speed, field_of_view_modifier,
|
|
default_position_spawn_x, default_position_spawn_y, default_position_spawn_z, default_position_spawn_angle,
|
|
time_of_day, world_age, world_border_x, world_border_z, world_border_old_diameter, world_border_new_diameter,
|
|
world_border_speed, world_border_portal_teleport_boundary, world_border_warning_blocks, world_border_warning_time)
|
|
VALUES (?, ?, NOW(), ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
serverID, response.ScanProgress, faviconID, response.RawMessage, response.Version.Name, response.Players.Max, response.Players.Online, response.Description.CleanText,
|
|
response.EnforcesSecureChat, response.PreventsChatReports, response.CompressionThreshold, response.IsOfflineMode, response.Encryption,
|
|
response.Message.CleanText, response.PlayerLoginInfo.EntityID, response.PlayerLoginInfo.Hardcore, response.PlayerLoginInfo.ViewDistance,
|
|
response.PlayerLoginInfo.SimulationDistance, response.PlayerLoginInfo.ReducedDebugInfo, response.PlayerLoginInfo.EnableRespawnScreen,
|
|
response.PlayerLoginInfo.DoLimitedCrafting, response.PlayerLoginInfo.DimensionType, response.PlayerLoginInfo.DimensionName,
|
|
response.PlayerLoginInfo.HashedSeed, response.PlayerLoginInfo.GameMode, response.PlayerLoginInfo.PreviousGameMode,
|
|
response.PlayerLoginInfo.IsDebug, response.PlayerLoginInfo.IsFlat, response.PlayerLoginInfo.HasDeathLocation,
|
|
response.PlayerLoginInfo.DeathDimensionName, response.PlayerLoginInfo.DeathLocation.X,
|
|
response.PlayerLoginInfo.DeathLocation.Y, response.PlayerLoginInfo.DeathLocation.Z, response.PlayerLoginInfo.PortalCooldown,
|
|
response.ServerDifficulty.Difficulty, response.ServerDifficulty.Locked, response.PlayerSlot,
|
|
response.PlayerLocation.X, response.PlayerLocation.Y, response.PlayerLocation.Z, response.PlayerLocation.Pitch, response.PlayerLocation.Yaw,
|
|
response.PlayerAbilities.Invulnerable, response.PlayerAbilities.Flying, response.PlayerAbilities.AllowFlying, response.PlayerAbilities.CreativeMode, response.PlayerAbilities.FlyingSpeed,
|
|
response.PlayerAbilities.FieldOfViewModifier, response.DefaultPositionSpawn.Location.X, response.DefaultPositionSpawn.Location.Y, response.DefaultPositionSpawn.Location.Z, response.DefaultPositionSpawn.Angle,
|
|
response.TimeOfDay, response.WorldAge, response.WorldBorder.X, response.WorldBorder.Z, response.WorldBorder.OldDiameter, response.WorldBorder.NewDiameter, response.WorldBorder.Speed, response.WorldBorder.PortalTeleportBoundary,
|
|
response.WorldBorder.WarningBlocks, response.WorldBorder.WarningTime)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
scanID, err := result.LastInsertId()
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
return int(scanID), nil
|
|
}
|
|
|
|
// Insert dimensions and link to scan
|
|
func insertDimensions(tx *sql.Tx, dimensions []string, scanID int) error {
|
|
for _, dimension := range dimensions {
|
|
var dimensionID int
|
|
err := tx.QueryRow(
|
|
"SELECT id FROM dimensions WHERE name = ?",
|
|
dimension,
|
|
).Scan(&dimensionID)
|
|
|
|
if errors.Is(err, sql.ErrNoRows) {
|
|
// If the dimension does not exist, insert it
|
|
result, err := tx.Exec(
|
|
"INSERT INTO dimensions (name) VALUES (?)",
|
|
dimension,
|
|
)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
dimensionID64, err := result.LastInsertId()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
dimensionID = int(dimensionID64)
|
|
} else if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Link the dimension to the scan
|
|
_, err = tx.Exec(
|
|
"INSERT INTO dimensions_scans (scan_id, dimension_id) VALUES (?, ?)",
|
|
scanID, dimensionID,
|
|
)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Insert players and seen players
|
|
func insertPlayersAndSeenPlayers(tx *sql.Tx, players []Player, scanID int, addedPlayers *[]AddedPlayer) (errOut error) {
|
|
if addedPlayers == nil {
|
|
return errors.New("added players cannot be nil")
|
|
}
|
|
for _, player := range players {
|
|
// Check if the player has already been added
|
|
canAdd := true
|
|
for _, addedPlayer := range *addedPlayers {
|
|
if addedPlayer.UUID == player.ID {
|
|
canAdd = false
|
|
break
|
|
}
|
|
}
|
|
if !canAdd {
|
|
continue
|
|
}
|
|
|
|
playerID, err := insertPlayer(tx, player)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
*addedPlayers = append(*addedPlayers, AddedPlayer{UUID: player.ID, PlayerId: playerID})
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Insert players and seen players updates
|
|
func insertPlayersAndSeenPlayersUpdate(tx *sql.Tx, players []PlayerUpdate, scanID int, addedPlayers *[]AddedPlayer) (errOut error) {
|
|
if addedPlayers == nil {
|
|
return errors.New("added players cannot be nil")
|
|
}
|
|
for _, player := range players {
|
|
// Check if the player has already been added
|
|
canAdd := true
|
|
for _, addedPlayer := range *addedPlayers {
|
|
if addedPlayer.UUID == player.UUID {
|
|
canAdd = false
|
|
break
|
|
}
|
|
}
|
|
if !canAdd {
|
|
continue
|
|
}
|
|
|
|
playerID, err := insertPlayerUpdateIntoPlayers(tx, player)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
*addedPlayers = append(*addedPlayers, AddedPlayer{UUID: player.UUID, PlayerId: playerID})
|
|
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Insert or update player (UUID and username)
|
|
func insertPlayer(tx *sql.Tx, player Player) (int, error) {
|
|
var playerID int
|
|
|
|
// Check if a player with the given UUID already exists
|
|
err := tx.QueryRow(
|
|
"SELECT id FROM players WHERE uuid = ?",
|
|
player.ID.String(),
|
|
).Scan(&playerID)
|
|
|
|
if err == nil {
|
|
// If the player exists, check if the username needs to be updated
|
|
_, err = tx.Exec(
|
|
"UPDATE players SET username = ? WHERE id = ? AND username != ?",
|
|
player.Name, playerID, player.Name,
|
|
)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
return playerID, nil
|
|
}
|
|
|
|
// If the player does not exist, insert a new record
|
|
if errors.Is(err, sql.ErrNoRows) {
|
|
result, err := tx.Exec(
|
|
"INSERT INTO players (uuid, username) VALUES (?, ?)",
|
|
player.ID.String(), player.Name,
|
|
)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
newPlayerID, err := result.LastInsertId()
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
return int(newPlayerID), nil
|
|
}
|
|
|
|
// Return error if something went wrong during the SELECT query
|
|
return 0, err
|
|
}
|
|
|
|
// Insert or update player with additional fields (UUID and username)
|
|
func insertPlayerUpdateIntoPlayers(tx *sql.Tx, player PlayerUpdate) (int, error) {
|
|
var playerID int
|
|
|
|
// Check if a player with the given UUID already exists
|
|
err := tx.QueryRow(
|
|
"SELECT id FROM players WHERE uuid = ?",
|
|
player.UUID.String(),
|
|
).Scan(&playerID)
|
|
|
|
if err == nil {
|
|
// If the player exists, update the relevant fields only if needed
|
|
_, err = tx.Exec(
|
|
"UPDATE players SET username = ?, game_mode = ?, listed = ?, ping = ?, display_name = ? WHERE id = ? AND (username != ? OR game_mode != ? OR listed != ? OR ping != ? OR display_name != ?)",
|
|
player.Name, player.GameMode, player.Listed, player.Ping, player.DisplayName,
|
|
playerID, player.Name, player.GameMode, player.Listed, player.Ping, player.DisplayName,
|
|
)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
return playerID, nil
|
|
}
|
|
|
|
// If the player does not exist, insert a new record
|
|
if errors.Is(err, sql.ErrNoRows) {
|
|
result, err := tx.Exec(
|
|
"INSERT INTO players (uuid, username, game_mode, listed, ping, display_name) VALUES (?, ?, ?, ?, ?, ?)",
|
|
player.UUID.String(), player.Name, player.GameMode, player.Listed, player.Ping, player.DisplayName,
|
|
)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
newPlayerID, err := result.LastInsertId()
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
return int(newPlayerID), nil
|
|
}
|
|
|
|
// Return error if something went wrong during the SELECT query
|
|
return 0, err
|
|
}
|
|
|
|
// Insert plugin data sent
|
|
func insertPluginData(tx *sql.Tx, pluginData map[string]string, scanID int) error {
|
|
for name, value := range pluginData {
|
|
_, err := tx.Exec("INSERT INTO plugin_data_sent (scan_id, name, value) VALUES (?, ?, ?) ON DUPLICATE KEY UPDATE id = LAST_INSERT_ID(id)", scanID, name, value)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func insertTag(tx *sql.Tx, tagName string) (int, error) {
|
|
var tagID int
|
|
err := tx.QueryRow("SELECT id FROM tags WHERE name = ?", tagName).Scan(&tagID)
|
|
if errors.Is(err, sql.ErrNoRows) {
|
|
result, err := tx.Exec("INSERT INTO tags (name) VALUES (?)", tagName)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
tagID64, err := result.LastInsertId()
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
tagID = int(tagID64)
|
|
} else if err != nil {
|
|
return 0, err
|
|
}
|
|
return tagID, nil
|
|
}
|
|
|
|
func insertEntry(tx *sql.Tx, value int32) (int, error) {
|
|
var entryID int
|
|
err := tx.QueryRow("SELECT id FROM entries WHERE value = ?", value).Scan(&entryID)
|
|
if errors.Is(err, sql.ErrNoRows) {
|
|
result, err := tx.Exec("INSERT INTO entries (value) VALUES (?)", value)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
entryID64, err := result.LastInsertId()
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
entryID = int(entryID64)
|
|
} else if err != nil {
|
|
return 0, err
|
|
}
|
|
return entryID, nil
|
|
}
|
|
|
|
func saveUpdateTags(tx *sql.Tx, updates []UpdateTag, scanID int) error {
|
|
for _, update := range updates {
|
|
// Insert the tag registry identifier
|
|
registryID, err := insertTagRegistry(tx, update.TagRegistryIdentifier)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
for _, tagArray := range update.Tags {
|
|
// Insert the tag
|
|
tagID, err := insertTag(tx, tagArray.TagName)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Link the tag with the registry
|
|
err = insertTagRegistryTag(tx, registryID, tagID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Insert the entries and link them with the tag
|
|
for _, entryValue := range tagArray.Entries {
|
|
entryID, err := insertEntry(tx, entryValue)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
err = insertTagEntry(tx, tagID, entryID, scanID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func insertTagRegistry(tx *sql.Tx, registryIdentifier string) (int, error) {
|
|
var registryID int
|
|
err := tx.QueryRow("SELECT id FROM tag_registries WHERE registry_identifier = ?", registryIdentifier).Scan(®istryID)
|
|
if errors.Is(err, sql.ErrNoRows) {
|
|
result, err := tx.Exec("INSERT INTO tag_registries (registry_identifier) VALUES (?)", registryIdentifier)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
registryID64, err := result.LastInsertId()
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
registryID = int(registryID64)
|
|
} else if err != nil {
|
|
return 0, err
|
|
}
|
|
return registryID, nil
|
|
}
|
|
|
|
func insertTagRegistryTag(tx *sql.Tx, registryID int, tagID int) error {
|
|
_, err := tx.Exec("INSERT IGNORE INTO tag_registry_tags (registry_id, tag_id) VALUES (?, ?)", registryID, tagID)
|
|
return err
|
|
}
|
|
|
|
func insertTagEntry(tx *sql.Tx, tagID int, entryID int, scanID int) error {
|
|
_, err := tx.Exec("INSERT IGNORE INTO tag_entries (tag_id, entry_id, scan_id) VALUES (?, ?, ?)", tagID, entryID, scanID)
|
|
return err
|
|
}
|
|
|
|
// Insert feature flags and link to scan
|
|
func insertFeatureFlags(tx *sql.Tx, featureFlags []string, scanID int) error {
|
|
for _, flagText := range featureFlags {
|
|
var featureID int
|
|
err := tx.QueryRow(
|
|
"SELECT id FROM feature_flags WHERE flag_text = ?",
|
|
flagText,
|
|
).Scan(&featureID)
|
|
|
|
if errors.Is(err, sql.ErrNoRows) {
|
|
// If the feature flag does not exist, insert it
|
|
featureID, err = insertFeatureFlag(tx, flagText)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
} else if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Link the feature flag to the scan
|
|
_, err = tx.Exec(
|
|
"INSERT INTO feature_flag_scans (feature_flag_id, scan_id) VALUES (?, ?)",
|
|
featureID, scanID,
|
|
)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Insert feature flag (ID, flagText)
|
|
func insertFeatureFlag(tx *sql.Tx, flagText string) (int, error) {
|
|
result, err := tx.Exec("INSERT INTO feature_flags (flag_text) VALUES (?) ON DUPLICATE KEY UPDATE id = LAST_INSERT_ID(id)", flagText)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
featureID, err := result.LastInsertId()
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
return int(featureID), nil
|
|
}
|
|
|
|
// Insert datapacks and link to scan
|
|
func insertDatapacks(tx *sql.Tx, datapacks []DatapackInfo, scanID int) error {
|
|
for _, dp := range datapacks {
|
|
datapackID, err := insertDatapack(tx, dp)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
_, err = tx.Exec("INSERT INTO datapack_scans (datapack_id, scan_id) VALUES (?, ?)", datapackID, scanID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Insert or update datapack (ID, namespace, datapack ID, version)
|
|
func insertDatapack(tx *sql.Tx, dp DatapackInfo) (int, error) {
|
|
// First, try to select the datapack with the provided namespace and datapack ID
|
|
var datapackID int
|
|
err := tx.QueryRow(
|
|
"SELECT id FROM datapacks WHERE namespace = ? AND datapack_id = ?",
|
|
dp.Namespace, dp.ID,
|
|
).Scan(&datapackID)
|
|
|
|
// If the datapack already exists, update the version
|
|
if err == nil {
|
|
_, err = tx.Exec(
|
|
"UPDATE datapacks SET version = ? WHERE id = ?",
|
|
dp.Version, datapackID,
|
|
)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
return datapackID, nil
|
|
}
|
|
|
|
// If the datapack does not exist, insert a new record
|
|
if errors.Is(err, sql.ErrNoRows) {
|
|
result, err := tx.Exec(
|
|
"INSERT INTO datapacks (namespace, datapack_id, version) VALUES (?, ?, ?)",
|
|
dp.Namespace, dp.ID, dp.Version,
|
|
)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
newDatapackID, err := result.LastInsertId()
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
return int(newDatapackID), nil
|
|
}
|
|
|
|
// Return error if something went wrong during the SELECT query
|
|
return 0, err
|
|
}
|
|
|
|
// Insert registry entries
|
|
func insertRegistryEntries(tx *sql.Tx, registryDatas []RegistryData, scanID int) error {
|
|
for _, entry1 := range registryDatas {
|
|
for _, entry := range entry1.Entries {
|
|
_, err := insertRegistryEntry(tx, entry, entry1.RegistryID, scanID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
// Assuming linking logic with scan ID is required
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Insert registry entry (ID, hasNBT, nbt_data as BLOB)
|
|
func insertRegistryEntry(tx *sql.Tx, entry RegistryEntry, registryID string, scanID int) (int, error) {
|
|
var nbtData []byte
|
|
if entry.HasNBT {
|
|
nbtData = entry.NBTData
|
|
} else {
|
|
nbtData = []byte{}
|
|
}
|
|
result, err := tx.Exec("INSERT IGNORE INTO registry_entries (scan_id, registry_id, entry_id, has_nbt, nbt_data) VALUES (?, ?, ?, ?, ?) ON DUPLICATE KEY UPDATE scan_id = LAST_INSERT_ID(scan_id)", scanID, registryID, entry.EntryID, entry.HasNBT, nbtData)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
entryID, err := result.LastInsertId()
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
return int(entryID), nil
|
|
}
|
|
|
|
// Insert player updates and properties
|
|
func insertPlayerUpdates(tx *sql.Tx, playerUpdates []PlayerUpdate, scanID int, addedPlayers *[]AddedPlayer) error {
|
|
for _, update := range playerUpdates {
|
|
updateID, err := insertPlayerUpdate(tx, update, scanID, addedPlayers)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
err = insertPlayerProperties(tx, update.Properties, updateID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Insert player update (linked to player and scan)
|
|
func insertPlayerUpdate(tx *sql.Tx, update PlayerUpdate, scanID int, addedPlayers *[]AddedPlayer) (int, error) {
|
|
playerID, err := getPlayerID(tx, update.UUID, addedPlayers)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
// If the update exists, update the existing record
|
|
|
|
res, err := tx.Exec(
|
|
"INSERT INTO player_sightnings (player_id, username, game_mode, listed, ping, display_name, scan_id) VALUES (?, ?, ?, ?, ?, ?, ?)",
|
|
playerID, update.Name, update.GameMode, update.Listed, update.Ping, update.DisplayName, scanID,
|
|
)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
lastID, err := res.LastInsertId()
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
return int(lastID), nil
|
|
}
|
|
|
|
// Insert player properties (linked to player update)
|
|
func insertPlayerProperties(tx *sql.Tx, properties []PlayerProperty, updateID int) error {
|
|
for _, prop := range properties {
|
|
_, err := tx.Exec("INSERT INTO player_properties (player_update_id, name, value, signature) VALUES (?, ?, ?, ?)", updateID, prop.Name, prop.Value, prop.Signature)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Helper function to get player ID by UUID
|
|
func getPlayerID(tx *sql.Tx, uuid uuid.UUID, addedPlayers *[]AddedPlayer) (int, error) {
|
|
for _, addedPlayer := range *addedPlayers {
|
|
if addedPlayer.UUID == uuid {
|
|
return addedPlayer.PlayerId, nil
|
|
}
|
|
}
|
|
var playerID int
|
|
err := tx.QueryRow("SELECT id FROM players WHERE uuid = ?", uuid.String()).Scan(&playerID)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
return playerID, nil
|
|
}
|