Add inventory managment to server.
This commit is contained in:
		
							parent
							
								
									04b203239d
								
							
						
					
					
						commit
						4f33492b23
					
				
					 18 changed files with 499 additions and 7 deletions
				
			
		| 
						 | 
					@ -4,6 +4,8 @@ import com.pixelized.server.lwa.model.campaign.CampaignService
 | 
				
			||||||
import com.pixelized.server.lwa.model.campaign.CampaignStore
 | 
					import com.pixelized.server.lwa.model.campaign.CampaignStore
 | 
				
			||||||
import com.pixelized.server.lwa.model.character.CharacterSheetService
 | 
					import com.pixelized.server.lwa.model.character.CharacterSheetService
 | 
				
			||||||
import com.pixelized.server.lwa.model.character.CharacterSheetStore
 | 
					import com.pixelized.server.lwa.model.character.CharacterSheetStore
 | 
				
			||||||
 | 
					import com.pixelized.server.lwa.model.inventory.InventoryService
 | 
				
			||||||
 | 
					import com.pixelized.server.lwa.model.inventory.InventoryStore
 | 
				
			||||||
import com.pixelized.server.lwa.model.item.ItemService
 | 
					import com.pixelized.server.lwa.model.item.ItemService
 | 
				
			||||||
import com.pixelized.server.lwa.model.item.ItemStore
 | 
					import com.pixelized.server.lwa.model.item.ItemStore
 | 
				
			||||||
import com.pixelized.server.lwa.model.tag.TagService
 | 
					import com.pixelized.server.lwa.model.tag.TagService
 | 
				
			||||||
| 
						 | 
					@ -36,18 +38,20 @@ val engineDependencies
 | 
				
			||||||
 | 
					
 | 
				
			||||||
