package divconq.ctp.f;
import java.util.Scanner;
import java.util.concurrent.CountDownLatch;
import divconq.ctp.CtpAdapter;
import divconq.ctp.CtpClient;
import divconq.ctp.CtpCommand;
import divconq.ctp.CtpConstants;
import divconq.ctp.cmd.RequestCommand;
import divconq.ctp.cmd.SimpleCommand;
import divconq.ctp.cmd.ProgressCommand;
import divconq.ctp.stream.CtpStreamDest;
import divconq.ctp.stream.CtpStreamSource;
import divconq.ctp.stream.FileSourceStream;
import divconq.ctp.stream.FolderDumpStream;
import divconq.ctp.stream.IStream;
import divconq.ctp.stream.IStreamDest;
import divconq.ctp.stream.NullStream;
import divconq.ctp.stream.StreamUtil;
import divconq.filestore.local.FileSystemDriver;
import divconq.filestore.select.FileSelection;
import divconq.filestore.select.FileSelectionMode;
import divconq.hub.Hub;
import divconq.lang.op.FuncCallback;
import divconq.lang.op.IOperationObserver;
import divconq.lang.op.OperationCallback;
import divconq.lang.op.OperationContext;
import divconq.lang.op.OperationObserver;
import divconq.struct.FieldStruct;
import divconq.struct.RecordStruct;
import divconq.util.StringUtil;
import divconq.work.IWork;
import divconq.work.Task;
import divconq.work.TaskRun;
/*
Title: Download Flow
Participant Client Code
Participant File Store A
Participant Pipe A
Participant Handler A
Participant Adapter A
Participant Server
Client Code->Adapter A: select
Adapter A->Server: SELECT
Server->Adapter A: SUCCESS
Adapter A->Handler A: SUCCESS
Handler A->Client Code: success
Client Code->Handler A: set pipe
Client Code->Adapter A: read
Adapter A->Server: READ
Server->Adapter A: BLOCK
Adapter A->Handler A: BLOCK
Handler A->Pipe A: BLOCK
Pipe A->File Store A: BLOCK
File Store A->Pipe A: request
Pipe A->Handler A: request
Handler A->Adapter A: read
Adapter A->Server: READ
Server->Adapter A: BLOCK*\netc...
Server->Adapter A: FINAL
Adapter A->Handler A: FINAL
Handler A->Client Code: final
Client Code->Handler A: close pipe
Client Code->Adapter A: success
Adapter A->Server: SUCCESS
*
*/
public class CtpFClient extends CtpClient {
protected TaskRun currTask = null;
protected CtpStreamSource readStream = null;
// when using this be sure to issue "read()" in callback
public void selectFiles(FileSelection sel, FuncCallback<RecordStruct> cb) {
RequestCommand cmd = new RequestCommand();
RecordStruct params = new RecordStruct(
new FieldStruct("Op", CtpConstants.CTP_F_OP_SELECT),
new FieldStruct("Select", sel.toInstructions())
);
cmd.setBody(params);
try {
this.adapter.sendCommand(cmd, cb);
}
catch (Exception x) {
System.out.println("ctp client send error: " + x);
}
}
public void handle(CtpCommand cmd, CtpAdapter adapter) throws Exception {
OperationContext ctx = adapter.getContext();
ctx.touch();
//System.out.println("Client got command: " + cmd.getCmdCode());
if (cmd instanceof ProgressCommand) {
if (ctx != null) {
// put the call back into the work pool, don't tie up the IO thread
Task t = new Task()
.withContext(ctx.subContext())
.withWork(new IWork() {
@Override
public void run(TaskRun trun) {
trun.getContext().setAmountCompleted(((ProgressCommand)cmd).getAmount());
adapter.read();
trun.complete();
}
});
Hub.instance.getWorkPool().submit(t);
}
return;
}
if (cmd.getCmdCode() == CtpConstants.CTP_F_CMD_STREAM_FINAL) {
//System.out.println("Client got Final!");
TaskRun brun = this.currTask;
CtpStreamSource src = this.readStream;
if (brun == null) {
System.out.println("Client READ error, missing task!!!!! " + ((BlockCommand) cmd).getPath());
}
else if (src == null) {
System.out.println("Client READ error, missing src!!!!! " + ((BlockCommand) cmd).getPath());
}
else {
src.setFinal();
brun.resume();
}
return;
}
if (cmd instanceof BlockCommand) {
//System.out.println("Client got block: " + ((BlockCommand) cmd).getPath());
//System.out.println("Client got block - is folder: " + ((BlockCommand) cmd).isFolder());
//System.out.println("Client got block - size: " + ((BlockCommand) cmd).getSize());
TaskRun brun = this.currTask;
CtpStreamSource src = this.readStream;
if (brun == null) {
System.out.println("Client READ error, missing task!!!!! " + ((BlockCommand) cmd).getPath());
}
else if (src == null) {
System.out.println("Client READ error, missing src!!!!! " + ((BlockCommand) cmd).getPath());
}
else {
src.addNext((BlockCommand)cmd);
brun.resume();
/*
Task t = new Task()
.withRootContext() // TODO use session context
.withWork(new IWork() {
@Override
public void run(TaskRun trun) {
if (((BlockCommand) cmd).getData() == null)
System.out.println("Client processed empty block");
else
System.out.println("Client processed block: " + ((BlockCommand) cmd).getData().readableBytes());
adapter.read();
cmd.release();
trun.complete();
}
});
*/
}
return;
}
// get more, unless a stream command - then let it handle automatically
/*
if (!(cmd instanceof IStreamCommand)) {
adapter.read();
cmd.release();
}
*/
}
public void writeFrom(OperationCallback cb, IStream... strm) {
OperationContext ctx = this.adapter.getContext();
ctx.setAmountCompleted(0);
Task t = new Task()
.withSubContext()
.withTitle("Stream Write");
@SuppressWarnings("resource")
IStreamDest writeStream = new CtpStreamDest(this.adapter, t.getContext());
t.withObserver(new OperationObserver() {
@Override
public void completed(OperationContext or) {
//System.out.println("READ server is complete!!");
//System.out.println("Context 3: " + OperationContext.get().getOpId());
/*
try {
CtpFClient.this.adapter.sendCommand(new ResponseCommand());
}
catch (Exception x) {
System.out.println("Unable to send SUCCESS for READ: " + x);
}
*/
cb.callback();
}
});
IStream[] tstrm = new IStream[strm.length + 1];
for (int i = 0; i < strm.length; i++)
tstrm[i] = strm[i];
tstrm[strm.length] = writeStream;
//System.out.println("strm 0: " + tstrm[0]);
//System.out.println("strm 1: " + tstrm[1]);
TaskRun trun = StreamUtil.composeStream(t, tstrm);
this.currTask = trun;
trun.resume();
// we can read while writing
this.adapter.read();
}
public void readTo(OperationCallback cb, IStream... strm) {
//System.out.println("Context 2: " + OperationContext.get().getOpId());
OperationContext ctx = this.adapter.getContext();
ctx.setAmountCompleted(0);
this.readStream = new CtpStreamSource(this.adapter);
Task t = new Task()
.withSubContext()
.withTitle("Stream Read");
t.withObserver(new OperationObserver() {
@Override
public void completed(OperationContext or) {
//System.out.println("WRITE client is complete!!");
//System.out.println("Context 3: " + OperationContext.get().getOpId());
/*
try {
CtpFClient.this.adapter.sendCommand(new ResponseCommand());
}
catch (Exception x) {
System.out.println("Unable to send SUCCESS for READ: " + x);
}
*/
cb.callback();
adapter.read();
}
});
IStream[] tstrm = new IStream[strm.length + 1];
tstrm[0] = this.readStream;
for (int i = 1; i < tstrm.length; i++)
tstrm[i] = strm[i - 1];
//System.out.println("strm 0: " + tstrm[0]);
//System.out.println("strm 1: " + tstrm[1]);
TaskRun trun = StreamUtil.composeStream(t, tstrm);
this.currTask = trun;
trun.resume();
}
@Override
public void connect(String host, int port, OperationCallback connCallback) {
//System.out.println("Context 1: " + OperationContext.get().getOpId());
super.connect(host, port, new OperationCallback() {
@Override
public void callback() {
adapter.setMapper(CtpfCommandMapper.instance);
/* TODO ???
CtpFClient.this.sendCommand(new InitCommand(), new FuncCallback<RecordStruct>() {
@Override
public void callback() {
System.out.println("Ctp F Client - Init complete");
adapter.read();
connCallback.complete();
}
});
*/
System.out.println("Ctp F Client - Init complete");
adapter.read();
connCallback.complete();
}
});
}
public void folderListing(String path) {
FileSelection sel = new FileSelection()
.withMode(FileSelectionMode.Listing)
.withFileSet(path)
.withAttrs(CtpConstants.CTP_F_ATTR_PREFERED);
try {
this.selectFiles(sel, new FuncCallback<RecordStruct>() {
@Override
public void callback() {
//System.out.println("Context 4: " + OperationContext.get().getOpId());
if (this.hasErrors()) {
System.out.println("Failed Selection: " + this.getMessage());
adapter.read(); // TODO or close?
return;
}
try {
//ctpf.sendCommand(new ReadCommand());
CtpFClient.this.readTo(new OperationCallback() {
@Override
public void callback() {
//System.out.println("Context 5: " + OperationContext.get().getOpId());
System.out.println("Directory listing completed!");
}
},
new FolderDumpStream());
}
catch (Exception x) {
System.out.println("Ctp-F Client cb error: " + x);
}
adapter.read(); // get that folder listing
}
});
}
catch (Exception x) {
System.out.println("Ctp-F Client error: " + x);
}
}
@Override
public void close() {
System.out.println("Client Connection closed");
}
static public void utilityMenu(Scanner scan) {
OperationContext ctx = OperationContext.get();
IOperationObserver oo = new OperationObserver() {
@Override
public void amount(OperationContext ctx, int v) {
System.out.println("Progress: " + v);
}
};
ctx.addObserver(oo);
CtpFClient ctpf = new CtpFClient();
CountDownLatch cdl = new CountDownLatch(1);
ctpf.connect("localhost", 8181, new OperationCallback() {
@Override
public void callback() {
cdl.countDown();
}
});
try {
cdl.await();
}
catch (InterruptedException x) {
System.out.println("Error connecting: " + x);
return;
}
boolean running = true;
while(running) {
try {
System.out.println();
System.out.println("-----------------------------------------------");
System.out.println(" Hub " + Hub.instance.getResources().getHubId() + " Utility Menu");
System.out.println("-----------------------------------------------");
System.out.println("0) Exit");
System.out.println("1) ls on karabiner");
System.out.println("2) Folder Listing");
System.out.println("3) Test Download");
System.out.println("4) Test Upload");
String opt = scan.nextLine();
Long mopt = StringUtil.parseInt(opt);
if (mopt == null)
continue;
switch (mopt.intValue()) {
case 0:
ctpf.sendCommand(SimpleCommand.EXIT_SIGN_OUT);
running = false;
break;
case 1: {
ctpf.folderListing("/User/karabiner");
break;
}
case 2: {
System.out.println("Folder to list: ");
ctpf.folderListing(scan.nextLine());
break;
}
case 3: {
FileSelection sel = new FileSelection()
.withMode(FileSelectionMode.Expanded)
.withFileSet("/User/Salt/long score 3.txt.out")
.withAttrs(CtpConstants.CTP_F_ATTR_PREFERED, CtpConstants.CTP_F_ATTR_DATA);
try {
ctpf.selectFiles(sel,
new FuncCallback<RecordStruct>() {
@Override
public void callback() {
if (this.hasErrors()) {
System.out.println("Failed Selection: " + this.getMessage());
ctpf.read(); // TODO or close?
return;
}
//System.out.println("Context 9: " + OperationContext.get().getOpId());
try {
ctpf.readTo(new OperationCallback() {
@Override
public void callback() {
//System.out.println("Context 10: " + OperationContext.get().getOpId());
System.out.println("Download completed!");
}
},
new NullStream());
}
catch (Exception x) {
System.out.println("Ctp-F Client cb error: " + x);
}
ctpf.read(); // get that folder listing
}
});
}
catch (Exception x) {
System.out.println("Ctp-F Client error: " + x);
}
break;
}
case 4: {
@SuppressWarnings("resource")
FileSystemDriver fsd = new FileSystemDriver();
fsd.setRootFolder("/Work/Temp/Dest/x");
FileSelection sel = new FileSelection()
.withFileSet("/cc-logo-sm.png");
ctpf.writeFrom(new OperationCallback() {
@Override
public void callback() {
//System.out.println("Context 10: " + OperationContext.get().getOpId());
System.out.println("Upload completed!");
}
},
new FileSourceStream(fsd.select(sel)));
break;
}
}
}
catch(Exception x) {
System.out.println("CLI error: " + x);
}
}
ctx.removeObserver(oo);
}
}