Skip to content

Commit

Permalink
Merge pull request #1936 from pantasystem/feature/mastodon-timeline-p…
Browse files Browse the repository at this point in the history
…erformance

Mastodonのタイムライン取得時のパフォーマンスを改善した
  • Loading branch information
pantasystem authored Oct 28, 2023
2 parents f2b6dae + b4e8b52 commit b38483f
Show file tree
Hide file tree
Showing 5 changed files with 165 additions and 45 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ import net.pantasystem.milktea.common.Logger
import net.pantasystem.milktea.data.infrastructure.toPoll
import net.pantasystem.milktea.model.account.Account
import net.pantasystem.milktea.model.drive.FileProperty
import net.pantasystem.milktea.model.image.ImageCache
import net.pantasystem.milktea.model.image.ImageCacheRepository
import net.pantasystem.milktea.model.instance.MastodonInstanceInfo
import net.pantasystem.milktea.model.instance.MastodonInstanceInfoRepository
import net.pantasystem.milktea.model.nodeinfo.NodeInfo
import net.pantasystem.milktea.model.nodeinfo.NodeInfoRepository
Expand All @@ -27,6 +29,28 @@ class TootDTOEntityConverter @Inject constructor(
loggerFactory.create("TootDTOEntityConverter")
}

suspend fun convertAll(account: Account, statusDTOs: List<TootStatusDTO>): List<Note> {
val nodeInfo = nodeInfoRepository.find(account.getHost()).getOrNull()
val instanceInfo = instanceInfoRepository.find(account.normalizedInstanceUri)
val isReactionAvailable = (instanceInfo.onFailure {
logger.error("Failed to find instance info", it)
}.getOrNull()?.isReactionAvailable ?: false) || nodeInfo?.type is NodeInfo.SoftwareType.Mastodon.Fedibird

val urls = statusDTOs.flatMap { statusDTO ->
(statusDTO.emojiReactions?.mapNotNull {
it.url
}?: emptyList()) + (statusDTO.emojiReactions?.mapNotNull {
it.url
}?: emptyList())
}
val imageCaches = imageCacheRepository.findBySourceUrls(urls).associateBy {
it.sourceUrl
}
return statusDTOs.map {
convert(account, it, instanceInfo, isReactionAvailable, imageCaches)
}
}

