Skip to content

Commit

Permalink
Refactor: Simplify empty file handling
Browse files Browse the repository at this point in the history
  • Loading branch information
davidkleiven committed Nov 18, 2023
1 parent e4decdf commit a7c07f8
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 76 deletions.
110 changes: 34 additions & 76 deletions src/main/App.kt
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,7 @@ fun Application.module() {

install(StatusPages) {
exception<Throwable> { call, cause ->
call.respondText(
"500: $cause.\nStack trace: ${cause.stackTraceToString()}",
status = HttpStatusCode.InternalServerError
)
ExceptionHandler().handle(call, cause)
}
}

Expand All @@ -43,43 +40,26 @@ fun Application.module() {

post("/buses") {
val files = multiPartDataHandler(call.receiveMultipart())

if (files.isEmpty()) {
call.response.status(HttpStatusCode.UnprocessableEntity)
} else {
val busProps = busesFromRequest(files[0])
call.respond(busProps)
}
val network = networkFromFirstFile(files)
call.respond(busPropertiesFromNetwork(network))
}

post("/generator-names") {
val files = multiPartDataHandler(call.receiveMultipart())
if (files.isEmpty()) {
call.response.status(HttpStatusCode.UnprocessableEntity)
} else {
val network = networkFromFileContent(files[0])
call.respond(generatorNames(network))
}
val network = networkFromFirstFile(files)
call.respond(generatorNames(network))
}

post("/load-names") {
val files = multiPartDataHandler(call.receiveMultipart())
if (files.isEmpty()) {
call.response.status(HttpStatusCode.UnprocessableEntity)
} else {
val network = networkFromFileContent(files[0])
call.respond(loadNames(network))
}
val network = networkFromFirstFile(files)
call.respond(loadNames(network))
}

post("/branch-names") {
val files = multiPartDataHandler(call.receiveMultipart())
if (files.isEmpty()) {
call.response.status(HttpStatusCode.UnprocessableEntity)
} else {
val network = networkFromFileContent(files[0])
call.respond(branchNames(network))
}
val network = networkFromFirstFile(files)
call.respond(branchNames(network))
}

get("/default-load-parameters") {
Expand All @@ -88,59 +68,40 @@ fun Application.module() {

post("/substation-names") {
val files = multiPartDataHandler(call.receiveMultipart())
if (files.isEmpty()) {
call.response.status(HttpStatusCode.UnprocessableEntity)
} else {
val network = networkFromFileContent(files[0])
call.respond(substationNames(network))
}
val network = networkFromFirstFile(files)
call.respond(substationNames(network))
}

post("/voltage-level-names") {
val files = multiPartDataHandler(call.receiveMultipart())
if (files.isEmpty()) {
call.response.status(HttpStatusCode.UnprocessableEntity)
} else {
val network = networkFromFileContent(files[0])
call.respond(voltageLevelNames(network))
}
val network = networkFromFirstFile(files)
call.respond(voltageLevelNames(network))
}

post("/run-load-flow") {
val paramContainer = LoadParameterContainer()
val files = multiPartDataHandler(call.receiveMultipart(), paramContainer::formItemHandler)

if (files.isEmpty()) {
call.response.status(HttpStatusCode.UnprocessableEntity)
} else {
val network = networkFromFileContent(files[0])
val result = solve(network, paramContainer.parameters)
call.respond(result)
}
val network = networkFromFirstFile(files)
val result = solve(network, paramContainer.parameters)
call.respond(result)
}

post("/diagram/{type}/{name}") {
val diagramType = getDiagramType(call.parameters["type"] ?: DiagramType.Generic.toString())
val name = call.parameters["name"] ?: ""
val files = multiPartDataHandler((call.receiveMultipart()))
if (files.isEmpty()) {
call.response.status(HttpStatusCode.UnprocessableEntity)
} else {
val network = networkFromFileContent(files[0])
val diagram = singleLineDiagram(diagramType, name, network)
call.respondText(diagram, ContentType.Image.SVG, HttpStatusCode.OK)
}

val network = networkFromFirstFile(files)
val diagram = singleLineDiagram(diagramType, name, network)
call.respondText(diagram, ContentType.Image.SVG, HttpStatusCode.OK)

}

post("/diagram") {
val files = multiPartDataHandler((call.receiveMultipart()))
if (files.isEmpty()) {
call.response.status(HttpStatusCode.UnprocessableEntity)
} else {
val network = networkFromFileContent(files[0])
val diagram = networkDiagram(network)
call.respondText(diagram, ContentType.Image.SVG, HttpStatusCode.OK)
}
val network = networkFromFirstFile(files)
val diagram = networkDiagram(network)
call.respondText(diagram, ContentType.Image.SVG, HttpStatusCode.OK)
}

post("/sensitivity-analysis") {
Expand All @@ -151,19 +112,16 @@ fun Application.module() {
val itemHandler = MultiFormItemLoaders(listOf(loadParamCnt, sensParamCnt, sensFactorCnt, contingencyCnt))

val files = multiPartDataHandler(call.receiveMultipart(), itemHandler::formItemHandler)
if (files.isEmpty()) {
call.response.status(HttpStatusCode.UnprocessableEntity)
} else {
sensParamCnt.parameters.setLoadFlowParameters(loadParamCnt.parameters)
val network = networkFromFileContent(files[0])
val result = runSensitivityAnalysis(
network,
sensFactorCnt.factors,
sensParamCnt.parameters,
contingencyCnt.contingencies
)
call.respondText(result, ContentType.Application.Json, HttpStatusCode.OK)
}

sensParamCnt.parameters.setLoadFlowParameters(loadParamCnt.parameters)
val network = networkFromFirstFile(files)
val result = runSensitivityAnalysis(
network,
sensFactorCnt.factors,
sensParamCnt.parameters,
contingencyCnt.contingencies
)
call.respondText(result, ContentType.Application.Json, HttpStatusCode.OK)
}
swaggerUI(path = "openapi", swaggerFile = "openapi/documentation.yaml")
}
Expand Down
25 changes: 25 additions & 0 deletions src/main/ExceptionHandler.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.github.statnett.loadflowservice

import io.ktor.http.*
import io.ktor.server.application.*
import io.ktor.server.response.*

class ExceptionHandler {
suspend fun handle(call: ApplicationCall, cause: Throwable) {
when (cause) {
is NoFileProvidedException -> {
call.respondText (
"$cause\nStack trace: ${cause.stackTraceToString()}",
status = HttpStatusCode.UnprocessableEntity,
)
}

else -> {
call.respondText(
"500: $cause.\nStack trace: ${cause.stackTraceToString()}",
status = HttpStatusCode.InternalServerError
)
}
}
}
}
9 changes: 9 additions & 0 deletions src/main/Solver.kt
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,15 @@ fun warnOnFewAvailableImporters() {
}
}

class NoFileProvidedException(message: String): Exception(message)

fun networkFromFirstFile(files: List<FileContent>): Network {
if (files.isEmpty()) {
throw NoFileProvidedException("No file with model data provided")
}
return networkFromFileContent(files[0])
}

// This function follows closely the functionality implemented in Powsybl-core Network.read
// However, here we create the ReadOnlyMemDataSource our self which supports constructing it
// from a zip archive (e.g. CIM/XML files zipped).
Expand Down

0 comments on commit a7c07f8

Please sign in to comment.