Проработаны операции с API сценария

Этот коммит содержится в:
Глеб Иваницкий 2024-08-29 18:05:59 +03:00
родитель a17736db9d
Коммит 829d41a70a
2 изменённых файлов: 113 добавлений и 29 удалений

Просмотреть файл

@ -57,6 +57,8 @@ import cit_is_bot.composeapp.generated.resources.baseline_title_24
import cit_is_bot.composeapp.generated.resources.outline_adjust_24 import cit_is_bot.composeapp.generated.resources.outline_adjust_24
import cit_is_bot.composeapp.generated.resources.outline_time_auto_24 import cit_is_bot.composeapp.generated.resources.outline_time_auto_24
import io.ktor.client.HttpClient import io.ktor.client.HttpClient
import io.ktor.client.request.delete
import io.ktor.client.request.post
import io.ktor.client.request.put import io.ktor.client.request.put
import io.ktor.client.request.setBody import io.ktor.client.request.setBody
import io.ktor.http.ContentType import io.ktor.http.ContentType
@ -87,7 +89,7 @@ enum class MessageType(
fun ScenarioDialog( fun ScenarioDialog(
scenarioDialogState: MutableState<Scenario?>, scenarioDialogState: MutableState<Scenario?>,
client: HttpClient, client: HttpClient,
onSuccess: () -> Unit, onSuccess: (message: String) -> Unit,
properties: DialogProperties = DialogProperties( properties: DialogProperties = DialogProperties(
usePlatformDefaultWidth = false, usePlatformDefaultWidth = false,
), ),
@ -155,6 +157,22 @@ fun ScenarioDialog(
scenarioDialogState.value?.name = nameState.value!! scenarioDialogState.value?.name = nameState.value!!
coroutine.launch { coroutine.launch {
progressIndicatorState.value = true progressIndicatorState.value = true
when(scenarioDialogState.value!!.id) {
null -> {
val url = URLBuilder(
protocol = URLProtocol.HTTPS,
host = "cit.csasq.ru",
pathSegments = listOf(
"api",
"scripts",
),
)
client.post(url.build()) {
contentType(ContentType.Application.Json)
setBody(scenarioDialogState.value)
}
}
else -> {
val url = URLBuilder( val url = URLBuilder(
protocol = URLProtocol.HTTPS, protocol = URLProtocol.HTTPS,
host = "cit.csasq.ru", host = "cit.csasq.ru",
@ -162,20 +180,23 @@ fun ScenarioDialog(
"api", "api",
"scripts", "scripts",
scenarioDialogState.value!!.id.toString(), scenarioDialogState.value!!.id.toString(),
),
) )
) client.put(url.build()) {
val response = client.put(url.build()) {
contentType(ContentType.Application.Json) contentType(ContentType.Application.Json)
setBody(scenarioDialogState.value) setBody(scenarioDialogState.value)
} }
}
}.also { response ->
progressIndicatorState.value = false progressIndicatorState.value = false
when (response.status) { when (response.status) {
HttpStatusCode.Created -> { HttpStatusCode.Created -> {
onSuccess() onSuccess("Сценарий сохранен")
scenarioDialogState.value = null scenarioDialogState.value = null
} }
} }
} }
}
}, },
) { ) {
Text( Text(
@ -209,7 +230,30 @@ fun ScenarioDialog(
) )
}, },
onClick = { onClick = {
coroutine.launch {
dropdownMenuState.value = false dropdownMenuState.value = false
progressIndicatorState.value = true
val url = URLBuilder(
protocol = URLProtocol.HTTPS,
host = "cit.csasq.ru",
pathSegments = listOf(
"api",
"scripts",
scenarioDialogState.value!!.id.toString(),
)
)
val response = client.delete(url.build()) {
contentType(ContentType.Application.Json)
setBody(scenarioDialogState.value)
}
progressIndicatorState.value = false
when (response.status) {
HttpStatusCode.NoContent -> {
onSuccess("Сценарий удален")
scenarioDialogState.value = null
}
}
}
}, },
) )
} }

Просмотреть файл