val storeDependencies
 | 
					val storeDependencies
 | 
				
			||||||
    get() = module {
 | 
					    get() = module {
 | 
				
			||||||
        singleOf(::CharacterSheetStore)
 | 
					 | 
				
			||||||
        singleOf(::CampaignStore)
 | 
					 | 
				
			||||||
        singleOf(::AlterationStore)
 | 
					        singleOf(::AlterationStore)
 | 
				
			||||||
        singleOf(::TagStore)
 | 
					        singleOf(::CampaignStore)
 | 
				
			||||||
 | 
					        singleOf(::CharacterSheetStore)
 | 
				
			||||||
 | 
					        singleOf(::InventoryStore)
 | 
				
			||||||
        singleOf(::ItemStore)
 | 
					        singleOf(::ItemStore)
 | 
				
			||||||
 | 
					        singleOf(::TagStore)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
val serviceDependencies
 | 
					val serviceDependencies
 | 
				
			||||||
    get() = module {
 | 
					    get() = module {
 | 
				
			||||||
        singleOf(::CharacterSheetService)
 | 
					 | 
				
			||||||
        singleOf(::CampaignService)
 | 
					 | 
				
			||||||
        singleOf(::AlterationService)
 | 
					        singleOf(::AlterationService)
 | 
				
			||||||
 | 
					        singleOf(::CampaignService)
 | 
				
			||||||
 | 
					        singleOf(::CharacterSheetService)
 | 
				
			||||||
 | 
					        singleOf(::InventoryService)
 | 
				
			||||||
        singleOf(::ItemService)
 | 
					        singleOf(::ItemService)
 | 
				
			||||||
        singleOf(::TagService)
 | 
					        singleOf(::TagService)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,52 @@
 | 
				
			||||||
 | 
					package com.pixelized.server.lwa.model.inventory
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.pixelized.shared.lwa.model.inventory.Inventory
 | 
				
			||||||
 | 
					import com.pixelized.shared.lwa.model.inventory.InventoryJson
 | 
				
			||||||
 | 
					import com.pixelized.shared.lwa.model.inventory.factory.InventoryJsonFactory
 | 
				
			||||||
 | 
					import kotlinx.coroutines.CoroutineScope
 | 
				
			||||||
 | 
					import kotlinx.coroutines.Dispatchers
 | 
				
			||||||
 | 
					import kotlinx.coroutines.Job
 | 
				
			||||||
 | 
					import kotlinx.coroutines.flow.SharingStarted
 | 
				
			||||||
 | 
					import kotlinx.coroutines.flow.map
 | 
				
			||||||
 | 
					import kotlinx.coroutines.flow.stateIn
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class InventoryService(
 | 
				
			||||||
 | 
					    private val inventoryStore: InventoryStore,
 | 
				
			||||||
 | 
					    private val factory: InventoryJsonFactory,
 | 
				
			||||||
 | 
					) {
 | 
				
			||||||
 | 
					    private val scope = CoroutineScope(Dispatchers.IO + Job())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private val inventoryJson = inventoryStore.inventoryFlow()
 | 
				
			||||||
 | 
					        .map { it.mapValues { entry -> factory.convertToJson(inventory = entry.value) } }
 | 
				
			||||||
 | 
					        .stateIn(
 | 
				
			||||||
 | 
					            scope = scope,
 | 
				
			||||||
 | 
					            started = SharingStarted.Eagerly,
 | 
				
			||||||
 | 
					            initialValue = emptyMap()
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fun inventory(characterSheetId: String): Inventory {
 | 
				
			||||||
 | 
					        return inventoryStore.inventoryFlow().value[characterSheetId]
 | 
				
			||||||
 | 
					            ?: Inventory.empty(characterSheetId = characterSheetId)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fun inventoryJson(characterSheetId: String): InventoryJson {
 | 
				
			||||||
 | 
					        return inventoryJson.value[characterSheetId]
 | 
				
			||||||
 | 
					            ?: factory.convertToJson(Inventory.empty(characterSheetId = characterSheetId))
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Throws
 | 
				
			||||||
 | 
					    fun save(
 | 
				
			||||||
 | 
					        inventoryJson: InventoryJson,
 | 
				
			||||||
 | 
					        create: Boolean,
 | 
				
			||||||
 | 
					    ) {
 | 
				
			||||||
 | 
					        inventoryStore.save(
 | 
				
			||||||
 | 
					            inventory = factory.convertFromJson(json = inventoryJson),
 | 
				
			||||||
 | 
					            create = create,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Throws
 | 
				
			||||||
 | 
					    fun delete(characterSheetId: String) {
 | 
				
			||||||
 | 
					        inventoryStore.delete(characterSheetId = characterSheetId)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,158 @@
 | 
				
			||||||
 | 
					package com.pixelized.server.lwa.model.inventory
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.pixelized.server.lwa.server.exception.BusinessException
 | 
				
			||||||
 | 
					import com.pixelized.server.lwa.server.exception.FileReadException
 | 
				
			||||||
 | 
					import com.pixelized.server.lwa.server.exception.FileWriteException
 | 
				
			||||||
 | 
					import com.pixelized.server.lwa.server.exception.JsonCodingException
 | 
				
			||||||
 | 
					import com.pixelized.server.lwa.server.exception.JsonConversionException
 | 
				
			||||||
 | 
					import com.pixelized.shared.lwa.model.inventory.Inventory
 | 
				
			||||||
 | 
					import com.pixelized.shared.lwa.model.inventory.InventoryJson
 | 
				
			||||||
 | 
					import com.pixelized.shared.lwa.model.inventory.factory.InventoryJsonFactory
 | 
				
			||||||
 | 
					import com.pixelized.shared.lwa.protocol.rest.APIResponse
 | 
				
			||||||
 | 
					import com.pixelized.shared.lwa.utils.PathProvider
 | 
				
			||||||
 | 
					import kotlinx.coroutines.CoroutineScope
 | 
				
			||||||
 | 
					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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class InventoryStore(
 | 
				
			||||||
 | 
					    private val pathProvider: PathProvider,
 | 
				
			||||||
 | 
					    private val factory: InventoryJsonFactory,
 | 
				
			||||||
 | 
					    private val json: Json,
 | 
				
			||||||
 | 
					) {
 | 
				
			||||||
 | 
					    private val directory = File(pathProvider.inventoryPath()).also { it.mkdirs() }
 | 
				
			||||||
 | 
					    private val inventoryFlow = MutableStateFlow<Map<String, Inventory>>(value = emptyMap())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    init {
 | 
				
			||||||
 | 
					        // build a coroutine scope for async calls
 | 
				
			||||||
 | 
					        val scope = CoroutineScope(Dispatchers.IO + Job())
 | 
				
			||||||
 | 
					        // load the initial data
 | 
				
			||||||
 | 
					        scope.launch {
 | 
				
			||||||
 | 
					            updateInventoryFlow()
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fun inventoryFlow(): StateFlow<Map<String, Inventory>> = inventoryFlow
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private suspend fun updateInventoryFlow() {
 | 
				
			||||||
 | 
					        inventoryFlow.value = try {
 | 
				
			||||||
 | 
					            load()
 | 
				
			||||||
 | 
					        } catch (exception: Exception) {
 | 
				
			||||||
 | 
					            println(exception.message) // TODO proper exception handling
 | 
				
			||||||
 | 
					            emptyMap()
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Throws(
 | 
				
			||||||
 | 
					        FileReadException::class,
 | 
				
			||||||
 | 
					        JsonCodingException::class,
 | 
				
			||||||
 | 
					        JsonConversionException::class,
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					    private fun load(
 | 
				
			||||||
 | 
					        directory: File = this.directory,
 | 
				
			||||||
 | 
					    ): Map<String, Inventory> {
 | 
				
			||||||
 | 
					        return directory
 | 
				
			||||||
 | 
					            .listFiles()
 | 
				
			||||||
 | 
					            ?.mapNotNull { file ->
 | 
				
			||||||
 | 
					                val json = try {
 | 
				
			||||||
 | 
					                    file.readText(charset = Charsets.UTF_8)
 | 
				
			||||||
 | 
					                } catch (exception: Exception) {
 | 
				
			||||||
 | 
					                    throw FileReadException(root = exception)
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                // Guard, if the json is blank no character have been save, ignore this file.
 | 
				
			||||||
 | 
					                if (json.isBlank()) {
 | 
				
			||||||
 | 
					                    return@mapNotNull null
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                // decode the file
 | 
				
			||||||
 | 
					                val data = try {
 | 
				
			||||||
 | 
					                    this.json.decodeFromString<InventoryJson>(json)
 | 
				
			||||||
 | 
					                } catch (exception: Exception) {
 | 
				
			||||||
 | 
					                    throw JsonCodingException(root = exception)
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                // parse the json string.
 | 
				
			||||||
 | 
					                val inventory = try {
 | 
				
			||||||
 | 
					                    factory.convertFromJson(data)
 | 
				
			||||||
 | 
					                } catch (exception: Exception) {
 | 
				
			||||||
 | 
					                    throw JsonConversionException(root = exception)
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                file.name to inventory
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            ?.toMap()
 | 
				
			||||||
 | 
					            ?: emptyMap()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Throws(
 | 
				
			||||||
 | 
					        BusinessException::class,
 | 
				
			||||||
 | 
					        JsonConversionException::class,
 | 
				
			||||||
 | 
					        JsonCodingException::class,
 | 
				
			||||||
 | 
					        FileWriteException::class,
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					    fun save(
 | 
				
			||||||
 | 
					        inventory: Inventory,
 | 
				
			||||||
 | 
					        create: Boolean,
 | 
				
			||||||
 | 
					    ) {
 | 
				
			||||||
 | 
					        val file = inventoryFile(id = inventory.characterSheetId)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (create && file.exists()) {
 | 
				
			||||||
 | 
					            throw BusinessException(message = "Inventory already exist, creation is impossible.")
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        val json = try {
 | 
				
			||||||
 | 
					            factory.convertToJson(inventory = inventory)
 | 
				
			||||||
 | 
					        } catch (exception: Exception) {
 | 
				
			||||||
 | 
					            throw JsonConversionException(root = exception)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        val data = try {
 | 
				
			||||||
 | 
					            this.json.encodeToString(json)
 | 
				
			||||||
 | 
					        } catch (exception: Exception) {
 | 
				
			||||||
 | 
					            throw JsonCodingException(root = exception)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					            file.writeText(
 | 
				
			||||||
 | 
					                text = data,
 | 
				
			||||||
 | 
					                charset = Charsets.UTF_8,
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					        } catch (exception: Exception) {
 | 
				
			||||||
 | 
					            throw FileWriteException(root = exception)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        inventoryFlow.update { flow ->
 | 
				
			||||||
 | 
					            flow.toMutableMap().also { data ->
 | 
				
			||||||
 | 
					                data[inventory.characterSheetId] = inventory
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Throws(BusinessException::class)
 | 
				
			||||||
 | 
					    fun delete(characterSheetId: String) {
 | 
				
			||||||
 | 
					        val file = inventoryFile(id = characterSheetId)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (file.exists().not()) {
 | 
				
			||||||
 | 
					            throw BusinessException(
 | 
				
			||||||
 | 
					                message = "Inventory file with id:$characterSheetId doesn't not exist.",
 | 
				
			||||||
 | 
					                code = APIResponse.ErrorCode.CharacterSheetId
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (file.delete().not()) {
 | 
				
			||||||
 | 
					            throw BusinessException(
 | 
				
			||||||
 | 
					                message = "Inventory file have not been deleted for unknown reason.",
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        inventoryFlow.update { characters ->
 | 
				
			||||||
 | 
					            characters.toMutableMap().also { data -> data.remove(characterSheetId) }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private fun inventoryFile(id: String): File {
 | 
				
			||||||
 | 
					        return File("${pathProvider.inventoryPath()}${id}.json")
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -27,7 +27,6 @@ class ItemStore(
 | 
				
			||||||
    private val json: Json,
 | 
					    private val json: Json,
 | 
				
			||||||
) {
 | 
					) {
 | 
				
			||||||
    private val directory = File(pathProvider.itemsPath()).also { it.mkdirs() }
 | 
					    private val directory = File(pathProvider.itemsPath()).also { it.mkdirs() }
 | 
				
			||||||
 | 
					 | 
				
			||||||
    private val itemFlow = MutableStateFlow<List<Item>>(emptyList())
 | 
					    private val itemFlow = MutableStateFlow<List<Item>>(emptyList())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    init {
 | 
					    init {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,6 +3,7 @@ package com.pixelized.server.lwa.server
 | 
				
			||||||
import com.pixelized.server.lwa.model.alteration.AlterationService
 | 
					import com.pixelized.server.lwa.model.alteration.AlterationService
 | 
				
			||||||
import com.pixelized.server.lwa.model.campaign.CampaignService
 | 
					import com.pixelized.server.lwa.model.campaign.CampaignService
 | 
				
			||||||
import com.pixelized.server.lwa.model.character.CharacterSheetService
 | 
					import com.pixelized.server.lwa.model.character.CharacterSheetService
 | 
				
			||||||
 | 
					import com.pixelized.server.lwa.model.inventory.InventoryService
 | 
				
			||||||
import com.pixelized.server.lwa.model.item.ItemService
 | 
					import com.pixelized.server.lwa.model.item.ItemService
 | 
				
			||||||
import com.pixelized.server.lwa.model.tag.TagService
 | 
					import com.pixelized.server.lwa.model.tag.TagService
 | 
				
			||||||
import com.pixelized.shared.lwa.model.campaign.factory.CampaignJsonFactory
 | 
					import com.pixelized.shared.lwa.model.campaign.factory.CampaignJsonFactory
 | 
				
			||||||
| 
						 | 
					@ -19,6 +20,7 @@ class Engine(
 | 
				
			||||||
    val campaignService: CampaignService,
 | 
					    val campaignService: CampaignService,
 | 
				
			||||||
    val alterationService: AlterationService,
 | 
					    val alterationService: AlterationService,
 | 
				
			||||||
    val itemService: ItemService,
 | 
					    val itemService: ItemService,
 | 
				
			||||||
 | 
					    val inventoryService: InventoryService,
 | 
				
			||||||
    val tagService: TagService,
 | 
					    val tagService: TagService,
 | 
				
			||||||
    val campaignJsonFactory: CampaignJsonFactory,
 | 
					    val campaignJsonFactory: CampaignJsonFactory,
 | 
				
			||||||
) {
 | 
					) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -19,6 +19,9 @@ import com.pixelized.server.lwa.server.rest.character.putCharacterAlteration
 | 
				
			||||||
import com.pixelized.server.lwa.server.rest.character.putCharacterDamage
 | 
					import com.pixelized.server.lwa.server.rest.character.putCharacterDamage
 | 
				
			||||||
import com.pixelized.server.lwa.server.rest.character.putCharacterDiminished
 | 
					import com.pixelized.server.lwa.server.rest.character.putCharacterDiminished
 | 
				
			||||||
import com.pixelized.server.lwa.server.rest.character.putCharacterFatigue
 | 
					import com.pixelized.server.lwa.server.rest.character.putCharacterFatigue
 | 
				
			||||||
 | 
					import com.pixelized.server.lwa.server.rest.inventory.deleteInventory
 | 
				
			||||||
 | 
					import com.pixelized.server.lwa.server.rest.inventory.getInventory
 | 
				
			||||||
 | 
					import com.pixelized.server.lwa.server.rest.inventory.putInventory
 | 
				
			||||||
import com.pixelized.server.lwa.server.rest.item.deleteItem
 | 
					import com.pixelized.server.lwa.server.rest.item.deleteItem
 | 
				
			||||||
import com.pixelized.server.lwa.server.rest.item.getItem
 | 
					import com.pixelized.server.lwa.server.rest.item.getItem
 | 
				
			||||||
import com.pixelized.server.lwa.server.rest.item.getItems
 | 
					import com.pixelized.server.lwa.server.rest.item.getItems
 | 
				
			||||||
| 
						 | 
					@ -246,6 +249,20 @@ class LocalServer {
 | 
				
			||||||
                            body = engine.getItemTags(),
 | 
					                            body = engine.getItemTags(),
 | 
				
			||||||
                        )
 | 
					                        )
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
 | 
					                    route(path = "inventory") {
 | 
				
			||||||
 | 
					                        get(
 | 
				
			||||||
 | 
					                            path = "/detail",
 | 
				
			||||||
 | 
					                            body = engine.getInventory(),
 | 
				
			||||||
 | 
					                        )
 | 
				
			||||||
 | 
					                        put(
 | 
				
			||||||
 | 
					                            path = "/update",
 | 
				
			||||||
 | 
					                            body = engine.putInventory()
 | 
				
			||||||
 | 
					                        )
 | 
				
			||||||
 | 
					                        delete(
 | 
				
			||||||
 | 
					                            path = "/delete",
 | 
				
			||||||
 | 
					                            body = engine.deleteInventory()
 | 
				
			||||||
 | 
					                        )
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,36 @@
 | 
				
			||||||
 | 
					package com.pixelized.server.lwa.server.rest.inventory
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.pixelized.server.lwa.server.Engine
 | 
				
			||||||
 | 
					import com.pixelized.server.lwa.utils.extentions.characterSheetId
 | 
				
			||||||
 | 
					import com.pixelized.server.lwa.utils.extentions.exception
 | 
				
			||||||
 | 
					import com.pixelized.shared.lwa.protocol.rest.APIResponse
 | 
				
			||||||
 | 
					import com.pixelized.shared.lwa.protocol.websocket.ApiSynchronisation
 | 
				
			||||||
 | 
					import io.ktor.server.response.respond
 | 
				
			||||||
 | 
					import io.ktor.server.routing.RoutingContext
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fun Engine.deleteInventory(): suspend RoutingContext.() -> Unit {
 | 
				
			||||||
 | 
					    return {
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					            // get the query parameter
 | 
				
			||||||
 | 
					            val characterSheetId = call.queryParameters.characterSheetId
 | 
				
			||||||
 | 
					            // delete the alteration.
 | 
				
			||||||
 | 
					            inventoryService.delete(
 | 
				
			||||||
 | 
					                characterSheetId = characterSheetId,
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					            // API & WebSocket responses.
 | 
				
			||||||
 | 
					            call.respond(
 | 
				
			||||||
 | 
					                message = APIResponse.success(),
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					            webSocket.emit(
 | 
				
			||||||
 | 
					                value = ApiSynchronisation.InventoryDelete(
 | 
				
			||||||
 | 
					                    timestamp = System.currentTimeMillis(),
 | 
				
			||||||
 | 
					                    characterSheetId = characterSheetId,
 | 
				
			||||||
 | 
					                ),
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					        } catch (exception: Exception) {
 | 
				
			||||||
 | 
					            call.exception(
 | 
				
			||||||
 | 
					                exception = exception,
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,31 @@
 | 
				
			||||||
 | 
					package com.pixelized.server.lwa.server.rest.inventory
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.pixelized.server.lwa.server.Engine
 | 
				
			||||||
 | 
					import com.pixelized.server.lwa.utils.extentions.characterSheetId
 | 
				
			||||||
 | 
					import com.pixelized.server.lwa.utils.extentions.exception
 | 
				
			||||||
 | 
					import com.pixelized.shared.lwa.protocol.rest.APIResponse
 | 
				
			||||||
 | 
					import io.ktor.server.response.respond
 | 
				
			||||||
 | 
					import io.ktor.server.routing.RoutingContext
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fun Engine.getInventory(): suspend RoutingContext.() -> Unit {
 | 
				
			||||||
 | 
					    return {
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					            // get the query parameter
 | 
				
			||||||
 | 
					            val characterSheetId = call.queryParameters.characterSheetId
 | 
				
			||||||
 | 
					            // get the character inventory
 | 
				
			||||||
 | 
					            val inventory = inventoryService.inventoryJson(
 | 
				
			||||||
 | 
					                characterSheetId = characterSheetId,
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					            // send it back to the user.
 | 
				
			||||||
 | 
					            call.respond(
 | 
				
			||||||
 | 
					                message = APIResponse.success(
 | 
				
			||||||
 | 
					                    data = inventory
 | 
				
			||||||
 | 
					                )
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					        } catch (exception: Exception) {
 | 
				
			||||||
 | 
					            call.exception(
 | 
				
			||||||
 | 
					                exception = exception
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,42 @@
 | 
				
			||||||
 | 
					package com.pixelized.server.lwa.server.rest.inventory
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.pixelized.server.lwa.server.Engine
 | 
				
			||||||
 | 
					import com.pixelized.server.lwa.utils.extentions.characterSheetId
 | 
				
			||||||
 | 
					import com.pixelized.server.lwa.utils.extentions.create
 | 
				
			||||||
 | 
					import com.pixelized.server.lwa.utils.extentions.exception
 | 
				
			||||||
 | 
					import com.pixelized.shared.lwa.model.characterSheet.CharacterSheetJson
 | 
				
			||||||
 | 
					import com.pixelized.shared.lwa.model.inventory.InventoryJson
 | 
				
			||||||
 | 
					import com.pixelized.shared.lwa.protocol.rest.APIResponse
 | 
				
			||||||
 | 
					import com.pixelized.shared.lwa.protocol.websocket.ApiSynchronisation
 | 
				
			||||||
 | 
					import io.ktor.server.request.receive
 | 
				
			||||||
 | 
					import io.ktor.server.response.respond
 | 
				
			||||||
 | 
					import io.ktor.server.routing.RoutingContext
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fun Engine.putInventory(): suspend RoutingContext.() -> Unit {
 | 
				
			||||||
 | 
					    return {
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					            // get the query parameter
 | 
				
			||||||
 | 
					            val form = call.receive<InventoryJson>()
 | 
				
			||||||
 | 
					            val create = call.queryParameters.create
 | 
				
			||||||
 | 
					            // get the character inventory
 | 
				
			||||||
 | 
					            inventoryService.save(
 | 
				
			||||||
 | 
					                inventoryJson = form,
 | 
				
			||||||
 | 
					                create = create,
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					            // send it back to the user.
 | 
				
			||||||
 | 
					            call.respond(
 | 
				
			||||||
 | 
					                message = APIResponse.success()
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					            webSocket.emit(
 | 
				
			||||||
 | 
					                value = ApiSynchronisation.InventoryUpdate(
 | 
				
			||||||
 | 
					                    timestamp = System.currentTimeMillis(),
 | 
				
			||||||
 | 
					                    characterSheetId = form.characterSheetId,
 | 
				
			||||||
 | 
					                ),
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					        } catch (exception: Exception) {
 | 
				
			||||||
 | 
					            call.exception(
 | 
				
			||||||
 | 
					                exception = exception
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -12,7 +12,7 @@ fun Engine.deleteItem(): suspend RoutingContext.() -> Unit {
 | 
				
			||||||
    return {
 | 
					    return {
 | 
				
			||||||
        try {
 | 
					        try {
 | 
				
			||||||
            // get the query parameter
 | 
					            // get the query parameter
 | 
				
			||||||
            val itemId = call.parameters.itemId
 | 
					            val itemId = call.queryParameters.itemId
 | 
				
			||||||
            // delete the alteration.
 | 
					            // delete the alteration.
 | 
				
			||||||
            itemService.delete(
 | 
					            itemService.delete(
 | 
				
			||||||
                itemId = itemId
 | 
					                itemId = itemId
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -7,6 +7,8 @@ import com.pixelized.shared.lwa.model.campaign.factory.CampaignJsonV1Factory
 | 
				
			||||||
import com.pixelized.shared.lwa.model.campaign.factory.CampaignJsonV2Factory
 | 
					import com.pixelized.shared.lwa.model.campaign.factory.CampaignJsonV2Factory
 | 
				
			||||||
import com.pixelized.shared.lwa.model.characterSheet.factory.CharacterSheetJsonFactory
 | 
					import com.pixelized.shared.lwa.model.characterSheet.factory.CharacterSheetJsonFactory
 | 
				
			||||||
import com.pixelized.shared.lwa.model.characterSheet.factory.CharacterSheetJsonV1Factory
 | 
					import com.pixelized.shared.lwa.model.characterSheet.factory.CharacterSheetJsonV1Factory
 | 
				
			||||||
 | 
					import com.pixelized.shared.lwa.model.inventory.factory.InventoryJsonFactory
 | 
				
			||||||
 | 
					import com.pixelized.shared.lwa.model.inventory.factory.InventoryJsonFactoryV1
 | 
				
			||||||
import com.pixelized.shared.lwa.model.item.factory.ItemJsonFactory
 | 
					import com.pixelized.shared.lwa.model.item.factory.ItemJsonFactory
 | 
				
			||||||
import com.pixelized.shared.lwa.model.item.factory.ItemJsonFactoryV1
 | 
					import com.pixelized.shared.lwa.model.item.factory.ItemJsonFactoryV1
 | 
				
			||||||
import com.pixelized.shared.lwa.model.tag.TagJsonFactory
 | 
					import com.pixelized.shared.lwa.model.tag.TagJsonFactory
 | 
				
			||||||
| 
						 | 
					@ -52,6 +54,8 @@ val factoryDependencies
 | 
				
			||||||
        factoryOf(::TagJsonFactory)
 | 
					        factoryOf(::TagJsonFactory)
 | 
				
			||||||
        factoryOf(::ItemJsonFactory)
 | 
					        factoryOf(::ItemJsonFactory)
 | 
				
			||||||
        factoryOf(::ItemJsonFactoryV1)
 | 
					        factoryOf(::ItemJsonFactoryV1)
 | 
				
			||||||
 | 
					        factoryOf(::InventoryJsonFactory)
 | 
				
			||||||
 | 
					        factoryOf(::InventoryJsonFactoryV1)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
val parserDependencies
 | 
					val parserDependencies
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,30 @@
 | 
				
			||||||
 | 
					package com.pixelized.shared.lwa.model.inventory
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					data class Inventory(
 | 
				
			||||||
 | 
					    val characterSheetId: String,
 | 
				
			||||||
 | 
					    val purse: Purse,
 | 
				
			||||||
 | 
					    val items: List<Item>,
 | 
				
			||||||
 | 
					) {
 | 
				
			||||||
 | 
					    data class Purse(
 | 
				
			||||||
 | 
					        val gold: Int,
 | 
				
			||||||
 | 
					        val silver: Int,
 | 
				
			||||||
 | 
					        val copper: Int,
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    data class Item(
 | 
				
			||||||
 | 
					        val itemId: String,
 | 
				
			||||||
 | 
					        val count: Int,
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    companion object {
 | 
				
			||||||
 | 
					        fun empty(characterSheetId: String) = Inventory(
 | 
				
			||||||
 | 
					            characterSheetId = characterSheetId,
 | 
				
			||||||
 | 
					            purse = Purse(
 | 
				
			||||||
 | 
					                gold = 0,
 | 
				
			||||||
 | 
					                silver = 0,
 | 
				
			||||||
 | 
					                copper = 0,
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					            items = emptyList(),
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,8 @@
 | 
				
			||||||
 | 
					package com.pixelized.shared.lwa.model.inventory
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import kotlinx.serialization.Serializable
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@Serializable
 | 
				
			||||||
 | 
					sealed interface InventoryJson {
 | 
				
			||||||
 | 
					    val characterSheetId: String
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,24 @@
 | 
				
			||||||
 | 
					package com.pixelized.shared.lwa.model.inventory
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import kotlinx.serialization.Serializable
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@Serializable
 | 
				
			||||||
 | 
					data class InventoryJsonV1(
 | 
				
			||||||
 | 
					    override val characterSheetId: String,
 | 
				
			||||||
 | 
					    val purse: PurseJson,
 | 
				
			||||||
 | 
					    val items: List<ItemJson>,
 | 
				
			||||||
 | 
					) : InventoryJson {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Serializable
 | 
				
			||||||
 | 
					    data class PurseJson(
 | 
				
			||||||
 | 
					        val gold: Int,
 | 
				
			||||||
 | 
					        val silver: Int,
 | 
				
			||||||
 | 
					        val copper: Int,
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Serializable
 | 
				
			||||||
 | 
					    data class ItemJson(
 | 
				
			||||||
 | 
					        val itemId: String,
 | 
				
			||||||
 | 
					        val count: Int,
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,19 @@
 | 
				
			||||||
 | 
					package com.pixelized.shared.lwa.model.inventory.factory
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.pixelized.shared.lwa.model.inventory.Inventory
 | 
				
			||||||
 | 
					import com.pixelized.shared.lwa.model.inventory.InventoryJson
 | 
				
			||||||
 | 
					import com.pixelized.shared.lwa.model.inventory.InventoryJsonV1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class InventoryJsonFactory(
 | 
				
			||||||
 | 
					    private val v1: InventoryJsonFactoryV1,
 | 
				
			||||||
 | 
					) {
 | 
				
			||||||
 | 
					    fun convertFromJson(json: InventoryJson): Inventory {
 | 
				
			||||||
 | 
					        return when (json) {
 | 
				
			||||||
 | 
					            is InventoryJsonV1 -> v1.convertFromJson(json = json)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fun convertToJson(inventory: Inventory): InventoryJson {
 | 
				
			||||||
 | 
					        return v1.convertToJson(inventory = inventory)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,41 @@
 | 
				
			||||||
 | 
					package com.pixelized.shared.lwa.model.inventory.factory
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.pixelized.shared.lwa.model.inventory.Inventory
 | 
				
			||||||
 | 
					import com.pixelized.shared.lwa.model.inventory.InventoryJsonV1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class InventoryJsonFactoryV1 {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fun convertFromJson(json: InventoryJsonV1): Inventory {
 | 
				
			||||||
 | 
					        return Inventory(
 | 
				
			||||||
 | 
					            characterSheetId = json.characterSheetId,
 | 
				
			||||||
 | 
					            purse = Inventory.Purse(
 | 
				
			||||||
 | 
					                gold = json.purse.gold,
 | 
				
			||||||
 | 
					                silver = json.purse.silver,
 | 
				
			||||||
 | 
					                copper = json.purse.copper,
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					            items = json.items.map {
 | 
				
			||||||
 | 
					                Inventory.Item(
 | 
				
			||||||
 | 
					                    itemId = it.itemId,
 | 
				
			||||||
 | 
					                    count = it.count,
 | 
				
			||||||
 | 
					                )
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fun convertToJson(inventory: Inventory): InventoryJsonV1 {
 | 
				
			||||||
 | 
					        return InventoryJsonV1(
 | 
				
			||||||
 | 
					            characterSheetId = inventory.characterSheetId,
 | 
				
			||||||
 | 
					            purse = InventoryJsonV1.PurseJson(
 | 
				
			||||||
 | 
					                gold = inventory.purse.gold,
 | 
				
			||||||
 | 
					                silver = inventory.purse.silver,
 | 
				
			||||||
 | 
					                copper = inventory.purse.copper,
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					            items = inventory.items.map {
 | 
				
			||||||
 | 
					                InventoryJsonV1.ItemJson(
 | 
				
			||||||
 | 
					                    itemId = it.itemId,
 | 
				
			||||||
 | 
					                    count = it.count,
 | 
				
			||||||
 | 
					                )
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -49,4 +49,19 @@ sealed interface ApiSynchronisation : SocketMessage {
 | 
				
			||||||
        override val timestamp: Long,
 | 
					        override val timestamp: Long,
 | 
				
			||||||
        val itemId: String,
 | 
					        val itemId: String,
 | 
				
			||||||
    ) : ItemApiSynchronisation
 | 
					    ) : ItemApiSynchronisation
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Serializable
 | 
				
			||||||
 | 
					    sealed interface InventoryApiSynchronisation : ApiSynchronisation, CharacterSheetIdMessage
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Serializable
 | 
				
			||||||
 | 
					    data class InventoryUpdate(
 | 
				
			||||||
 | 
					        override val timestamp: Long,
 | 
				
			||||||
 | 
					        override val characterSheetId: String,
 | 
				
			||||||
 | 
					    ) : InventoryApiSynchronisation
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Serializable
 | 
				
			||||||
 | 
					    data class InventoryDelete(
 | 
				
			||||||
 | 
					        override val timestamp: Long,
 | 
				
			||||||
 | 
					        override val characterSheetId: String,
 | 
				
			||||||
 | 
					    ) : InventoryApiSynchronisation
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -73,4 +73,14 @@ class PathProvider(
 | 
				
			||||||
            OperatingSystem.Macintosh -> "${storePath(os = os, app = app)}tags/"
 | 
					            OperatingSystem.Macintosh -> "${storePath(os = os, app = app)}tags/"
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fun inventoryPath(
 | 
				
			||||||
 | 
					        os: OperatingSystem = this.operatingSystem,
 | 
				
			||||||
 | 
					        app: String = this.appName,
 | 
				
			||||||
 | 
					    ): String {
 | 
				
			||||||
 | 
					        return when (os) {
 | 
				
			||||||
 | 
					            OperatingSystem.Windows -> "${storePath(os = os, app = app)}inventory\\"
 | 
				
			||||||
 | 
					            OperatingSystem.Macintosh -> "${storePath(os = os, app = app)}inventory/"
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue