Skip to content

Commit

Permalink
add test
Browse files Browse the repository at this point in the history
  • Loading branch information
storytellerF committed Dec 22, 2024
1 parent e49d3fc commit b262c62
Show file tree
Hide file tree
Showing 25 changed files with 287 additions and 171 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,11 @@ import co.elastic.clients.elasticsearch._types.query_dsl.Operator
import co.elastic.clients.elasticsearch._types.query_dsl.Query
import co.elastic.clients.elasticsearch._types.query_dsl.RangeQuery
import co.elastic.clients.elasticsearch._types.query_dsl.TermQuery
import co.elastic.clients.elasticsearch.core.BulkRequest
import co.elastic.clients.elasticsearch.core.MgetRequest
import co.elastic.clients.elasticsearch.core.SearchRequest
import co.elastic.clients.elasticsearch.core.bulk.BulkOperation
import co.elastic.clients.elasticsearch.core.bulk.IndexOperation
import co.elastic.clients.json.JsonData
import co.elastic.clients.json.jackson.JacksonJsonpMapper
import co.elastic.clients.transport.TransportUtils
Expand All @@ -31,44 +35,62 @@ import org.elasticsearch.client.RestClient
import java.io.File
import java.io.FileInputStream
import java.net.ConnectException
import javax.net.ssl.SSLContext

private const val topicIndexName = "topics"

