package jp.juggler.subwaytooter.column import jp.juggler.subwaytooter.api.TootApiClient import jp.juggler.subwaytooter.api.TootParser import jp.juggler.subwaytooter.api.entity.* import jp.juggler.subwaytooter.table.AcctSet import jp.juggler.subwaytooter.table.TagSet import jp.juggler.subwaytooter.table.UserRelation import jp.juggler.util.LogCategory import jp.juggler.util.toJsonArray import jp.juggler.util.toPostRequestBuilder import java.util.HashSet class UserRelationLoader(val column: Column) { companion object { private val log = LogCategory("UserRelationLoader") } val whoSet = HashSet() val acctSet = HashSet() private val tagSet = HashSet() fun add(whoRef: TootAccountRef?) { add(whoRef?.get()) } fun add(who: TootAccount?) { who ?: return whoSet.add(who.id) val fullAcct = column.accessInfo.getFullAcct(who) acctSet.add("@${fullAcct.ascii}") acctSet.add("@${fullAcct.pretty}") // add(who.movedRef) } fun add(s: TootStatus?) { if (s == null) return add(s.accountRef) add(s.reblog) s.tags?.forEach { tagSet.add(it.name) } } fun add(n: TootNotification?) { if (n == null) return add(n.accountRef) add(n.status) } suspend fun update(client: TootApiClient, parser: TootParser) { var n: Int var size: Int if (column.isMisskey) { // parser内部にアカウントIDとRelationのマップが生成されるので、それをデータベースに記録する run { val now = System.currentTimeMillis() val whoList = parser.misskeyUserRelationMap.entries.toMutableList() var start = 0 val end = whoList.size while (start < end) { var step = end - start if (step > Column.RELATIONSHIP_LOAD_STEP) step = Column.RELATIONSHIP_LOAD_STEP UserRelation.saveListMisskey(now, column.accessInfo.db_id, whoList, start, step) start += step } log.d("updateRelation: update $end relations.") } // 2018/11/1 Misskeyにもリレーション取得APIができた // アカウントIDの集合からRelationshipを取得してデータベースに記録する size = whoSet.size if (size > 0) { val whoList = ArrayList(size) whoList.addAll(whoSet) val now = System.currentTimeMillis() n = 0 while (n < whoList.size) { val userIdList = ArrayList(Column.RELATIONSHIP_LOAD_STEP) for (i in 0 until Column.RELATIONSHIP_LOAD_STEP) { if (n >= size) break if (!parser.misskeyUserRelationMap.containsKey(whoList[n])) { userIdList.add(whoList[n]) } ++n } if (userIdList.isEmpty()) continue val result = client.request( "/api/users/relation", column.accessInfo.putMisskeyApiToken().apply { put( "userId", userIdList.map { it.toString() }.toJsonArray() ) }.toPostRequestBuilder() ) if (result == null || result.response?.code in 400 until 500) break val list = parseList(::TootRelationShip, parser, result.jsonArray) if (list.size == userIdList.size) { for (i in 0 until list.size) { list[i].id = userIdList[i] } UserRelation.saveListMisskeyRelationApi(now, column.accessInfo.db_id, list) } } log.d("updateRelation: update $n relations.") } } else { // アカウントIDの集合からRelationshipを取得してデータベースに記録する size = whoSet.size if (size > 0) { val whoList = ArrayList(size) whoList.addAll(whoSet) val now = System.currentTimeMillis() n = 0 while (n < whoList.size) { val sb = StringBuilder() sb.append("/api/v1/accounts/relationships") for (i in 0 until Column.RELATIONSHIP_LOAD_STEP) { if (n >= size) break sb.append(if (i == 0) '?' else '&') sb.append("id[]=") sb.append(whoList[n++].toString()) } val result = client.request(sb.toString()) ?: break // cancelled. val list = parseList(::TootRelationShip, parser, result.jsonArray) if (list.size > 0) UserRelation.saveListMastodon( now, column.accessInfo.db_id, list ) } log.d("updateRelation: update $n relations.") } } // 出現したacctをデータベースに記録する size = acctSet.size if (size > 0) { val acctList = ArrayList(size) acctList.addAll(acctSet) val now = System.currentTimeMillis() n = 0 while (n < acctList.size) { var length = size - n if (length > Column.ACCT_DB_STEP) length = Column.ACCT_DB_STEP AcctSet.saveList(now, acctList, n, length) n += length } log.d("updateRelation: update $n acct.") } // 出現したタグをデータベースに記録する size = tagSet.size if (size > 0) { val tagList = ArrayList(size) tagList.addAll(tagSet) val now = System.currentTimeMillis() n = 0 while (n < tagList.size) { var length = size - n if (length > Column.ACCT_DB_STEP) length = Column.ACCT_DB_STEP TagSet.saveList(now, tagList, n, length) n += length } log.d("updateRelation: update $n tag.") } } }