From 0e7bc87cde421640fcd651d716591ae7e93759c0 Mon Sep 17 00:00:00 2001 From: Thomas Andres Gomez Date: Sun, 30 Mar 2025 18:25:27 +0200 Subject: [PATCH] Server : Campaign error management --- .../lwa/model/campaign/CampaignService.kt | 268 +++++------------- .../lwa/model/campaign/CampaignStore.kt | 60 ++-- .../rest/alteration/DELETE_Alteration.kt | 11 +- .../server/rest/alteration/PUT_Alateration.kt | 7 - .../campaign/DELETE_Campaign_Character.kt | 31 +- .../rest/campaign/DELETE_Campaign_Npc.kt | 31 +- .../lwa/server/rest/campaign/GET_Campaign.kt | 16 +- .../rest/campaign/PUT_Campaign_Character.kt | 33 ++- .../server/rest/campaign/PUT_Campaign_Npc.kt | 33 ++- .../rest/campaign/PUT_Campaign_Scene_Name.kt | 29 +- .../server/rest/character/DELETE_Character.kt | 5 - .../rest/{PutResultJson.kt => ResultJson.kt} | 7 +- 12 files changed, 222 insertions(+), 309 deletions(-) rename shared/src/commonMain/kotlin/com/pixelized/shared/lwa/protocol/rest/{PutResultJson.kt => ResultJson.kt} (78%) diff --git a/server/src/main/kotlin/com/pixelized/server/lwa/model/campaign/CampaignService.kt b/server/src/main/kotlin/com/pixelized/server/lwa/model/campaign/CampaignService.kt index d57577d..105df98 100644 --- a/server/src/main/kotlin/com/pixelized/server/lwa/model/campaign/CampaignService.kt +++ b/server/src/main/kotlin/com/pixelized/server/lwa/model/campaign/CampaignService.kt @@ -37,223 +37,95 @@ class CampaignService( return campaignJsonFlow.value } + @Throws fun addCharacter( characterSheetId: String, - ): Boolean { - // check if the character is already in the campaign. - if (campaign.characters.contains(characterSheetId)) return false - // update the corresponding instance - val characters = campaign.characters.toMutableSet().also { it.add(characterSheetId) } - // save the campaign to the disk (update the flow). - return try { - store.save( - campaign = campaign.copy(characters = characters) - ) - true - } catch (exception: Exception) { - false + ) { + // Check if the character is already in the campaign. + if (campaign.instances.contains(characterSheetId)) { + val root = Exception("Character with id:$characterSheetId is already in the campaign.") + throw CampaignStore.BusinessException(root = root) } - } - - suspend fun addNpc( - characterSheetId: String, - ): Boolean { - // check if the character is already in the campaign. - if (campaign.npcs.contains(characterSheetId)) return false - // update the corresponding instance - val characters = campaign.npcs.toMutableSet().also { it.add(characterSheetId) } - // save the campaign to the disk (update the flow). - return try { - store.save( - campaign = campaign.copy(npcs = characters) - ) - true - } catch (exception: Exception) { - false + // Update the corresponding instance + val characters = campaign.characters.toMutableSet().also { + it.add(characterSheetId) } + // Save the campaign to the disk (update the flow). + store.save( + campaign = campaign.copy(characters = characters) + ) } - suspend fun removeCharacter( + @Throws + fun addNpc( characterSheetId: String, - ): Boolean { - // check if the character is in the campaign. - if (campaign.characters.contains(characterSheetId).not()) return false - // update the corresponding instance - val characters = campaign.characters.toMutableSet().also { it.remove(characterSheetId) } - // save the campaign to the disk + update the flow. - return try { - store.save( - campaign = campaign.copy(characters = characters) - ) - true - } catch (exception: Exception) { - false + ) { + // Check if the character is already in the campaign. + if (campaign.instances.contains(characterSheetId)) { + val root = Exception("Character with id:$characterSheetId is already in the campaign.") + throw CampaignStore.BusinessException(root = root) } - } - - suspend fun removeNpc( - characterSheetId: String, - ): Boolean { - // check if the character is in the campaign. - if (campaign.npcs.contains(characterSheetId).not()) return false - // update the corresponding instance - val characters = campaign.npcs.toMutableSet().also { it.remove(characterSheetId) } - // save the campaign to the disk + update the flow. - return try { - store.save( - campaign = campaign.copy(npcs = characters) - ) - true - } catch (exception: Exception) { - false + // Update the corresponding instance + val characters = campaign.npcs.toMutableSet().also { + it.add(characterSheetId) } + // Save the campaign to the disk (update the flow). + store.save( + campaign = campaign.copy(npcs = characters) + ) } - suspend fun removeInstance( + @Throws + fun removeCharacter( characterSheetId: String, - ): Boolean { - return removeCharacter(characterSheetId) || removeNpc(characterSheetId) + ) { + // Check if the character is in the campaign. + if (campaign.characters.contains(characterSheetId).not()) { + val root = Exception("Character with id:$characterSheetId is not in the party.") + throw CampaignStore.BusinessException(root = root) + } + // Update the corresponding instance + val characters = campaign.characters.toMutableSet().also { + it.remove(characterSheetId) + } + // Save the campaign to the disk + update the flow. + store.save( + campaign = campaign.copy(characters = characters) + ) } - suspend fun setScene( + @Throws + fun removeNpc( + characterSheetId: String, + ) { + // Check if the character is in the campaign. + if (campaign.npcs.contains(characterSheetId).not()) { + val root = Exception("Character with id:$characterSheetId is not in the npcs.") + throw CampaignStore.BusinessException(root = root) + } + // Update the corresponding instance + val characters = campaign.npcs.toMutableSet().also { + it.remove(characterSheetId) + } + // Save the campaign to the disk + update the flow. + store.save( + campaign = campaign.copy(npcs = characters) + ) + } + + @Throws + fun setScene( scene: Campaign.Scene, - ): Boolean { + ) { // save the campaign to the disk + update the flow. - return try { - store.save( - campaign.copy(scene = scene) - ) - true - } catch (exception: Exception) { - false - } + store.save( + campaign = campaign.copy(scene = scene) + ) } // Data manipulation through WebSocket. -// suspend fun updateCharacteristic( -// characterInstanceId: Campaign.CharacterInstance.Id, -// characteristic: Campaign.CharacterInstance.Characteristic, -// value: Int, -// ) { -// when (characterInstanceId.prefix) { -// Campaign.CharacterInstance.Id.PLAYER -> { -// // fetch all the current campaign character -// val characters = campaign.characters.toMutableMap() -// // update the corresponding character using the use case. -// characters[characterInstanceId] = useCase.updateCharacteristic( -// instance = campaign.character(id = characterInstanceId), -// characteristic = characteristic, -// value = value, -// ) -// // save the campaign to the disk + update the flow. -// store.save( -// campaign = campaign.copy(characters = characters) -// ) -// } -// -// Campaign.CharacterInstance.Id.NPC -> { -// // fetch all the current campaign character -// val npcs = campaign.npcs.toMutableMap() -// // update the corresponding character using the use case. -// npcs[characterInstanceId] = useCase.updateCharacteristic( -// instance = campaign.npc(id = characterInstanceId), -// characteristic = characteristic, -// value = value, -// ) -// // save the campaign to the disk + update the flow. -// store.save( -// campaign = campaign.copy(npcs = npcs) -// ) -// } -// } -// } -// -// suspend fun updateDiminished( -// characterInstanceId: Campaign.CharacterInstance.Id, -// diminished: Int, -// ) { -// when (characterInstanceId.prefix) { -// Campaign.CharacterInstance.Id.PLAYER -> { -// // fetch all the current campaign character -// val characters = campaign.characters.toMutableMap() -// // update the corresponding character using the use case. -// characters[characterInstanceId] = useCase.updateDiminished( -// instance = campaign.character(id = characterInstanceId), -// diminished = diminished, -// ) -// // save the campaign to the disk + update the flow. -// store.save( -// campaign = campaign.copy(characters = characters) -// ) -// } -// -// Campaign.CharacterInstance.Id.NPC -> { -// // fetch all the current campaign character -// val npcs = campaign.npcs.toMutableMap() -// // update the corresponding character using the use case. -// npcs[characterInstanceId] = useCase.updateDiminished( -// instance = campaign.npc(id = characterInstanceId), -// diminished = diminished, -// ) -// // save the campaign to the disk + update the flow. -// store.save( -// campaign = campaign.copy(npcs = npcs) -// ) -// } -// } -// } -// -// suspend fun toggleAlteration( -// characterInstanceId: Campaign.CharacterInstance.Id, -// alterationId: String, -// ) { -// when (characterInstanceId.prefix) { -// Campaign.CharacterInstance.Id.PLAYER -> { -// // fetch all the current campaign character -// val characters = campaign.characters.toMutableMap() -// // update the corresponding character alterations -// characters[characterInstanceId]?.let { character -> -// characters[characterInstanceId] = character.copy( -// alterations = character.alterations.toMutableList().also { alterations -> -// if (alterations.contains(alterationId)) { -// alterations.remove(alterationId) -// } else { -// alterations.add(alterationId) -// } -// }, -// ) -// } -// // save the campaign to the disk + update the flow. -// store.save( -// campaign = campaign.copy(characters = characters) -// ) -// } -// -// Campaign.CharacterInstance.Id.NPC -> { -// // fetch all the current campaign character -// val characters = campaign.npcs.toMutableMap() -// // update the corresponding character alterations -// characters[characterInstanceId]?.let { character -> -// characters[characterInstanceId] = character.copy( -// alterations = character.alterations.toMutableList().also { alterations -> -// if (alterations.contains(alterationId)) { -// alterations.remove(alterationId) -// } else { -// alterations.add(alterationId) -// } -// }, -// ) -// } -// // save the campaign to the disk + update the flow. -// store.save( -// campaign = campaign.copy(npcs = characters) -// ) -// } -// } -// } - - suspend fun updateToggleParty() { + fun updateToggleParty() { store.save( campaign = campaign.copy( options = campaign.options.copy( @@ -263,7 +135,7 @@ class CampaignService( ) } - suspend fun updateToggleNpc() { + fun updateToggleNpc() { store.save( campaign = campaign.copy( options = campaign.options.copy( diff --git a/server/src/main/kotlin/com/pixelized/server/lwa/model/campaign/CampaignStore.kt b/server/src/main/kotlin/com/pixelized/server/lwa/model/campaign/CampaignStore.kt index e81062f..16fd568 100644 --- a/server/src/main/kotlin/com/pixelized/server/lwa/model/campaign/CampaignStore.kt +++ b/server/src/main/kotlin/com/pixelized/server/lwa/model/campaign/CampaignStore.kt @@ -1,5 +1,6 @@ package com.pixelized.server.lwa.model.campaign +import com.pixelized.server.lwa.model.alteration.AlterationStore.AlterationStoreException import com.pixelized.shared.lwa.model.campaign.Campaign import com.pixelized.shared.lwa.model.campaign.CampaignJson import com.pixelized.shared.lwa.model.campaign.factory.CampaignJsonFactory @@ -9,6 +10,7 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch import kotlinx.serialization.json.Json import java.io.File @@ -27,15 +29,15 @@ class CampaignStore( val scope = CoroutineScope(Dispatchers.IO + Job()) // load the initial data scope.launch { - updateCampaignFromDisk() + updateCampaignFlow() } } fun campaignFlow(): StateFlow = campaignFlow - private fun updateCampaignFromDisk() { + private fun updateCampaignFlow() { campaignFlow.value = try { - loadCampaign() + load() } catch (exception: Exception) { println(exception) // TODO proper exception handling Campaign.empty() @@ -44,60 +46,74 @@ class CampaignStore( @Throws( FileReadException::class, + JsonCodingException::class, JsonConversionException::class, ) - fun loadCampaign(): Campaign { - val file = file() - val json = try { + fun load(): Campaign { + val file = campaignFile() + // Read the campaign file. + val data = try { file.readText(charset = Charsets.UTF_8) } catch (exception: Exception) { throw FileReadException(root = exception) } - // Guard, if the file is empty we load a default campaign. - if (json.isBlank()) return Campaign.empty() - + if (data.isBlank()) return Campaign.empty() + // Decode the json into a string. + val json = try { + this.json.decodeFromString(data) + } catch (exception: Exception) { + throw JsonCodingException(root = exception) + } + // Convert from the Json format val campaign = try { - val data = this.json.decodeFromString(json) - factory.convertFromJson(data) + factory.convertFromJson(json) } catch (exception: Exception) { throw JsonConversionException(root = exception) } - return campaign } @Throws( JsonConversionException::class, + JsonCodingException::class, FileWriteException::class, ) fun save(campaign: Campaign) { - // convert the data to json format + // Transform the json into the model. val json = try { - factory.convertToJson(campaign = campaign).let(json::encodeToString) + factory.convertToJson(campaign = campaign) } catch (exception: Exception) { throw JsonConversionException(root = exception) } - // write the file + // Encode the json into a string. + val data = try { + this.json.encodeToString(json) + } catch (exception: Exception) { + throw JsonCodingException(root = exception) + } + // Write the file try { - val file = file() + val file = campaignFile() file.writeText( - text = json, + text = data, charset = Charsets.UTF_8, ) } catch (exception: Exception) { throw FileWriteException(root = exception) } // Update the dataflow. - campaignFlow.value = campaign + campaignFlow.update { campaign } + } + + private fun campaignFile(): File { + return File("${pathProvider.campaignPath()}campaign.json") } sealed class CampaignStoreException(root: Exception) : Exception(root) class JsonConversionException(root: Exception) : CampaignStoreException(root) + class JsonCodingException(root: Exception) : CampaignStoreException(root) + class BusinessException(root: Exception) : CampaignStoreException(root) class FileWriteException(root: Exception) : CampaignStoreException(root) class FileReadException(root: Exception) : CampaignStoreException(root) - - private fun file(): File { - return File("${pathProvider.campaignPath()}campaign.json") - } } \ No newline at end of file diff --git a/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/alteration/DELETE_Alteration.kt b/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/alteration/DELETE_Alteration.kt index 99fa222..0652f60 100644 --- a/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/alteration/DELETE_Alteration.kt +++ b/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/alteration/DELETE_Alteration.kt @@ -11,11 +11,13 @@ import io.ktor.server.response.respond fun Engine.deleteAlteration(): suspend io.ktor.server.routing.RoutingContext.() -> Unit { return { try { + // get the query parameter val alterationId = call.parameters.alterationId - + // delete the alteration. alterationService.delete( alterationId = alterationId ) + // API & WebSocket responses. call.respond( message = ResultJson.Success(), ) @@ -32,13 +34,6 @@ fun Engine.deleteAlteration(): suspend io.ktor.server.routing.RoutingContext.() message = exception.message ?: "?", ) ) - } catch (exception: AlterationStore.BusinessException) { - call.respond( - message = ResultJson.Error( - status = ResultJson.Error.FILE_DOES_NOT_EXIST, - message = "Alteration doesn't exist." - ) - ) } catch (exception: Exception) { call.respond( message = ResultJson.Error( diff --git a/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/alteration/PUT_Alateration.kt b/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/alteration/PUT_Alateration.kt index 141c60c..c8bed66 100644 --- a/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/alteration/PUT_Alateration.kt +++ b/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/alteration/PUT_Alateration.kt @@ -36,13 +36,6 @@ fun Engine.putAlteration(): suspend io.ktor.server.routing.RoutingContext.() -> message = exception.message ?: "?", ) ) - } catch (exception: AlterationStore.BusinessException) { - call.respond( - message = ResultJson.Error( - status = ResultJson.Error.FILE_ALREADY_EXIST, - message = "Alteration file already exist." - ) - ) } catch (exception: Exception) { call.respond( message = ResultJson.Error( diff --git a/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/campaign/DELETE_Campaign_Character.kt b/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/campaign/DELETE_Campaign_Character.kt index 42bf910..e73e688 100644 --- a/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/campaign/DELETE_Campaign_Character.kt +++ b/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/campaign/DELETE_Campaign_Character.kt @@ -1,10 +1,11 @@ package com.pixelized.server.lwa.server.rest.campaign import com.pixelized.server.lwa.server.Engine +import com.pixelized.server.lwa.utils.extentions.MissingParameterException import com.pixelized.server.lwa.utils.extentions.characterSheetId +import com.pixelized.shared.lwa.protocol.rest.ResultJson import com.pixelized.shared.lwa.protocol.websocket.CampaignEvent -import io.ktor.http.HttpStatusCode -import io.ktor.server.response.respondText +import io.ktor.server.response.respond fun Engine.removeCampaignCharacter(): suspend io.ktor.server.routing.RoutingContext.() -> Unit { return { @@ -12,17 +13,12 @@ fun Engine.removeCampaignCharacter(): suspend io.ktor.server.routing.RoutingCont // get the query parameter val characterSheetId = call.queryParameters.characterSheetId // remove the character form the party - val updated = campaignService.removeCharacter( + campaignService.removeCharacter( characterSheetId = characterSheetId, ) - // error case - if (updated.not()) { - error("Unexpected error when removing character (characterSheetId:$characterSheetId) from party.") - } // API & WebSocket responses - call.respondText( - text = "${HttpStatusCode.OK}", - status = HttpStatusCode.OK, + call.respond( + message = ResultJson.Success(), ) webSocket.emit( value = CampaignEvent.CharacterRemoved( @@ -30,10 +26,19 @@ fun Engine.removeCampaignCharacter(): suspend io.ktor.server.routing.RoutingCont characterSheetId = characterSheetId, ) ) + } catch (exception: MissingParameterException) { + call.respond( + message = ResultJson.Error( + status = exception.errorCode, + message = exception.message ?: "?", + ) + ) } catch (exception: Exception) { - call.respondText( - text = exception.localizedMessage, - status = HttpStatusCode.UnprocessableEntity, + call.respond( + message = ResultJson.Error( + status = ResultJson.Error.GENERIC, + message = exception.message ?: "?", + ) ) } } diff --git a/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/campaign/DELETE_Campaign_Npc.kt b/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/campaign/DELETE_Campaign_Npc.kt index fadfbd0..8a85c97 100644 --- a/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/campaign/DELETE_Campaign_Npc.kt +++ b/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/campaign/DELETE_Campaign_Npc.kt @@ -1,9 +1,12 @@ package com.pixelized.server.lwa.server.rest.campaign import com.pixelized.server.lwa.server.Engine +import com.pixelized.server.lwa.utils.extentions.MissingParameterException import com.pixelized.server.lwa.utils.extentions.characterSheetId +import com.pixelized.shared.lwa.protocol.rest.ResultJson import com.pixelized.shared.lwa.protocol.websocket.CampaignEvent import io.ktor.http.HttpStatusCode +import io.ktor.server.response.respond import io.ktor.server.response.respondText fun Engine.removeCampaignNpc(): suspend io.ktor.server.routing.RoutingContext.() -> Unit { @@ -12,15 +15,12 @@ fun Engine.removeCampaignNpc(): suspend io.ktor.server.routing.RoutingContext.() // get the query parameter val characterSheetId = call.queryParameters.characterSheetId // remove the character form the party - val updated = campaignService.removeNpc(characterSheetId = characterSheetId) - // error case - if (updated.not()) { - error("Unexpected error when removing character (characterSheetId:$characterSheetId) from npcs.") - } + campaignService.removeNpc( + characterSheetId = characterSheetId, + ) // API & WebSocket responses - call.respondText( - text = "${HttpStatusCode.OK}", - status = HttpStatusCode.OK, + call.respond( + message = ResultJson.Success(), ) webSocket.emit( value = CampaignEvent.NpcRemoved( @@ -28,10 +28,19 @@ fun Engine.removeCampaignNpc(): suspend io.ktor.server.routing.RoutingContext.() characterSheetId = characterSheetId, ) ) + } catch (exception: MissingParameterException) { + call.respond( + message = ResultJson.Error( + status = exception.errorCode, + message = exception.message ?: "?", + ) + ) } catch (exception: Exception) { - call.respondText( - text = exception.localizedMessage, - status = HttpStatusCode.UnprocessableEntity, + call.respond( + message = ResultJson.Error( + status = ResultJson.Error.GENERIC, + message = exception.message ?: "?", + ) ) } } diff --git a/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/campaign/GET_Campaign.kt b/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/campaign/GET_Campaign.kt index 13bf259..135c559 100644 --- a/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/campaign/GET_Campaign.kt +++ b/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/campaign/GET_Campaign.kt @@ -1,12 +1,22 @@ package com.pixelized.server.lwa.server.rest.campaign import com.pixelized.server.lwa.server.Engine +import com.pixelized.shared.lwa.protocol.rest.ResultJson import io.ktor.server.response.respond fun Engine.getCampaign(): suspend io.ktor.server.routing.RoutingContext.() -> Unit { return { - call.respond( - message = campaignService.campaignJson(), - ) + try { + call.respond( + message = campaignService.campaignJson(), + ) + } catch (exception: Exception) { + call.respond( + message = ResultJson.Error( + status = ResultJson.Error.GENERIC, + message = exception.message ?: "?", + ) + ) + } } } \ No newline at end of file diff --git a/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/campaign/PUT_Campaign_Character.kt b/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/campaign/PUT_Campaign_Character.kt index 1c5a381..fea4532 100644 --- a/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/campaign/PUT_Campaign_Character.kt +++ b/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/campaign/PUT_Campaign_Character.kt @@ -1,10 +1,11 @@ package com.pixelized.server.lwa.server.rest.campaign import com.pixelized.server.lwa.server.Engine +import com.pixelized.server.lwa.utils.extentions.MissingParameterException import com.pixelized.server.lwa.utils.extentions.characterSheetId +import com.pixelized.shared.lwa.protocol.rest.ResultJson import com.pixelized.shared.lwa.protocol.websocket.CampaignEvent -import io.ktor.http.HttpStatusCode -import io.ktor.server.response.respondText +import io.ktor.server.response.respond fun Engine.putCampaignCharacter(): suspend io.ktor.server.routing.RoutingContext.() -> Unit { return { @@ -12,15 +13,12 @@ fun Engine.putCampaignCharacter(): suspend io.ktor.server.routing.RoutingContext // get the query parameter val characterSheetId = call.queryParameters.characterSheetId // add the character to the party. - val update = campaignService.addCharacter(characterSheetId = characterSheetId) - // error case - if (update.not()) { - error("Unexpected error occurred when the character instance was added to the party") - } + campaignService.addCharacter( + characterSheetId = characterSheetId, + ) // API & WebSocket responses. - call.respondText( - text = "Character $characterSheetId successfully added to the party", - status = HttpStatusCode.OK, + call.respond( + message = ResultJson.Success(), ) webSocket.emit( value = CampaignEvent.CharacterAdded( @@ -28,10 +26,19 @@ fun Engine.putCampaignCharacter(): suspend io.ktor.server.routing.RoutingContext characterSheetId = characterSheetId, ) ) + } catch (exception: MissingParameterException) { + call.respond( + message = ResultJson.Error( + status = exception.errorCode, + message = exception.message ?: "?", + ) + ) } catch (exception: Exception) { - call.respondText( - text = "${exception.message}", - status = HttpStatusCode.UnprocessableEntity, + call.respond( + message = ResultJson.Error( + status = ResultJson.Error.GENERIC, + message = exception.message ?: "?", + ) ) } } diff --git a/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/campaign/PUT_Campaign_Npc.kt b/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/campaign/PUT_Campaign_Npc.kt index d9d31aa..f461b19 100644 --- a/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/campaign/PUT_Campaign_Npc.kt +++ b/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/campaign/PUT_Campaign_Npc.kt @@ -1,10 +1,11 @@ package com.pixelized.server.lwa.server.rest.campaign import com.pixelized.server.lwa.server.Engine +import com.pixelized.server.lwa.utils.extentions.MissingParameterException import com.pixelized.server.lwa.utils.extentions.characterSheetId +import com.pixelized.shared.lwa.protocol.rest.ResultJson import com.pixelized.shared.lwa.protocol.websocket.CampaignEvent -import io.ktor.http.HttpStatusCode -import io.ktor.server.response.respondText +import io.ktor.server.response.respond fun Engine.putCampaignNpc(): suspend io.ktor.server.routing.RoutingContext.() -> Unit { return { @@ -12,15 +13,12 @@ fun Engine.putCampaignNpc(): suspend io.ktor.server.routing.RoutingContext.() -> // get the query parameter val characterSheetId = call.queryParameters.characterSheetId // add the character to the npcs. - val update = campaignService.addNpc(characterSheetId = characterSheetId) - // error case - if (update.not()) { - error("Unexpected error occurred when the character instance was added to the npcs") - } + campaignService.addNpc( + characterSheetId = characterSheetId, + ) // API & WebSocket responses. - call.respondText( - text = "Character $characterSheetId successfully added to the npcs", - status = HttpStatusCode.OK, + call.respond( + message = ResultJson.Success(), ) webSocket.emit( value = CampaignEvent.NpcAdded( @@ -28,10 +26,19 @@ fun Engine.putCampaignNpc(): suspend io.ktor.server.routing.RoutingContext.() -> characterSheetId = characterSheetId, ) ) + } catch (exception: MissingParameterException) { + call.respond( + message = ResultJson.Error( + status = exception.errorCode, + message = exception.message ?: "?", + ) + ) } catch (exception: Exception) { - call.respondText( - text = "${exception.message}", - status = HttpStatusCode.UnprocessableEntity, + call.respond( + message = ResultJson.Error( + status = ResultJson.Error.GENERIC, + message = exception.message ?: "?", + ) ) } } diff --git a/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/campaign/PUT_Campaign_Scene_Name.kt b/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/campaign/PUT_Campaign_Scene_Name.kt index 0eeb799..e5b2d1e 100644 --- a/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/campaign/PUT_Campaign_Scene_Name.kt +++ b/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/campaign/PUT_Campaign_Scene_Name.kt @@ -1,10 +1,13 @@ package com.pixelized.server.lwa.server.rest.campaign import com.pixelized.server.lwa.server.Engine +import com.pixelized.server.lwa.utils.extentions.MissingParameterException import com.pixelized.shared.lwa.model.campaign.CampaignJsonV2 +import com.pixelized.shared.lwa.protocol.rest.ResultJson import com.pixelized.shared.lwa.protocol.websocket.CampaignEvent import io.ktor.http.HttpStatusCode import io.ktor.server.request.receive +import io.ktor.server.response.respond import io.ktor.server.response.respondText fun Engine.putCampaignScene(): suspend io.ktor.server.routing.RoutingContext.() -> Unit { @@ -15,15 +18,10 @@ fun Engine.putCampaignScene(): suspend io.ktor.server.routing.RoutingContext.() // convert the scene into the a usable data model. val scene = campaignJsonFactory.convertFromJson(json = form) // update the campaign. - val updated = campaignService.setScene(scene = scene) - // error case - if (updated.not()) { - error("Unexpected error when updating the scene.") - } + campaignService.setScene(scene = scene) // API & WebSocket responses - call.respondText( - text = "${HttpStatusCode.OK}", - status = HttpStatusCode.OK, + call.respond( + message = ResultJson.Success(), ) webSocket.emit( value = CampaignEvent.UpdateScene( @@ -31,10 +29,19 @@ fun Engine.putCampaignScene(): suspend io.ktor.server.routing.RoutingContext.() name = scene.name, ) ) + } catch (exception: MissingParameterException) { + call.respond( + message = ResultJson.Error( + status = exception.errorCode, + message = exception.message ?: "?", + ) + ) } catch (exception: Exception) { - call.respondText( - text = exception.localizedMessage, - status = HttpStatusCode.UnprocessableEntity, + call.respond( + message = ResultJson.Error( + status = ResultJson.Error.GENERIC, + message = exception.message ?: "?", + ) ) } } diff --git a/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/character/DELETE_Character.kt b/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/character/DELETE_Character.kt index 28dea04..ca99cda 100644 --- a/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/character/DELETE_Character.kt +++ b/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/character/DELETE_Character.kt @@ -13,11 +13,6 @@ fun Engine.deleteCharacter(): suspend io.ktor.server.routing.RoutingContext.() - val deleted = characterService.deleteCharacterSheet( characterSheetId = characterSheetId ) - // Remove the character fom the campaign if needed. - // TODO probably useless because all data will not be cleaned up (all campaign / screnes) - campaignService.removeInstance( - characterSheetId = characterSheetId, - ) if (deleted) { call.respondText( diff --git a/shared/src/commonMain/kotlin/com/pixelized/shared/lwa/protocol/rest/PutResultJson.kt b/shared/src/commonMain/kotlin/com/pixelized/shared/lwa/protocol/rest/ResultJson.kt similarity index 78% rename from shared/src/commonMain/kotlin/com/pixelized/shared/lwa/protocol/rest/PutResultJson.kt rename to shared/src/commonMain/kotlin/com/pixelized/shared/lwa/protocol/rest/ResultJson.kt index c646c0f..c23172c 100644 --- a/shared/src/commonMain/kotlin/com/pixelized/shared/lwa/protocol/rest/PutResultJson.kt +++ b/shared/src/commonMain/kotlin/com/pixelized/shared/lwa/protocol/rest/ResultJson.kt @@ -13,12 +13,9 @@ sealed interface ResultJson { val message: String, ) : ResultJson { companion object { - const val GENERIC = 500 + const val GENERIC = 600 - const val FILE_ALREADY_EXIST = GENERIC + 1 - const val FILE_DOES_NOT_EXIST = GENERIC + 2 - - const val MISSING_PARAMETER = 1000 + const val MISSING_PARAMETER = 700 const val MISSING_CHARACTER_SHEET_ID = MISSING_PARAMETER + 1 const val MISSING_ALTERATION_ID = MISSING_PARAMETER + 2 const val MISSING_CREATE = MISSING_PARAMETER + 3