Sending the error in case of GRPC with full duplex ReadStream and WriteStream - vert.x

Can someone help me understand how I can send the error in case of full duplex with ReadStream and WriteStream.
This is the sample proto file.
syntax = "proto3";
option java_multiple_files = true;
option java_package = "com.pace.vertx.grpc.generated";
package com.pace.vertx.grpc.generated;
service ArrangementService {
rpc GetArrangementDetails (stream ArrangementRequest) returns (stream ArrangementAllDetails) {}
}
message ArrangementRequest {
string arrangementId = 1;
}
message ArrangementAllDetails {
string arrangementDetails = 1;
}
This is the code I have so far.
BindableService vertxArrangementServiceGrpc = new VertxArrangementServiceGrpc.ArrangementServiceVertxImplBase() {
#Override
public void getArrangementDetails(ReadStream<ArrangementRequest> request, WriteStream<ArrangementAllDetails> response) {
Pump.pump((ReadStream)request, response).start();
request.handler(arrangementRequest -> {
couchbaseDAO.getReactiveCollection()
.get(arrangementRequest.getArrangementId())
.map(getResult -> getResult
.contentAsObject()
.removeKey("key_tx")
.removeKey("version"))
.subscribe(
jsonObject -> response.end(ArrangementAllDetails.newBuilder().setArrangementDetails(jsonObject.toString()).build()),
error -> ?????
);
});
}
}
.withCompression("gzip");
How can I send the error back in the error subscription block ?

This answer to "Pattern for rich error handling in gRPC" question might be helpful.

Related

data exchange using socket between Julia and Groovy

Recently I'm trying to use a socket to exchange data between a solver in Julia as a server and a client in Groovy. Im new to the socket concept and both the language. The thing is that it seems that once julia server done 'readLine()', the socket close and the 'write()' cannot proceed. I cannot send messages to the Groovy client nor exchange data.
Server code(Julia):
using Sockets
server = listen(2000)
while true
conn = accept(server)
println("connection accepted")
#async begin
try
line = readlines(conn)
println(line)
str = "server"
write(conn,str)
println("write done")
sleep(2)
catch err
print("connection ended with error $err")
sleep(2)
end
end
end
Client code(Groovy):
class groovy_client {
static void main(String[] args) {
while (true) {
try {
dataTransfer()
println 'dataTransfer success'
}catch (e) {
println(e)
sleep(2000)
}
}
}
private static void dataTransfer() {
Socket s = new Socket('localhost', 2000)
println 'connect to the server'
s.withStreams { input, output ->
// BufferedReader reader = new BufferedReader(new InputStreamReader(input))
// str = reader.readLine()
// println(str)
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(output))
writer.write('Hi server')
writer.flush()
input.withReader{reader ->
str = reader.readLine()
println 'haha'
println(str)
// def reader = input.newReader()
// def buffer = reader.readLine()
// println "server: $buffer"
sleep(2000)
}
println 'disconnect'
}
}
}
And I also have a doubt about how the socket works. Do server and client send and receive messages at the same time? Like server tells the client to add 1 to int_a while client send int_a back to the sender. Does int_a remain the original value or with 1 added and sent to the server?

Unity Mirror - NetworkServer Send Message To Target Client

I'm not sure what I'm doing wrong here but I can't seem to get my message from the server to the client. Here is what I have so far:
protected virtual void RegisterHandlers(bool enable)
{
if (enable)
{
NetworkServer.RegisterHandler<ClientRequestLoadScene>(OnClientRequestedToLoadScene);
NetworkClient.RegisterHandler<ServerRequestLoadScene>(OnServerRequestLoadScene);
}
else
{
NetworkServer.UnregisterHandler<ClientRequestLoadScene>();
NetworkClient.UnregisterHandler<ServerRequestLoadScene>();
}
}
The above is called when the instance starts to register a new handler. Then I have the client call:
ClientRequestLoadScene msg = new ClientRequestLoadScene();
msg.scene = scene;
NetworkClient.Send(msg);
This is received by the server fine. Then the server runs the following:
private void OnClientRequestedToLoadScene(NetworkConnection conn, ClientRequestLoadScene msg)
{
...
...
ServerRequestLoadScene server_msg = new ServerRequestLoadScene();
server_msg.scene = msg.scene;
NetworkServer.SendToClientOfPlayer(conn.identity, msg);
...
...
}
The above message is never received by the client. I have also tried: NetworkServer.SendToAll(msg); and that is never received by the client either. What am I doing wrong?
The issue with the above is with these lines:
server_msg.scene = msg.scene;
NetworkServer.SendToClientOfPlayer(conn.identity, msg);
It needed to be:
server_msg.scene = msg.scene;
conn.Send(server_msg);

