mirror of
https://github.com/fabianonline/telegram_backup.git
synced 2024-11-22 16:56:16 +00:00
WIP: Started rewriting the code to make it more null-safe.
This commit is contained in:
parent
6276651b84
commit
97cf26b46d
@ -0,0 +1,5 @@
|
|||||||
|
package de.fabianonline.telegram_backup
|
||||||
|
|
||||||
|
class Account(val file_base: String, val phone_number: String) {
|
||||||
|
|
||||||
|
}
|
@ -31,7 +31,11 @@ import org.slf4j.Logger
|
|||||||
|
|
||||||
class CommandLineController {
|
class CommandLineController {
|
||||||
private val storage: ApiStorage
|
private val storage: ApiStorage
|
||||||
var app: TelegramApp
|
val app: TelegramApp
|
||||||
|
val target_dir: String
|
||||||
|
val file_base: String
|
||||||
|
val phone_number: String
|
||||||
|
val account_file_base: String
|
||||||
|
|
||||||
private fun getLine(): String {
|
private fun getLine(): String {
|
||||||
if (System.console() != null) {
|
if (System.console() != null) {
|
||||||
@ -53,25 +57,45 @@ class CommandLineController {
|
|||||||
init {
|
init {
|
||||||
logger.info("CommandLineController started. App version {}", Config.APP_APPVER)
|
logger.info("CommandLineController started. App version {}", Config.APP_APPVER)
|
||||||
|
|
||||||
this.printHeader()
|
printHeader()
|
||||||
if (CommandLineOptions.cmd_version) {
|
if (CommandLineOptions.cmd_version) {
|
||||||
System.exit(0)
|
System.exit(0)
|
||||||
} else if (CommandLineOptions.cmd_help) {
|
} else if (CommandLineOptions.cmd_help) {
|
||||||
this.show_help()
|
show_help()
|
||||||
System.exit(0)
|
System.exit(0)
|
||||||
} else if (CommandLineOptions.cmd_license) {
|
} else if (CommandLineOptions.cmd_license) {
|
||||||
CommandLineController.show_license()
|
show_license()
|
||||||
System.exit(0)
|
System.exit(0)
|
||||||
}
|
}
|
||||||
this.setupFileBase()
|
|
||||||
|
// Setup file_base
|
||||||
|
logger.debug("Target dir from Config: {}", Config.TARGET_DIR.anonymize())
|
||||||
|
target_dir = CommandLineOptions.val_target ?: Config.TARGET_DIR
|
||||||
|
logger.debug("Target dir after options: {}", target_dir)
|
||||||
|
println("Base directory for files: ${target_dir.anonymize()}")
|
||||||
|
|
||||||
if (CommandLineOptions.cmd_list_accounts) {
|
if (CommandLineOptions.cmd_list_accounts) {
|
||||||
this.list_accounts()
|
Utils.print_accounts(target_dir)
|
||||||
System.exit(0)
|
System.exit(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
logger.trace("Checking accounts")
|
||||||
|
try {
|
||||||
|
phone_number = selectAccount(target_dir, CommandLineOptions.val_account)
|
||||||
|
} catch(e: AccountNotFoundException) {
|
||||||
|
show_error("The specified account could not be found.")
|
||||||
|
} catch(e: NoAccountsException) {
|
||||||
|
println("No accounts found. Starting login process...")
|
||||||
|
CommandLineOptions.cmd_login = true
|
||||||
|
}
|
||||||
|
|
||||||
|
file_base = target_dir + File.separatorChar + account_to_use
|
||||||
|
|
||||||
|
account = Account(file_base, account_to_use)
|
||||||
|
|
||||||
logger.debug("Initializing TelegramApp")
|
logger.debug("Initializing TelegramApp")
|
||||||
app = TelegramApp(Config.APP_ID, Config.APP_HASH, Config.APP_MODEL, Config.APP_SYSVER, Config.APP_APPVER, Config.APP_LANG)
|
app = TelegramApp(Config.APP_ID, Config.APP_HASH, Config.APP_MODEL, Config.APP_SYSVER, Config.APP_APPVER, Config.APP_LANG)
|
||||||
logger.trace("Checking accounts")
|
|
||||||
val account = this.selectAccount()
|
|
||||||
logger.debug("CommandLineOptions.cmd_login: {}", CommandLineOptions.cmd_login)
|
logger.debug("CommandLineOptions.cmd_login: {}", CommandLineOptions.cmd_login)
|
||||||
logger.info("Initializing ApiStorage")
|
logger.info("Initializing ApiStorage")
|
||||||
storage = ApiStorage(account)
|
storage = ApiStorage(account)
|
||||||
@ -196,44 +220,22 @@ class CommandLineController {
|
|||||||
println()
|
println()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setupFileBase() {
|
private fun selectAccount(file_base: String, requested_account: String?): String {
|
||||||
logger.debug("Target dir at startup: {}", Config.FILE_BASE.anonymize())
|
val found_account: String?
|
||||||
if (CommandLineOptions.val_target != null) {
|
val accounts = Utils.getAccounts(file_base)
|
||||||
Config.FILE_BASE = CommandLineOptions.val_target!!
|
if (requested_account != null) {
|
||||||
}
|
logger.debug("Account requested: {}", requested_account.anonymize())
|
||||||
logger.debug("Target dir after options: {}", Config.FILE_BASE.anonymize())
|
|
||||||
System.out.println("Base directory for files: " + Config.FILE_BASE.anonymize())
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun selectAccount(): String? {
|
|
||||||
var account = "none"
|
|
||||||
val accounts = Utils.getAccounts()
|
|
||||||
if (CommandLineOptions.cmd_login) {
|
|
||||||
logger.debug("Login requested, doing nothing.")
|
|
||||||
// do nothing
|
|
||||||
} else if (CommandLineOptions.val_account != null) {
|
|
||||||
logger.debug("Account requested: {}", CommandLineOptions.val_account!!.anonymize())
|
|
||||||
logger.trace("Checking accounts for match.")
|
logger.trace("Checking accounts for match.")
|
||||||
var found = false
|
found_account = accounts.find{it == requested_account}
|
||||||
for (acc in accounts) {
|
|
||||||
logger.trace("Checking {}", acc.anonymize())
|
if (found_account == null) {
|
||||||
if (acc == CommandLineOptions.val_account) {
|
throw AccountNotFoundException()
|
||||||
found = true
|
|
||||||
logger.trace("Matches.")
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (!found) {
|
|
||||||
show_error("Couldn't find account '" + CommandLineOptions.val_account!!.anonymize() + "'. Maybe you want to use '--login' first?")
|
|
||||||
}
|
|
||||||
account = CommandLineOptions.val_account!!
|
|
||||||
} else if (accounts.size == 0) {
|
} else if (accounts.size == 0) {
|
||||||
println("No accounts found. Starting login process...")
|
throw NoAccountsException()
|
||||||
CommandLineOptions.cmd_login = true
|
|
||||||
return null
|
|
||||||
} else if (accounts.size == 1) {
|
} else if (accounts.size == 1) {
|
||||||
account = accounts.firstElement()
|
found_account = accounts.firstElement()
|
||||||
System.out.println("Using only available account: " + account.anonymize())
|
println("Using only available account: " + account.anonymize())
|
||||||
} else {
|
} else {
|
||||||
show_error(("You didn't specify which account to use.\n" +
|
show_error(("You didn't specify which account to use.\n" +
|
||||||
"Use '--account <x>' to use account <x>.\n" +
|
"Use '--account <x>' to use account <x>.\n" +
|
||||||
@ -241,8 +243,8 @@ class CommandLineController {
|
|||||||
System.exit(1)
|
System.exit(1)
|
||||||
}
|
}
|
||||||
logger.debug("accounts.size: {}", accounts.size)
|
logger.debug("accounts.size: {}", accounts.size)
|
||||||
logger.debug("account: {}", account.anonymize())
|
logger.debug("account: {}", found_account.anonymize())
|
||||||
return account
|
return found_account!!
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun cmd_stats() {
|
private fun cmd_stats() {
|
||||||
@ -315,20 +317,6 @@ class CommandLineController {
|
|||||||
println(" --list-channels Lists all channels together with their ID")
|
println(" --list-channels Lists all channels together with their ID")
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun list_accounts() {
|
|
||||||
println("List of available accounts:")
|
|
||||||
val accounts = Utils.getAccounts()
|
|
||||||
if (accounts.size > 0) {
|
|
||||||
for (str in accounts) {
|
|
||||||
System.out.println(" " + str.anonymize())
|
|
||||||
}
|
|
||||||
println("Use '--account <x>' to use one of those accounts.")
|
|
||||||
} else {
|
|
||||||
println("NO ACCOUNTS FOUND")
|
|
||||||
println("Use '--login' to login to a telegram account.")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val logger = LoggerFactory.getLogger(CommandLineController::class.java)
|
private val logger = LoggerFactory.getLogger(CommandLineController::class.java)
|
||||||
|
|
||||||
@ -342,4 +330,7 @@ class CommandLineController {
|
|||||||
println("TODO: Print the GPL.")
|
println("TODO: Print the GPL.")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class AccountNotFoundException() : Exception("Account not found") {}
|
||||||
|
class NoAccountsException() : Exception("No accounts found") {}
|
||||||
}
|
}
|
||||||
|
@ -29,7 +29,7 @@ object Config {
|
|||||||
val APP_APPVER: String
|
val APP_APPVER: String
|
||||||
val APP_LANG = "en"
|
val APP_LANG = "en"
|
||||||
|
|
||||||
var FILE_BASE = System.getProperty("user.home") + File.separatorChar + ".telegram_backup"
|
var TARGET_DIR = System.getProperty("user.home") + File.separatorChar + ".telegram_backup"
|
||||||
val FILE_NAME_AUTH_KEY = "auth.dat"
|
val FILE_NAME_AUTH_KEY = "auth.dat"
|
||||||
val FILE_NAME_DC = "dc.dat"
|
val FILE_NAME_DC = "dc.dat"
|
||||||
val FILE_NAME_DB = "database.sqlite"
|
val FILE_NAME_DB = "database.sqlite"
|
||||||
|
@ -52,6 +52,33 @@ class Database private constructor(var client: TelegramClient) {
|
|||||||
private var stmt: Statement? = null
|
private var stmt: Statement? = null
|
||||||
var user_manager: UserManager
|
var user_manager: UserManager
|
||||||
|
|
||||||
|
init {
|
||||||
|
private val logger = LoggerFactory.getLogger(Database::class.java)
|
||||||
|
|
||||||
|
this.user_manager = UserManager.getInstance()
|
||||||
|
System.out.println("Opening database...")
|
||||||
|
try {
|
||||||
|
Class.forName("org.sqlite.JDBC")
|
||||||
|
} catch (e: ClassNotFoundException) {
|
||||||
|
CommandLineController.show_error("Could not load jdbc-sqlite class.")
|
||||||
|
}
|
||||||
|
|
||||||
|
val path = "jdbc:sqlite:${user_manager.fileBase}${Config.FILE_NAME_DB}"
|
||||||
|
|
||||||
|
try {
|
||||||
|
conn = DriverManager.getConnection(path)
|
||||||
|
stmt = conn!!.createStatement()
|
||||||
|
} catch (e: SQLException) {
|
||||||
|
CommandLineController.show_error("Could not connect to SQLITE database.")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run updates
|
||||||
|
val updates = DatabaseUpdates(conn!!, this)
|
||||||
|
updates.doUpdates()
|
||||||
|
|
||||||
|
System.out.println("Database is ready.")
|
||||||
|
}
|
||||||
|
|
||||||
fun getTopMessageID(): Int {
|
fun getTopMessageID(): Int {
|
||||||
try {
|
try {
|
||||||
val rs = stmt!!.executeQuery("SELECT MAX(message_id) FROM messages WHERE source_type IN ('group', 'dialog')")
|
val rs = stmt!!.executeQuery("SELECT MAX(message_id) FROM messages WHERE source_type IN ('group', 'dialog')")
|
||||||
@ -69,34 +96,32 @@ class Database private constructor(var client: TelegramClient) {
|
|||||||
fun getChatCount(): Int = queryInt("SELECT COUNT(*) FROM chats")
|
fun getChatCount(): Int = queryInt("SELECT COUNT(*) FROM chats")
|
||||||
fun getUserCount(): Int = queryInt("SELECT COUNT(*) FROM users")
|
fun getUserCount(): Int = queryInt("SELECT COUNT(*) FROM users")
|
||||||
|
|
||||||
val missingIDs: LinkedList<Int>
|
fun getMissingIDs: LinkedList<Int>()
|
||||||
get() {
|
try {
|
||||||
try {
|
val missing = LinkedList<Int>()
|
||||||
val missing = LinkedList<Int>()
|
val max = getTopMessageID()
|
||||||
val max = getTopMessageID()
|
val rs = stmt!!.executeQuery("SELECT message_id FROM messages WHERE source_type IN ('group', 'dialog') ORDER BY id")
|
||||||
val rs = stmt!!.executeQuery("SELECT message_id FROM messages WHERE source_type IN ('group', 'dialog') ORDER BY id")
|
rs.next()
|
||||||
rs.next()
|
var id = rs.getInt(1)
|
||||||
var id = rs.getInt(1)
|
for (i in 1..max) {
|
||||||
for (i in 1..max) {
|
if (i == id) {
|
||||||
if (i == id) {
|
rs.next()
|
||||||
rs.next()
|
if (rs.isClosed()) {
|
||||||
if (rs.isClosed()) {
|
id = Integer.MAX_VALUE
|
||||||
id = Integer.MAX_VALUE
|
} else {
|
||||||
} else {
|
id = rs.getInt(1)
|
||||||
id = rs.getInt(1)
|
|
||||||
}
|
|
||||||
} else if (i < id) {
|
|
||||||
missing.add(i)
|
|
||||||
}
|
}
|
||||||
|
} else if (i < id) {
|
||||||
|
missing.add(i)
|
||||||
}
|
}
|
||||||
rs.close()
|
|
||||||
return missing
|
|
||||||
} catch (e: SQLException) {
|
|
||||||
e.printStackTrace()
|
|
||||||
throw RuntimeException("Could not get list of ids.")
|
|
||||||
}
|
}
|
||||||
|
rs.close()
|
||||||
|
return missing
|
||||||
|
} catch (e: SQLException) {
|
||||||
|
e.printStackTrace()
|
||||||
|
throw RuntimeException("Could not get list of ids.")
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun getMessagesWithMedia(): LinkedList<TLMessage?> {
|
fun getMessagesWithMedia(): LinkedList<TLMessage?> {
|
||||||
try {
|
try {
|
||||||
@ -207,30 +232,7 @@ class Database private constructor(var client: TelegramClient) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
init {
|
|
||||||
this.user_manager = UserManager.getInstance()
|
|
||||||
System.out.println("Opening database...")
|
|
||||||
try {
|
|
||||||
Class.forName("org.sqlite.JDBC")
|
|
||||||
} catch (e: ClassNotFoundException) {
|
|
||||||
CommandLineController.show_error("Could not load jdbc-sqlite class.")
|
|
||||||
}
|
|
||||||
|
|
||||||
val path = "jdbc:sqlite:${user_manager.fileBase}${Config.FILE_NAME_DB}"
|
|
||||||
|
|
||||||
try {
|
|
||||||
conn = DriverManager.getConnection(path)
|
|
||||||
stmt = conn!!.createStatement()
|
|
||||||
} catch (e: SQLException) {
|
|
||||||
CommandLineController.show_error("Could not connect to SQLITE database.")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Run updates
|
|
||||||
val updates = DatabaseUpdates(conn!!, this)
|
|
||||||
updates.doUpdates()
|
|
||||||
|
|
||||||
System.out.println("Database is ready.")
|
|
||||||
}
|
|
||||||
|
|
||||||
fun backupDatabase(currentVersion: Int) {
|
fun backupDatabase(currentVersion: Int) {
|
||||||
val filename = String.format(Config.FILE_NAME_DB_BACKUP, currentVersion)
|
val filename = String.format(Config.FILE_NAME_DB_BACKUP, currentVersion)
|
||||||
@ -550,7 +552,9 @@ class Database private constructor(var client: TelegramClient) {
|
|||||||
fun fetchSetting(key: String): String? {
|
fun fetchSetting(key: String): String? {
|
||||||
val rs = stmt!!.executeQuery("SELECT value FROM settings WHERE key='${key}'")
|
val rs = stmt!!.executeQuery("SELECT value FROM settings WHERE key='${key}'")
|
||||||
rs.next()
|
rs.next()
|
||||||
return rs.getString(1)
|
val result = rs.getString(1)
|
||||||
|
rs.close()
|
||||||
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
fun saveSetting(key: String, value: String?) {
|
fun saveSetting(key: String, value: String?) {
|
||||||
@ -562,6 +566,7 @@ class Database private constructor(var client: TelegramClient) {
|
|||||||
ps.setString(2, value)
|
ps.setString(2, value)
|
||||||
}
|
}
|
||||||
ps.execute()
|
ps.execute()
|
||||||
|
ps.close()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getIdsFromQuery(query: String): LinkedList<Int> {
|
fun getIdsFromQuery(query: String): LinkedList<Int> {
|
||||||
@ -787,18 +792,6 @@ class Database private constructor(var client: TelegramClient) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val logger = LoggerFactory.getLogger(Database::class.java)
|
|
||||||
internal var instance: Database? = null
|
|
||||||
|
|
||||||
fun init(c: TelegramClient) {
|
|
||||||
instance = Database(c)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getInstance(): Database {
|
|
||||||
if (instance == null) throw RuntimeException("Database is not initialized but getInstance() was called.")
|
|
||||||
return instance!!
|
|
||||||
}
|
|
||||||
|
|
||||||
fun bytesToTLMessage(b: ByteArray?): TLMessage? {
|
fun bytesToTLMessage(b: ByteArray?): TLMessage? {
|
||||||
try {
|
try {
|
||||||
if (b == null) return null
|
if (b == null) return null
|
||||||
|
@ -34,9 +34,23 @@ object Utils {
|
|||||||
|
|
||||||
private val logger = LoggerFactory.getLogger(Utils::class.java) as Logger
|
private val logger = LoggerFactory.getLogger(Utils::class.java) as Logger
|
||||||
|
|
||||||
fun getAccounts(): Vector<String> {
|
fun print_accounts(file_base: String) {
|
||||||
|
println("List of available accounts:")
|
||||||
|
val accounts = getAccounts(file_base)
|
||||||
|
if (accounts.size > 0) {
|
||||||
|
for (str in accounts) {
|
||||||
|
println(" " + str.anonymize())
|
||||||
|
}
|
||||||
|
println("Use '--account <x>' to use one of those accounts.")
|
||||||
|
} else {
|
||||||
|
println("NO ACCOUNTS FOUND")
|
||||||
|
println("Use '--login' to login to a telegram account.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getAccounts(file_base: String): Vector<String> {
|
||||||
val accounts = Vector<String>()
|
val accounts = Vector<String>()
|
||||||
val folder = File(Config.FILE_BASE)
|
val folder = File(file_base)
|
||||||
val files = folder.listFiles()
|
val files = folder.listFiles()
|
||||||
if (files != null)
|
if (files != null)
|
||||||
for (f in files) {
|
for (f in files) {
|
||||||
|
Loading…
Reference in New Issue
Block a user