@ -27,11 +27,18 @@ import cit_is_bot.composeapp.generated.resources.baseline_add_24
import io.ktor.client.HttpClient import io.ktor.client.HttpClient
import io.ktor.client.call.body import io.ktor.client.call.body
import io.ktor.client.plugins.contentnegotiation.ContentNegotiation import io.ktor.client.plugins.contentnegotiation.ContentNegotiation
import io.ktor.client.plugins.websocket.WebSockets
import io.ktor.client.plugins.websocket.receiveDeserialized
import io.ktor.client.plugins.websocket.webSocket
import io.ktor.client.request.get import io.ktor.client.request.get
import io.ktor.http.HttpStatusCode import io.ktor.http.HttpStatusCode
import io.ktor.http.URLBuilder
import io.ktor.http.URLProtocol
import io.ktor.serialization.kotlinx.KotlinxWebsocketSerializationConverter
import io.ktor.serialization.kotlinx.json.json import io.ktor.serialization.kotlinx.json.json
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import kotlinx.serialization.json.Json
import org.jetbrains.compose.resources.painterResource import org.jetbrains.compose.resources.painterResource
import ru.csasq.cit_is_bot.ui.components.SwitchButton import ru.csasq.cit_is_bot.ui.components.SwitchButton
import ru.csasq.cit_is_bot.ui.dialogs.ScenarioDialog import ru.csasq.cit_is_bot.ui.dialogs.ScenarioDialog
@ -45,6 +52,12 @@ data class Scenario(
var isEnabled: Boolean, var isEnabled: Boolean,
) )
@Serializable
data class WebSocketAction(
val action: String,
val target: Scenario,
)
@Composable @Composable
fun ScenariosScreen( fun ScenariosScreen(
navController: NavController, navController: NavController,
@ -53,6 +66,8 @@ fun ScenariosScreen(
snackbarHostState: SnackbarHostState, snackbarHostState: SnackbarHostState,
floatingActionButtonState: MutableState<(@Composable () -> Unit)?>, floatingActionButtonState: MutableState<(@Composable () -> Unit)?>,
) { ) {
val webSocketCoroutineScope = rememberCoroutineScope()
val httpRequestCoroutineScope = rememberCoroutineScope()
val snackbarCoroutineScope = rememberCoroutineScope() val snackbarCoroutineScope = rememberCoroutineScope()
val verticalScrollState = rememberScrollState() val verticalScrollState = rememberScrollState()
val floatingActionButtonExpandedState = remember { val floatingActionButtonExpandedState = remember {
@ -71,24 +86,49 @@ fun ScenariosScreen(
mutableStateListOf<Scenario>() mutableStateListOf<Scenario>()
} }
val client = HttpClient { val client = HttpClient {
install(WebSockets) {
contentConverter = KotlinxWebsocketSerializationConverter(Json)
}
install(ContentNegotiation) { install(ContentNegotiation) {
json() json()
} }
// install(WebSockets) {
// contentConverter = KotlinxWebsocketSerializationConverter(Json)
// }
} }
LaunchedEffect(false) { LaunchedEffect(false) {
client.launch { webSocketCoroutineScope.launch {
val url = URLBuilder(
protocol = URLProtocol.WSS,
host = "cit.csasq.ru",
pathSegments = listOf(
"ws",
),
)
client.webSocket(url.buildString()) {
while (true) {
val webSocketAction = receiveDeserialized<WebSocketAction>()
val scenarioIndex = scenarioList.indexOfFirst { scenario ->
scenario.id == webSocketAction.target.id
}
when (webSocketAction.action) {
"insert" -> {
scenarioList.add(webSocketAction.target)
}
"update" -> {
scenarioList[scenarioIndex] = webSocketAction.target
}
"delete" -> {
scenarioList.removeAt(scenarioIndex)
}
}
}
}
}
httpRequestCoroutineScope.launch {
progressIndicatorState.value = true progressIndicatorState.value = true
val response = client.get("https://cit.csasq.ru/api/scripts") val response = client.get("https://cit.csasq.ru/api/scripts")
progressIndicatorState.value = false progressIndicatorState.value = false
when (response.status) { when (response.status) {
HttpStatusCode.OK -> scenarioList.addAll(response.body()) HttpStatusCode.OK -> scenarioList.addAll(response.body())
} }
// client.webSocket("wss://cit.csasq.ru/ws/scripts") {
// scenarioList.addAll(receiveDeserialized<List<Scenario>>())
// }
} }
} }
Column( Column(
@ -155,10 +195,10 @@ fun ScenariosScreen(
ScenarioDialog( ScenarioDialog(
scenarioDialogState = scenarioDialogState, scenarioDialogState = scenarioDialogState,
client = client, client = client,
onSuccess = { onSuccess = { message ->
snackbarCoroutineScope.launch { snackbarCoroutineScope.launch {
snackbarHostState.showSnackbar( snackbarHostState.showSnackbar(
message = "Сценарий сохранен", message = message,
duration = SnackbarDuration.Short, duration = SnackbarDuration.Short,
) )
} }