suspend fun convert(statusDTO: TootStatusDTO, account: Account): Note {
val nodeInfo = nodeInfoRepository.find(account.getHost()).getOrNull()
val instanceInfoResult = instanceInfoRepository.find(account.normalizedInstanceUri)
Expand All @@ -45,6 +69,22 @@ class TootDTOEntityConverter @Inject constructor(
val imageCaches = imageCacheRepository.findBySourceUrls(urls).associateBy {
it.sourceUrl
}
return convert(
account = account,
statusDTO = statusDTO,
instanceInfoResult = instanceInfoResult,
isReactionAvailable = isReactionAvailable,
imageCaches = imageCaches,
)
}

private fun convert(
account: Account,
statusDTO: TootStatusDTO,
instanceInfoResult: Result<MastodonInstanceInfo>,
isReactionAvailable: Boolean,
imageCaches: Map<String, ImageCache>,
): Note {
return with(statusDTO) {
Note(
id = Note.Id(account.accountId, id),
Expand Down Expand Up @@ -111,6 +151,5 @@ class TootDTOEntityConverter @Inject constructor(
),
)
}

}
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
package net.pantasystem.milktea.data.infrastructure

import net.pantasystem.milktea.api.mastodon.status.TootStatusDTO
import net.pantasystem.milktea.api.misskey.groups.GroupDTO
import net.pantasystem.milktea.api.misskey.list.UserListDTO
import net.pantasystem.milktea.api.misskey.notes.NoteDTO
import net.pantasystem.milktea.model.account.Account
import net.pantasystem.milktea.model.drive.FileProperty
import net.pantasystem.milktea.model.group.Group
import net.pantasystem.milktea.model.list.UserList
import net.pantasystem.milktea.model.note.Note
import net.pantasystem.milktea.model.user.User


Expand Down Expand Up @@ -37,16 +37,16 @@ fun GroupDTO.toGroup(accountId: Long): Group {
}


data class NoteRelationEntities(
val note: Note,
val notes: List<Note>,
data class NoteDTOUnpacked(
val note: NoteDTO,
val notes: List<NoteDTO>,
val users: List<User>,
val files: List<FileProperty>
)

data class NoteDTOUnpacked(
val note: NoteDTO,
val notes: List<NoteDTO>,
data class TootDTOUnpacked(
val toot: TootStatusDTO,
val toots: List<TootStatusDTO>,
val users: List<User>,
val files: List<FileProperty>
)
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import net.pantasystem.milktea.api.mastodon.notification.MstNotificationDTO
import net.pantasystem.milktea.api.mastodon.poll.TootPollDTO
import net.pantasystem.milktea.api.mastodon.status.StatusVisibilityType
import net.pantasystem.milktea.api.mastodon.status.TootStatusDTO
import net.pantasystem.milktea.data.converters.TootDTOEntityConverter
import net.pantasystem.milktea.model.account.Account
import net.pantasystem.milktea.model.drive.FileProperty
import net.pantasystem.milktea.model.instance.MastodonInstanceInfo
Expand Down Expand Up @@ -63,39 +62,37 @@ fun TootMediaAttachment.toFileProperty(account: Account, isSensitive: Boolean):
}


suspend fun TootStatusDTO.toEntities(
converter: TootDTOEntityConverter,
fun TootStatusDTO.toEntities(
account: Account,
): NoteRelationEntities {
): TootDTOUnpacked {
val users = mutableListOf<User>()
val notes = mutableListOf<Note>()
val notes = mutableListOf<TootStatusDTO>()
val files = mutableListOf<FileProperty>()
pickEntities(converter, account, notes, users, files)
return NoteRelationEntities(
note = converter.convert(this, account),
pickEntities(account, notes, users, files)
return TootDTOUnpacked(
this,
files = files,
users = users,
notes = notes,
toots = notes,
)
}

suspend fun TootStatusDTO.pickEntities(
converter: TootDTOEntityConverter,
fun TootStatusDTO.pickEntities(
account: Account,
notes: MutableList<Note>,
notes: MutableList<TootStatusDTO>,
users: MutableList<User>,
files: MutableList<FileProperty>,
) {
val (note, user) = converter.convert(this, account) to this.account.toModel(account)
notes.add(note)
val user = this.account.toModel(account)
notes.add(this)
users.add(user)
files.addAll(
mediaAttachments.map {
it.toFileProperty(account, sensitive)
}
)
this.reblog?.pickEntities(converter, account, notes, users, files)
this.quote?.pickEntities(converter, account, notes, users, files)
this.reblog?.pickEntities(account, notes, users, files)
this.quote?.pickEntities(account, notes, users, files)
}

fun MastodonAccountRelationshipDTO.toUserRelated(): User.Related {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,7 @@ internal class MastodonTimelineStorePagingStoreImpl(

override suspend fun convertAll(list: List<TootStatusDTO>): List<Note.Id> {
val account = getAccount()
return list.map {
noteAdder.addTootStatusDtoIntoDataSource(account, it).id
}
return noteAdder.addTootStatusDtoListIntoDataSource(account, list)
}

override suspend fun loadFuture(): Result<List<TootStatusDTO>> = runCancellableCatching {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,11 +98,13 @@ class NoteDataSourceAdder @Inject constructor(
}).onFailure {
logger.error("UserDataSourceへの追加に失敗", it)
}
noteDataSource.addAll(noteDTOEntityConverter.convertAll(
account,
notes,
info,
)).onFailure {
noteDataSource.addAll(
noteDTOEntityConverter.convertAll(
account,
notes,
info,
)
).onFailure {
logger.error("NoteDataSourceへの追加に失敗", it)
}
filePropertyDataSource.addAll(entities.flatMap {
Expand Down Expand Up @@ -167,10 +169,12 @@ class NoteDataSourceAdder @Inject constructor(
userDataSource.addAll(entities.users).onFailure {
logger.error("UserDataSourceへの追加に失敗", it)
}
noteDataSource.addAll(noteDTOEntityConverter.convertAll(
account,
entities.notes
)).onFailure {
noteDataSource.addAll(
noteDTOEntityConverter.convertAll(
account,
entities.notes
)
).onFailure {
logger.error("NoteDataSourceへの追加に失敗", it)
}
filePropertyDataSource.addAll(entities.files).onFailure {
Expand All @@ -181,12 +185,86 @@ class NoteDataSourceAdder @Inject constructor(
return willReturnNote
}

suspend fun addTootStatusDtoListIntoDataSource(
account: Account,
statuses: List<TootStatusDTO>,
skipExists: Boolean = false
): List<Note.Id> {
val entities = statuses.map {
it.toEntities(
account,
)
}
val notes = entities.flatMap {
it.toots
} + entities.map {
it.toot
}
val users = entities.flatMap {
it.users
}
val files = entities.flatMap {
it.files
}

if (skipExists) {
userDataSource.addAll(
users.filterNot {
userDataSource.get(it.id).isSuccess
}
).onFailure {
logger.error("UserDataSourceへの追加に失敗", it)
}
noteDataSource.addAll(
tootDTOEntityConverter.convertAll(
account,
notes.filterNot {
noteDataSource.exists(Note.Id(account.accountId, it.id))
}
)
).onFailure {
logger.error("NoteDataSourceへの追加に失敗", it)
}
filePropertyDataSource.addAll(
files.filterNot {
filePropertyDataSource.find(it.id).isSuccess
}
).onFailure {
logger.error("FilePropertyDataSourceへの追加に失敗", it)
}

} else {
userDataSource.addAll(users).onFailure {
logger.error("UserDataSourceへの追加に失敗", it)
}
noteDataSource.addAll(
tootDTOEntityConverter.convertAll(
account,
notes
)
).onFailure {
logger.error("NoteDataSourceへの追加に失敗", it)
}
filePropertyDataSource.addAll(files).onFailure {
logger.error("FilePropertyDataSourceへの追加に失敗", it)
}
}
return entities.map {
Note.Id(
account.accountId,
it.toot.id
)
}
}

suspend fun addTootStatusDtoIntoDataSource(
account: Account,
status: TootStatusDTO,
skipExists: Boolean = false
): Note {
val entities = status.toEntities(tootDTOEntityConverter, account)
val entities = status.toEntities(account)
val willReturnNote = tootDTOEntityConverter.convert(entities.toot, account)
noteDataSource.add(willReturnNote)
if (skipExists) {
userDataSource.addAll(
entities.users.filterNot {
Expand All @@ -196,14 +274,17 @@ class NoteDataSourceAdder @Inject constructor(
logger.error("UserDataSourceへの追加に失敗", it)
}
noteDataSource.addAll(
entities.notes.filterNot {
noteDataSource.exists(it.id)
}
tootDTOEntityConverter.convertAll(
account,
entities.toots.filterNot {
noteDataSource.exists(Note.Id(account.accountId, it.id))
}
)
).onFailure {
logger.error("NoteDataSourceへの追加に失敗", it)
}
if (!noteDataSource.exists(entities.note.id)) {
noteDataSource.add(entities.note).onFailure {
if (!noteDataSource.exists(Note.Id(account.accountId, entities.toot.id))) {
noteDataSource.add(willReturnNote).onFailure {
logger.error("NoteDataSourceへの追加に失敗", it)
}
}
Expand All @@ -218,18 +299,23 @@ class NoteDataSourceAdder @Inject constructor(
userDataSource.addAll(entities.users).onFailure {
logger.error("UserDataSourceへの追加に失敗", it)
}
noteDataSource.addAll(entities.notes).onFailure {
noteDataSource.addAll(
tootDTOEntityConverter.convertAll(
account,
entities.toots,
)
).onFailure {
logger.error("NoteDataSourceへの追加に失敗", it)
}
noteDataSource.add(entities.note).onFailure {
noteDataSource.add(willReturnNote).onFailure {
logger.error("NoteDataSourceへの追加に失敗", it)
}
filePropertyDataSource.addAll(entities.files).onFailure {
logger.error("FilePropertyDataSourceへの追加に失敗", it)
}
}

return entities.note
return willReturnNote
}
}

Expand Down

0 comments on commit b38483f

Please sign in to comment.