Skip to content

Commit

Permalink
Merge pull request #50 from cloudoptlab/3.x
Browse files Browse the repository at this point in the history
3.0.2.0
  • Loading branch information
T-baby authored Oct 10, 2021
2 parents 0fd7cfa + 1dd39a0 commit 46ceb5f
Show file tree
Hide file tree
Showing 39 changed files with 343 additions and 350 deletions.
1 change: 1 addition & 0 deletions cloudopt-next-core/build.gradle
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
dependencies {
api project(":cloudopt-next-json")
api project(":cloudopt-next-logging")
api "io.vertx:vertx-core:${rootProject.property('vertx_version')}"
api "io.vertx:vertx-lang-kotlin:${rootProject.property('vertx_version')}"
api "io.vertx:vertx-lang-kotlin-coroutines:${rootProject.property('vertx_version')}"
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,9 @@ object NextServer {

open val interceptors = mutableMapOf<String, MutableList<KClass<out Interceptor>>>()

val beforeRouteHandlersTable = mutableMapOf<String, MutableMap<HttpMethod, Array<Annotation>>>()
val beforeRouteHandlersTable = mutableMapOf<String, MutableMap<HttpMethod, MutableList<Annotation>>>()

val afterRouteHandlersTable = mutableMapOf<String, MutableMap<HttpMethod, Array<Annotation>>>()
val afterRouteHandlersTable = mutableMapOf<String, MutableMap<HttpMethod, MutableList<Annotation>>>()

val resourceTable = arrayListOf<ResourceTable>()

Expand Down Expand Up @@ -166,27 +166,27 @@ object NextServer {
if (annotation.annotationClass.hasAnnotation<Before>()) {
if (beforeRouteHandlersTable.containsKey(resourceUrl)) {
if (beforeRouteHandlersTable[resourceUrl]?.containsKey(httpMethod) == true) {
beforeRouteHandlersTable[resourceUrl]?.get(httpMethod)?.plus(annotation)
beforeRouteHandlersTable[resourceUrl]?.get(httpMethod)?.add(annotation)
} else {
beforeRouteHandlersTable[resourceUrl]?.set(httpMethod, arrayOf(annotation))
beforeRouteHandlersTable[resourceUrl]?.set(httpMethod, mutableListOf(annotation))
}
} else {
val temp = mutableMapOf<HttpMethod, Array<Annotation>>()
temp[httpMethod] = arrayOf(annotation)
val temp = mutableMapOf<HttpMethod, MutableList<Annotation>>()
temp[httpMethod] = mutableListOf(annotation)
beforeRouteHandlersTable[resourceUrl] = temp
}
}
if (annotation.annotationClass.hasAnnotation<After>()) {

if (afterRouteHandlersTable.containsKey(resourceUrl)) {
if (afterRouteHandlersTable[resourceUrl]?.containsKey(httpMethod) == true) {
afterRouteHandlersTable[resourceUrl]?.get(httpMethod)?.plus(annotation)
afterRouteHandlersTable[resourceUrl]?.get(httpMethod)?.add(annotation)
} else {
afterRouteHandlersTable[resourceUrl]?.set(httpMethod, arrayOf(annotation))
afterRouteHandlersTable[resourceUrl]?.set(httpMethod, mutableListOf(annotation))
}
} else {
val temp = mutableMapOf<HttpMethod, Array<Annotation>>()
temp[httpMethod] = arrayOf(annotation)
val temp = mutableMapOf<HttpMethod, MutableList<Annotation>>()
temp[httpMethod] = mutableListOf(annotation)
afterRouteHandlersTable[resourceUrl] = temp
}
}
Expand All @@ -205,7 +205,7 @@ object NextServer {
Logger.configuration.color = webConfig.logColor

//Scan cloudopt handler
Classer.scanPackageByAnnotation("net.cloudopt.next", true, AutoHandler::class)
Classer.scanPackageByAnnotation("net.cloudopt.next.web", true, AutoHandler::class)
.forEach { kclass ->
handlers.add(kclass.createInstance() as Handler)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import net.cloudopt.next.validator.ValidatorTool
import net.cloudopt.next.waf.Wafer
import net.cloudopt.next.web.annotation.*
import net.cloudopt.next.web.handler.ErrorHandler
import java.lang.RuntimeException
import java.sql.Timestamp
import java.text.DateFormat
import java.time.LocalDate
Expand Down Expand Up @@ -171,7 +172,7 @@ class NextServerVerticle : CoroutineVerticle() {
* Set csrf
*/
if (Wafer.config.csrf) {
router.route("/*").handler(CSRFHandler.create(vertx, Wafer.config.encryption))
router.route("/*").handler(CSRFHandler.create(Worker.vertx, Wafer.config.encryption))
}

/**
Expand All @@ -180,12 +181,12 @@ class NextServerVerticle : CoroutineVerticle() {
NextServer.logger.info("[FAILURE HANDLER] Registered failure handler:${NextServer.webConfig.errorHandler}")

router.route("/*").failureHandler { context ->
errorProcessing(context)
errorProcessing(context, context.failure())
}

for (i in 400..500) {
router.errorHandler(i) { context ->
errorProcessing(context)
errorProcessing(context, context.failure())
}
}

Expand Down Expand Up @@ -354,15 +355,15 @@ class NextServerVerticle : CoroutineVerticle() {
* @see ErrorHandler
* @see RoutingContext
*/
private fun errorProcessing(context: RoutingContext) {
private fun errorProcessing(context: RoutingContext, throwable: Throwable? = RuntimeException()) {
context.response().endHandler {
NextServer.handlers.forEach { handler ->
handler.afterCompletion(Resource().init(context))
}
}
val errorHandler = NextServer.errorHandler.createInstance()
errorHandler.init(context)
errorHandler.handle()
errorHandler.handle(context.response().statusCode, throwable)
if (context.failure() != null) {
context.failure().printStackTrace()
logger.error(context.failure().toString())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import net.cloudopt.next.json.Jsoner.toJsonString
import net.cloudopt.next.waf.Wafer
import net.cloudopt.next.web.render.RenderFactory
import net.cloudopt.next.web.render.Template
import java.lang.RuntimeException
import kotlin.reflect.KClass

open class Resource {
Expand Down Expand Up @@ -118,7 +119,6 @@ open class Resource {
fun <T> getAttrs(clazz: KClass<*>): Any {
val map = context.request().formAttributes()
map.forEach {
it
map[it.key] = Wafer.contentFilter(it.value)
}
return (context.request().formAttributes() as MutableMap<String, Any>).toObject(clazz)
Expand Down Expand Up @@ -202,7 +202,7 @@ open class Resource {
cookie.domain = domain
}
if (age > 0) {
cookie.setMaxAge(age)
cookie.maxAge = age
}
if (path.isNotBlank()) {
cookie.path = path
Expand Down Expand Up @@ -236,10 +236,10 @@ open class Resource {
*/
fun getIp(): String {
var ip: String = request.getHeader("x-forwarded-for") ?: ""
if (ip.isBlank()) {
ip = request.getHeader("X-Real-IP") ?: ""
ip = if (ip.isBlank()) {
request.getHeader("X-Real-IP") ?: ""
} else {
ip = ip.split(",".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()[0]
ip.split(",".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()[0]
}
if (ip.isBlank() || "unknown".equals(ip, ignoreCase = true)) {
ip = request.getHeader("Proxy-Client-IP") ?: ""
Expand Down Expand Up @@ -379,10 +379,11 @@ open class Resource {
* {@link Router#errorHandler(int, Handler)}. If no error handler is not defined, It will send a default failure
* response with provided status code.
*
* @param code the HTTP status code
* @param statusCode Int the HTTP status code of the response
* @param throwable Throwable the throwable used when signalling failure
*/
fun fail(code: Int) {
context.fail(code)
fun fail(statusCode: Int, throwable: Throwable? = null) {
context.fail(statusCode, throwable)
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import kotlin.math.abs
class DefaultErrorHandler : ErrorHandler() {


override fun handle() {
override fun handle(statusCode: Int, throwable: Throwable?) {
if (abs(errorStatusCode) == 404) {
response.putHeader(HttpHeaders.CONTENT_TYPE, "text/html;charset=utf-8")
context.response().end(Welcomer.notFound())
Expand All @@ -34,15 +34,17 @@ class DefaultErrorHandler : ErrorHandler() {
context.response().end(Welcomer.systemError())
return
}
val errorMessage = if (context.data().containsKey("errorMessage")) {
val errorMessage = if ((throwable?.message ?: "").isNotBlank()) {
throwable?.message ?: ""
} else if (context.data().containsKey("errorMessage")) {
context.data()["errorMessage"].toString()
} else {
"This is a bad http request, please check if the parameters match the requirements."
}
renderJson(restult(errorStatusCode.toString(), errorMessage))
renderJson(creatResult(errorStatusCode.toString(), errorMessage))
}

private fun restult(error: String, errorMessage: String): HashMap<String, String> {
private fun creatResult(error: String, errorMessage: String): HashMap<String, String> {
val map = hashMapOf<String, String>()
map["error"] = error
map["errorMessage"] = errorMessage
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,12 @@ import net.cloudopt.next.web.Resource

abstract class ErrorHandler : Resource() {

abstract fun handle()
/**
* Used to catch exceptions in context.
* @param statusCode Int the HTTP status code of the response
* @param throwable Throwable the throwable used when signalling failure
*/
abstract fun handle(statusCode: Int, throwable: Throwable?)

}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package net.cloudopt.next.web.test

import io.vertx.kotlin.core.json.get
import io.vertx.kotlin.coroutines.await
import kotlinx.coroutines.runBlocking
import net.cloudopt.next.client.HttpClient
Expand Down Expand Up @@ -50,4 +51,20 @@ class TestRestful : TestStart() {
}
}

@Test
fun testDefaultError() = runBlocking {
val httpCode = client.get("/restful/defaultError").send().await().statusCode()
assertTrue {
httpCode == 402
}
}

@Test
fun testCustomError() = runBlocking {
val result = client.get("/restful/customError").send().await().bodyAsJsonObject()
assertTrue {
result.get<String>("errorMessage") == "401"
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import io.vertx.core.http.ServerWebSocket
import io.vertx.core.http.WebSocketFrame
import net.cloudopt.next.web.WebSocketResource
import net.cloudopt.next.web.annotation.WebSocket
import net.cloudopt.next.web.getCookie
import net.cloudopt.next.web.getIP

@WebSocket("/websocket")
class WebSocketHandler : WebSocketResource {
Expand All @@ -19,6 +21,8 @@ class WebSocketHandler : WebSocketResource {
websocket.writeBinaryMessage(buffer) {
println("The event of after write binary.")
}
websocket.getCookie("key")
websocket.getIP()
}

override suspend fun onConnectionFailure(throwable: Throwable) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,18 @@ package net.cloudopt.next.web.test.controller
import net.cloudopt.next.json.Jsoner.json
import net.cloudopt.next.web.Resource
import net.cloudopt.next.web.annotation.*
import net.cloudopt.next.web.test.handler.TestAfterPrint2Annotation
import net.cloudopt.next.web.test.handler.TestAfterPrintAnnotation
import net.cloudopt.next.web.test.handler.TestBeforePrint2Annotation
import net.cloudopt.next.web.test.handler.TestBeforePrintAnnotation

@API("/restful")
class RestController : Resource() {

@TestBeforePrintAnnotation
@TestBeforePrint2Annotation
@TestAfterPrintAnnotation
@TestAfterPrint2Annotation
@GET
fun get() {
renderJson(json("result" to "get"))
Expand All @@ -32,4 +40,15 @@ class RestController : Resource() {
renderJson(json("result" to "patch"))
}

@GET("/defaultError")
fun defaultError() {
fail(402)
}


@GET("/customError")
fun customError() {
fail(401, RuntimeException("401"))
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package net.cloudopt.next.web.test.handler

import net.cloudopt.next.web.annotation.Before

@Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.FUNCTION)
@MustBeDocumented
@Before(invokeBy = [TestAfterPrint2Handler::class])
annotation class TestAfterPrint2Annotation()
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package net.cloudopt.next.web.test.handler

import net.cloudopt.next.web.Resource
import net.cloudopt.next.web.RouteHandler

class TestAfterPrint2Handler : RouteHandler {

override suspend fun handle(annotation: Annotation, resource: Resource): Boolean {
val afterAnnotation = annotation as TestAfterPrint2Annotation
println("Pass the first TestAfterPrint2Handler")
return true
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package net.cloudopt.next.web.test.handler

import net.cloudopt.next.web.annotation.Before

@Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.FUNCTION)
@MustBeDocumented
@Before(invokeBy = [TestAfterPrintHandler::class])
annotation class TestAfterPrintAnnotation()
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package net.cloudopt.next.web.test.handler

import net.cloudopt.next.web.Resource
import net.cloudopt.next.web.RouteHandler

class TestAfterPrintHandler : RouteHandler {

override suspend fun handle(annotation: Annotation, resource: Resource): Boolean {
val afterAnnotation = annotation as TestAfterPrintAnnotation
println("Pass the first TestAfterPrintHandler")
return true
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package net.cloudopt.next.web.test.handler

import net.cloudopt.next.web.annotation.Before

@Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.FUNCTION)
@MustBeDocumented
@Before(invokeBy = [TestBeforePrint2Handler::class])
annotation class TestBeforePrint2Annotation()
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package net.cloudopt.next.web.test.handler

import net.cloudopt.next.web.Resource
import net.cloudopt.next.web.RouteHandler

class TestBeforePrint2Handler : RouteHandler {

override suspend fun handle(annotation: Annotation, resource: Resource): Boolean {
val beforeAnnotation = annotation as TestBeforePrint2Annotation
println("Pass the first TestBeforePrint2Handler")
return true
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package net.cloudopt.next.web.test.handler

import net.cloudopt.next.web.annotation.Before

@Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.FUNCTION)
@MustBeDocumented
@Before(invokeBy = [TestBeforePrintHandler::class])
annotation class TestBeforePrintAnnotation()
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package net.cloudopt.next.web.test.handler

import net.cloudopt.next.web.Resource
import net.cloudopt.next.web.RouteHandler

class TestBeforePrintHandler : RouteHandler {

override suspend fun handle(annotation: Annotation, resource: Resource): Boolean {
val beforeAnnotation = annotation as TestBeforePrintAnnotation
println("Pass the first TestBeforePrintHandler")
return true
}
}
Loading

0 comments on commit 46ceb5f

Please sign in to comment.