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 objects.Car
|
||||
|
||||
/**
|
||||
* Created by user on 8/18/16.
|
||||
*/
|
||||
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() {
|
||||
|
||||
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)
|
||||
val routeRegex = Regex("route [0-9]{1,10}")
|
||||
val sonarRegex = Regex("sonar [0-9]{1,10}")
|
||||
val environment = objects.Environment.instance
|
||||
while (true) {
|
||||
val readedString = readLine()
|
||||
if (readedString == null) {
|
||||
val readString = readLine()
|
||||
if (readString == null || readString.equals("stop")) {
|
||||
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, {
|
||||
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
|
||||
try {
|
||||
id = readedString.split(" ")[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("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) u need enter: 1 0[press enter] 1 180[press enter] done")
|
||||
|
||||
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")
|
||||
}
|
||||
private fun executeDebugInfoCommand(readString: String) {
|
||||
val params = readString.split(" ")
|
||||
if (params.size != 3) {
|
||||
println("incorrect args of command debug info.")
|
||||
println(helpString)
|
||||
return
|
||||
}
|
||||
val id: Int
|
||||
try {
|
||||
id = params[1].toInt()
|
||||
} catch (e: NumberFormatException) {
|
||||
e.printStackTrace()
|
||||
println("error in converting id to int type")
|
||||
println(helpString)
|
||||
return
|
||||
}
|
||||
val car: Car? =
|
||||
synchronized(environment, {
|
||||
for (id in inactiveCarUids) {
|
||||
environment.map.remove(id)
|
||||
}
|
||||
environment.map[id]
|
||||
})
|
||||
} else if (readedString.equals("stop")) {
|
||||
break
|
||||
} else if (sonarRegex.matches(readedString)) {
|
||||
val id: Int
|
||||
try {
|
||||
id = readedString.split(" ")[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
|
||||
}
|
||||
println("print angles, after printing all angles print done")
|
||||
val angles = arrayListOf<Int>()
|
||||
while (true) {
|
||||
val command = readLine()!!
|
||||
if (command.equals("done", true)) {
|
||||
val sonarBuilder = SonarRequest.BuilderSonarRequest(angles.toIntArray())
|
||||
val requestObject = sonarBuilder.build()
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
if (car == null) {
|
||||
println("car with id=$id not found")
|
||||
return
|
||||
}
|
||||
val paramType = params[2]//maybe string or int
|
||||
val type: DebugRequest.Type
|
||||
try {
|
||||
type = DebugRequest.Type.fromIntToType(paramType.toInt())
|
||||
} catch (e: NumberFormatException) {
|
||||
try {
|
||||
type = DebugRequest.Type.valueOf(paramType)
|
||||
} catch (e: IllegalArgumentException) {
|
||||
type = DebugRequest.Type.Unexpected
|
||||
}
|
||||
}
|
||||
if (type == DebugRequest.Type.Unexpected) {
|
||||
println("type with name/id $paramType not found")
|
||||
return
|
||||
}
|
||||
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, getRequestOptionId(car.uid))
|
||||
} catch (e: InactiveCarException) {
|
||||
println("this car is inactive")
|
||||
}
|
||||
}
|
||||
|
||||
} else if (readedString.contains("dbinfo")) {
|
||||
val params = readedString.split(" ")
|
||||
if (!params[0].equals("dbinfo")) {
|
||||
println("not supported command: $readedString")
|
||||
println(helpString)
|
||||
continue
|
||||
private fun executeSonarCommand(readString: String) {
|
||||
if (!sonarRegex.matches(readString)) {
|
||||
println("incorrect args of command sonar.")
|
||||
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 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) {
|
||||
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) {
|
||||
else -> {
|
||||
try {
|
||||
type = DebugRequest.Type.valueOf(paramType)
|
||||
} catch (e: IllegalArgumentException) {
|
||||
type = DebugRequest.Type.Unexpected
|
||||
val angle = command.toInt()
|
||||
if (angle < 0 || angle > 180) {
|
||||
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 {
|
||||
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.CONNECTION, HttpHeaderValues.CLOSE)
|
||||
request.headers().setInt(HttpHeaderNames.CONTENT_LENGTH, request.content().readableBytes())
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
package Exceptions
|
||||
|
||||
/**
|
||||
* Created by user on 7/28/16.
|
||||
*/
|
||||
|
||||
class InactiveCarException : Exception() {
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
object RoomBypassingAlgorithm {
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -1,14 +1,8 @@
|
||||
import io.netty.bootstrap.ServerBootstrap
|
||||
import io.netty.channel.nio.NioEventLoopGroup
|
||||
import io.netty.channel.socket.nio.NioServerSocketChannel
|
||||
import kotlin.concurrent.thread
|
||||
import car.Dropper
|
||||
|
||||
val timeDeltaToDrop = 600000//time in ms. if car is inactive more than this time, server drop session with car
|
||||
val carServerPort: Int = 7925
|
||||
val webServerPort: Int = 7926
|
||||
val handlerThreadsCount: Int = 100
|
||||
val getLocationUrl = "/getLocation"
|
||||
val routeDoneUrl = "/routeDone"
|
||||
val setRouteUrl = "/route"
|
||||
val connectUrl = "/connect"
|
||||
val debugMemoryUrl = "/debug/memory"
|
||||
@@ -16,9 +10,9 @@ val sonarUrl = "/sonar"
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
|
||||
val carServer = getCarServerThread()
|
||||
val webServer = getWebServerThread()
|
||||
val carsDestroy = getCarsDestroyThread()
|
||||
val carServer = car.server.Server.getCarServerThread(carServerPort)
|
||||
val webServer = web.server.Server.getWebServerThread(webServerPort)
|
||||
val carsDestroy = Dropper.getCarsDestroyThread()
|
||||
carServer.start()
|
||||
carsDestroy.start()
|
||||
webServer.start()
|
||||
@@ -28,81 +22,5 @@ fun main(args: Array<String>) {
|
||||
|
||||
carsDestroy.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 java.net.ConnectException
|
||||
|
||||
/**
|
||||
* Created by user on 7/8/16.
|
||||
*/
|
||||
object Client {
|
||||
|
||||
val bootstrap: Bootstrap = makeBootstrap()
|
||||
@@ -24,18 +21,19 @@ object Client {
|
||||
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 {
|
||||
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()
|
||||
ch.writeAndFlush(request)
|
||||
ch.closeFuture().sync()//wait for answer
|
||||
// ch.closeFuture().sync()//wait for answer
|
||||
} catch (e: InterruptedException) {
|
||||
|
||||
} catch (e: ConnectException) {
|
||||
throw InactiveCarException()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,7 +1,9 @@
|
||||
package car.client
|
||||
|
||||
import CodedInputStream
|
||||
import DebugResponseMemoryStats
|
||||
import LocationResponse
|
||||
import SonarResponse
|
||||
import debugMemoryUrl
|
||||
import getLocationUrl
|
||||
import io.netty.channel.ChannelHandlerContext
|
||||
@@ -12,47 +14,32 @@ import objects.Environment
|
||||
import sonarUrl
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* Created by user on 7/8/16.
|
||||
*/
|
||||
class ClientHandler : SimpleChannelInboundHandler<Any> {
|
||||
|
||||
constructor()
|
||||
|
||||
var contentBytes: ByteArray = ByteArray(0);
|
||||
var contentBytes: ByteArray = ByteArray(0)
|
||||
|
||||
override fun channelReadComplete(ctx: ChannelHandlerContext) {
|
||||
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) {
|
||||
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))
|
||||
|
||||
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
|
||||
}
|
||||
})
|
||||
}
|
||||
handlerGetLocationResponse(response, carUid)
|
||||
}
|
||||
debugMemoryUrl -> {
|
||||
val response = DebugResponseMemoryStats.BuilderDebugResponseMemoryStats(0, 0, 0, 0).build()
|
||||
response.mergeFrom(CodedInputStream(contentBytes))
|
||||
println("heapDynamicMaxBytes ${response.heapDynamicMaxBytes}")
|
||||
println("heapDynamicTail ${response.heapDynamicTail}")
|
||||
println("heapDynamicTotalBytes ${response.heapDynamicTotalBytes}")
|
||||
println("heapStaticTail ${response.heapStaticTail}")
|
||||
handlerDebugMemoryResponse(response)
|
||||
}
|
||||
sonarUrl -> {
|
||||
val sonarDistances = SonarResponse.BuilderSonarResponse(IntArray(0)).build()
|
||||
sonarDistances.mergeFrom(CodedInputStream(contentBytes))
|
||||
println("distances from sonar: ${Arrays.toString(sonarDistances.distances)}")
|
||||
val response = SonarResponse.BuilderSonarResponse(IntArray(0)).build()
|
||||
response.mergeFrom(CodedInputStream(contentBytes))
|
||||
val angles = ctx.channel().attr(AttributeKey.valueOf<IntArray>("angles")).get()
|
||||
handlerSonarResponse(response, angles)
|
||||
}
|
||||
else -> {
|
||||
|
||||
@@ -61,9 +48,36 @@ class ClientHandler : SimpleChannelInboundHandler<Any> {
|
||||
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?) {
|
||||
if (msg is DefaultHttpContent) {
|
||||
val contentsBytes = msg.content();
|
||||
val contentsBytes = msg.content()
|
||||
contentBytes = ByteArray(contentsBytes.capacity())
|
||||
contentsBytes.readBytes(contentBytes)
|
||||
}
|
||||
|
||||
@@ -4,9 +4,6 @@ import io.netty.channel.ChannelInitializer
|
||||
import io.netty.channel.socket.SocketChannel
|
||||
import io.netty.handler.codec.http.HttpClientCodec
|
||||
|
||||
/**
|
||||
* Created by user on 7/8/16.
|
||||
*/
|
||||
class ClientInitializer : ChannelInitializer<SocketChannel> {
|
||||
|
||||
constructor()
|
||||
|
||||
@@ -4,8 +4,6 @@ import CodedInputStream
|
||||
import CodedOutputStream
|
||||
import ConnectionRequest
|
||||
import ConnectionResponse
|
||||
import RouteDoneRequest
|
||||
import RouteDoneResponse
|
||||
import connectUrl
|
||||
import io.netty.buffer.Unpooled
|
||||
import io.netty.channel.ChannelFutureListener
|
||||
@@ -13,59 +11,35 @@ import io.netty.channel.ChannelHandlerContext
|
||||
import io.netty.channel.SimpleChannelInboundHandler
|
||||
import io.netty.handler.codec.http.*
|
||||
import objects.Environment
|
||||
import routeDoneUrl
|
||||
|
||||
class Handler : SimpleChannelInboundHandler<Any>() {
|
||||
|
||||
var url: String = ""
|
||||
var contentBytes: ByteArray = ByteArray(0);
|
||||
var contentBytes: ByteArray = ByteArray(0)
|
||||
|
||||
override fun channelReadComplete(ctx: ChannelHandlerContext) {
|
||||
|
||||
val environment = Environment.instance
|
||||
var success = true;
|
||||
var success = true
|
||||
var answer = ByteArray(0)
|
||||
when (url) {
|
||||
connectUrl -> {
|
||||
val data = ConnectionRequest.BuilderConnectionRequest(IntArray(0), 0).build();
|
||||
val data = ConnectionRequest.BuilderConnectionRequest(IntArray(0), 0).build()
|
||||
data.mergeFrom(CodedInputStream(contentBytes))
|
||||
if (success) {
|
||||
val ipStr = data.ipValues.map { elem -> elem.toString() }.reduce { elem1, elem2 -> elem1 + "." + elem2 }
|
||||
val uid = environment.connectCar(ipStr, data.port)
|
||||
val responseObject = ConnectionResponse.BuilderConnectionResponse(uid, 0).build()
|
||||
answer = ByteArray(responseObject.getSizeNoTag())
|
||||
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))
|
||||
}
|
||||
})
|
||||
}
|
||||
val ipStr = data.ipValues.map { elem -> elem.toString() }.reduce { elem1, elem2 -> elem1 + "." + elem2 }
|
||||
val uid = environment.connectCar(ipStr, data.port)
|
||||
val responseObject = ConnectionResponse.BuilderConnectionResponse(uid, 0).build()
|
||||
answer = ByteArray(responseObject.getSizeNoTag())
|
||||
responseObject.writeTo(CodedOutputStream(answer))
|
||||
}
|
||||
else -> {
|
||||
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())
|
||||
ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
|
||||
ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE)
|
||||
}
|
||||
|
||||
override fun channelRead0(ctx: ChannelHandlerContext, msg: Any) {
|
||||
@@ -74,7 +48,7 @@ class Handler : SimpleChannelInboundHandler<Any>() {
|
||||
}
|
||||
|
||||
if (msg is DefaultHttpContent) {
|
||||
val contentsBytes = msg.content();
|
||||
val contentsBytes = msg.content()
|
||||
contentBytes = ByteArray(contentsBytes.capacity())
|
||||
contentsBytes.readBytes(contentBytes)
|
||||
}
|
||||
@@ -84,8 +58,6 @@ class Handler : SimpleChannelInboundHandler<Any>() {
|
||||
override fun exceptionCaught(ctx: ChannelHandlerContext?, cause: Throwable?) {
|
||||
println("exception")
|
||||
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.EventExecutorGroup
|
||||
|
||||
/**
|
||||
* Created by user on 7/6/16.
|
||||
*/
|
||||
class Initializer : ChannelInitializer<SocketChannel> {
|
||||
|
||||
val group: EventExecutorGroup;
|
||||
val group: EventExecutorGroup
|
||||
|
||||
constructor(handlerThreadCount: Int) {
|
||||
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
|
||||
|
||||
/**
|
||||
* Created by user on 7/7/16.
|
||||
*/
|
||||
|
||||
class Car constructor(uid: Int, host: String, port: Int) {
|
||||
|
||||
val uid: Int
|
||||
val host: String
|
||||
val port: Int
|
||||
|
||||
var free: Boolean
|
||||
var lastAction: Long
|
||||
|
||||
var x: Int
|
||||
var y: Int
|
||||
var angle: Int
|
||||
|
||||
init {
|
||||
this.uid = uid
|
||||
this.host = host
|
||||
this.port = port
|
||||
this.free = true
|
||||
x = 0
|
||||
y = 0
|
||||
angle = 0
|
||||
this.lastAction = System.currentTimeMillis()
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return "$uid ; x:$x; y:$y"
|
||||
return "$uid ; x:$x; y:$y; angle:$angle"
|
||||
}
|
||||
}
|
||||
@@ -1,22 +1,16 @@
|
||||
package objects
|
||||
|
||||
import java.util.Random
|
||||
|
||||
/**
|
||||
* Created by user on 7/7/16.
|
||||
*/
|
||||
class Environment private constructor() {
|
||||
|
||||
val map: MutableMap<Int, Car>
|
||||
private var uid = 0
|
||||
|
||||
companion object {
|
||||
|
||||
val instance = Environment()
|
||||
}
|
||||
|
||||
init {
|
||||
map = mutableMapOf();
|
||||
map = mutableMapOf()
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
|
||||
@@ -1,15 +1,11 @@
|
||||
package web.server
|
||||
|
||||
import io.netty.buffer.Unpooled
|
||||
import io.netty.channel.ChannelFutureListener
|
||||
import io.netty.channel.ChannelHandlerContext
|
||||
import io.netty.channel.SimpleChannelInboundHandler
|
||||
import io.netty.handler.codec.http.*
|
||||
import io.netty.util.CharsetUtil
|
||||
|
||||
/**
|
||||
* Created by user on 7/6/16.
|
||||
*/
|
||||
class Handler : SimpleChannelInboundHandler<Any>() {
|
||||
|
||||
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))
|
||||
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) {
|
||||
if (msg is DefaultHttpContent) {
|
||||
val contentsBytes = msg.content();
|
||||
val contentsBytes = msg.content()
|
||||
contentBytes = ByteArray(contentsBytes.capacity())
|
||||
contentsBytes.readBytes(contentBytes)
|
||||
}
|
||||
@@ -33,8 +29,6 @@ class Handler : SimpleChannelInboundHandler<Any>() {
|
||||
override fun exceptionCaught(ctx: ChannelHandlerContext?, cause: Throwable?) {
|
||||
println("exception")
|
||||
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.EventExecutorGroup
|
||||
|
||||
/**
|
||||
* Created by user on 7/6/16.
|
||||
*/
|
||||
class Initializer : ChannelInitializer<SocketChannel> {
|
||||
|
||||
val group: EventExecutorGroup;
|
||||
val group: EventExecutorGroup
|
||||
|
||||
constructor(handlerThreadCount: Int) {
|
||||
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