class ElasticTopicSearchService(private val connection: ElasticConnection) : TopicSearchService {
companion object {
var INJECTED_SSL_CONTEXT: SSLContext? = null
}

override suspend fun saveDocument(topics: List<TopicDocument>): Result<Unit> {
return useElasticClient(connection) {
topics.map { topic ->
override suspend fun saveDocument(topics: List<TopicDocument>): Result<Long> {
return if (topics.size == 1) {
val topic = topics.first()
useElasticClient(connection) {
index {
it.index("topics").id(topic.id.toString()).document(topic)
}
}.forEach {
it.await()
it.index(topicIndexName).id(topic.id.toString()).document(topic)
}.await().seqNo()!!
}
} else {
useElasticClient(connection) {
bulk(BulkRequest.of {
it.operations(topics.map { document ->
BulkOperation.of { op ->
op.index(
IndexOperation.Builder<TopicDocument>()
.index(topicIndexName)
.id(document.id.toString()) // 指定文档 ID
.document(document)
.build()
)
}
})
}).await().items().size.toLong()
}
}
}

override suspend fun getDocument(idList: List<PrimaryKey>): Result<List<TopicDocument?>> {
return useElasticClient(connection) {
idList.map { id ->
get({
it.index("topics")
return if (idList.size == 1) {
useElasticClient(connection) {
val id = idList.first()
listOf(get({
it.index(topicIndexName)
.id(id.toString())
}, TopicDocument::class.java)
}.map {
it.await()
}.map {
it.source()
}, TopicDocument::class.java).await().source())
}
} else {
useElasticClient(connection) {
mget(MgetRequest.of {
it.index(topicIndexName).ids(idList.map { it.toString() })
}, TopicDocument::class.java).await().docs().map {
it.result().source()
}
}
}
}

override suspend fun clean(): Result<Unit> {
return useElasticClient(connection) {
indices().delete {
it.index("topics")
it.index(topicIndexName)
}.await()
Unit
}
Expand All @@ -88,7 +110,7 @@ class ElasticTopicSearchService(private val connection: ElasticConnection) : Top

// 构建排序条件:按 ID 升序排序
val request = SearchRequest.of { s ->
s.index("topics") // 指定索引名称
s.index(topicIndexName) // 指定索引名称
.query(boolQuery._toQuery())
.sort { sort ->
sort.field { f ->
Expand All @@ -97,7 +119,7 @@ class ElasticTopicSearchService(private val connection: ElasticConnection) : Top
}.trackScores(true)
}
return useElasticClient(connection) {
val response = search<TopicDocument>(request, TopicDocument::class.java).await()
val response = search(request, TopicDocument::class.java).await()
val hits = response.hits()
val total = hits.total()
PaginationResult(hits.hits().mapNotNull {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@ import java.nio.file.Path
class LuceneTopicSearchService(private val path: Path) : TopicSearchService {
private val analyzer = StandardAnalyzer()

override suspend fun saveDocument(topics: List<TopicDocument>): Result<Unit> {
override suspend fun saveDocument(topics: List<TopicDocument>): Result<Long> {
return useLucene {
IndexWriter(it, IndexWriterConfig(analyzer)).use { writer ->
val addDocuments = writer.addDocuments(
val r = writer.addDocuments(
topics.map { document ->
val doc = Document()
doc.add(LongField("id1", document.id, Field.Store.YES))
Expand All @@ -39,29 +39,52 @@ class LuceneTopicSearchService(private val path: Path) : TopicSearchService {
}
)
Napier.d {
"save document $addDocuments in `lucene`"
"save document $r in `lucene`"
}
r
}
}
}

override suspend fun getDocument(idList: List<PrimaryKey>): Result<List<TopicDocument?>> {
if (idList.isEmpty()) return Result.success(emptyList())
return useLucene {
try {
DirectoryReader.open(it).use { reader ->
val searcher = IndexSearcher(reader)
idList.map { id ->
if (idList.size == 1) {
return useLucene {
try {
DirectoryReader.open(it).use { reader ->
val searcher = IndexSearcher(reader)
val id = idList.first()
val topDocs = searcher.search(LongPoint.newExactQuery("id1", id), 1)
topDocs.scoreDocs.firstOrNull()?.let { scoreDoc ->
listOf(topDocs.scoreDocs.firstOrNull()?.let { scoreDoc ->
val document = searcher.storedFields().document(scoreDoc.doc)
restoreDocument(id, document)
}
})
}
} catch (_: IndexNotFoundException) {
List(idList.size) {
null
}
}
} catch (_: IndexNotFoundException) {
List(idList.size) {
null
}
} else {
return useLucene {
try {
DirectoryReader.open(it).use { reader ->
val searcher = IndexSearcher(reader)
val query = LongPoint.newSetQuery("id1", idList)
val topDocs = searcher.search(query, idList.size)
val map = topDocs.scoreDocs.map { scoreDoc ->
val document = searcher.storedFields().document(scoreDoc.doc)
restoreDocument(document.get("id1").toPrimaryKey(), document)
}.associateBy { it.id }
idList.map { id ->
map[id]
}
}
} catch (_: IndexNotFoundException) {
List(idList.size) {
null
}
}
}
}
Expand Down Expand Up @@ -104,7 +127,7 @@ class LuceneTopicSearchService(private val path: Path) : TopicSearchService {
MultiFieldQueryParser(
arrayOf("content"),
analyzer
).parse(filtered.joinToString<String>(" ")),
).parse(filtered.joinToString(" ")),
BooleanClause.Occur.MUST
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ data class TopicDocument(
}

interface TopicSearchService {
suspend fun saveDocument(topics: List<TopicDocument>): Result<Unit>
suspend fun saveDocument(topics: List<TopicDocument>): Result<Long>

suspend fun getDocument(idList: List<PrimaryKey>): Result<List<TopicDocument?>>

Expand Down
6 changes: 3 additions & 3 deletions backend/src/main/kotlin/com/storyteller_f/tables/Reactions.kt
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ suspend fun commonReactions(
val selection = reactionAuthorContains(uid)

return DatabaseFactory.mapQuery({
ReactionInfo(data1, objectId, ObjectType.TOPIC, data3, data2, data4 == 1L)
ReactionInfo(data1, objectId, ObjectType.TOPIC, data2, data4 == 1L)
}, {
Tuple4(
it[Reactions.emoji],
Expand Down Expand Up @@ -94,9 +94,9 @@ suspend fun getReaction(uid: PrimaryKey, objectId: PrimaryKey, emojiText: String
val containsExpression = reactionAuthorContainsIfUidNotNull(uid)
val countExpression = Reactions.id.count()
return DatabaseFactory.first({
ReactionInfo(emojiText, objectId, ObjectType.TOPIC, third, first, second == 1L)
ReactionInfo(emojiText, objectId, ObjectType.TOPIC, first, second == 1L)
}, {
Triple(it[countExpression], it[containsExpression], it[Reactions.createdTime])
Pair(it[countExpression], it[containsExpression])
}) {
Reactions.select(countExpression, containsExpression).where {
(Reactions.objectId eq objectId) and (Reactions.emoji eq emojiText)
Expand Down
1 change: 0 additions & 1 deletion backend/src/main/kotlin/com/storyteller_f/tables/Topics.kt
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,6 @@ suspend fun saveTopic(
)
)
)
topic.toTopicInfo().copy(content = TopicContent.Plain(content))
}

suspend fun saveTopic1(
Expand Down
38 changes: 15 additions & 23 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -72,46 +72,38 @@ subprojects {
}
}

dependencies {
kover(project(":server"))
}

subprojects {
val androidLibModules = emptyList<String>()
val jvmLibModules = listOf<String>("server", "crypto-jvm", "backend")
val libModulesMap = mapOf(
"server" to listOf(
"crypto-jvm", "backend"
)
)
val jvmLibModules = listOf("server", "crypto-jvm", "backend")
if (jvmLibModules.contains(name) || androidLibModules.contains(name)) {
apply(plugin = "org.jetbrains.kotlinx.kover")
if (androidLibModules.contains(name)) {
apply(plugin = "com.android.library")
}

dependencies {
if (name == "server") {
val action = { it: String ->
kover(project(":$it"))
Unit
}
androidLibModules.forEach(action)
jvmLibModules.forEach(action)
libModulesMap[name]?.forEach {
kover(project(":$it"))
}
if (androidLibModules.contains(name)) {
val robolectricVersion = "4.11.1"
"testImplementation"("org.robolectric:robolectric:$robolectricVersion")
"testImplementation"(libs.robolectric)
}
}
koverReport {
if (androidLibModules.contains(name)) {
defaults {
mergeWith("release")
}
kover {
reports {
// filters for all report types of all build variants
filters {
excludes {
classes(
"*Fragment",
"*Fragment\$*",
"*Activity",
"*Activity\$*",
"*.databinding.*",
"*.BuildConfig"
)
androidGeneratedClasses()
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,9 @@ class ClientWebSocket(
}
}

fun useWebSocket(block: suspend DefaultClientWebSocketSession.() -> Unit) {
fun useWebSocket(block: suspend DefaultClientWebSocketSession.() -> Unit): Job? {
val old = connectionHandler.data.value
if (old != null && old.isActive) {
return if (old != null && old.isActive) {
GlobalScope.launch {
localState.value = LoadingState.Loading
try {
Expand All @@ -45,6 +45,8 @@ class ClientWebSocket(
localState.value = LoadingState.Error(e)
}
}
} else {
null
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,17 @@ package com.storyteller_f.a.client_lib

import com.storyteller_f.shared.SignInPack
import com.storyteller_f.shared.SignUpPack
import com.storyteller_f.shared.encrypt
import com.storyteller_f.shared.encryptAesKey
import com.storyteller_f.shared.model.*
import com.storyteller_f.shared.obj.JoinStatusSearch
import com.storyteller_f.shared.obj.NewReaction
import com.storyteller_f.shared.obj.NewTopic
import com.storyteller_f.shared.obj.ServerResponse
import com.storyteller_f.shared.obj.*
import com.storyteller_f.shared.type.ObjectType
import com.storyteller_f.shared.type.PrimaryKey
import io.github.aakira.napier.Napier
import io.ktor.client.*
import io.ktor.client.call.*
import io.ktor.client.plugins.*
import io.ktor.client.plugins.websocket.*
import io.ktor.client.request.*
import io.ktor.client.request.forms.*
import io.ktor.client.statement.*
Expand Down Expand Up @@ -391,3 +391,36 @@ suspend fun HttpClient.upload(
}
}.body<ServerResponse<MediaInfo>>()
}

@OptIn(ExperimentalStdlibApi::class)
suspend fun DefaultClientWebSocketSession.sendMessage(
roomInfo: RoomInfo,
input: String,
keyData: List<Pair<PrimaryKey, String>>,
topicId: PrimaryKey?,
) {
val content = if (roomInfo.isPrivate) {
val (encrypted, aes) = encrypt(input)
TopicContent.Encrypted(encrypted.toHexString(), keyData.associate {
it.first to encryptAesKey(it.second, aes).toHexString()
})
} else {
TopicContent.Plain(input)
}
val message: RoomFrame = RoomFrame.Message(
if (topicId != null) {
NewTopic(
ObjectType.TOPIC,
topicId,
content
)
} else {
NewTopic(
ObjectType.ROOM,
roomInfo.id,
content
)
}
)
sendSerialized(message)
}

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ val client by lazy {
}
}

val clientWs by lazy {
val wsClient by lazy {
ClientWebSocket({
client.webSocketSession(BuildKonfig.WS_SERVER_URL + "link") {
addRequestHeaders(LoginViewModel.session?.first)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ import androidx.navigation.NavOptions
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController
import coil3.compose.AsyncImage
import com.storyteller_f.a.app.common.CenterBox
import com.storyteller_f.a.app.community.MyCommunitiesPage
import com.storyteller_f.a.app.compontents.ButtonNav
Expand Down
Loading

0 comments on commit b262c62

Please sign in to comment.