// Copyright (c) 2014 Tom Zhou<iwebpp@gmail.com>
package com.iwebpp.node.stream;
import com.iwebpp.node.NodeContext;
import com.iwebpp.node.NodeContext.nextTickListener;
public abstract class Duplex
extends Readable2
implements Writable {
private Writable2 _writable;
protected Writable2.State _writableState;
private boolean allowHalfOpen;
private NodeContext context;
/**
* @return the allowHalfOpen
*/
public boolean isAllowHalfOpen() {
return allowHalfOpen;
}
/**
* @return the _writableState
*/
public Writable2.State get_writableState() {
return _writableState;
}
private class DuplexWritable extends Writable2 {
private Duplex hold;
protected DuplexWritable(NodeContext context, Options options, Duplex hold) {
super(context, options);
this.hold = hold;
}
private DuplexWritable() {super(null, null);}
@Override
protected void _write(Object chunk, String encoding, WriteCB cb) throws Exception {
hold._write(chunk, encoding, cb);
}
}
public static class Options {
private boolean allowHalfOpen = true;
private Readable2.Options roptions;
private Writable2.Options woptions;
public Options(Readable2.Options roptions, Writable2.Options woptions, boolean allowHalfOpen) {
this.roptions = roptions;
this.woptions = woptions;
this.allowHalfOpen = allowHalfOpen;
}
@SuppressWarnings("unused")
private Options(){}
}
protected Duplex(NodeContext ctx, Options options) {
super(ctx, options.roptions);
this.context = ctx;
_writable = new DuplexWritable(ctx, options.woptions, this);
_writableState = _writable._writableState;
final Duplex self = this;
/*
if (options && options.readable === false)
this.readable = false;
if (options && options.writable === false)
this.writable = false;
this.allowHalfOpen = true;
if (options && options.allowHalfOpen === false)
this.allowHalfOpen = false;
*/
this.allowHalfOpen = options.allowHalfOpen;
this.once("end", new Listener(){
@Override
public void onEvent(Object data) throws Exception {
// the no-half-open enforcer
///function onend() {
// if we allow half-open state, or if the writable side ended,
// then we're ok.
if (self.allowHalfOpen || self._writableState.isEnded())
return;
// no more data can be written.
// But allow more writes to happen in this tick.
///process.nextTick(this.end.bind(this));
context.nextTick(new nextTickListener(){
@Override
public void onNextTick() throws Exception {
self.end(null, null, null);
}
});
///}
}
});
}
private Duplex(){
super(null, null);
}
@Override
public boolean write(Object chunk, String encoding, WriteCB cb) throws Exception {
return _writable.write(chunk, encoding, cb);
}
@Override
public boolean write(Object chunk, String encoding) throws Exception {
return _writable.write(chunk, encoding);
}
@Override
public boolean write(Object chunk) throws Exception {
return _writable.write(chunk);
}
@Override
public boolean write() throws Exception {
return _writable.write();
}
@Override
public boolean end(Object chunk, String encoding, WriteCB cb) throws Exception {
return _writable.end(chunk, encoding, cb);
}
@Override
public boolean end(Object chunk, String encoding) throws Exception {
return _writable.end(chunk, encoding);
}
@Override
public boolean end(Object chunk) throws Exception {
return _writable.end(chunk);
}
@Override
public boolean end() throws Exception {
return _writable.end();
}
@Override
public boolean writable() {
return _writable.writable();
}
public void writable(boolean writable) {
_writable.writable(writable);
}
public void cork() {
_writable.cork();
}
public void uncork() throws Exception {
_writable.uncork();
}
public int corked() {
return _writable.corked();
}
public boolean isNeedDrain() {
return _writable.isNeedDrain();
}
@Override
protected abstract void _read(int size) throws Exception;
protected abstract void _write(Object chunk, String encoding, WriteCB cb) throws Exception;
}