package nginx.clojure.net;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.CharacterCodingException;
import java.nio.charset.CharsetEncoder;
import java.util.Map;
import nginx.clojure.ChannelListener;
import nginx.clojure.NginxClojureRT;
import nginx.clojure.NginxHttpServerChannel;
import nginx.clojure.NginxRequest;
import nginx.clojure.java.ArrayMap;
import nginx.clojure.java.NginxJavaRingHandler;
import nginx.clojure.logger.TinyLogService;
import nginx.clojure.logger.TinyLogService.MsgType;
import nginx.clojure.net.NginxClojureAsynChannel.CompletionListener;
public class SimpleHandler4TestNginxClojureAsynChannel implements NginxJavaRingHandler {
TinyLogService log = new TinyLogService(MsgType.debug, System.err, System.err);
private void handleError(long status, NginxClojureAsynChannel upstream, NginxHttpServerChannel downstream) {
upstream.close();
if (downstream.getContext() == "sent") {
downstream.send("\r\n************Error Happended************\r\n"+upstream.buildError(status), true, true);
log.warn("error happened: %s", upstream.buildError(status));
}else {
downstream.sendResponse(new Object[] {500, ArrayMap.create("Content-Type", "text/html") , upstream.buildError(status)});
}
}
private boolean checkDownStreamClosed(NginxClojureAsynChannel upstream, NginxHttpServerChannel downstream) {
if (downstream.isClosed()) {
log.info("downstream is closed!");
upstream.close();
return true;
}
return false;
}
@Override
public Object[] invoke(Map<String, Object> request) {
NginxRequest req = (NginxRequest) request;
NginxHttpServerChannel downstream = req.handler().hijack(req, true);
downstream.addListener(downstream, new ChannelListener<NginxHttpServerChannel>() {
@Override
public void onClose(NginxHttpServerChannel data) {
log.info("***downstream closed!");
}
@Override
public void onConnect(long status, NginxHttpServerChannel data) {
}
});
final NginxClojureAsynChannel upstream = new NginxClojureAsynChannel();
String url = "mirror.bit.edu.cn:80";
upstream.setTimeout(5000, 20000, 20000);
upstream.connect(url, downstream, new CompletionListener<NginxHttpServerChannel>() {
@Override
public void onError(long code, NginxHttpServerChannel downstream) {
log.info("connected error : " + code);
handleError(code, upstream, downstream);
}
@Override
public void onDone(long status, final NginxHttpServerChannel downstream) {
log.info("connected successfully : " + status);
if (checkDownStreamClosed(upstream, downstream)) {
return;
}
CharsetEncoder encoder = NginxClojureRT.DEFAULT_ENCODING.newEncoder();
ByteBuffer getCommand;
try {
getCommand = encoder.encode(CharBuffer
.wrap("GET /apache/httpcomponents/httpclient/RELEASE_NOTES-4.3.x.txt HTTP/1.1\r\n"
+ "User-Agent: nginx-clojure/0.2.5\r\n"
+ "Host: mirror.bit.edu.cn\r\nAccept: */*\r\n"
+ "Connection: close\r\n\r\n"));
upstream.write(getCommand, upstream, new CompletionListener<NginxClojureAsynChannel>() {
public void onError(long code, NginxClojureAsynChannel attachment) {
attachment.close();
handleError(code, upstream, downstream);
};
@Override
public void onDone(long status, final NginxClojureAsynChannel upstream) {
log.info("write onDone status : " + status);
upstream.getAsynSocket().shutdown(NginxClojureAsynSocket.NGX_HTTP_CLOJURE_SOCKET_SHUTDOWN_SOFT_WRITE);
if (checkDownStreamClosed(upstream, downstream)) {
return;
}
ByteBuffer buffer = ByteBuffer.allocateDirect(1024*4);
CompletionListener<ByteBuffer> upstreamListener = new CompletionListener<ByteBuffer>() {
public void onError(long code, ByteBuffer attachment) {
handleError(code, upstream, downstream);
};
@Override
public void onDone(long status, ByteBuffer buffer) {
log.info("read onDone status : " + status);
if (checkDownStreamClosed(upstream, downstream)) {
return;
}
boolean end = buffer.hasRemaining() || status == 0;
buffer.flip();
downstream.setContext("sent");//have sent something
downstream.send(buffer, true, end);
buffer.clear();
if (!end) {
upstream.read(buffer, buffer, this);
}else {
upstream.close();
}
}
};
upstream.read(buffer, buffer, upstreamListener);
}
});
} catch (CharacterCodingException e) {// should not happend!
}
}
});
return null;
}
}