refactoring main server, corrected errors
This commit is contained in:
@@ -4,226 +4,264 @@ import io.netty.buffer.Unpooled
|
|||||||
import io.netty.handler.codec.http.*
|
import io.netty.handler.codec.http.*
|
||||||
import objects.Car
|
import objects.Car
|
||||||
|
|
||||||
/**
|
|
||||||
* Created by user on 8/18/16.
|
|
||||||
*/
|
|
||||||
class DebugClInterface {
|
class DebugClInterface {
|
||||||
|
|
||||||
|
private val routeRegex = Regex("route [0-9]{1,10}")
|
||||||
|
private val sonarRegex = Regex("sonar [0-9]{1,10}")
|
||||||
|
private val environment = objects.Environment.instance
|
||||||
|
private val helpString = "available commands:\n" +
|
||||||
|
"cars - get list of connected cars\n" +
|
||||||
|
"route [car_id] - setting a route for car with car id.\n" +
|
||||||
|
"refloc - refresh all car locations\n" +
|
||||||
|
"sonar [car_id] - get sonar data\n" +
|
||||||
|
"dbinfo [car_id] [type] - refresh all car locations\n." +
|
||||||
|
"type is string name of value or int value. available values: MEMORYSTATS - 0"
|
||||||
|
|
||||||
fun run() {
|
fun run() {
|
||||||
|
|
||||||
val helpString = "available commands:\n" +
|
|
||||||
"cars - get list of connected cars\n" +
|
|
||||||
"route [car_id] - setting a route for car with car id.\n" +
|
|
||||||
"refloc - refresh all car locations\n" +
|
|
||||||
"sonar [car_id] - get sonar data\n" +
|
|
||||||
"dbinfo [car_id] [type] - refresh all car locations\n." +
|
|
||||||
"type is string name of value or int value. available values: MEMORYSTATS - 0"
|
|
||||||
// "stop - exit from this interface and stop all servers\n"//todo sometimes server not completed. some threads dont stop
|
|
||||||
println(helpString)
|
println(helpString)
|
||||||
val routeRegex = Regex("route [0-9]{1,10}")
|
|
||||||
val sonarRegex = Regex("sonar [0-9]{1,10}")
|
|
||||||
val environment = objects.Environment.instance
|
|
||||||
while (true) {
|
while (true) {
|
||||||
val readedString = readLine()
|
val readString = readLine()
|
||||||
if (readedString == null) {
|
if (readString == null || readString.equals("stop")) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if (readedString.equals("cars", true)) {
|
if (readString.equals("")) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
executeCommand(readString)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun printNotSupportedCommand(command: String) {
|
||||||
|
println("not supported command: $command")
|
||||||
|
println(helpString)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun executeCommand(readString: String) {
|
||||||
|
val commandType = readString.split(" ")[0].toLowerCase()
|
||||||
|
when (commandType) {
|
||||||
|
"cars" -> {
|
||||||
synchronized(environment, {
|
synchronized(environment, {
|
||||||
println(environment.map.values)
|
println(environment.map.values)
|
||||||
})
|
})
|
||||||
} else if (routeRegex.matches(readedString)) {
|
}
|
||||||
|
"route" -> executeRouteCommand(readString)
|
||||||
|
"refloc" -> executeRefreshLocationCommand()
|
||||||
|
"sonar" -> executeSonarCommand(readString)
|
||||||
|
"dbinfo" -> executeDebugInfoCommand(readString)
|
||||||
|
else -> printNotSupportedCommand(readString)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
val id: Int
|
private fun executeDebugInfoCommand(readString: String) {
|
||||||
try {
|
val params = readString.split(" ")
|
||||||
id = readedString.split(" ")[1].toInt()
|
if (params.size != 3) {
|
||||||
} catch (e: NumberFormatException) {
|
println("incorrect args of command debug info.")
|
||||||
e.printStackTrace()
|
println(helpString)
|
||||||
println("error in converting id to int type")
|
return
|
||||||
println(helpString)
|
}
|
||||||
continue
|
val id: Int
|
||||||
}
|
try {
|
||||||
val car: Car? =
|
id = params[1].toInt()
|
||||||
synchronized(environment, {
|
} catch (e: NumberFormatException) {
|
||||||
environment.map.get(id)
|
e.printStackTrace()
|
||||||
})
|
println("error in converting id to int type")
|
||||||
if (car != null) {
|
println(helpString)
|
||||||
println("print way points in polar coordinate als [distance] [rotation angle] in metres and degrees. after enter all points print \"done\". for reset route print \"reset\"")
|
return
|
||||||
println("e.g. for move from (x,y) to (x+1,y) and back to (x,y) u need enter: 1 0[press enter] 1 180[press enter] done")
|
}
|
||||||
|
val car: Car? =
|
||||||
val distances = arrayListOf<Int>()
|
|
||||||
val angles = arrayListOf<Int>()
|
|
||||||
while (true) {
|
|
||||||
val wayPointInputString = readLine()!!
|
|
||||||
if (wayPointInputString.equals("reset", true)) {
|
|
||||||
break
|
|
||||||
} else if (wayPointInputString.equals("done", true)) {
|
|
||||||
val routeBuilder = RouteRequest.BuilderRouteRequest(distances.toIntArray(), angles.toIntArray())
|
|
||||||
val requestObject = routeBuilder.build()
|
|
||||||
val requestBytes = ByteArray(requestObject.getSizeNoTag())
|
|
||||||
requestObject.writeTo(CodedOutputStream(requestBytes))
|
|
||||||
val request = getDefaultHttpRequest(car.host, setRouteUrl, requestBytes)
|
|
||||||
try {
|
|
||||||
Client.sendRequest(request, car.host, car.port, id)
|
|
||||||
} catch (e: InactiveCarException) {
|
|
||||||
synchronized(environment, {
|
|
||||||
environment.map.remove(id)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
break
|
|
||||||
} else {
|
|
||||||
val wayPointData = wayPointInputString.split(" ")
|
|
||||||
val distance: Int
|
|
||||||
val angle: Int
|
|
||||||
try {
|
|
||||||
distance = wayPointData[0].toInt()
|
|
||||||
angle = wayPointData[1].toInt()
|
|
||||||
} catch (e: NumberFormatException) {
|
|
||||||
println("error in converting angle or distance to int. try again")
|
|
||||||
continue
|
|
||||||
} catch (e: IndexOutOfBoundsException) {
|
|
||||||
println("format error, u must print two number separated by spaces. Try again")
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
distances.add(distance)
|
|
||||||
angles.add(angle)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
println("car with id=$id not found")
|
|
||||||
}
|
|
||||||
} else if (readedString.equals("refloc", true)) {
|
|
||||||
val cars = synchronized(environment, { environment.map.values })
|
|
||||||
val inactiveCarUids = mutableListOf<Int>()
|
|
||||||
for (car in cars) {
|
|
||||||
val request = getDefaultHttpRequest(car.host, getLocationUrl, ByteArray(0))
|
|
||||||
try {
|
|
||||||
Client.sendRequest(request, car.host, car.port, car.uid)
|
|
||||||
} catch (e: InactiveCarException) {
|
|
||||||
inactiveCarUids.add(car.uid)
|
|
||||||
}
|
|
||||||
println("ref loc done")
|
|
||||||
}
|
|
||||||
synchronized(environment, {
|
synchronized(environment, {
|
||||||
for (id in inactiveCarUids) {
|
environment.map[id]
|
||||||
environment.map.remove(id)
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
} else if (readedString.equals("stop")) {
|
if (car == null) {
|
||||||
break
|
println("car with id=$id not found")
|
||||||
} else if (sonarRegex.matches(readedString)) {
|
return
|
||||||
val id: Int
|
}
|
||||||
try {
|
val paramType = params[2]//maybe string or int
|
||||||
id = readedString.split(" ")[1].toInt()
|
val type: DebugRequest.Type
|
||||||
} catch (e: NumberFormatException) {
|
try {
|
||||||
e.printStackTrace()
|
type = DebugRequest.Type.fromIntToType(paramType.toInt())
|
||||||
println("error in converting id to int type")
|
} catch (e: NumberFormatException) {
|
||||||
println(helpString)
|
try {
|
||||||
continue
|
type = DebugRequest.Type.valueOf(paramType)
|
||||||
}
|
} catch (e: IllegalArgumentException) {
|
||||||
val car: Car? =
|
type = DebugRequest.Type.Unexpected
|
||||||
synchronized(environment, {
|
}
|
||||||
environment.map.get(id)
|
}
|
||||||
})
|
if (type == DebugRequest.Type.Unexpected) {
|
||||||
if (car == null) {
|
println("type with name/id $paramType not found")
|
||||||
println("car with id=$id not found")
|
return
|
||||||
continue
|
}
|
||||||
}
|
val requestObject = DebugRequest.BuilderDebugRequest(type).build()
|
||||||
println("print angles, after printing all angles print done")
|
val bytes = ByteArray(requestObject.getSizeNoTag())
|
||||||
val angles = arrayListOf<Int>()
|
requestObject.writeTo(CodedOutputStream(bytes))
|
||||||
while (true) {
|
val request = getDefaultHttpRequest(car.host, debugMemoryUrl, bytes)
|
||||||
val command = readLine()!!
|
try {
|
||||||
if (command.equals("done", true)) {
|
Client.sendRequest(request, car.host, car.port, getRequestOptionId(car.uid))
|
||||||
val sonarBuilder = SonarRequest.BuilderSonarRequest(angles.toIntArray())
|
} catch (e: InactiveCarException) {
|
||||||
val requestObject = sonarBuilder.build()
|
println("this car is inactive")
|
||||||
val requestBytes = ByteArray(requestObject.getSizeNoTag())
|
}
|
||||||
requestObject.writeTo(CodedOutputStream(requestBytes))
|
}
|
||||||
val request = getDefaultHttpRequest(car.host, sonarUrl, requestBytes)
|
|
||||||
try {
|
|
||||||
Client.sendRequest(request, car.host, car.port, id)
|
|
||||||
} catch (e: InactiveCarException) {
|
|
||||||
synchronized(environment, {
|
|
||||||
environment.map.remove(id)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
break
|
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
val angle = command.toInt()
|
|
||||||
if (angle < 0 || angle > 180) {
|
|
||||||
println("incorrect angle $angle. angle must be in [0,180] and div on 4")
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
angles.add(angle)
|
|
||||||
} catch (e: NumberFormatException) {
|
|
||||||
println("error in converting angle to int. try again")
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} else if (readedString.contains("dbinfo")) {
|
private fun executeSonarCommand(readString: String) {
|
||||||
val params = readedString.split(" ")
|
if (!sonarRegex.matches(readString)) {
|
||||||
if (!params[0].equals("dbinfo")) {
|
println("incorrect args of command sonar.")
|
||||||
println("not supported command: $readedString")
|
println(helpString)
|
||||||
println(helpString)
|
return
|
||||||
continue
|
}
|
||||||
|
val id: Int
|
||||||
|
try {
|
||||||
|
id = readString.split(" ")[1].toInt()
|
||||||
|
} catch (e: NumberFormatException) {
|
||||||
|
e.printStackTrace()
|
||||||
|
println("error in converting id to int type")
|
||||||
|
println(helpString)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val car: Car? =
|
||||||
|
synchronized(environment, {
|
||||||
|
environment.map[id]
|
||||||
|
})
|
||||||
|
if (car == null) {
|
||||||
|
println("car with id=$id not found")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val requestMessage = getSonarRequest() ?: return
|
||||||
|
val requestBytes = ByteArray(requestMessage.getSizeNoTag())
|
||||||
|
requestMessage.writeTo(CodedOutputStream(requestBytes))
|
||||||
|
val request = getDefaultHttpRequest(car.host, sonarUrl, requestBytes)
|
||||||
|
try {
|
||||||
|
Client.sendRequest(request, car.host, car.port, mapOf(Pair("angles", requestMessage.angles)))
|
||||||
|
} catch (e: InactiveCarException) {
|
||||||
|
synchronized(environment, {
|
||||||
|
environment.map.remove(id)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getSonarRequest(): SonarRequest? {
|
||||||
|
println("print angles, after printing all angles print done")
|
||||||
|
val angles = arrayListOf<Int>()
|
||||||
|
while (true) {
|
||||||
|
val command = readLine()!!.toLowerCase()
|
||||||
|
when (command) {
|
||||||
|
"reset" -> return null
|
||||||
|
"done" -> {
|
||||||
|
val sonarBuilder = SonarRequest.BuilderSonarRequest(angles.toIntArray())
|
||||||
|
return sonarBuilder.build()
|
||||||
}
|
}
|
||||||
if (params.size != 3) {
|
else -> {
|
||||||
println("incorrect args of command dbinfo.")
|
|
||||||
println(helpString)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
val id: Int
|
|
||||||
try {
|
|
||||||
id = params[1].toInt()
|
|
||||||
} catch (e: NumberFormatException) {
|
|
||||||
e.printStackTrace()
|
|
||||||
println("error in converting id to int type")
|
|
||||||
println(helpString)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
val car: Car? =
|
|
||||||
synchronized(environment, {
|
|
||||||
environment.map.get(id)
|
|
||||||
})
|
|
||||||
if (car == null) {
|
|
||||||
println("car with id=$id not found")
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
val paramType = params[2]//maybe string or int
|
|
||||||
val type: DebugRequest.Type
|
|
||||||
try {
|
|
||||||
type = DebugRequest.Type.fromIntToType(paramType.toInt())
|
|
||||||
} catch (e: NumberFormatException) {
|
|
||||||
try {
|
try {
|
||||||
type = DebugRequest.Type.valueOf(paramType)
|
val angle = command.toInt()
|
||||||
} catch (e: IllegalArgumentException) {
|
if (angle < 0 || angle > 180) {
|
||||||
type = DebugRequest.Type.Unexpected
|
println("incorrect angle $angle. angle must be in [0,180] and div on 4")
|
||||||
|
} else {
|
||||||
|
angles.add(angle)
|
||||||
|
}
|
||||||
|
} catch (e: NumberFormatException) {
|
||||||
|
println("error in converting angle to int. try again")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (type == DebugRequest.Type.Unexpected) {
|
|
||||||
println("type with name/id $paramType not found")
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
val requestObject = DebugRequest.BuilderDebugRequest(type).build()
|
|
||||||
val bytes = ByteArray(requestObject.getSizeNoTag())
|
|
||||||
requestObject.writeTo(CodedOutputStream(bytes))
|
|
||||||
val request = getDefaultHttpRequest(car.host, debugMemoryUrl, bytes)
|
|
||||||
try {
|
|
||||||
Client.sendRequest(request, car.host, car.port, car.uid)
|
|
||||||
} catch (e: InactiveCarException) {
|
|
||||||
println("this car is inactive")
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
println("not supported command: $readedString")
|
|
||||||
println(helpString)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun getRequestOptionId(id: Int): Map<String, Int> {
|
||||||
|
return mapOf(Pair("uid", id))
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun executeRefreshLocationCommand() {
|
||||||
|
val cars = synchronized(environment, { environment.map.values })
|
||||||
|
val inactiveCars = mutableListOf<Int>()
|
||||||
|
for (car in cars) {
|
||||||
|
val request = getDefaultHttpRequest(car.host, getLocationUrl, ByteArray(0))
|
||||||
|
try {
|
||||||
|
Client.sendRequest(request, car.host, car.port, getRequestOptionId(car.uid))
|
||||||
|
} catch (e: InactiveCarException) {
|
||||||
|
inactiveCars.add(car.uid)
|
||||||
|
}
|
||||||
|
println("ref loc done")
|
||||||
|
}
|
||||||
|
synchronized(environment, {
|
||||||
|
for (id in inactiveCars) {
|
||||||
|
environment.map.remove(id)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun executeRouteCommand(readString: String) {
|
||||||
|
if (!routeRegex.matches(readString)) {
|
||||||
|
println("incorrect args of command route.")
|
||||||
|
println(helpString)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val id: Int
|
||||||
|
try {
|
||||||
|
id = readString.split(" ")[1].toInt()
|
||||||
|
} catch (e: NumberFormatException) {
|
||||||
|
e.printStackTrace()
|
||||||
|
println("error in converting id to int type")
|
||||||
|
println(helpString)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val car: Car? =
|
||||||
|
synchronized(environment, {
|
||||||
|
environment.map[id]
|
||||||
|
})
|
||||||
|
if (car == null) {
|
||||||
|
println("car with id=$id not found")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val routeMessage = getRouteMessage() ?: return
|
||||||
|
val requestBytes = ByteArray(routeMessage.getSizeNoTag())
|
||||||
|
routeMessage.writeTo(CodedOutputStream(requestBytes))
|
||||||
|
val request = getDefaultHttpRequest(car.host, setRouteUrl, requestBytes)
|
||||||
|
try {
|
||||||
|
Client.sendRequest(request, car.host, car.port, mapOf(Pair("uid", id)))
|
||||||
|
} catch (e: InactiveCarException) {
|
||||||
|
synchronized(environment, {
|
||||||
|
environment.map.remove(id)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getRouteMessage(): RouteRequest? {
|
||||||
|
println("print way points in polar coordinate als [distance] [rotation angle] in metres and degrees." +
|
||||||
|
"after enter all points print \"done\". for reset route print \"reset\"")
|
||||||
|
println("e.g. for move from (x,y) to (x+1,y) and back to (x,y) you need enter:" +
|
||||||
|
"1 0[enter] 1 180[enter] done")
|
||||||
|
val distances = arrayListOf<Int>()
|
||||||
|
val angles = arrayListOf<Int>()
|
||||||
|
while (true) {
|
||||||
|
val readLine = readLine()!!.toLowerCase()
|
||||||
|
when (readLine) {
|
||||||
|
"reset" -> return null
|
||||||
|
"done" -> {
|
||||||
|
val routeBuilder = RouteRequest.BuilderRouteRequest(distances.toIntArray(), angles.toIntArray())
|
||||||
|
return routeBuilder.build()
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
val wayPointData = readLine.split(" ")
|
||||||
|
val distance: Int
|
||||||
|
val angle: Int
|
||||||
|
try {
|
||||||
|
distance = wayPointData[0].toInt()
|
||||||
|
angle = wayPointData[1].toInt()
|
||||||
|
distances.add(distance)
|
||||||
|
angles.add(angle)
|
||||||
|
} catch (e: NumberFormatException) {
|
||||||
|
println("error in converting angle or distance to int. try again")
|
||||||
|
} catch (e: IndexOutOfBoundsException) {
|
||||||
|
println("format error, u must print two number separated by spaces. Try again")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
fun getDefaultHttpRequest(host: String, url: String, bytes: ByteArray): DefaultFullHttpRequest {
|
fun getDefaultHttpRequest(host: String, url: String, bytes: ByteArray): DefaultFullHttpRequest {
|
||||||
val request = DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.POST, url, Unpooled.copiedBuffer(bytes));
|
val request = DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.POST, url, Unpooled.copiedBuffer(bytes))
|
||||||
request.headers().set(HttpHeaderNames.HOST, host)
|
request.headers().set(HttpHeaderNames.HOST, host)
|
||||||
request.headers().set(HttpHeaderNames.CONNECTION, HttpHeaderValues.CLOSE)
|
request.headers().set(HttpHeaderNames.CONNECTION, HttpHeaderValues.CLOSE)
|
||||||
request.headers().setInt(HttpHeaderNames.CONTENT_LENGTH, request.content().readableBytes())
|
request.headers().setInt(HttpHeaderNames.CONTENT_LENGTH, request.content().readableBytes())
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
package Exceptions
|
package Exceptions
|
||||||
|
|
||||||
/**
|
|
||||||
* Created by user on 7/28/16.
|
|
||||||
*/
|
|
||||||
class InactiveCarException : Exception() {
|
class InactiveCarException : Exception() {
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
object RoomBypassingAlgorithm {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,14 +1,8 @@
|
|||||||
import io.netty.bootstrap.ServerBootstrap
|
import car.Dropper
|
||||||
import io.netty.channel.nio.NioEventLoopGroup
|
|
||||||
import io.netty.channel.socket.nio.NioServerSocketChannel
|
|
||||||
import kotlin.concurrent.thread
|
|
||||||
|
|
||||||
val timeDeltaToDrop = 600000//time in ms. if car is inactive more than this time, server drop session with car
|
|
||||||
val carServerPort: Int = 7925
|
val carServerPort: Int = 7925
|
||||||
val webServerPort: Int = 7926
|
val webServerPort: Int = 7926
|
||||||
val handlerThreadsCount: Int = 100
|
|
||||||
val getLocationUrl = "/getLocation"
|
val getLocationUrl = "/getLocation"
|
||||||
val routeDoneUrl = "/routeDone"
|
|
||||||
val setRouteUrl = "/route"
|
val setRouteUrl = "/route"
|
||||||
val connectUrl = "/connect"
|
val connectUrl = "/connect"
|
||||||
val debugMemoryUrl = "/debug/memory"
|
val debugMemoryUrl = "/debug/memory"
|
||||||
@@ -16,9 +10,9 @@ val sonarUrl = "/sonar"
|
|||||||
|
|
||||||
fun main(args: Array<String>) {
|
fun main(args: Array<String>) {
|
||||||
|
|
||||||
val carServer = getCarServerThread()
|
val carServer = car.server.Server.getCarServerThread(carServerPort)
|
||||||
val webServer = getWebServerThread()
|
val webServer = web.server.Server.getWebServerThread(webServerPort)
|
||||||
val carsDestroy = getCarsDestroyThread()
|
val carsDestroy = Dropper.getCarsDestroyThread()
|
||||||
carServer.start()
|
carServer.start()
|
||||||
carsDestroy.start()
|
carsDestroy.start()
|
||||||
webServer.start()
|
webServer.start()
|
||||||
@@ -28,81 +22,5 @@ fun main(args: Array<String>) {
|
|||||||
|
|
||||||
carsDestroy.interrupt()
|
carsDestroy.interrupt()
|
||||||
carServer.interrupt()
|
carServer.interrupt()
|
||||||
|
webServer.interrupt()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getCarServerThread(): Thread {
|
|
||||||
return thread(false, false, null, "carServer", -1, {
|
|
||||||
println("car server started")
|
|
||||||
val bossGroup = NioEventLoopGroup(1)
|
|
||||||
val workerGroup = NioEventLoopGroup()
|
|
||||||
val b = ServerBootstrap()
|
|
||||||
val initializer = car.server.Initializer(handlerThreadsCount)
|
|
||||||
b.group(bossGroup, workerGroup)
|
|
||||||
.channel(NioServerSocketChannel().javaClass)
|
|
||||||
.childHandler(initializer)
|
|
||||||
|
|
||||||
try {
|
|
||||||
val channel = b.bind(carServerPort).sync().channel()
|
|
||||||
channel.closeFuture().sync()
|
|
||||||
} catch (e: InterruptedException) {
|
|
||||||
println("car server stoped")
|
|
||||||
} finally {
|
|
||||||
bossGroup.shutdownGracefully()
|
|
||||||
workerGroup.shutdownGracefully()
|
|
||||||
initializer.group.shutdownGracefully()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getWebServerThread(): Thread {
|
|
||||||
return thread(false, false, null, "webServer", -1, {
|
|
||||||
println("web server started")
|
|
||||||
val bossGroup = NioEventLoopGroup(1)
|
|
||||||
val workerGroup = NioEventLoopGroup()
|
|
||||||
val b = ServerBootstrap()
|
|
||||||
val initializer = web.server.Initializer(handlerThreadsCount)
|
|
||||||
b.group(bossGroup, workerGroup)
|
|
||||||
.channel(NioServerSocketChannel().javaClass)
|
|
||||||
.childHandler(initializer)
|
|
||||||
|
|
||||||
try {
|
|
||||||
val channel = b.bind(webServerPort).sync().channel()
|
|
||||||
channel.closeFuture().sync()
|
|
||||||
} catch (e: InterruptedException) {
|
|
||||||
println("web server stoped")
|
|
||||||
} finally {
|
|
||||||
bossGroup.shutdownGracefully()
|
|
||||||
workerGroup.shutdownGracefully()
|
|
||||||
initializer.group.shutdownGracefully()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
//thread, that dropped inactive car. every minute check all connected cars and if car is inactive more, als timeDeltaToDrop then remove this car.
|
|
||||||
fun getCarsDestroyThread(): Thread {
|
|
||||||
return thread(false, false, null, "dropCar", -1, {
|
|
||||||
var stoped = false
|
|
||||||
while (!stoped) {
|
|
||||||
val environment = objects.Environment.instance
|
|
||||||
synchronized(environment, {
|
|
||||||
val currentTime = System.currentTimeMillis()
|
|
||||||
val keysToRemove = mutableListOf<Int>();
|
|
||||||
for (keyValue in environment.map) {
|
|
||||||
if ((keyValue.value.lastAction + timeDeltaToDrop) < currentTime) {
|
|
||||||
keysToRemove.add(keyValue.key)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (key in keysToRemove) {
|
|
||||||
//todo this car is MAYBE disconnect. need ping this car and if dont have answer - drop
|
|
||||||
// environment.map.remove(key)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
try {
|
|
||||||
Thread.sleep(60000)
|
|
||||||
} catch (e: InterruptedException) {
|
|
||||||
println("thread for destroy cars stoped")
|
|
||||||
stoped = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
package car
|
||||||
|
|
||||||
|
import Exceptions.InactiveCarException
|
||||||
|
import car.client.Client
|
||||||
|
import io.netty.handler.codec.http.DefaultHttpRequest
|
||||||
|
import io.netty.handler.codec.http.HttpMethod
|
||||||
|
import io.netty.handler.codec.http.HttpVersion
|
||||||
|
import objects.Environment
|
||||||
|
import kotlin.concurrent.thread
|
||||||
|
|
||||||
|
object Dropper {
|
||||||
|
private val timeDeltaToDrop = 600000//time in ms.
|
||||||
|
// if car is inactive more than this time, this thread drop session with car
|
||||||
|
|
||||||
|
fun getCarsDestroyThread(): Thread {
|
||||||
|
return thread(false, false, null, "dropCar", -1, getThreadCode())
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getThreadCode(): () -> Unit {
|
||||||
|
return {
|
||||||
|
var stopped = false
|
||||||
|
while (!stopped) {
|
||||||
|
val environment = Environment.instance
|
||||||
|
synchronized(environment, {
|
||||||
|
val currentTime = System.currentTimeMillis()
|
||||||
|
val keysToRemove = mutableListOf<Int>()
|
||||||
|
for ((key, value) in environment.map) {
|
||||||
|
if ((value.lastAction + timeDeltaToDrop) < currentTime) {
|
||||||
|
keysToRemove.add(key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dropInactiveCar(keysToRemove, environment)
|
||||||
|
})
|
||||||
|
try {
|
||||||
|
Thread.sleep(60000)
|
||||||
|
} catch (e: InterruptedException) {
|
||||||
|
println("thread for destroy cars stopped")
|
||||||
|
stopped = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun dropInactiveCar(keysToRemove: List<Int>, environment: Environment) {
|
||||||
|
for (key in keysToRemove) {
|
||||||
|
try {
|
||||||
|
val carValue = environment.map[key] ?: continue
|
||||||
|
val request = DefaultHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.POST, "/ping")
|
||||||
|
Client.sendRequest(request, carValue.host, carValue.port, mapOf(Pair("uid", key)))
|
||||||
|
} catch (e: InactiveCarException) {
|
||||||
|
environment.map.remove(key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,9 +8,6 @@ import io.netty.handler.codec.http.HttpRequest
|
|||||||
import io.netty.util.AttributeKey
|
import io.netty.util.AttributeKey
|
||||||
import java.net.ConnectException
|
import java.net.ConnectException
|
||||||
|
|
||||||
/**
|
|
||||||
* Created by user on 7/8/16.
|
|
||||||
*/
|
|
||||||
object Client {
|
object Client {
|
||||||
|
|
||||||
val bootstrap: Bootstrap = makeBootstrap()
|
val bootstrap: Bootstrap = makeBootstrap()
|
||||||
@@ -24,18 +21,19 @@ object Client {
|
|||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
fun sendRequest(request: HttpRequest, host: String, port: Int, carUid: Int) {
|
fun <T> sendRequest(request: HttpRequest, host: String, port: Int, options: Map<String, T>) {
|
||||||
try {
|
try {
|
||||||
bootstrap.attr(AttributeKey.valueOf<String>("url"), request.uri())
|
bootstrap.attr(AttributeKey.valueOf<String>("url"), request.uri())
|
||||||
bootstrap.attr(AttributeKey.valueOf<Int>("uid"), carUid)
|
for ((key, value) in options) {
|
||||||
|
bootstrap.attr(AttributeKey.valueOf<T>(key), value)
|
||||||
|
}
|
||||||
val ch = bootstrap.connect(host, port).sync().channel()
|
val ch = bootstrap.connect(host, port).sync().channel()
|
||||||
ch.writeAndFlush(request)
|
ch.writeAndFlush(request)
|
||||||
ch.closeFuture().sync()//wait for answer
|
// ch.closeFuture().sync()//wait for answer
|
||||||
} catch (e: InterruptedException) {
|
} catch (e: InterruptedException) {
|
||||||
|
|
||||||
} catch (e: ConnectException) {
|
} catch (e: ConnectException) {
|
||||||
throw InactiveCarException()
|
throw InactiveCarException()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,9 @@
|
|||||||
package car.client
|
package car.client
|
||||||
|
|
||||||
import CodedInputStream
|
import CodedInputStream
|
||||||
|
import DebugResponseMemoryStats
|
||||||
import LocationResponse
|
import LocationResponse
|
||||||
|
import SonarResponse
|
||||||
import debugMemoryUrl
|
import debugMemoryUrl
|
||||||
import getLocationUrl
|
import getLocationUrl
|
||||||
import io.netty.channel.ChannelHandlerContext
|
import io.netty.channel.ChannelHandlerContext
|
||||||
@@ -12,47 +14,32 @@ import objects.Environment
|
|||||||
import sonarUrl
|
import sonarUrl
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
/**
|
|
||||||
* Created by user on 7/8/16.
|
|
||||||
*/
|
|
||||||
class ClientHandler : SimpleChannelInboundHandler<Any> {
|
class ClientHandler : SimpleChannelInboundHandler<Any> {
|
||||||
|
|
||||||
constructor()
|
constructor()
|
||||||
|
|
||||||
var contentBytes: ByteArray = ByteArray(0);
|
var contentBytes: ByteArray = ByteArray(0)
|
||||||
|
|
||||||
override fun channelReadComplete(ctx: ChannelHandlerContext) {
|
override fun channelReadComplete(ctx: ChannelHandlerContext) {
|
||||||
val url = ctx.channel().attr(AttributeKey.valueOf<String>("url")).get()
|
val url = ctx.channel().attr(AttributeKey.valueOf<String>("url")).get()
|
||||||
val carUid = ctx.channel().attr(AttributeKey.valueOf<Int>("uid")).get()
|
|
||||||
val environment = Environment.instance
|
|
||||||
when (url) {
|
when (url) {
|
||||||
getLocationUrl -> {
|
getLocationUrl -> {
|
||||||
val response = LocationResponse.BuilderLocationResponse(LocationResponse.LocationData.BuilderLocationData(0, 0, 0).build(), 0).build()
|
val carUid = ctx.channel().attr(AttributeKey.valueOf<Int>("uid")).get()
|
||||||
|
val locData = LocationResponse.LocationData.BuilderLocationData(0, 0, 0).build()
|
||||||
|
val response = LocationResponse.BuilderLocationResponse(locData, 0).build()
|
||||||
response.mergeFrom(CodedInputStream(contentBytes))
|
response.mergeFrom(CodedInputStream(contentBytes))
|
||||||
|
handlerGetLocationResponse(response, carUid)
|
||||||
if (response.code == 0) {
|
|
||||||
val data = response.locationResponseData
|
|
||||||
synchronized(environment, {
|
|
||||||
val car = environment.map.get(carUid)
|
|
||||||
if (car != null) {
|
|
||||||
car.x = data.x
|
|
||||||
car.y = data.y
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
debugMemoryUrl -> {
|
debugMemoryUrl -> {
|
||||||
val response = DebugResponseMemoryStats.BuilderDebugResponseMemoryStats(0, 0, 0, 0).build()
|
val response = DebugResponseMemoryStats.BuilderDebugResponseMemoryStats(0, 0, 0, 0).build()
|
||||||
response.mergeFrom(CodedInputStream(contentBytes))
|
response.mergeFrom(CodedInputStream(contentBytes))
|
||||||
println("heapDynamicMaxBytes ${response.heapDynamicMaxBytes}")
|
handlerDebugMemoryResponse(response)
|
||||||
println("heapDynamicTail ${response.heapDynamicTail}")
|
|
||||||
println("heapDynamicTotalBytes ${response.heapDynamicTotalBytes}")
|
|
||||||
println("heapStaticTail ${response.heapStaticTail}")
|
|
||||||
}
|
}
|
||||||
sonarUrl -> {
|
sonarUrl -> {
|
||||||
val sonarDistances = SonarResponse.BuilderSonarResponse(IntArray(0)).build()
|
val response = SonarResponse.BuilderSonarResponse(IntArray(0)).build()
|
||||||
sonarDistances.mergeFrom(CodedInputStream(contentBytes))
|
response.mergeFrom(CodedInputStream(contentBytes))
|
||||||
println("distances from sonar: ${Arrays.toString(sonarDistances.distances)}")
|
val angles = ctx.channel().attr(AttributeKey.valueOf<IntArray>("angles")).get()
|
||||||
|
handlerSonarResponse(response, angles)
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
|
|
||||||
@@ -61,9 +48,36 @@ class ClientHandler : SimpleChannelInboundHandler<Any> {
|
|||||||
ctx.close()
|
ctx.close()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun handlerGetLocationResponse(message: LocationResponse, carUid: Int) {
|
||||||
|
val environment = Environment.instance
|
||||||
|
if (message.code == 0) {
|
||||||
|
val data = message.locationResponseData
|
||||||
|
synchronized(environment, {
|
||||||
|
val car = environment.map[carUid]
|
||||||
|
if (car != null) {
|
||||||
|
car.x = data.x
|
||||||
|
car.y = data.y
|
||||||
|
car.angle = data.angle
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handlerDebugMemoryResponse(message: DebugResponseMemoryStats) {
|
||||||
|
println("heapDynamicMaxBytes ${message.heapDynamicMaxBytes}")
|
||||||
|
println("heapDynamicTail ${message.heapDynamicTail}")
|
||||||
|
println("heapDynamicTotalBytes ${message.heapDynamicTotalBytes}")
|
||||||
|
println("heapStaticTail ${message.heapStaticTail}")
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handlerSonarResponse(message: SonarResponse, angles: IntArray) {
|
||||||
|
println("request angles: ${Arrays.toString(angles)}")
|
||||||
|
println("distances from sonar: ${Arrays.toString(message.distances)}")
|
||||||
|
}
|
||||||
|
|
||||||
override fun channelRead0(ctx: ChannelHandlerContext?, msg: Any?) {
|
override fun channelRead0(ctx: ChannelHandlerContext?, msg: Any?) {
|
||||||
if (msg is DefaultHttpContent) {
|
if (msg is DefaultHttpContent) {
|
||||||
val contentsBytes = msg.content();
|
val contentsBytes = msg.content()
|
||||||
contentBytes = ByteArray(contentsBytes.capacity())
|
contentBytes = ByteArray(contentsBytes.capacity())
|
||||||
contentsBytes.readBytes(contentBytes)
|
contentsBytes.readBytes(contentBytes)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,9 +4,6 @@ import io.netty.channel.ChannelInitializer
|
|||||||
import io.netty.channel.socket.SocketChannel
|
import io.netty.channel.socket.SocketChannel
|
||||||
import io.netty.handler.codec.http.HttpClientCodec
|
import io.netty.handler.codec.http.HttpClientCodec
|
||||||
|
|
||||||
/**
|
|
||||||
* Created by user on 7/8/16.
|
|
||||||
*/
|
|
||||||
class ClientInitializer : ChannelInitializer<SocketChannel> {
|
class ClientInitializer : ChannelInitializer<SocketChannel> {
|
||||||
|
|
||||||
constructor()
|
constructor()
|
||||||
|
|||||||
@@ -4,8 +4,6 @@ import CodedInputStream
|
|||||||
import CodedOutputStream
|
import CodedOutputStream
|
||||||
import ConnectionRequest
|
import ConnectionRequest
|
||||||
import ConnectionResponse
|
import ConnectionResponse
|
||||||
import RouteDoneRequest
|
|
||||||
import RouteDoneResponse
|
|
||||||
import connectUrl
|
import connectUrl
|
||||||
import io.netty.buffer.Unpooled
|
import io.netty.buffer.Unpooled
|
||||||
import io.netty.channel.ChannelFutureListener
|
import io.netty.channel.ChannelFutureListener
|
||||||
@@ -13,59 +11,35 @@ import io.netty.channel.ChannelHandlerContext
|
|||||||
import io.netty.channel.SimpleChannelInboundHandler
|
import io.netty.channel.SimpleChannelInboundHandler
|
||||||
import io.netty.handler.codec.http.*
|
import io.netty.handler.codec.http.*
|
||||||
import objects.Environment
|
import objects.Environment
|
||||||
import routeDoneUrl
|
|
||||||
|
|
||||||
class Handler : SimpleChannelInboundHandler<Any>() {
|
class Handler : SimpleChannelInboundHandler<Any>() {
|
||||||
|
|
||||||
var url: String = ""
|
var url: String = ""
|
||||||
var contentBytes: ByteArray = ByteArray(0);
|
var contentBytes: ByteArray = ByteArray(0)
|
||||||
|
|
||||||
override fun channelReadComplete(ctx: ChannelHandlerContext) {
|
override fun channelReadComplete(ctx: ChannelHandlerContext) {
|
||||||
|
|
||||||
val environment = Environment.instance
|
val environment = Environment.instance
|
||||||
var success = true;
|
var success = true
|
||||||
var answer = ByteArray(0)
|
var answer = ByteArray(0)
|
||||||
when (url) {
|
when (url) {
|
||||||
connectUrl -> {
|
connectUrl -> {
|
||||||
val data = ConnectionRequest.BuilderConnectionRequest(IntArray(0), 0).build();
|
val data = ConnectionRequest.BuilderConnectionRequest(IntArray(0), 0).build()
|
||||||
data.mergeFrom(CodedInputStream(contentBytes))
|
data.mergeFrom(CodedInputStream(contentBytes))
|
||||||
if (success) {
|
val ipStr = data.ipValues.map { elem -> elem.toString() }.reduce { elem1, elem2 -> elem1 + "." + elem2 }
|
||||||
val ipStr = data.ipValues.map { elem -> elem.toString() }.reduce { elem1, elem2 -> elem1 + "." + elem2 }
|
val uid = environment.connectCar(ipStr, data.port)
|
||||||
val uid = environment.connectCar(ipStr, data.port)
|
val responseObject = ConnectionResponse.BuilderConnectionResponse(uid, 0).build()
|
||||||
val responseObject = ConnectionResponse.BuilderConnectionResponse(uid, 0).build()
|
answer = ByteArray(responseObject.getSizeNoTag())
|
||||||
answer = ByteArray(responseObject.getSizeNoTag())
|
responseObject.writeTo(CodedOutputStream(answer))
|
||||||
responseObject.writeTo(CodedOutputStream(answer))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
routeDoneUrl -> {
|
|
||||||
val data = RouteDoneRequest.BuilderRouteDoneRequest(0).build()
|
|
||||||
data.mergeFrom(CodedInputStream(contentBytes))
|
|
||||||
if (success) {
|
|
||||||
val id = data.uid
|
|
||||||
synchronized(environment.map, {
|
|
||||||
val car = environment.map.get(id)
|
|
||||||
if (car != null) {
|
|
||||||
car.free = true
|
|
||||||
car.lastAction = System.currentTimeMillis()
|
|
||||||
val responseObject = RouteDoneResponse.BuilderRouteDoneResponse(0).build()
|
|
||||||
answer = ByteArray(responseObject.getSizeNoTag())
|
|
||||||
responseObject.writeTo(CodedOutputStream(answer))
|
|
||||||
} else {
|
|
||||||
success = false
|
|
||||||
val responseObject = RouteDoneResponse.BuilderRouteDoneResponse(2).build()
|
|
||||||
answer = ByteArray(responseObject.getSizeNoTag())
|
|
||||||
responseObject.writeTo(CodedOutputStream(answer))
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
success = false
|
success = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val response = DefaultFullHttpResponse(HttpVersion.HTTP_1_1, if (success) HttpResponseStatus.OK else HttpResponseStatus.BAD_REQUEST, Unpooled.copiedBuffer(answer))
|
val responseStatus = if (success) HttpResponseStatus.OK else HttpResponseStatus.BAD_REQUEST
|
||||||
|
val response = DefaultFullHttpResponse(HttpVersion.HTTP_1_1, responseStatus, Unpooled.copiedBuffer(answer))
|
||||||
response.headers().setInt(HttpHeaderNames.CONTENT_LENGTH, response.content().readableBytes())
|
response.headers().setInt(HttpHeaderNames.CONTENT_LENGTH, response.content().readableBytes())
|
||||||
ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
|
ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun channelRead0(ctx: ChannelHandlerContext, msg: Any) {
|
override fun channelRead0(ctx: ChannelHandlerContext, msg: Any) {
|
||||||
@@ -74,7 +48,7 @@ class Handler : SimpleChannelInboundHandler<Any>() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (msg is DefaultHttpContent) {
|
if (msg is DefaultHttpContent) {
|
||||||
val contentsBytes = msg.content();
|
val contentsBytes = msg.content()
|
||||||
contentBytes = ByteArray(contentsBytes.capacity())
|
contentBytes = ByteArray(contentsBytes.capacity())
|
||||||
contentsBytes.readBytes(contentBytes)
|
contentsBytes.readBytes(contentBytes)
|
||||||
}
|
}
|
||||||
@@ -84,8 +58,6 @@ class Handler : SimpleChannelInboundHandler<Any>() {
|
|||||||
override fun exceptionCaught(ctx: ChannelHandlerContext?, cause: Throwable?) {
|
override fun exceptionCaught(ctx: ChannelHandlerContext?, cause: Throwable?) {
|
||||||
println("exception")
|
println("exception")
|
||||||
cause?.printStackTrace()
|
cause?.printStackTrace()
|
||||||
if (ctx != null) {
|
ctx?.close()
|
||||||
ctx.close()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -7,12 +7,9 @@ import io.netty.handler.codec.http.HttpServerCodec
|
|||||||
import io.netty.util.concurrent.DefaultEventExecutorGroup
|
import io.netty.util.concurrent.DefaultEventExecutorGroup
|
||||||
import io.netty.util.concurrent.EventExecutorGroup
|
import io.netty.util.concurrent.EventExecutorGroup
|
||||||
|
|
||||||
/**
|
|
||||||
* Created by user on 7/6/16.
|
|
||||||
*/
|
|
||||||
class Initializer : ChannelInitializer<SocketChannel> {
|
class Initializer : ChannelInitializer<SocketChannel> {
|
||||||
|
|
||||||
val group: EventExecutorGroup;
|
val group: EventExecutorGroup
|
||||||
|
|
||||||
constructor(handlerThreadCount: Int) {
|
constructor(handlerThreadCount: Int) {
|
||||||
this.group = DefaultEventExecutorGroup(handlerThreadCount)
|
this.group = DefaultEventExecutorGroup(handlerThreadCount)
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
package car.server
|
||||||
|
|
||||||
|
import io.netty.bootstrap.ServerBootstrap
|
||||||
|
import io.netty.channel.nio.NioEventLoopGroup
|
||||||
|
import io.netty.channel.socket.nio.NioServerSocketChannel
|
||||||
|
import kotlin.concurrent.thread
|
||||||
|
|
||||||
|
|
||||||
|
object Server {
|
||||||
|
private val handlerThreadsCount: Int = 100
|
||||||
|
fun getCarServerThread(carServerPort: Int): Thread {
|
||||||
|
return thread(false, false, null, "carServer", -1, {
|
||||||
|
println("car server started")
|
||||||
|
val bossGroup = NioEventLoopGroup(1)
|
||||||
|
val workerGroup = NioEventLoopGroup()
|
||||||
|
val b = ServerBootstrap()
|
||||||
|
val initializer = Initializer(handlerThreadsCount)
|
||||||
|
b.group(bossGroup, workerGroup)
|
||||||
|
.channel(NioServerSocketChannel().javaClass)
|
||||||
|
.childHandler(initializer)
|
||||||
|
|
||||||
|
try {
|
||||||
|
val channel = b.bind(carServerPort).sync().channel()
|
||||||
|
channel.closeFuture().sync()
|
||||||
|
} catch (e: InterruptedException) {
|
||||||
|
println("car server stopped")
|
||||||
|
} finally {
|
||||||
|
bossGroup.shutdownGracefully()
|
||||||
|
workerGroup.shutdownGracefully()
|
||||||
|
initializer.group.shutdownGracefully()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,31 +1,29 @@
|
|||||||
package objects
|
package objects
|
||||||
|
|
||||||
/**
|
|
||||||
* Created by user on 7/7/16.
|
|
||||||
*/
|
|
||||||
class Car constructor(uid: Int, host: String, port: Int) {
|
class Car constructor(uid: Int, host: String, port: Int) {
|
||||||
|
|
||||||
val uid: Int
|
val uid: Int
|
||||||
val host: String
|
val host: String
|
||||||
val port: Int
|
val port: Int
|
||||||
|
|
||||||
var free: Boolean
|
|
||||||
var lastAction: Long
|
var lastAction: Long
|
||||||
|
|
||||||
var x: Int
|
var x: Int
|
||||||
var y: Int
|
var y: Int
|
||||||
|
var angle: Int
|
||||||
|
|
||||||
init {
|
init {
|
||||||
this.uid = uid
|
this.uid = uid
|
||||||
this.host = host
|
this.host = host
|
||||||
this.port = port
|
this.port = port
|
||||||
this.free = true
|
|
||||||
x = 0
|
x = 0
|
||||||
y = 0
|
y = 0
|
||||||
|
angle = 0
|
||||||
this.lastAction = System.currentTimeMillis()
|
this.lastAction = System.currentTimeMillis()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun toString(): String {
|
override fun toString(): String {
|
||||||
return "$uid ; x:$x; y:$y"
|
return "$uid ; x:$x; y:$y; angle:$angle"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,22 +1,16 @@
|
|||||||
package objects
|
package objects
|
||||||
|
|
||||||
import java.util.Random
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Created by user on 7/7/16.
|
|
||||||
*/
|
|
||||||
class Environment private constructor() {
|
class Environment private constructor() {
|
||||||
|
|
||||||
val map: MutableMap<Int, Car>
|
val map: MutableMap<Int, Car>
|
||||||
private var uid = 0
|
private var uid = 0
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
val instance = Environment()
|
val instance = Environment()
|
||||||
}
|
}
|
||||||
|
|
||||||
init {
|
init {
|
||||||
map = mutableMapOf();
|
map = mutableMapOf()
|
||||||
}
|
}
|
||||||
|
|
||||||
@Synchronized
|
@Synchronized
|
||||||
|
|||||||
@@ -1,15 +1,11 @@
|
|||||||
package web.server
|
package web.server
|
||||||
|
|
||||||
import io.netty.buffer.Unpooled
|
import io.netty.buffer.Unpooled
|
||||||
import io.netty.channel.ChannelFutureListener
|
|
||||||
import io.netty.channel.ChannelHandlerContext
|
import io.netty.channel.ChannelHandlerContext
|
||||||
import io.netty.channel.SimpleChannelInboundHandler
|
import io.netty.channel.SimpleChannelInboundHandler
|
||||||
import io.netty.handler.codec.http.*
|
import io.netty.handler.codec.http.*
|
||||||
import io.netty.util.CharsetUtil
|
import io.netty.util.CharsetUtil
|
||||||
|
|
||||||
/**
|
|
||||||
* Created by user on 7/6/16.
|
|
||||||
*/
|
|
||||||
class Handler : SimpleChannelInboundHandler<Any>() {
|
class Handler : SimpleChannelInboundHandler<Any>() {
|
||||||
|
|
||||||
var contentBytes: ByteArray = ByteArray(0)
|
var contentBytes: ByteArray = ByteArray(0)
|
||||||
@@ -18,12 +14,12 @@ class Handler : SimpleChannelInboundHandler<Any>() {
|
|||||||
|
|
||||||
val response = DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, Unpooled.copiedBuffer("" + Math.random() * 10000, CharsetUtil.UTF_8))
|
val response = DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, Unpooled.copiedBuffer("" + Math.random() * 10000, CharsetUtil.UTF_8))
|
||||||
response.headers().setInt(HttpHeaderNames.CONTENT_LENGTH, response.content().readableBytes())
|
response.headers().setInt(HttpHeaderNames.CONTENT_LENGTH, response.content().readableBytes())
|
||||||
ctx.writeAndFlush(response).addListener(io.netty.channel.ChannelFutureListener.CLOSE);
|
ctx.writeAndFlush(response).addListener(io.netty.channel.ChannelFutureListener.CLOSE)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun channelRead0(ctx: ChannelHandlerContext, msg: Any) {
|
override fun channelRead0(ctx: ChannelHandlerContext, msg: Any) {
|
||||||
if (msg is DefaultHttpContent) {
|
if (msg is DefaultHttpContent) {
|
||||||
val contentsBytes = msg.content();
|
val contentsBytes = msg.content()
|
||||||
contentBytes = ByteArray(contentsBytes.capacity())
|
contentBytes = ByteArray(contentsBytes.capacity())
|
||||||
contentsBytes.readBytes(contentBytes)
|
contentsBytes.readBytes(contentBytes)
|
||||||
}
|
}
|
||||||
@@ -33,8 +29,6 @@ class Handler : SimpleChannelInboundHandler<Any>() {
|
|||||||
override fun exceptionCaught(ctx: ChannelHandlerContext?, cause: Throwable?) {
|
override fun exceptionCaught(ctx: ChannelHandlerContext?, cause: Throwable?) {
|
||||||
println("exception")
|
println("exception")
|
||||||
cause?.printStackTrace()
|
cause?.printStackTrace()
|
||||||
if (ctx != null) {
|
ctx?.close()
|
||||||
ctx.close()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -7,12 +7,9 @@ import io.netty.handler.codec.http.HttpServerCodec
|
|||||||
import io.netty.util.concurrent.DefaultEventExecutorGroup
|
import io.netty.util.concurrent.DefaultEventExecutorGroup
|
||||||
import io.netty.util.concurrent.EventExecutorGroup
|
import io.netty.util.concurrent.EventExecutorGroup
|
||||||
|
|
||||||
/**
|
|
||||||
* Created by user on 7/6/16.
|
|
||||||
*/
|
|
||||||
class Initializer : ChannelInitializer<SocketChannel> {
|
class Initializer : ChannelInitializer<SocketChannel> {
|
||||||
|
|
||||||
val group: EventExecutorGroup;
|
val group: EventExecutorGroup
|
||||||
|
|
||||||
constructor(handlerThreadCount: Int) {
|
constructor(handlerThreadCount: Int) {
|
||||||
this.group = DefaultEventExecutorGroup(handlerThreadCount)
|
this.group = DefaultEventExecutorGroup(handlerThreadCount)
|
||||||
|
|||||||
@@ -0,0 +1,33 @@
|
|||||||
|
package web.server
|
||||||
|
|
||||||
|
import io.netty.bootstrap.ServerBootstrap
|
||||||
|
import io.netty.channel.nio.NioEventLoopGroup
|
||||||
|
import io.netty.channel.socket.nio.NioServerSocketChannel
|
||||||
|
import kotlin.concurrent.thread
|
||||||
|
|
||||||
|
object Server {
|
||||||
|
private val handlerThreadsCount: Int = 10
|
||||||
|
fun getWebServerThread(webServerPort: Int): Thread {
|
||||||
|
return thread(false, false, null, "webServer", -1, {
|
||||||
|
println("web server started")
|
||||||
|
val bossGroup = NioEventLoopGroup(1)
|
||||||
|
val workerGroup = NioEventLoopGroup()
|
||||||
|
val b = ServerBootstrap()
|
||||||
|
val initializer = Initializer(handlerThreadsCount)
|
||||||
|
b.group(bossGroup, workerGroup)
|
||||||
|
.channel(NioServerSocketChannel().javaClass)
|
||||||
|
.childHandler(initializer)
|
||||||
|
|
||||||
|
try {
|
||||||
|
val channel = b.bind(webServerPort).sync().channel()
|
||||||
|
channel.closeFuture().sync()
|
||||||
|
} catch (e: InterruptedException) {
|
||||||
|
println("web server stopped")
|
||||||
|
} finally {
|
||||||
|
bossGroup.shutdownGracefully()
|
||||||
|
workerGroup.shutdownGracefully()
|
||||||
|
initializer.group.shutdownGracefully()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user