refactoring main server, corrected errors

This commit is contained in:
MaximZaitsev
2016-08-23 12:47:04 +03:00
parent abd2b39565
commit e7120103ee
16 changed files with 436 additions and 393 deletions
+234 -196
View File
@@ -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 {
}
+5 -87
View File
@@ -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
}
}
})
}
+55
View File
@@ -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)
}
}
}
}
+5 -7
View File
@@ -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()
+13 -41
View File
@@ -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)
+35
View File
@@ -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()
}
})
}
}
+4 -6
View File
@@ -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 -7
View File
@@ -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
+3 -9
View File
@@ -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)
+33
View File
@@ -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()
}
})
}
}