Netty Client: request-response in same future

I'm trying to implement a Netty client which will send a TCP request and receive a response in the same Future. The code is below
public void sendMessage(String msg) {
Future<Channel> future = simpleChannelPool.acquire();
future.addListener((FutureListener<Channel>) f -> {
if (f.isSuccess()) {
Channel ch = f.getNow();
ChannelFuture channelFuture = ch.writeAndFlush((msg + " " + now() + lineSeparator()));
channelFuture.addListener(writeFuture -> {
if (writeFuture.isSuccess()) {
System.out.println("Channel write successful");
// how to READ data here?
}
});
// Release back to pool
simpleChannelPool.release(ch);
} else {
System.out.println("Failed to acquire a channel");
}
});
}
The part that I'm missing is how to read the data after successful write, line if (writeFuture.isSuccess()) {.... Basically I need to wait until next read is finished.
Also, given Netty's asynchronous nature, is it a right tool for request/response protocols?
Netty version used: 4.1.39.Final.
The complete code is available here.

Matching a String in a text file, and return back the meaning of the word in the client part (Scala)

I would like to solve a problem where the client will send a word to the server, and server will run through the text file and return the meaning of the word that is typed by the user. My problem is when a matching word is typed, i will return the match word meaning, at the same time return back other "Word not found" (which is my control statement). So i would like to just return the meaning of the word only if the word is matched and found
Heres my code:
Server part
Future {
//store local socket references for processing
val client = socket
try {
// Get a communication stream associated with the socket
val is = new BufferedReader(new InputStreamReader(client.getInputStream))
// Get a communication stream associated with the socket
val os = new PrintStream(client.getOutputStream)
val inFile = new File(filename)
val readFile = new Scanner(inFile)
var input : String = null;
while (true) {
// Read from input stream
var line: String = is.readLine() // read the word from client
println("The client send " + line)
while (readFile.hasNext()) {
input = readFile.nextLine()
println("From the file " + input)
if (input.contains(line)) {
os.println(input)
os.flush()
}
else{
os.println("Word not found")
}
}
}
} catch {
case e: Exception => e.printStackTrace
} finally {
// Close the connection, but not the server socket
client.close()
}
}
Client Part
val is = new BufferedReader(new InputStreamReader(client.get.getInputStream))
val os = new PrintStream(client.get.getOutputStream) // write to server a strin
println("Please Input Ur word ")
val user = readLine
os.println(user)
while (true) {
var line: String = is.readLine() //receive string from server
println(line)
}
My text file is formatted this way:
super-very good or pleasant; excellent.
Use the following approach:
var found = false;
while (readFile.hasNext() && !found) {
input = readFile.nextLine()
println("From the file " + input)
if (input.contains(line)) {
os.println(input)
os.flush()
found = true;
}
}
if(!found) {
os.println("Word not found")
os.flush()
}
There are much more beautiful ways to do this, but as you seem to be a beginner, this is the simplest solution possible.
If you are interested in a functional approach, I will gladly help.
Hope this helps.

Apache Camel REST DSL - Validating Request Payload and return error response

