mirror of
https://github.com/vrcx-team/VRCX.git
synced 2026-04-06 00:32:02 +02:00
* refactor: frontend * Fix avatar gallery sort * Update .NET dependencies * Update npm dependencies electron v37.1.0 * bulkRefreshFriends * fix dark theme * Remove crowdin * Fix config.json dialog not updating * VRCX log file fixes & add Cef log * Remove SharedVariable, fix startup * Revert init theme change * Logging date not working? Fix WinformThemer designer error * Add Cef request hander, no more escaping main page * clean * fix * fix * clean * uh * Apply thememode at startup, fixes random user colours * Split database into files * Instance info remove empty lines * Open external VRC links with VRCX * Electron fixes * fix userdialog style * ohhhh * fix store * fix store * fix: load all group members after kicking a user * fix: world dialog favorite button style * fix: Clear VRCX Cache Timer input value * clean * Fix VR overlay * Fix VR overlay 2 * Fix Discord discord rich presence for RPC worlds * Clean up age verified user tags * Fix playerList being occupied after program reload * no `this` * Fix login stuck loading * writable: false * Hide dialogs on logout * add flush sync option * rm LOGIN event * rm LOGOUT event * remove duplicate event listeners * remove duplicate event listeners * clean * remove duplicate event listeners * clean * fix theme style * fix t * clearable * clean * fix ipcEvent * Small changes * Popcorn Palace support * Remove checkActiveFriends * Clean up * Fix dragEnterCef * Block API requests when not logged in * Clear state on login & logout * Fix worldDialog instances not updating * use <script setup> * Fix avatar change event, CheckGameRunning at startup * Fix image dragging * fix * Remove PWI * fix updateLoop * add webpack-dev-server to dev environment * rm unnecessary chunks * use <script setup> * webpack-dev-server changes * use <script setup> * use <script setup> * Fix UGC text size * Split login event * t * use <script setup> * fix * Update .gitignore and enable checkJs in jsconfig * fix i18n t * use <script setup> * use <script setup> * clean * global types * fix * use checkJs for debugging * Add watchState for login watchers * fix .vue template * type fixes * rm Vue.filter * Cef v138.0.170, VC++ 2022 * Settings fixes * Remove 'USER:CURRENT' * clean up 2FA callbacks * remove userApply * rm i18n import * notification handling to use notification store methods * refactor favorite handling to use favorite store methods and clean up event emissions * refactor moderation handling to use dedicated functions for player moderation events * refactor friend handling to use dedicated functions for friend events * Fix program startup, move lang init * Fix friend state * Fix status change error * Fix user notes diff * fix * rm group event * rm auth event * rm avatar event * clean * clean * getUser * getFriends * getFavoriteWorlds, getFavoriteAvatars * AvatarGalleryUpload btn style & package.json update * Fix friend requests * Apply user * Apply world * Fix note diff * Fix VR overlay * Fixes * Update build scripts * Apply avatar * Apply instance * Apply group * update hidden VRC+ badge * Fix sameInstance "private" * fix 502/504 API errors * fix 502/504 API errors * clean * Fix friend in same instance on orange showing twice in friends list * Add back in broken friend state repair methods * add types --------- Co-authored-by: Natsumi <cmcooper123@hotmail.com>
208 lines
7.7 KiB
C#
208 lines
7.7 KiB
C#
using NLog;
|
|
using NLog.Targets;
|
|
using SQLite;
|
|
using System;
|
|
|
|
// Use different command line parser for more standardized output
|
|
// (like help text)
|
|
using System.CommandLine;
|
|
using System.CommandLine.Parsing;
|
|
using System.Diagnostics;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Reflection;
|
|
|
|
namespace DBMerger
|
|
{
|
|
public class Program
|
|
{
|
|
private static readonly Logger logger = LogManager.GetLogger("DBMerger");
|
|
|
|
// TODO: Consider config class?
|
|
public static SQLiteConnection DBConn { get; private set; }
|
|
public static SQLiteConnection OldDBConn { get; private set; }
|
|
public static Config Config { get; private set; }
|
|
|
|
public static void Main(string[] args)
|
|
{
|
|
ProcessArgs(args);
|
|
|
|
ConfigureLogger();
|
|
|
|
if (Config.Debug)
|
|
{
|
|
// Needed? mostly just covering my ass
|
|
logger.Warn(new string('=', 100));
|
|
logger.Warn("WARNING:".PadLeft(46));
|
|
logger.Warn("Debug mode will output some sensitive information (friends list, friend history, etc.)");
|
|
logger.Warn("Only use this mode for debug purposes. Enter `y` to confirm or anything else to exit.");
|
|
logger.Warn(new string('=', 100));
|
|
if (Console.ReadLine() != "y")
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
|
|
var asm = Assembly.GetExecutingAssembly();
|
|
var versionInfo = FileVersionInfo.GetVersionInfo(asm.Location);
|
|
logger.Info($"{versionInfo.ProductName}-{versionInfo.ProductVersion}");
|
|
logger.Info($"by {versionInfo.LegalCopyright}\n");
|
|
|
|
if (Path.GetFullPath(Config.NewDBPath) == Path.GetFullPath(Config.OldDBPath))
|
|
{
|
|
logger.Fatal("Database pathes cannot be the same!");
|
|
return;
|
|
}
|
|
|
|
try
|
|
{
|
|
logger.Debug("Creating connection to old DB");
|
|
try
|
|
{
|
|
DBConn = new SQLiteConnection(Config.OldDBPath) { Tracer = logger.Trace, Trace = true };
|
|
}
|
|
catch (SQLiteException)
|
|
{
|
|
logger.Fatal("Could not connect to old DB. Perhaps passed in db is corrupt or not a valid sqlite db?");
|
|
return;
|
|
}
|
|
|
|
logger.Debug("Creating connection to new DB");
|
|
try
|
|
{
|
|
DBConn.Execute("ATTACH DATABASE ? AS new_db", Config.NewDBPath);
|
|
}
|
|
catch (SQLiteException)
|
|
{
|
|
logger.Fatal("Could not connect to new DB. Perhaps passed in db is corrupt or not a valid sqlite db?");
|
|
return;
|
|
}
|
|
logger.Info("Database connections created successfully!");
|
|
|
|
CreateBackup();
|
|
|
|
try
|
|
{
|
|
new Merger(DBConn, "main", "new_db", Config).Merge();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
logger.Fatal(ex, "Merge process failed with error:\n");
|
|
}
|
|
}
|
|
finally
|
|
{
|
|
logger.Debug("Closing database connection...");
|
|
DBConn.Close();
|
|
}
|
|
|
|
}
|
|
|
|
private static void ProcessArgs(string[] args)
|
|
{
|
|
static string validateDBPath(ArgumentResult arg)
|
|
{
|
|
string path = arg.Tokens[0].Value;
|
|
Option option = arg.Argument.Parents.Single() as Option;
|
|
|
|
string extension = Path.GetExtension(path);
|
|
if (extension == "")
|
|
{
|
|
path += Path.ChangeExtension(path, "sqlite3");
|
|
}
|
|
else if (extension != ".sqlite3")
|
|
{
|
|
arg.ErrorMessage = $"File given to option `{option.Aliases.First()}` is not a sqlite database!";
|
|
return null;
|
|
}
|
|
|
|
if (!File.Exists(path))
|
|
{
|
|
arg.ErrorMessage = $"File given to option `{option.Aliases.First()}` does not exist!";
|
|
return null;
|
|
}
|
|
|
|
return path;
|
|
}
|
|
|
|
var rootCommand = new RootCommand("Merge an old and new VRCX sqlite database into one.");
|
|
|
|
var newDBOption = new Option<string>(
|
|
["-n", "--new-db-path"],
|
|
description: "The path of the new DB to merge the old onto.",
|
|
parseArgument: validateDBPath
|
|
) { IsRequired = true };
|
|
rootCommand.AddOption(newDBOption);
|
|
|
|
var oldDBOption = new Option<string>(
|
|
["-o", "--old-db-path"],
|
|
description: "The path of the old DB to merge into the new.",
|
|
parseArgument: validateDBPath
|
|
) { IsRequired = true };
|
|
rootCommand.AddOption(oldDBOption);
|
|
|
|
// Add `debug` option to be consistent with args from the main exe
|
|
var debugOption = new Option<bool>(["-v", "--verbose", "-d", "--debug"], () => false, "Add debug information to the output.");
|
|
rootCommand.AddOption(debugOption);
|
|
|
|
var importConfigOption = new Option<bool>(["--import-config"], () => false, "Imports the config values from the old database. This will override the config in the new database.");
|
|
rootCommand.AddOption(importConfigOption);
|
|
|
|
rootCommand.SetHandler((newDBPath, oldDBPath, debug, importConfig) =>
|
|
{
|
|
Config = new Config(newDBPath, oldDBPath, debug, importConfig);
|
|
}, newDBOption, oldDBOption, debugOption, importConfigOption);
|
|
|
|
// If the args weren't parsable or verifiable, exit
|
|
if (rootCommand.Invoke(args) != 0)
|
|
{
|
|
Environment.Exit(0);
|
|
}
|
|
}
|
|
|
|
private static void ConfigureLogger()
|
|
{
|
|
LogManager.Setup().LoadConfiguration(builder =>
|
|
{
|
|
var fileTarget = new FileTarget("fileTarget")
|
|
{
|
|
FileName = "DBMerger.log",
|
|
Layout = "${longdate} [${level:uppercase=true:padding=-5}] ${logger:padding=-20} - ${message} ${exception:format=tostring}",
|
|
ArchiveSuffixFormat = "{1:yyyy-MM-dd.HH-mm-ss}",
|
|
ArchiveOldFileOnStartup = true,
|
|
KeepFileOpen = true,
|
|
AutoFlush = true,
|
|
Encoding = System.Text.Encoding.UTF8
|
|
};
|
|
|
|
var consoleTarget = new ColoredConsoleTarget()
|
|
{
|
|
Layout = "[${level:uppercase=true:padding=-5}] ${message} ${exception:format=tostring}",
|
|
AutoFlush = true,
|
|
Encoding = System.Text.Encoding.UTF8
|
|
};
|
|
|
|
builder.ForLogger().FilterMinLevel(Config.Debug ? LogLevel.Trace : LogLevel.Debug).WriteTo(fileTarget);
|
|
builder.ForLogger().FilterMinLevel(Config.Debug ? LogLevel.Trace : LogLevel.Info).WriteTo(consoleTarget);
|
|
});
|
|
}
|
|
|
|
private static void CreateBackup()
|
|
{
|
|
// Get unique name for backup. Format matches the log file name format
|
|
string date = DateTime.Now.ToString("yyyyMMdd");
|
|
int counter = 0;
|
|
string backupPath;
|
|
do
|
|
{
|
|
backupPath = Path.Combine(Path.GetDirectoryName(Config.NewDBPath), $"VRCX.back.{date}.{counter}.sqlite3");
|
|
counter++;
|
|
}
|
|
while (File.Exists(backupPath));
|
|
|
|
File.Copy(Config.NewDBPath, backupPath);
|
|
logger.Info($"Created backup of new DB at {backupPath}");
|
|
}
|
|
}
|
|
}
|