From e7120103eef065ea0c795cc36e7545d274d9cb2f Mon Sep 17 00:00:00 2001 From: MaximZaitsev Date: Tue, 23 Aug 2016 12:47:04 +0300 Subject: [PATCH] refactoring main server, corrected errors --- server/src/main/java/DebugClInterface.kt | 430 ++++++++++-------- .../java/Exceptions/InactiveCarException.kt | 4 +- .../src/main/java/RoomBypassingAlgorithm.kt | 5 + server/src/main/java/ServerMain.kt | 92 +--- server/src/main/java/car/Dropper.kt | 55 +++ server/src/main/java/car/client/Client.kt | 12 +- .../src/main/java/car/client/ClientHandler.kt | 66 +-- .../main/java/car/client/ClientInitializer.kt | 3 - server/src/main/java/car/server/Handler.kt | 54 +-- .../src/main/java/car/server/Initializer.kt | 5 +- server/src/main/java/car/server/Server.kt | 35 ++ server/src/main/java/objects/Car.kt | 10 +- server/src/main/java/objects/Environment.kt | 8 +- server/src/main/java/web/server/Handler.kt | 12 +- .../src/main/java/web/server/Initializer.kt | 5 +- server/src/main/java/web/server/Server.kt | 33 ++ 16 files changed, 436 insertions(+), 393 deletions(-) create mode 100644 server/src/main/java/RoomBypassingAlgorithm.kt create mode 100644 server/src/main/java/car/Dropper.kt create mode 100644 server/src/main/java/car/server/Server.kt create mode 100644 server/src/main/java/web/server/Server.kt diff --git a/server/src/main/java/DebugClInterface.kt b/server/src/main/java/DebugClInterface.kt index 2285b152c0d..6ccc155c82e 100644 --- a/server/src/main/java/DebugClInterface.kt +++ b/server/src/main/java/DebugClInterface.kt @@ -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() - val angles = arrayListOf() - 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() - 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() - 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() + 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 { + return mapOf(Pair("uid", id)) + } + + private fun executeRefreshLocationCommand() { + val cars = synchronized(environment, { environment.map.values }) + val inactiveCars = mutableListOf() + 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() + val angles = arrayListOf() + 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()) diff --git a/server/src/main/java/Exceptions/InactiveCarException.kt b/server/src/main/java/Exceptions/InactiveCarException.kt index fed00479424..2cb8af5042c 100644 --- a/server/src/main/java/Exceptions/InactiveCarException.kt +++ b/server/src/main/java/Exceptions/InactiveCarException.kt @@ -1,7 +1,5 @@ package Exceptions -/** - * Created by user on 7/28/16. - */ + class InactiveCarException : Exception() { } \ No newline at end of file diff --git a/server/src/main/java/RoomBypassingAlgorithm.kt b/server/src/main/java/RoomBypassingAlgorithm.kt new file mode 100644 index 00000000000..65ac4ff6cba --- /dev/null +++ b/server/src/main/java/RoomBypassingAlgorithm.kt @@ -0,0 +1,5 @@ +object RoomBypassingAlgorithm { + + + +} \ No newline at end of file diff --git a/server/src/main/java/ServerMain.kt b/server/src/main/java/ServerMain.kt index 0201d4e9d4b..59e866a4b5b 100644 --- a/server/src/main/java/ServerMain.kt +++ b/server/src/main/java/ServerMain.kt @@ -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) { - 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) { 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(); - 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 - } - } - }) -} \ No newline at end of file diff --git a/server/src/main/java/car/Dropper.kt b/server/src/main/java/car/Dropper.kt new file mode 100644 index 00000000000..1e522e80b0d --- /dev/null +++ b/server/src/main/java/car/Dropper.kt @@ -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() + 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, 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) + } + } + } +} \ No newline at end of file diff --git a/server/src/main/java/car/client/Client.kt b/server/src/main/java/car/client/Client.kt index 9b4617b4d0a..83fc9bcb331 100644 --- a/server/src/main/java/car/client/Client.kt +++ b/server/src/main/java/car/client/Client.kt @@ -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 sendRequest(request: HttpRequest, host: String, port: Int, options: Map) { try { bootstrap.attr(AttributeKey.valueOf("url"), request.uri()) - bootstrap.attr(AttributeKey.valueOf("uid"), carUid) + for ((key, value) in options) { + bootstrap.attr(AttributeKey.valueOf(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() } } - } \ No newline at end of file diff --git a/server/src/main/java/car/client/ClientHandler.kt b/server/src/main/java/car/client/ClientHandler.kt index 187d59c7d36..d960a84c2dc 100644 --- a/server/src/main/java/car/client/ClientHandler.kt +++ b/server/src/main/java/car/client/ClientHandler.kt @@ -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 { constructor() - var contentBytes: ByteArray = ByteArray(0); + var contentBytes: ByteArray = ByteArray(0) override fun channelReadComplete(ctx: ChannelHandlerContext) { val url = ctx.channel().attr(AttributeKey.valueOf("url")).get() - val carUid = ctx.channel().attr(AttributeKey.valueOf("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("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("angles")).get() + handlerSonarResponse(response, angles) } else -> { @@ -61,9 +48,36 @@ class ClientHandler : SimpleChannelInboundHandler { 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) } diff --git a/server/src/main/java/car/client/ClientInitializer.kt b/server/src/main/java/car/client/ClientInitializer.kt index 9b122271baa..e5a40583e37 100644 --- a/server/src/main/java/car/client/ClientInitializer.kt +++ b/server/src/main/java/car/client/ClientInitializer.kt @@ -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 { constructor() diff --git a/server/src/main/java/car/server/Handler.kt b/server/src/main/java/car/server/Handler.kt index 7b569645d8a..ef03555e326 100644 --- a/server/src/main/java/car/server/Handler.kt +++ b/server/src/main/java/car/server/Handler.kt @@ -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() { 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() { } 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() { override fun exceptionCaught(ctx: ChannelHandlerContext?, cause: Throwable?) { println("exception") cause?.printStackTrace() - if (ctx != null) { - ctx.close() - } + ctx?.close() } } \ No newline at end of file diff --git a/server/src/main/java/car/server/Initializer.kt b/server/src/main/java/car/server/Initializer.kt index fe79794d319..5619e2afe7f 100644 --- a/server/src/main/java/car/server/Initializer.kt +++ b/server/src/main/java/car/server/Initializer.kt @@ -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 { - val group: EventExecutorGroup; + val group: EventExecutorGroup constructor(handlerThreadCount: Int) { this.group = DefaultEventExecutorGroup(handlerThreadCount) diff --git a/server/src/main/java/car/server/Server.kt b/server/src/main/java/car/server/Server.kt new file mode 100644 index 00000000000..30f7e3a6e79 --- /dev/null +++ b/server/src/main/java/car/server/Server.kt @@ -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() + } + }) + } + +} \ No newline at end of file diff --git a/server/src/main/java/objects/Car.kt b/server/src/main/java/objects/Car.kt index c969a9335a7..d1900bf028d 100644 --- a/server/src/main/java/objects/Car.kt +++ b/server/src/main/java/objects/Car.kt @@ -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" } } \ No newline at end of file diff --git a/server/src/main/java/objects/Environment.kt b/server/src/main/java/objects/Environment.kt index 89283b90963..96c4857a8a3 100644 --- a/server/src/main/java/objects/Environment.kt +++ b/server/src/main/java/objects/Environment.kt @@ -1,22 +1,16 @@ package objects -import java.util.Random - -/** - * Created by user on 7/7/16. - */ class Environment private constructor() { val map: MutableMap private var uid = 0 companion object { - val instance = Environment() } init { - map = mutableMapOf(); + map = mutableMapOf() } @Synchronized diff --git a/server/src/main/java/web/server/Handler.kt b/server/src/main/java/web/server/Handler.kt index df57e0b9c0d..e76ff595a26 100644 --- a/server/src/main/java/web/server/Handler.kt +++ b/server/src/main/java/web/server/Handler.kt @@ -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() { var contentBytes: ByteArray = ByteArray(0) @@ -18,12 +14,12 @@ class Handler : SimpleChannelInboundHandler() { 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() { override fun exceptionCaught(ctx: ChannelHandlerContext?, cause: Throwable?) { println("exception") cause?.printStackTrace() - if (ctx != null) { - ctx.close() - } + ctx?.close() } } \ No newline at end of file diff --git a/server/src/main/java/web/server/Initializer.kt b/server/src/main/java/web/server/Initializer.kt index 79098751d04..628c8416e93 100644 --- a/server/src/main/java/web/server/Initializer.kt +++ b/server/src/main/java/web/server/Initializer.kt @@ -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 { - val group: EventExecutorGroup; + val group: EventExecutorGroup constructor(handlerThreadCount: Int) { this.group = DefaultEventExecutorGroup(handlerThreadCount) diff --git a/server/src/main/java/web/server/Server.kt b/server/src/main/java/web/server/Server.kt new file mode 100644 index 00000000000..00e2b665036 --- /dev/null +++ b/server/src/main/java/web/server/Server.kt @@ -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() + } + }) + } +} \ No newline at end of file