I am exposing a rest service using "CamelHttpTransportServlet" that receive orders and place in jms queue. The code works fine on happy path and returns 200 response.
I have written Processor to validate the input JSON, and set http_response_code based on the input.
The issue is - for invalid requests though failure response code - 400 is set, the flow continues to the next route and pushes the data to the queue instead of sending the 400 response back to the calling app.
rest("/ordermanagement")
.post("/order").to("direct:checkInput");
from("direct:checkInput")
.process(new Processor() {
#Override
public void process(final Exchange exchange) throws Exception {
String requestBody = exchange.getIn().getBody(String.class);
if(requestBody == "" || requestBody== null) {
exchange.getIn().setBody("{ "error": Bad Request}");
exchange.getIn().setHeader(Exchange.CONTENT_TYPE, "application/json");
exchange.getIn().setHeader(Exchange.HTTP_RESPONSE_CODE, 400);
}
}
})
.to("direct:sendToQ");
from("direct:sendToQ")
.to("jms:queue:orderReceiver")
.log("Sent to JMS");
Can someone advise what is missing here and provide a sample if possible?
Trying to implement onException approach:
rest("/ordermanagement")
.post("/order").to("direct:checkInput");
onException(CustomException.class).handled(true)
.setHeader(Exchange.HTTP_RESPONSE_CODE, code)
.setBody(jsonObject);
from("direct:checkInput")
.process(new Processor() {
#Override
public void process(final Exchange exchange) throws Exception {
String requestBody = exchange.getIn().getBody(String.class);
if(requestBody == "" || requestBody== null) {
throw CustomException(code, jsonObject)
}
}
})
.to("direct:sendToQ");
from("direct:sendToQ")
.to("jms:queue:orderReceiver")
.log("Sent to JMS");
However I could not figure out how to pass the parameters - code,jsonObject from processor to onException block.
Any help on this? Is this feasible?
I'd use something along the lines of the code example below:
onException(CustomException.class)
.handled(true)
.bean(PrepareErrorResponse.class)
.log("Error response processed");
rest("/ordermanagement")
.post("/order")
.to("direct:checkInput");
from("direct:checkInput")
.process((Exchange exchange) -> {
String requestBody = exchange.getIn().getBody(String.class);
if(requestBody == "" || requestBody== null) {
throw new CustomException(code, jsonObject);
}
})
.to("direct:sendToQ");
from("direct:sendToQ")
.to("jms:queue:orderReceiver")
.log("Sent to JMS");
Camel will store any exception caught in the exchange's property and should be therefore obtainable via the Exchange.EXCEPTION_CAUGHT property key. The sample below illustrates how such a custom error message bean can look like:
public class PrepareErrorResponse {
#Handler
public void prepareErrorResponse(Exchange exchange) {
Throwable cause = exchange.getProperty(Exchange.EXCEPTION_CAUGHT, Throwable.class);
if (cause instanceof CustomException) {
CustomException validationEx = (CustomException) cause;
// ...
}
Message msg = exchange.getOut();
msg.setHeader(Exchange.CONTENT_TYPE, MediaType.APPLICATION_JSON);
msg.setHeader(Exchange.HTTP_RESPONSE_CODE, 400);
JsonObject errorMessage = new JsonObject();
errorMessage.put("error", "Bad Request");
errorMessage.put("reason", cause.getMessage());
msg.setBody(errorMessage.toString());
// we need to do the fault=false below in order to prevent a
// HTTP 500 error code from being returned
msg.setFault(false);
}
}
Camel provides a couple of ways actually to deal with exceptions. The presented way here is just one example. The proposed code however allows to use custom redelivery strategies for different caught exceptions as well as additional stuff. If the error could get resolved within the exception handler, the route is proceeded at the point the exception occurred (i.e. temporary network issue with a redelivery strategy applied). If the error could not get fixed within the handler, the exchange will be stopped. Usually one would then send the currently processed message to a DLQ and log something about the error.
Note that this example will assume that CustomException is an unchecked exception as the processor is replaced with a simpler lambda. If you can't or don't want to use such an exception (or lambda expressions) replace the lambda-processor with new Processor() { #Override public void process(Exchange exchange) throws Exception { ... } } construct.
Here is one way to do it. You can use choice
rest("/ordermanagement")
.post("/order").to("direct:checkInput");
from("direct:checkInput")
.process(exchange -> {
String requestBody = exchange.getIn().getBody(String.class);
if(requestBody == null || requestBody.equals("")) {
exchange.getIn().setBody("{ "error": Bad Request}");
exchange.getIn().setHeader(Exchange.CONTENT_TYPE, "application/json");
exchange.getIn().setHeader(Exchange.HTTP_RESPONSE_CODE, 400);
}
})
.choice()
.when(exchange -> {
Object header = exchange.getIn().getHeader(Exchange.HTTP_RESPONSE_CODE);
return header != null && header.equals(400);
})
.stop()
.otherwise()
.to("direct:sendToQ")
.endChoice();
from("direct:sendToQ")
.to("jms:queue:orderReceiver")
.log("Sent to JMS");
Setting ROUTE_STOP property to true in the processor should prevent further flow and return your response:
...
exchange.getIn().setBody("{ "error": Bad Request}");
exchange.getIn().setHeader(Exchange.CONTENT_TYPE, "application/json");
exchange.getIn().setHeader(Exchange.HTTP_RESPONSE_CODE, 400);
exchange.setProperty(Exchange.ROUTE_STOP, Boolean.TRUE);
...