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 lastLocationPoints = mutableMapOf<LocationHistoryPoint, LatLon>()
private var lastLocationPoints = mutableListOf<LocationMessage>()
private val dbHelper: SQLiteHelper
@ -85,30 +85,39 @@ class LocationMessages(val app: TelegramApplication) {
}
fun addNewLocationMessage(message: TdApi.Message) {
log.debug("addNewLocationMessage ${message.id}")
log.debug("try addNewLocationMessage ${message.id}")
val type = OsmandLocationUtils.getMessageType(message)
val senderId = OsmandLocationUtils.getSenderMessageId(message)
val content = OsmandLocationUtils.parseMessageContent(message, app.telegramHelper)
val deviceName = if (content is OsmandLocationUtils.MessageOsmAndBotLocation) content.deviceName else ""
val newItem = LocationHistoryPoint(OsmandLocationUtils.getSenderMessageId(message), message.chatId, type, deviceName)
val previousMessageLatLon = lastLocationPoints[newItem]
val locationMessage = OsmandLocationUtils.createLocationMessage(message, content, previousMessageLatLon)
if (locationMessage != null) {
dbHelper.addLocationMessage(locationMessage)
lastLocationPoints[newItem] = LatLon(locationMessage.lat, locationMessage.lon)
if (content != null) {
val deviceName = if (content is OsmandLocationUtils.MessageOsmAndBotLocation) content.deviceName else ""
val previousLocationMessage = lastLocationPoints.sortedBy { it.time }.firstOrNull {
it.userId == senderId && it.chatId == message.chatId && it.deviceName == deviceName && it.type == type
}
if (previousLocationMessage == null || content.lastUpdated * 1000L > previousLocationMessage.time) {
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) {
log.debug("addMyLocationMessage")
val currentUserId = app.telegramHelper.getCurrentUserId()
val newItem = LocationHistoryPoint(currentUserId, 0, LocationMessages.TYPE_MY_LOCATION, "")
val previousMessageLatLon = lastLocationPoints[newItem]
val distance = if (previousMessageLatLon != null) { MapUtils.getDistance(previousMessageLatLon, loc.latitude, loc.longitude) } else 0.0
val previousLocationMessage = lastLocationPoints.sortedBy { it.time }.firstOrNull { it.userId == currentUserId && it.type == TYPE_MY_LOCATION }
val distance = if (previousLocationMessage != null) MapUtils.getDistance(previousLocationMessage.lat, previousLocationMessage.lon, loc.latitude, loc.longitude) else 0.0
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, "")
dbHelper.addLocationMessage(message)
lastLocationPoints[newItem] = LatLon(message.lat, message.lon)
lastLocationPoints.remove(previousLocationMessage)
lastLocationPoints.add(message)
}
fun clearBufferedMessages() {
@ -291,21 +300,14 @@ class LocationMessages(val app: TelegramApplication) {
return res
}
internal fun getLastMessages(): MutableMap<LocationHistoryPoint, LatLon> {
val res = mutableMapOf<LocationHistoryPoint, LatLon>()
readableDatabase?.rawQuery("$TIMELINE_TABLE_SELECT_HISTORY_POINTS GROUP BY $COL_USER_ID, $COL_CHAT_ID, $COL_DEVICE_NAME, $COL_TYPE", null)?.apply {
internal fun getLastMessages(): MutableList<LocationMessage> {
val res = arrayListOf<LocationMessage>()
readableDatabase?.rawQuery("$TIMELINE_TABLE_SELECT_LAST_LOCATIONS GROUP BY $COL_USER_ID, $COL_CHAT_ID, $COL_DEVICE_NAME, $COL_TYPE", null)?.apply {
if (moveToFirst()) {
do {
val userId = getInt(0)
val chatId = getLong(1)
val lat = getDouble(2)
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")
val locationMessage = readLocationMessage(this@apply)
res.add(locationMessage)
log.debug("add last location message - $locationMessage")
} while (moveToNext())
}
close()
@ -403,8 +405,8 @@ class LocationMessages(val app: TelegramApplication) {
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"
private const val TIMELINE_TABLE_SELECT_HISTORY_POINTS =
"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"
private const val TIMELINE_TABLE_SELECT_LAST_LOCATIONS =
"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"
@ -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 {
const val TYPE_MAP = 0

View file

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