use of primal.fp.Funs.Sink in project suite by stupidsing.
the class Dump method toLine.
private static void toLine(Object node, Sink<String> sink) {
var dumpedObjects = new IdentityHashMap<Object, Object>();
new Object() {
private void d(Object object, String suffix) {
if (object == null)
sink.f("null");
else if (dumpedObjects.put(object, true) == null)
try {
d_(object);
} finally {
dumpedObjects.remove(object);
}
else
sink.f("(recursed)");
sink.f(suffix);
}
private void d_(Object object) {
var clazz = object.getClass();
if (clazz.isArray()) {
sink.f("[");
for (var i = 0; i < Array.getLength(object); i++) d(Array.get(object, i), ",");
sink.f("]");
} else if (Util.isSimple(clazz))
sink.f(object.toString());
else
new //
Switch<Object>(//
object).doIf(Collection.class, collection -> {
sink.f("[");
for (var object1 : collection) d(object1, ",");
sink.f("]");
}).doIf(Map.class, map -> {
sink.f("{");
for (var e : ((Map<?, ?>) object).entrySet()) {
d(e.getKey(), ":");
d(e.getValue(), ",");
}
sink.f("}");
}).doIf(MapObject.class, mi -> {
sink.f(mi.getClass().getSimpleName());
sink.f("{");
for (var object1 : MapObject_.list(mi)) d(object1, ",");
sink.f("}");
}).doIf(Pair.class, pair -> {
sink.f("<");
d(pair.k, "|");
d(pair.v, ">");
}).doIf(Object.class, o -> {
sink.f(o.getClass().getSimpleName());
sink.f("{");
for (var pair : readers(object)) {
Object value;
try {
value = pair.v.call();
} catch (Throwable ex) {
value = "<" + ex.getClass() + ">";
}
if (value != null) {
sink.f(pair.k + ":");
d(value, ",");
}
}
sink.f("}");
}).nonNullResult();
}
}.d(node, "");
}
use of primal.fp.Funs.Sink in project suite by stupidsing.
the class HttpNio method listen.
private void listen(Reg reg) {
var rw = new Object() {
// 0 - read, 1 - write, 2 - close after all written
private int stage = 0;
private Bytes br = Bytes.empty;
private Bytes bw = Bytes.empty;
private Puller<Bytes> write;
private Source<Boolean> eater = () -> parseLine(line -> handleRequest1stLine(line.trim(), response -> {
var data = //
"HTTP/1.1 " + response.status + "\r\n" + response.headers.streamlet().map((k, v) -> k + ": " + v + "\r\n").toJoinedString() + "\r\n";
stage = 1;
if (response.body != null)
write = Puller.concat(Pull.from(data), response.body);
else {
bw = Bytes.of(data.getBytes(Utf8.charset));
response.write.f(bytes -> {
if (bytes != null)
bw = bw.append(bytes);
else
stage = 2;
listen();
});
}
}));
private void listen() {
if (!bw.isEmpty())
reg.listenWrite(() -> bw, this::written);
else if (stage == 0)
reg.listenRead(in -> {
read(in);
listen();
});
else if (stage == 1 && write != null)
reg.listenWrite(() -> bw = write.pull(), this::written);
else if (stage == 2)
reg.listenWrite(() -> null, null);
else if (stage == 3)
reg.listen(0, null, null, null);
}
private void read(Bytes in) {
if (in != null) {
br = br.append(in);
while (eater.g()) ;
} else
// closes connection
write = Puller.empty();
}
private void written(int n) {
if (0 <= n)
bw = bw.range(n);
else
stage = 3;
listen();
}
private void handleRequest1stLine(String line, Sink<Response> cb) {
var hrhl = handleRequestHeaderLine(lines -> handleRequestBody(line, lines, cb));
eater = () -> parseLine(hrhl);
}
private Sink<String> handleRequestHeaderLine(Sink<List<String>> cb) {
var lines = new ArrayList<String>();
return line0 -> {
var line1 = line0.trim();
if (!line1.isEmpty())
lines.add(line1);
else
cb.f(lines);
};
}
private void handleRequestBody(String line0, List<String> headerLines, Sink<Response> cb) {
eater = () -> //
FixieArray.of(//
line0.split(" ")).map((method, url, proto) -> handleRequestBody(proto, method, url, headerLines, cb));
}
private //
boolean handleRequestBody(//
String proto, //
String method, //
String url, //
List<String> lines, Sink<Response> cb) {
var headers = //
Read.from(//
lines).fold(new Header(), (headers_, line_) -> //
Split.strl(line_, //
":").map((k, v) -> headers_.put(k, v)));
var queue = new ArrayBlockingQueue<Bytes>(Buffer.size);
Sink<Bytes> offer = queue::add;
Source<Bytes> take = queue::poll;
Fun2<String, String, Request> requestFun = (host, pqs) -> Split.strl(pqs, "?").map((path0, query) -> {
var path1 = path0.startsWith("/") ? path0 : "/" + path0;
var path2 = ex(() -> URLDecoder.decode(path1, Utf8.charset));
return //
Equals.string(proto, "HTTP/1.1") ? //
new Request(method, host, path2, query, headers, Puller.of(take)) : fail("only HTTP/1.1 is supported");
});
var pp = Split.string(url, "://");
var request = pp != null ? Split.strl(pp.v, "/").map(requestFun) : requestFun.apply("", url);
var cl = request.headers.getOpt("Content-Length").map(Long::parseLong);
var te = Equals.ab(request.headers.getOpt("Transfer-Encoding"), Opt.of("chunked"));
Log_.info(request.getLogString());
if (te)
eater = handleChunkedRequestBody(request, offer, cb);
else if (cl.hasValue())
eater = handleRequestBody(request, offer, cl.g(), cb);
else
eater = handleRequestBody(request, offer, 0, cb);
return true;
}
private //
Source<Boolean> handleRequestBody(//
Request request, //
Sink<Bytes> body, //
long contentLength, Sink<Response> cb) {
return new Source<>() {
private int n;
public Boolean g() {
body.f(br);
var isOpen = br != null;
if (isOpen) {
n += br.size();
br = Bytes.empty;
}
if (!isOpen || contentLength <= n)
cb.f(handler.handle(request));
return false;
}
};
}
private Source<Boolean> handleChunkedRequestBody(Request request, Sink<Bytes> body, Sink<Response> cb) {
return () -> {
for (var i0 = 0; i0 < br.size(); i0++) if (br.get(i0) == 10) {
var line = new String(br.range(0, i0).toArray(), Utf8.charset);
var size = Integer.parseInt(line.trim(), 16);
for (var i1 = i0 + 1 + size; i1 < br.size(); i1++) if (br.get(i1) == 10) {
var chunk = br.range(i0 + 1, i1);
br = br.range(i1);
body.f(chunk);
return true;
}
if (size == 0)
cb.f(handler.handle(request));
}
return false;
};
}
private boolean parseLine(Sink<String> handleLine) {
for (var i = 0; i < br.size(); i++) if (br.get(i) == 10) {
var line = new String(br.range(0, i).toArray(), Utf8.charset);
br = br.range(i + 1);
handleLine.f(line);
return true;
}
return false;
}
};
rw.listen();
}
use of primal.fp.Funs.Sink in project suite by stupidsing.
the class NioClusterMapTest method testClusterMap.
@Test
public void testClusterMap() throws IOException {
var nNodes = 3;
var peers = forInt(nNodes).map2(i -> "NODE" + i, i -> new InetSocketAddress(localHost, 3000 + i)).toMap();
var clusters = //
Read.from2(//
peers).keys().map2(name -> name, //
name -> ex(() -> new NioCluster(name, peers))).toMap();
for (var cluster : clusters.values()) cluster.start();
var peerNames = new ArrayList<>(peers.keySet());
var clMap = //
Read.from2(//
peers).keys().map2(name -> name, //
name -> new NioClusterMap<Integer, String>(clusters.get(name))).toMap();
Sleep.quietly(5 * 1000);
System.out.println("=== CLUSTER FORMED (" + LocalDateTime.now() + ") ===\n");
Source<NioClusterMap<Integer, String>> peerf = () -> clMap.get(peerNames.get(random.nextInt(nNodes)));
Int_Obj<Sink<Runnable>> setf = i -> cont -> peerf.g().set(i, Integer.toString(i), v0 -> cont.run(), fail);
Int_Obj<Sink<Runnable>> getf = i -> cont -> peerf.g().get(i, v -> {
assertEquals(Integer.toString(i), v);
cont.run();
}, fail);
Fun<NioCluster, Sink<Runnable>> closef = cluster -> cont -> {
try {
cluster.stop();
System.out.println("=== CLUSTER STOPPED (" + LocalDateTime.now() + ") ===\n");
} catch (IOException ex) {
fail(ex);
}
cont.run();
};
var sinks = //
Streamlet.concat(//
forInt(9).map(setf), //
forInt(9).map(getf), Read.from2(clusters).values().map(closef)).toList();
new Object() {
public void run(int i) {
if (i < sinks.size())
sinks.get(i).f(() -> run(i + 1));
}
}.run(0);
Read.from2(clusters).values().map(cluster -> New.thread(cluster::run)).collect(Start::thenJoin);
for (var cluster : clusters.values()) cluster.close();
}
use of primal.fp.Funs.Sink in project suite by stupidsing.
the class IterativeParser method parse.
public Node parse(String in0) {
var in = Preprocess.transform(PreprocessorFactory.create(operators), in0).k;
var stack = new ArrayDeque<Section>();
Sink<Operator> addOperator = operator -> {
var section = stack.peek();
var tree = section.unwind(operator);
var tree0 = tree.getRight();
var tree1 = Tree.of(operator, tree0, Atom.NIL);
Tree.forceSetRight(tree, tree1);
section.push(tree1);
};
Sink<Node> add = node -> {
var section = stack.peek();
if (!section.isDanglingRight)
addOperator.f(opTuple);
Tree.forceSetRight(section.list.getLast(), node);
section.isDanglingRight = false;
};
var lex = new Lexer(operators, opTuple, in);
stack.push(new Section(' '));
Token token;
while ((token = lex.lex()) != null) {
var operator = token.operator;
var data = token.getData();
var ch = data.charAt(0);
if (operator != null) {
addOperator.f(operator);
if (operator == TermOp.BRACES)
stack.push(new Section('{'));
} else if (ch == '(' || ch == '[' || ch == '{')
stack.push(new Section(ch));
else if (ch == ')' || ch == ']' || ch == '}') {
var section = stack.pop();
var kind = section.kind;
if (kind == '(' && ch == ')' || kind == '[' && ch == ']' || kind == '{' && ch == '}') {
var node = section.unwind(null).getRight();
if (ch == ']')
node = TreeTuple.of(Atom.of("["), node);
else if (ch == '}')
node = TreeTuple.of(Atom.of("{"), node);
add.f(node);
} else
fail("cannot parse " + in);
} else if (ch == '`')
if (stack.peek().kind == ch) {
var node = stack.pop().unwind(null).getRight();
node = TreeTuple.of(Atom.of("`"), node);
add.f(node);
} else
stack.push(new Section(ch));
else if (Is.notBlank(data))
add.f(terminalParser.parseTerminal(data));
}
return stack.size() == 1 ? stack.pop().unwind(null).getRight() : fail("cannot parse " + in);
}
Aggregations