Merge pull request #6556 from osmandapp/TelegramImprovements

Telegram scan improvements
This commit is contained in:
Alexey 2019-02-15 16:16:17 +03:00 committed by GitHub
commit 13af951629
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 62 additions and 94 deletions

View file

@ -18,7 +18,7 @@ class LocationMessages(val app: TelegramApplication) {
private var bufferedMessages = emptyList<BufferMessage>() private var bufferedMessages = emptyList<BufferMessage>()
private var lastLocationPoints = mutableMapOf<LocationHistoryPoint, LatLon>() private var lastLocationPoints = mutableListOf<LocationMessage>()
private val dbHelper: SQLiteHelper private val dbHelper: SQLiteHelper
@ -85,30 +85,39 @@ class LocationMessages(val app: TelegramApplication) {
} }
fun addNewLocationMessage(message: TdApi.Message) { fun addNewLocationMessage(message: TdApi.Message) {
log.debug("addNewLocationMessage ${message.id}") log.debug("try addNewLocationMessage ${message.id}")
val type = OsmandLocationUtils.getMessageType(message) val type = OsmandLocationUtils.getMessageType(message)
val senderId = OsmandLocationUtils.getSenderMessageId(message)
val content = OsmandLocationUtils.parseMessageContent(message, app.telegramHelper) val content = OsmandLocationUtils.parseMessageContent(message, app.telegramHelper)
val deviceName = if (content is OsmandLocationUtils.MessageOsmAndBotLocation) content.deviceName else "" if (content != null) {
val newItem = LocationHistoryPoint(OsmandLocationUtils.getSenderMessageId(message), message.chatId, type, deviceName) val deviceName = if (content is OsmandLocationUtils.MessageOsmAndBotLocation) content.deviceName else ""
val previousMessageLatLon = lastLocationPoints[newItem] val previousLocationMessage = lastLocationPoints.sortedBy { it.time }.firstOrNull {
val locationMessage = OsmandLocationUtils.createLocationMessage(message, content, previousMessageLatLon) it.userId == senderId && it.chatId == message.chatId && it.deviceName == deviceName && it.type == type
if (locationMessage != null) { }
dbHelper.addLocationMessage(locationMessage) if (previousLocationMessage == null || content.lastUpdated * 1000L > previousLocationMessage.time) {
lastLocationPoints[newItem] = LatLon(locationMessage.lat, locationMessage.lon) log.debug("addNewLocationMessage passed ${message.id}")
val previousMessageLatLon = if (previousLocationMessage != null) LatLon(previousLocationMessage.lat, previousLocationMessage.lon) else null
val locationMessage = OsmandLocationUtils.createLocationMessage(message, content, previousMessageLatLon)
if (locationMessage != null) {
dbHelper.addLocationMessage(locationMessage)
lastLocationPoints.remove(previousLocationMessage)
lastLocationPoints.add(locationMessage)
}
}
} }
} }
fun addMyLocationMessage(loc: Location) { fun addMyLocationMessage(loc: Location) {
log.debug("addMyLocationMessage") log.debug("addMyLocationMessage")
val currentUserId = app.telegramHelper.getCurrentUserId() val currentUserId = app.telegramHelper.getCurrentUserId()
val newItem = LocationHistoryPoint(currentUserId, 0, LocationMessages.TYPE_MY_LOCATION, "") val previousLocationMessage = lastLocationPoints.sortedBy { it.time }.firstOrNull { it.userId == currentUserId && it.type == TYPE_MY_LOCATION }
val previousMessageLatLon = lastLocationPoints[newItem] val distance = if (previousLocationMessage != null) MapUtils.getDistance(previousLocationMessage.lat, previousLocationMessage.lon, loc.latitude, loc.longitude) else 0.0
val distance = if (previousMessageLatLon != null) { MapUtils.getDistance(previousMessageLatLon, loc.latitude, loc.longitude) } else 0.0
val message = LocationMessages.LocationMessage(currentUserId, 0, loc.latitude, loc.longitude, loc.altitude, val message = LocationMessages.LocationMessage(currentUserId, 0, loc.latitude, loc.longitude, loc.altitude,
loc.speed.toDouble(), loc.accuracy.toDouble(), loc.bearing.toDouble(), loc.time, TYPE_MY_LOCATION, 0, distance, "") loc.speed.toDouble(), loc.accuracy.toDouble(), loc.bearing.toDouble(), loc.time, TYPE_MY_LOCATION, 0, distance, "")
dbHelper.addLocationMessage(message) dbHelper.addLocationMessage(message)
lastLocationPoints[newItem] = LatLon(message.lat, message.lon) lastLocationPoints.remove(previousLocationMessage)
lastLocationPoints.add(message)
} }
fun clearBufferedMessages() { fun clearBufferedMessages() {
@ -291,21 +300,14 @@ class LocationMessages(val app: TelegramApplication) {
return res return res
} }
internal fun getLastMessages(): MutableMap<LocationHistoryPoint, LatLon> { internal fun getLastMessages(): MutableList<LocationMessage> {
val res = mutableMapOf<LocationHistoryPoint, LatLon>() val res = arrayListOf<LocationMessage>()
readableDatabase?.rawQuery("$TIMELINE_TABLE_SELECT_HISTORY_POINTS GROUP BY $COL_USER_ID, $COL_CHAT_ID, $COL_DEVICE_NAME, $COL_TYPE", null)?.apply { readableDatabase?.rawQuery("$TIMELINE_TABLE_SELECT_LAST_LOCATIONS GROUP BY $COL_USER_ID, $COL_CHAT_ID, $COL_DEVICE_NAME, $COL_TYPE", null)?.apply {
if (moveToFirst()) { if (moveToFirst()) {
do { do {
val userId = getInt(0) val locationMessage = readLocationMessage(this@apply)
val chatId = getLong(1) res.add(locationMessage)
val lat = getDouble(2) log.debug("add last location message - $locationMessage")
val lon = getDouble(3)
val time = getLong(4)
val type = getInt(5)
val deviceName = getString(6)
val locationHistoryPoint = LocationHistoryPoint(userId, chatId, type, deviceName)
res[locationHistoryPoint] = LatLon(lat, lon)
log.debug("$locationHistoryPoint time: $time coords: $lat, $lon")
} while (moveToNext()) } while (moveToNext())
} }
close() close()
@ -403,8 +405,8 @@ class LocationMessages(val app: TelegramApplication) {
private const val TIMELINE_TABLE_SELECT = private const val TIMELINE_TABLE_SELECT =
"SELECT $COL_USER_ID, $COL_CHAT_ID, $COL_LAT, $COL_LON, $COL_ALTITUDE, $COL_SPEED, $COL_HDOP, $COL_BEARING, $COL_TIME, $COL_TYPE, $COL_MESSAGE_ID, $COL_DISTANCE_FROM_PREV, $COL_DEVICE_NAME FROM $TIMELINE_TABLE_NAME" "SELECT $COL_USER_ID, $COL_CHAT_ID, $COL_LAT, $COL_LON, $COL_ALTITUDE, $COL_SPEED, $COL_HDOP, $COL_BEARING, $COL_TIME, $COL_TYPE, $COL_MESSAGE_ID, $COL_DISTANCE_FROM_PREV, $COL_DEVICE_NAME FROM $TIMELINE_TABLE_NAME"
private const val TIMELINE_TABLE_SELECT_HISTORY_POINTS = private const val TIMELINE_TABLE_SELECT_LAST_LOCATIONS =
"SELECT $COL_USER_ID, $COL_CHAT_ID, $COL_LAT, $COL_LON, $COL_TIME, $COL_TYPE, $COL_DEVICE_NAME, MAX($COL_TIME) FROM $TIMELINE_TABLE_NAME" "SELECT $COL_USER_ID, $COL_CHAT_ID, $COL_LAT, $COL_LON, $COL_ALTITUDE, $COL_SPEED, $COL_HDOP, $COL_BEARING, $COL_TIME, $COL_TYPE, $COL_MESSAGE_ID, $COL_DISTANCE_FROM_PREV, $COL_DEVICE_NAME, MAX($COL_TIME) FROM $TIMELINE_TABLE_NAME"
private const val TIMELINE_TABLE_CLEAR = "DELETE FROM $TIMELINE_TABLE_NAME" private const val TIMELINE_TABLE_CLEAR = "DELETE FROM $TIMELINE_TABLE_NAME"
@ -505,36 +507,6 @@ class LocationMessages(val app: TelegramApplication) {
} }
} }
data class LocationHistoryPoint(
val userId: Int,
val chatId: Long,
val type: Int,
val deviceName: String
) {
override fun equals(other: Any?): Boolean {
if (other == null) {
return false
}
if (other !is LocationHistoryPoint) {
return false
}
val o = other as LocationHistoryPoint?
return this.userId == o!!.userId && this.chatId == o.chatId && this.type == o.type && this.deviceName == o.deviceName
}
override fun hashCode(): Int {
val prime = 31
var result = 1
result = prime * result + userId.hashCode()
result = prime * result + chatId.hashCode()
result = prime * result + type.hashCode()
result = prime * result + deviceName.hashCode()
return result
}
}
companion object { companion object {
const val TYPE_MAP = 0 const val TYPE_MAP = 0

View file

@ -574,7 +574,7 @@ class TelegramHelper private constructor() {
fun scanChatsHistory() { fun scanChatsHistory() {
log.debug("scanChatsHistory: chatList: ${chatList.size}") log.debug("scanChatsHistory: chatList: ${chatList.size}")
chatList.forEach { chatList.forEach {
scanChatHistory(it.chatId, 0, 0, 100) scanChatHistory(it.chatId, 0, 0, 100, mutableListOf<TdApi.Message>())
} }
} }
@ -583,9 +583,9 @@ class TelegramHelper private constructor() {
fromMessageId: Long, fromMessageId: Long,
offset: Int, offset: Int,
limit: Int, limit: Int,
onlyLocal: Boolean = false locations: MutableList<TdApi.Message>
) { ) {
client?.send(TdApi.GetChatHistory(chatId, fromMessageId, offset, limit, onlyLocal)) { obj -> client?.send(TdApi.GetChatHistory(chatId, fromMessageId, offset, limit, false)) { obj ->
when (obj.constructor) { when (obj.constructor) {
TdApi.Error.CONSTRUCTOR -> { TdApi.Error.CONSTRUCTOR -> {
val error = obj as TdApi.Error val error = obj as TdApi.Error
@ -597,23 +597,35 @@ class TelegramHelper private constructor() {
val messages = (obj as TdApi.Messages).messages val messages = (obj as TdApi.Messages).messages
log.debug("scanChatHistory: chatId: $chatId fromMessageId: $fromMessageId size: ${messages.size}") log.debug("scanChatHistory: chatId: $chatId fromMessageId: $fromMessageId size: ${messages.size}")
if (messages.isNotEmpty()) { if (messages.isNotEmpty()) {
messages.forEach { locations.addAll(messages.filter { it.isAppropriate() && !it.isOutgoing })
addNewMessage(it)
}
val lastMessage = messages.last() val lastMessage = messages.last()
val currentTime = System.currentTimeMillis() / 1000 val currentTime = System.currentTimeMillis() / 1000
if (currentTime-Math.max(lastMessage.date, lastMessage.editDate) < MAX_LOCATION_MESSAGE_HISTORY_SCAN_SEC) { if (currentTime - Math.max(lastMessage.date, lastMessage.editDate) < MAX_LOCATION_MESSAGE_HISTORY_SCAN_SEC) {
scanChatHistory(chatId, lastMessage.id, 0, 100) scanChatHistory(chatId, lastMessage.id, 0, 100, locations)
log.debug("scanChatHistory searchMessageId: ${lastMessage.id}") log.debug("scanChatHistory searchMessageId: ${lastMessage.id}")
} else { } else {
log.debug("scanChatHistory finishForChat: $chatId") log.debug("scanChatHistory finishForChat: $chatId")
processScannedLocationsForChat(chatId, locations)
} }
} else {
log.debug("scanChatHistory finishForChat: $chatId")
processScannedLocationsForChat(chatId, locations)
} }
} }
} }
} }
} }
private fun processScannedLocationsForChat(chatId: Long, locations: MutableList<TdApi.Message>) {
if (locations.isNotEmpty()) {
locations.sortBy { message -> OsmandLocationUtils.getLastUpdatedTime(message) }
updateLastMessage(locations.last())
incomingMessagesListeners.forEach {
it.onReceiveChatLocationMessages(chatId, *locations.toTypedArray())
}
}
}
private fun requestUser(id: Int) { private fun requestUser(id: Int) {
client?.send(TdApi.GetUser(id)) { obj -> client?.send(TdApi.GetUser(id)) { obj ->
when (obj.constructor) { when (obj.constructor) {
@ -674,16 +686,7 @@ class TelegramHelper private constructor() {
if (message.isOutgoing && !fromBot && !viaBot) { if (message.isOutgoing && !fromBot && !viaBot) {
return return
} }
removeOldMessages(message, fromBot, viaBot) updateLastMessage(message)
val oldMessage = usersLocationMessages.values.firstOrNull {
OsmandLocationUtils.getSenderMessageId(it) == OsmandLocationUtils.getSenderMessageId(message) && it.chatId == message.chatId
&& OsmandLocationUtils.getOsmAndBotDeviceName(it) == OsmandLocationUtils.getOsmAndBotDeviceName(message)
}
val hasNewerMessage = oldMessage != null && (Math.max(message.editDate, message.date) < Math.max(oldMessage.editDate, oldMessage.date))
if (!hasNewerMessage) {
message.content = OsmandLocationUtils.parseMessageContent(message, this)
usersLocationMessages[message.id] = message
}
if (message.isOutgoing) { if (message.isOutgoing) {
if (fromBot||viaBot) { if (fromBot||viaBot) {
outgoingMessagesListeners.forEach { outgoingMessagesListeners.forEach {
@ -698,24 +701,17 @@ class TelegramHelper private constructor() {
} }
} }
private fun removeOldMessages(newMessage: TdApi.Message, fromBot: Boolean, viaBot: Boolean) { private fun updateLastMessage(message: TdApi.Message) {
val iterator = usersLocationMessages.entries.iterator() val oldMessage = usersLocationMessages.values.firstOrNull {
while (iterator.hasNext()) { OsmandLocationUtils.getSenderMessageId(it) == OsmandLocationUtils.getSenderMessageId(message)
val message = iterator.next().value && it.chatId == message.chatId && message.viaBotUserId == message.viaBotUserId
if (newMessage.chatId == message.chatId) { && OsmandLocationUtils.getOsmAndBotDeviceName(it) == OsmandLocationUtils.getOsmAndBotDeviceName(message)
val sameSender = OsmandLocationUtils.getSenderMessageId(newMessage) == OsmandLocationUtils.getSenderMessageId(message) }
val viaSameBot = newMessage.viaBotUserId == message.viaBotUserId if (oldMessage == null || (Math.max(message.editDate, message.date) > Math.max(oldMessage.editDate, oldMessage.date))) {
if (fromBot || viaBot) { message.content = OsmandLocationUtils.parseMessageContent(message, this)
if ((fromBot && sameSender) || (viaBot && viaSameBot)) { usersLocationMessages[message.id] = message
val newDeviceName = OsmandLocationUtils.getOsmAndBotDeviceName(newMessage) oldMessage?.let {
val contDeviceName = OsmandLocationUtils.getOsmAndBotDeviceName(newMessage) usersLocationMessages.remove(it.id)
if (newDeviceName == contDeviceName) {
iterator.remove()
}
}
} else if (sameSender && Math.max(newMessage.editDate, newMessage.date) >= Math.max(message.editDate, message.date)) {
iterator.remove()
}
} }
} }
} }