I’m stuck on Stage #(Implement the ECHO command #QQ0).
Seems like there is a problem with single quote and double quotes when sending the commands to CLI.
If it is sent with single quotes:
echo -ne '*2\r\n$4\r\nECHO\r\n$10\r\nstrawberry\r\n' | nc localhost 6379
Then all is parsed successfully and code prints something like this:
*2
$4
ECHO
$10
strawberry
But when it is sent with double quotes:
echo -ne "*2\r\n$4\r\nECHO\r\n$10\r\nstrawberry\r\n" | nc localhost 6379
It looks like this:
*2
ECHO
strawberry
Then the $4 and $10 are wiped, because they are treated like special character (bash - Why quotes are retained in string variables when surrounded by single quotes? - Unix & Linux Stack Exchange).
Here are my logs:
Debug = true
[tester::#QQ0] Running tests for Stage #QQ0 (Implement the ECHO command)
[tester::#QQ0] $ ./spawn_redis_server.sh
[your_program] Server listening on port: 6379
[tester::#QQ0] $ redis-cli ECHO pear
[tester::#QQ0] Sent bytes: "*2\r\n$4\r\nECHO\r\n$10\r\nstrawberry\r\n"
[your_program] Creating Redis CLI client thread: 1
[your_program] Starting Redis CLI client thread: 1
[your_program] Running Redis CLI client thread: 1
[tester::#QQ0] Received: "" (no content received)
[tester::#QQ0] ^ error
[tester::#QQ0] Error: Expected start of a new RESP2 value (either +, -, :, $ or *)
[tester::#QQ0] Test failed
[tester::#QQ0] Terminating program
[tester::#QQ0] Program terminated successfully
And here’s a snippet of my Main.java:
import commandprocessor.RedisCommandParser;
import commandprocessor.RedisRespParser;
import java.io.IOException;
import java.io.InputStream;
import java.net.Socket;
import java.util.List;
import static commandprocessor.util.InputStreamUtil.getInputStreamBytes;
public class RedisCliThread implements Runnable {
private final Socket clientSocket;
private final String threadName;
private final RedisCommandParser commandParser;
private final RedisRespParser respParser;
private Thread thread;
public RedisCliThread(Socket clientSocket, String threadName) {
this.clientSocket = clientSocket;
this.threadName = threadName;
this.commandParser = new RedisCommandParser();
this.respParser = new RedisRespParser();
System.out.println("Creating " + threadName);
}
@Override
public void run() {
System.out.println("Running " + this.threadName);
// Wait for connection from client.
try (InputStream inputStream = this.clientSocket.getInputStream()) {
byte[] clientInput = getInputStreamBytes(inputStream);
List<String> parsedParts = respParser.parse(clientInput);
byte[] result = commandParser.parse(parsedParts);
if (result != null) {
this.clientSocket.getOutputStream().write(result);
}
} catch (IOException e) {
System.err.println("IOException while reading input from client: " + e.getMessage());
} finally {
closeClientSocket(this.clientSocket);
}
}
public void start() {
System.out.println("Starting " + this.threadName);
if (thread == null) {
thread = new Thread(this);
thread.start();
}
}
private static void closeClientSocket(Socket clientSocket) {
try {
clientSocket.close();
} catch (IOException e) {
System.err.println("IOException while closing client socket: " + e.getMessage());
}
}
}
I’ve tried to use BufferedReader with InputStreamReader then appending every line to StringBuilder, but the result was the same. the $ was removed.
Looked something like this:
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
StringBuilder sb = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
sb.append(line).append("\n");
}
I am sure I am missing something out…
Any help would be appreciated!
Thank you!