maked car control client
This commit is contained in:
@@ -17,11 +17,33 @@ apply plugin: 'kotlin'
|
|||||||
|
|
||||||
sourceCompatibility = 1.5
|
sourceCompatibility = 1.5
|
||||||
|
|
||||||
|
task getDeps(type: Copy) {
|
||||||
|
from sourceSets.main.compileClasspath
|
||||||
|
into 'build/libs'
|
||||||
|
}
|
||||||
|
|
||||||
|
build.dependsOn getDeps
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
jar {
|
||||||
|
manifest {
|
||||||
|
attributes("Implementation-Title": "Gradle",
|
||||||
|
"Implementation-Version": version,
|
||||||
|
"Class-Path": "jsap-2.1.jar kotlin-runtime-1.0.3.jar kotlin-stdlib-1.0.3.jar netty-all-4.1.2.Final.jar protobuf-java-3.0.0-beta-3.jar",
|
||||||
|
"Main-Class": "MainKt")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
|
compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
|
||||||
|
compile "io.netty:netty-all:4.1.2.Final"
|
||||||
|
compile "com.google.protobuf:protobuf-java:3.0.0-beta-3"
|
||||||
|
compile group: "com.martiansoftware",name:"jsap",version:"2.1"
|
||||||
|
|
||||||
|
|
||||||
testCompile group: 'junit', name: 'junit', version: '4.11'
|
testCompile group: 'junit', name: 'junit', version: '4.11'
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,50 @@
|
|||||||
|
import io.netty.buffer.Unpooled
|
||||||
|
import io.netty.handler.codec.http.*
|
||||||
|
import proto.car.RouteP
|
||||||
|
import proto.car.RouteP.Direction.Command
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by user on 7/14/16.
|
||||||
|
*/
|
||||||
|
class CarControl constructor(host: String, port: Int) {
|
||||||
|
|
||||||
|
val host: String;
|
||||||
|
val port: Int
|
||||||
|
|
||||||
|
init {
|
||||||
|
this.host = host;
|
||||||
|
this.port = port;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fun executeCommand(direction: Char) {
|
||||||
|
|
||||||
|
val directionBuilder = RouteP.Direction.newBuilder()
|
||||||
|
when (direction) {
|
||||||
|
'f' -> {
|
||||||
|
directionBuilder.setCommand(Command.forward)
|
||||||
|
}
|
||||||
|
'b' -> {
|
||||||
|
directionBuilder.setCommand(Command.backward)
|
||||||
|
}
|
||||||
|
'r' -> {
|
||||||
|
directionBuilder.setCommand(Command.right)
|
||||||
|
}
|
||||||
|
'l' -> {
|
||||||
|
directionBuilder.setCommand(Command.left)
|
||||||
|
}
|
||||||
|
's' -> {
|
||||||
|
directionBuilder.setCommand(Command.stop)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val request = DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.POST, "/control", Unpooled.copiedBuffer(directionBuilder.build().toByteArray()));
|
||||||
|
request.headers().set(HttpHeaderNames.HOST, host)
|
||||||
|
request.headers().set(HttpHeaderNames.CONNECTION, HttpHeaderValues.CLOSE)
|
||||||
|
request.headers().setInt(HttpHeaderNames.CONTENT_LENGTH, request.content().readableBytes())
|
||||||
|
request.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/plain; charset=UTF-8")
|
||||||
|
|
||||||
|
client.Client.sendRequest(request, host, port)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1,3 +1,68 @@
|
|||||||
|
import com.martiansoftware.jsap.FlaggedOption
|
||||||
|
import com.martiansoftware.jsap.JSAP
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by user on 7/14/16.
|
* Created by user on 7/14/16.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
val correctDirectionValues: Array<Char> = arrayOf('f', 'b', 'l', 'r', 's');
|
||||||
|
|
||||||
|
fun main(args: Array<String>) {
|
||||||
|
val jsap: JSAP = JSAP()
|
||||||
|
setOptions(jsap)
|
||||||
|
val config = jsap.parse(args)
|
||||||
|
if (!config.success() || config.getBoolean("help")) {
|
||||||
|
println(jsap.getHelp())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
val host = config.getString("host")
|
||||||
|
val port = config.getInt("port")
|
||||||
|
val direction = config.getChar("direction")
|
||||||
|
|
||||||
|
val carControl = CarControl(host, port)
|
||||||
|
if (direction.equals('t', true)) {
|
||||||
|
initTextInterface(carControl)
|
||||||
|
} else if (correctDirectionValues.contains(direction)) {
|
||||||
|
carControl.executeCommand(direction)
|
||||||
|
} else {
|
||||||
|
println("incorrect direction.")
|
||||||
|
println(jsap.getHelp())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun initTextInterface(carControl: CarControl) {
|
||||||
|
val helpMessage = "type f, b, l, r, s for command forward, backward, left, right, stop. to exit type q or quit ";
|
||||||
|
println(helpMessage)
|
||||||
|
val scanner = Scanner(System.`in`)
|
||||||
|
while (scanner.hasNext()) {
|
||||||
|
val nextLine = scanner.nextLine()
|
||||||
|
if (nextLine.equals("q", true) || nextLine.equals("quit", true)) {
|
||||||
|
return
|
||||||
|
} else if (nextLine.length != 1) {
|
||||||
|
println("incorrect argument \"$nextLine\"")
|
||||||
|
println(helpMessage)
|
||||||
|
} else {
|
||||||
|
val directionChar = nextLine.get(0)
|
||||||
|
if (!correctDirectionValues.contains(directionChar)) {
|
||||||
|
println("incorrect argument \"$nextLine\"")
|
||||||
|
println(helpMessage)
|
||||||
|
} else {
|
||||||
|
carControl.executeCommand(directionChar)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setOptions(jsap: JSAP) {
|
||||||
|
val opthost = FlaggedOption("host").setStringParser(JSAP.STRING_PARSER).setRequired(true).setShortFlag('h').setLongFlag("host")
|
||||||
|
val optPort = FlaggedOption("port").setStringParser(JSAP.INTEGER_PARSER).setDefault("8888").setRequired(false).setShortFlag('p').setLongFlag("port")
|
||||||
|
val optHelp = FlaggedOption("help").setStringParser(JSAP.BOOLEAN_PARSER).setRequired(false).setDefault("false").setLongFlag("help")
|
||||||
|
val optDirection = FlaggedOption("direction").setStringParser(JSAP.CHARACTER_PARSER).setRequired(false).setDefault("t").setShortFlag('d')
|
||||||
|
optDirection.setHelp("move direction: available values - one symbol:\n\"f (forward),b (backward),l (left),r (right),s (stop)\". example: -d f\nwithout argument used default \"t\" - running text interface")
|
||||||
|
jsap.registerParameter(opthost)
|
||||||
|
jsap.registerParameter(optPort)
|
||||||
|
jsap.registerParameter(optHelp)
|
||||||
|
jsap.registerParameter(optDirection)
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
package client
|
||||||
|
|
||||||
|
import io.netty.bootstrap.Bootstrap
|
||||||
|
import io.netty.channel.nio.NioEventLoopGroup
|
||||||
|
import io.netty.channel.socket.nio.NioSocketChannel
|
||||||
|
import io.netty.handler.codec.http.HttpRequest
|
||||||
|
import java.net.ConnectException
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by user on 7/8/16.
|
||||||
|
*/
|
||||||
|
object Client {
|
||||||
|
|
||||||
|
fun sendRequest(request: HttpRequest, host: String, port: Int): Int {
|
||||||
|
val group = NioEventLoopGroup()
|
||||||
|
try {
|
||||||
|
val bootstrap: Bootstrap = Bootstrap()
|
||||||
|
bootstrap.group(group).channel(NioSocketChannel().javaClass).handler(ClientInitializer())
|
||||||
|
val channelFuture = bootstrap.connect(host, port).sync()
|
||||||
|
val channel = channelFuture.channel()
|
||||||
|
channel.writeAndFlush(request)
|
||||||
|
channel.closeFuture().sync()
|
||||||
|
} catch (e: InterruptedException) {
|
||||||
|
println("interrupted before request done")
|
||||||
|
return 2
|
||||||
|
} catch (e: ConnectException) {
|
||||||
|
println("connection error to $host:$port")
|
||||||
|
return 1
|
||||||
|
} finally {
|
||||||
|
group.shutdownGracefully()
|
||||||
|
}
|
||||||
|
return ClientHandler.requestResult.code
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
package client
|
||||||
|
|
||||||
|
import io.netty.channel.ChannelHandlerContext
|
||||||
|
import io.netty.channel.SimpleChannelInboundHandler
|
||||||
|
import io.netty.handler.codec.http.HttpContent
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by user on 7/8/16.
|
||||||
|
*/
|
||||||
|
class ClientHandler : SimpleChannelInboundHandler<Any> {
|
||||||
|
|
||||||
|
object requestResult {
|
||||||
|
var code: Int = -1
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor()
|
||||||
|
|
||||||
|
var contentBytes: ByteArray = ByteArray(0);
|
||||||
|
|
||||||
|
override fun channelReadComplete(ctx: ChannelHandlerContext) {
|
||||||
|
|
||||||
|
var resultCode: Int = 0
|
||||||
|
// try {
|
||||||
|
// val uploadResult: Carkot.UploadResult = Carkot.UploadResult.parseFrom(contentBytes)
|
||||||
|
// resultCode = uploadResult.resultCode
|
||||||
|
// } catch (e: InvalidProtocolBufferException) {
|
||||||
|
// e.printStackTrace()
|
||||||
|
//
|
||||||
|
// resultCode = 2
|
||||||
|
// }
|
||||||
|
synchronized(requestResult, {
|
||||||
|
requestResult.code = resultCode
|
||||||
|
})
|
||||||
|
ctx.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun channelRead0(ctx: ChannelHandlerContext?, msg: Any?) {
|
||||||
|
if (msg is HttpContent) {
|
||||||
|
val contentsBytes = msg.content();
|
||||||
|
contentBytes = ByteArray(contentsBytes.capacity())
|
||||||
|
contentsBytes.readBytes(contentBytes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun exceptionCaught(ctx: ChannelHandlerContext?, cause: Throwable) {
|
||||||
|
cause.printStackTrace()
|
||||||
|
if (ctx != null) {
|
||||||
|
ctx.close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package client
|
||||||
|
|
||||||
|
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()
|
||||||
|
|
||||||
|
override fun initChannel(ch: SocketChannel) {
|
||||||
|
val p = ch.pipeline()
|
||||||
|
p.addLast(HttpClientCodec())
|
||||||
|
p.addLast(ClientHandler())
|
||||||
|
}
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user