Skip to content

Commit

Permalink
feat: auto publish server images
Browse files Browse the repository at this point in the history
fix: emoji picker style
  • Loading branch information
storytellerF committed Dec 8, 2024
1 parent 78c6314 commit 40a9eba
Show file tree
Hide file tree
Showing 19 changed files with 130 additions and 60 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,5 @@ deploy/docker-images
scripts/download-image.sh
deploy/preset.zip
node_modules
bin
bin
remote.pem
8 changes: 1 addition & 7 deletions backend/src/main/kotlin/com/storyteller_f/DatabaseFactory.kt
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package com.storyteller_f

import com.impossibl.postgres.jdbc.PGSQLIntegrityConstraintViolationException
import com.storyteller_f.shared.utils.recoverError
import com.storyteller_f.tables.*
import io.github.aakira.napier.Napier
import kotlinx.coroutines.Dispatchers
Expand Down Expand Up @@ -68,16 +67,11 @@ object DatabaseFactory {
block()
} catch (e: Throwable) {
Napier.e(e, "database failed") {
statements.toString()
"$statements\nat ${r.stackTraceToString()}"
}
throw e
}
}
}.recoverError { throwable ->
if (throwable.cause == null) {
throwable.initCause(r)
}
Result.failure(throwable)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,15 @@ import io.ktor.client.plugins.contentnegotiation.*
import io.ktor.client.plugins.cookies.*
import io.ktor.client.plugins.logging.*
import io.ktor.client.plugins.websocket.*
import io.ktor.client.statement.bodyAsText
import io.ktor.http.*
import io.ktor.serialization.kotlinx.*
import io.ktor.serialization.kotlinx.json.*
import kotlinx.serialization.json.Json
import kotlin.time.Duration.Companion.seconds

class ServerErrorException(val text: String) : Exception()

expect fun getClient(block: HttpClientConfig<*>.() -> Unit): HttpClient

fun HttpClientConfig<*>.defaultClientConfigure() {
Expand Down Expand Up @@ -49,4 +52,12 @@ fun HttpClientConfig<*>.defaultClientConfigure() {
pingInterval = 2.seconds
contentConverter = KotlinxWebsocketSerializationConverter(Json)
}
HttpResponseValidator {
handleResponseExceptionWithRequest { exception, request ->
val clientException = exception as? ClientRequestException ?: return@handleResponseExceptionWithRequest
val exceptionResponse = clientException.response
val exceptionResponseText = exceptionResponse.bodyAsText()
throw ServerErrorException(exceptionResponseText)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import com.storyteller_f.shared.SignInPack
import com.storyteller_f.shared.SignUpPack
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.type.ObjectType
Expand Down Expand Up @@ -254,13 +255,13 @@ suspend fun HttpClient.exitCommunity(communityId: PrimaryKey) = post(
).body<CommunityInfo>()

suspend fun HttpClient.addReaction(topicId: PrimaryKey, emoji: String) = post("topics/$topicId/reactions") {
contentType(ContentType.Text.Plain)
setBody(emoji)
contentType(ContentType.Application.Json)
setBody(NewReaction(emoji))
}.body<ReactionInfo>()

suspend fun HttpClient.deleteReaction(emoji: String) = post("reactions/delete") {
contentType(ContentType.Text.Plain)
setBody(emoji)
contentType(ContentType.Application.Json)
setBody(NewReaction(emoji))
}.body<Boolean>()

suspend fun HttpClient.getReactions(topicId: PrimaryKey) =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import app.cash.paging.LoadStateNotLoading
import app.cash.paging.compose.LazyPagingItems
import app.cash.paging.compose.itemContentType
import app.cash.paging.compose.itemKey
import com.storyteller_f.a.app.compontents.ExceptionView
import com.storyteller_f.a.app.globalDialogState
import com.storyteller_f.a.client_lib.LoadingHandler
import com.storyteller_f.a.client_lib.LoadingState
Expand Down Expand Up @@ -85,7 +86,7 @@ fun StateView(state: LoadingState?, refresh: () -> Unit, content: @Composable ()

is LoadingState.Error -> CenterBox {
Column(modifier = Modifier.padding(20.dp)) {
Text(text = state.e.message.toString())
ExceptionView(state.e)
Button({
refresh()
}, modifier = Modifier.align(Alignment.CenterHorizontally)) {
Expand Down Expand Up @@ -153,7 +154,7 @@ fun <T : Identifiable> LazyListScope.nestedStateView(items: LazyPagingItems<T>,
is LoadStateError -> {
item {
Column(modifier = Modifier.fillMaxWidth().height(100.dp)) {
Text(text = refreshState.error.message ?: refreshState.error.stackTraceToString())
ExceptionView(refreshState.error)
Button({
items.refresh()
}, modifier = Modifier.align(Alignment.CenterHorizontally)) {
Expand Down Expand Up @@ -203,8 +204,7 @@ fun <T : Any> RefCellStateView(
}.padding(vertical = 8.dp),
contentAlignment = Alignment.Center
) {
val e = localState.e
Text(e.message.toString().take(100), modifier = Modifier.fillMaxHeight(), maxLines = 1)
ExceptionView(localState.e)
}

else -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ fun GlobalDialogInternal(message: DialogState, updateNewState: (DialogState) ->
Text("Close")
}
}, title = {
Text(throwable.message ?: throwable::class.simpleName ?: throwable.toString())
ExceptionView(throwable)
}, text = {
if (!BuildKonfig.IS_PROD) {
val text = throwable.stackTraceToString()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.storyteller_f.a.app.compontents

import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import com.mohamedrejeb.richeditor.model.rememberRichTextState
import com.mohamedrejeb.richeditor.ui.BasicRichTextEditor
import com.storyteller_f.a.client_lib.ServerErrorException

@Composable
fun ExceptionView(throwable: Throwable) {
if (throwable is ServerErrorException) {
val state = rememberRichTextState()

LaunchedEffect(throwable.message) {
state.setHtml(throwable.text)
}

BasicRichTextEditor(state = state, readOnly = true)
} else {
Text((throwable.message ?: throwable::class.simpleName ?: throwable.toString()).take(100))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,15 @@ import androidx.compose.foundation.lazy.grid.GridCells
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
import androidx.compose.foundation.lazy.grid.items
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Clear
import androidx.compose.material.icons.filled.Topic
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
Expand Down Expand Up @@ -129,12 +131,22 @@ private fun EmojiPickerInternal(
updateQuery: (String) -> Unit,
) {
Column(modifier = Modifier.fillMaxWidth().consumeWindowInsets(WindowInsets.navigationBars)) {
Spacer(modifier = Modifier.height(10.dp))
TextField(query, {
updateQuery(it)
}, suffix = {
Icon(Icons.Default.Clear, "clear reaction query")
}, modifier = Modifier.align(Alignment.CenterHorizontally))
Spacer(modifier = Modifier.height(20.dp))
TextField(
query,
{
updateQuery(it)
},
suffix = {
Icon(Icons.Default.Clear, "clear reaction query")
},
modifier = Modifier.align(Alignment.CenterHorizontally).fillMaxWidth().padding(horizontal = 20.dp),
shape = RoundedCornerShape(10.dp),
colors = TextFieldDefaults.colors(
focusedIndicatorColor = Color.Transparent,
unfocusedIndicatorColor = Color.Transparent
)
)
Spacer(modifier = Modifier.height(10.dp))
val emojiList by produceState(emptyList<Emoji>(), query) {
value = if (query.isEmpty()) {
Expand Down
2 changes: 2 additions & 0 deletions deploy/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ services:
- LETS_ENCRYPT_CLEAR_OLD_CERTS=yes
- DISABLE_DEFAULT_SERVER=no
- USE_LIMIT_REQ=no
- SERVE_FILES=no
- INTERCEPTED_ERROR_CODES=
networks:
- bw-universe
- bw-services
Expand Down
2 changes: 2 additions & 0 deletions dev.env
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,5 @@ PRESET_WORKING_DIR='../deploy'
PRESET_SCRIPT='./flush-database-singleton.sh ../cli/build/install/cli/bin/cli ./preset_data'
PRESET_ENCRYPTED_URI=
PRESET_ENCRYPTED_PASSWORD=

REMOTE_ENCODED_CERT=
2 changes: 2 additions & 0 deletions dev.win.env
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,5 @@ PRESET_WORKING_DIR='../deploy'
PRESET_SCRIPT='./flush-database-singleton.sh ../cli/build/install/cli/bin/cli ./preset_data'
PRESET_ENCRYPTED_URI=
PRESET_ENCRYPTED_PASSWORD=

REMOTE_ENCODED_CERT=
1 change: 1 addition & 0 deletions env-filter
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,4 @@ PRESET_WORKING_DIR
PRESET_SCRIPT
PRESET_ENCRYPTED_URI
PRESET_ENCRYPTED_PASSWORD
REMOTE_ENCODED_CERT
5 changes: 5 additions & 0 deletions scripts/build_scripts/build-service-on-ci.sh
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,8 @@ done < $TEMP_FILE
mkdir -p "build/outputs/apk/release"

mv composeApp/build/outputs/apk/release/*.apk "build/outputs/apk/release/s-$FLAVOR.apk"

echo "$REMOTE_ENCODED_CERT" | base64 --decode -o remote.pem

HOST_TYPE=local \
./scripts/service_scripts/build-service.sh mini ubuntu@acommunity.link ./remote.pem "sudo bash ./start.sh"
23 changes: 17 additions & 6 deletions scripts/service_scripts/build-service.sh
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ if [ -z "$FLAVOR" ]; then
exit 1
fi

PUSH_TO_REMOTE_URI=$2
REMOTE_URI=$2
REMOTE_CERT_FILE=$3
REMOTE_COMMAND=$4

Expand All @@ -24,12 +24,14 @@ while IFS= read -r line; do
export "$key"="$value"
done <"$FLAVOR.env"

if [ -z "$PUSH_TO_REMOTE_URI" ] || [ -z "$REMOTE_CERT_FILE" ] || [ -z "$REMOTE_COMMAND" ]; then
if [ -z "$REMOTE_URI" ] || [ -z "$REMOTE_CERT_FILE" ] || [ -z "$REMOTE_COMMAND" ]; then
if [ "$HOST_TYPE" = "local" ]; then
echo "build on local"
# 在本地启动
./scripts/build_scripts/build-all-in-flavor.sh "$FLAVOR" true
"./scripts/service_scripts/start-$FLAVOR-compose.sh" false 'up -d --build'
else
echo "build on remote"
# 在远程主机上启动
# load image
docker load -i "/tmp/A/$FLAVOR.image.tar"
Expand All @@ -39,8 +41,17 @@ if [ -z "$PUSH_TO_REMOTE_URI" ] || [ -z "$REMOTE_CERT_FILE" ] || [ -z "$REMOTE_C
fi

else
./scripts/build_scripts/build-all-in-flavor.sh "$FLAVOR" true
args=$(grep -v '^#' "$FLAVOR".env | grep -v '^$' | awk -F '=' '{print "--build-arg " $1 "=\"" $2 "\""}' ORS=' ')
./scripts/tool_scripts/exec-until-success.sh docker build --platform linux/amd64 "$args" -t "a-server:latest" .
./scripts/service_scripts/start-service-on-remote.sh "$PUSH_TO_REMOTE_URI" "$REMOTE_CERT_FILE" "$REMOTE_COMMAND $FLAVOR"
echo "build for remote"
# 定义要保存的文件名
FILE="build/images/$FLAVOR.image.tar"

# 检查文件是否存在
if [ ! -f "$FILE" ]; then
./scripts/build_scripts/build-all-in-flavor.sh "$FLAVOR" true
args=$(grep -v '^#' "$FLAVOR".env | grep -v '^$' | awk -F '=' '{print "--build-arg " $1 "=\"" $2 "\""}' ORS=' ')
./scripts/tool_scripts/exec-until-success.sh docker build --platform linux/amd64 "$args" -t "a-server:latest" .
else
echo "$FILE already exists. Skipping docker image build."
fi
./scripts/service_scripts/start-service-on-remote.sh "$REMOTE_URI" "$REMOTE_CERT_FILE" "$REMOTE_COMMAND $FLAVOR"
fi
44 changes: 24 additions & 20 deletions scripts/service_scripts/start-service-on-remote.sh
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
#!/bin/bash
set -e
PUSH_TO_REMOTE_URI=$1
REMOTE_URI=$1
REMOTE_CERT_FILE=$2
REMOTE_COMMAND=$3
if [ -z "$PUSH_TO_REMOTE_URI" ] || [ -z "$REMOTE_CERT_FILE" ]; then
echo "PUSH_TO_REMOTE_URI and REMOTE_CERT_FILE must be set"
if [ -z "$REMOTE_URI" ] || [ -z "$REMOTE_CERT_FILE" ] || [ -z "$REMOTE_COMMAND" ]; then
echo "REMOTE_URI, REMOTE_COMMAND and REMOTE_CERT_FILE must be set"
exit 1
fi

Expand All @@ -22,24 +22,28 @@ else
echo "$FILE already exists. Skipping docker save."
fi

./scripts/tool_scripts/exec-until-success.sh ssh -i "$REMOTE_CERT_FILE" -p 422 "$PUSH_TO_REMOTE_URI" "mkdir -p a-server && mkdir -p /tmp/A"
./scripts/tool_scripts/exec-until-success.sh ssh -i "$REMOTE_CERT_FILE" -p 422 "$REMOTE_URI" "mkdir -p a-server && mkdir -p /tmp/A"
sleep 2

md=$(md5sum "$FILE" | awk '{print $1}')
#mdRemote=$(ssh -i ~/Downloads/default.pem -p 422 ubuntu@54.153.231.70 "md5sum ./a-server/$FLAVOR.image.tar | awk '{print \$1}'")
#echo "local: $md remote: $mdRemote"
echo "put $FILE ./a-server/$FLAVOR.image.tar" | sftp -i "$REMOTE_CERT_FILE" -P 422 "$PUSH_TO_REMOTE_URI"
sleep 2

# 验证上传的文件完整性
ssh -i "$REMOTE_CERT_FILE" -p 422 "$PUSH_TO_REMOTE_URI" "echo ""$md" "./a-server/$FLAVOR.image.tar"" | md5sum -c -"
sleep 2

./scripts/tool_scripts/exec-until-success.sh ssh -i "$REMOTE_CERT_FILE" -p 422 "$PUSH_TO_REMOTE_URI" "cp ./a-server/$FLAVOR.image.tar /tmp/A/$FLAVOR.image.tar"
sleep 2

# 验证上传的文件完整性
ssh -i "$REMOTE_CERT_FILE" -p 422 "$PUSH_TO_REMOTE_URI" "echo ""$md" "/tmp/A/$FLAVOR.image.tar"" | md5sum -c -"
sleep 2
mdRemote=$(ssh -i ~/Downloads/default.pem -p 422 ubuntu@54.153.231.70 "md5sum ./a-server/$FLAVOR.image.tar | awk '{print \$1}'")
echo "local: $md remote: $mdRemote"
if [ "$md" != "$mdRemote" ]; then
echo "put $FILE ./a-server/$FLAVOR.image.tar" | sftp -i "$REMOTE_CERT_FILE" -P 422 "$REMOTE_URI"
sleep 2

# 验证上传的文件完整性
ssh -i "$REMOTE_CERT_FILE" -p 422 "$REMOTE_URI" "echo ""$md" "./a-server/$FLAVOR.image.tar"" | md5sum -c -"
sleep 2

./scripts/tool_scripts/exec-until-success.sh ssh -i "$REMOTE_CERT_FILE" -p 422 "$REMOTE_URI" "cp ./a-server/$FLAVOR.image.tar /tmp/A/$FLAVOR.image.tar"
sleep 2

# 验证上传的文件完整性
ssh -i "$REMOTE_CERT_FILE" -p 422 "$REMOTE_URI" "echo ""$md" "/tmp/A/$FLAVOR.image.tar"" | md5sum -c -"
sleep 2
else
echo "docker image same, skip upload."
fi

./scripts/tool_scripts/exec-until-success.sh ssh -i "$REMOTE_CERT_FILE" -p 422 "$PUSH_TO_REMOTE_URI" "$REMOTE_COMMAND"
./scripts/tool_scripts/exec-until-success.sh ssh -i "$REMOTE_CERT_FILE" -p 422 "$REMOTE_URI" "$REMOTE_COMMAND"
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import com.storyteller_f.a.server.service.reactionList
import com.storyteller_f.a.server.service.recommendTopics
import com.storyteller_f.a.server.service.searchPublicTopics
import com.storyteller_f.shared.model.TopicInfo
import com.storyteller_f.shared.obj.NewReaction
import com.storyteller_f.shared.type.ObjectType
import com.storyteller_f.shared.type.PrimaryKey
import com.storyteller_f.tables.deleteReaction
Expand Down Expand Up @@ -77,7 +78,7 @@ fun Route.bindProtectedSafeTopicRoute(backend: Backend) {

post<RouteTopics.Id.Reactions> {
usePrincipal { id ->
val emoji = call.receive<String>()
val emoji = call.receive<NewReaction>().emoji
if (EmojiReader.getTextLength(emoji) == 1 && EmojiReader.isEmojiOfCharIndex(emoji, 0)) {
addReaction(id, it.parent.id, emoji)
} else {
Expand All @@ -88,7 +89,7 @@ fun Route.bindProtectedSafeTopicRoute(backend: Backend) {

post<RouteReactions.Delete> {
usePrincipal { id ->
val emoji = call.receive<String>()
val emoji = call.receive<NewReaction>().emoji
if (EmojiReader.getTextLength(emoji) == 1 && EmojiReader.isEmojiOfCharIndex(emoji, 0)) {
deleteReaction(id, emoji)
} else {
Expand Down
10 changes: 1 addition & 9 deletions server/src/test/kotlin/CommunityTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -111,20 +111,12 @@ class CommunityTest {
@Test
fun `test hmac`() {
runBlocking {
val backend = buildBackendFromEnv(readEnv())
val hmacKey = backend.config.hmacKey
val hmacKey = newHmacSha512()
val s = hmacSign(hmacKey, "text")
assertTrue(hmacVerify(hmacKey, s, "text"))
}
}

@Test
fun `test generate hmac key`() {
runBlocking {
println(newHmacSha512())
}
}

@Test
fun `test search community`() {
test { client ->
Expand Down
Loading

0 comments on commit 40a9eba

Please sign in to comment.