WIP: Started rewriting the code to make it more null-safe.

This commit is contained in:
Fabian Schlenz 2018-03-14 06:08:07 +01:00
parent 6276651b84
commit 97cf26b46d
5 changed files with 125 additions and 122 deletions

View File

@ -0,0 +1,5 @@
package de.fabianonline.telegram_backup
class Account(val file_base: String, val phone_number: String) {
}

View File

@ -31,7 +31,11 @@ import org.slf4j.Logger
class CommandLineController {
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 {
if (System.console() != null) {
@ -53,25 +57,45 @@ class CommandLineController {
init {
logger.info("CommandLineController started. App version {}", Config.APP_APPVER)
this.printHeader()
printHeader()
if (CommandLineOptions.cmd_version) {
System.exit(0)
} else if (CommandLineOptions.cmd_help) {
this.show_help()
show_help()
System.exit(0)
} else if (CommandLineOptions.cmd_license) {
CommandLineController.show_license()
show_license()
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) {
this.list_accounts()
Utils.print_accounts(target_dir)
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")
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.info("Initializing ApiStorage")
storage = ApiStorage(account)
@ -196,44 +220,22 @@ class CommandLineController {
println()
}
private fun setupFileBase() {
logger.debug("Target dir at startup: {}", Config.FILE_BASE.anonymize())
if (CommandLineOptions.val_target != null) {
Config.FILE_BASE = CommandLineOptions.val_target!!
}
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())
private fun selectAccount(file_base: String, requested_account: String?): String {
val found_account: String?
val accounts = Utils.getAccounts(file_base)
if (requested_account != null) {
logger.debug("Account requested: {}", requested_account.anonymize())
logger.trace("Checking accounts for match.")
var found = false
for (acc in accounts) {
logger.trace("Checking {}", acc.anonymize())
if (acc == CommandLineOptions.val_account) {
found = true
logger.trace("Matches.")
break
}
found_account = accounts.find{it == requested_account}
if (found_account == null) {
throw AccountNotFoundException()
}
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) {
println("No accounts found. Starting login process...")
CommandLineOptions.cmd_login = true
return null
throw NoAccountsException()
} else if (accounts.size == 1) {
account = accounts.firstElement()
System.out.println("Using only available account: " + account.anonymize())
found_account = accounts.firstElement()
println("Using only available account: " + account.anonymize())
} else {
show_error(("You didn't specify which account to use.\n" +
"Use '--account <x>' to use account <x>.\n" +
@ -241,8 +243,8 @@ class CommandLineController {
System.exit(1)
}
logger.debug("accounts.size: {}", accounts.size)
logger.debug("account: {}", account.anonymize())
return account
logger.debug("account: {}", found_account.anonymize())
return found_account!!
}
private fun cmd_stats() {
@ -315,20 +317,6 @@ class CommandLineController {
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 {
private val logger = LoggerFactory.getLogger(CommandLineController::class.java)
@ -342,4 +330,7 @@ class CommandLineController {
println("TODO: Print the GPL.")
}
}
class AccountNotFoundException() : Exception("Account not found") {}
class NoAccountsException() : Exception("No accounts found") {}
}

View File

@ -29,7 +29,7 @@ object Config {
val APP_APPVER: String
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_DC = "dc.dat"
val FILE_NAME_DB = "database.sqlite"

View File

@ -51,6 +51,33 @@ class Database private constructor(var client: TelegramClient) {
private var conn: Connection? = null
private var stmt: Statement? = null
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 {
try {
@ -69,34 +96,32 @@ class Database private constructor(var client: TelegramClient) {
fun getChatCount(): Int = queryInt("SELECT COUNT(*) FROM chats")
fun getUserCount(): Int = queryInt("SELECT COUNT(*) FROM users")
val missingIDs: LinkedList<Int>
get() {
try {
val missing = LinkedList<Int>()
val max = getTopMessageID()
val rs = stmt!!.executeQuery("SELECT message_id FROM messages WHERE source_type IN ('group', 'dialog') ORDER BY id")
rs.next()
var id = rs.getInt(1)
for (i in 1..max) {
if (i == id) {
rs.next()
if (rs.isClosed()) {
id = Integer.MAX_VALUE
} else {
id = rs.getInt(1)
}
} else if (i < id) {
missing.add(i)
fun getMissingIDs: LinkedList<Int>()
try {
val missing = LinkedList<Int>()
val max = getTopMessageID()
val rs = stmt!!.executeQuery("SELECT message_id FROM messages WHERE source_type IN ('group', 'dialog') ORDER BY id")
rs.next()
var id = rs.getInt(1)
for (i in 1..max) {
if (i == id) {
rs.next()
if (rs.isClosed()) {
id = Integer.MAX_VALUE
} else {
id = rs.getInt(1)
}
} 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?> {
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) {
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? {
val rs = stmt!!.executeQuery("SELECT value FROM settings WHERE key='${key}'")
rs.next()
return rs.getString(1)
val result = rs.getString(1)
rs.close()
return result
}
fun saveSetting(key: String, value: String?) {
@ -562,6 +566,7 @@ class Database private constructor(var client: TelegramClient) {
ps.setString(2, value)
}
ps.execute()
ps.close()
}
fun getIdsFromQuery(query: String): LinkedList<Int> {
@ -787,18 +792,6 @@ class Database private constructor(var client: TelegramClient) {
}
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? {
try {
if (b == null) return null

View File

@ -34,9 +34,23 @@ object Utils {
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 folder = File(Config.FILE_BASE)
val folder = File(file_base)
val files = folder.listFiles()
if (files != null)
for (f in files) {