/*
* Copyright 2016 The Simple File Server Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sfs.io;
import io.vertx.core.Handler;
import io.vertx.core.buffer.Buffer;
import io.vertx.core.file.AsyncFile;
import io.vertx.core.logging.Logger;
import io.vertx.core.logging.LoggerFactory;
import io.vertx.core.streams.ReadStream;
import io.vertx.core.streams.WriteStream;
import org.sfs.Server;
import org.sfs.VertxContext;
import org.sfs.rx.Defer;
import org.sfs.rx.ObservableFuture;
import org.sfs.rx.RxHelper;
import rx.Observable;
import java.nio.channels.AsynchronousFileChannel;
public class AsyncIO {
private static final Logger LOGGER = LoggerFactory.getLogger(AsyncIO.class);
public static Observable<Void> append(Buffer buffer, final WriteStream<Buffer> ws) {
return Observable.defer(() -> {
ObservableFuture<Void> drainHandler = RxHelper.observableFuture();
ws.exceptionHandler(drainHandler::fail);
if (ws.writeQueueFull()) {
ws.drainHandler(drainHandler::complete);
} else {
drainHandler.complete(null);
}
return drainHandler.flatMap(aVoid -> {
ObservableFuture<Void> writeHandler = RxHelper.observableFuture();
ws.exceptionHandler(writeHandler::fail);
ws.write(buffer);
if (ws.writeQueueFull()) {
ws.drainHandler(writeHandler::complete);
} else {
writeHandler.complete(null);
}
return writeHandler;
});
});
}
public static Observable<Void> end(Buffer buffer, final BufferEndableWriteStream ws) {
return Observable.defer(() -> {
ObservableFuture<Void> drainHandler = RxHelper.observableFuture();
ws.exceptionHandler(drainHandler::fail);
if (ws.writeQueueFull()) {
ws.drainHandler(drainHandler::complete);
} else {
drainHandler.complete(null);
}
return drainHandler.flatMap(aVoid -> {
ObservableFuture<Void> endHandler = RxHelper.observableFuture();
ws.exceptionHandler(endHandler::fail);
ws.endHandler(endHandler::complete);
ws.end(buffer);
return endHandler;
});
});
}
public static Observable<Void> append(Buffer buffer, final BufferEndableWriteStream ws) {
return Observable.defer(() -> {
ObservableFuture<Void> drainHandler = RxHelper.observableFuture();
ws.exceptionHandler(drainHandler::fail);
if (ws.writeQueueFull()) {
ws.drainHandler(drainHandler::complete);
} else {
drainHandler.complete(null);
}
return drainHandler.flatMap(aVoid -> {
ObservableFuture<Void> writeHandler = RxHelper.observableFuture();
ws.exceptionHandler(writeHandler::fail);
ws.write(buffer);
if (ws.writeQueueFull()) {
ws.drainHandler(writeHandler::complete);
} else {
writeHandler.complete(null);
}
return writeHandler;
});
});
}
public static <M> Observable<Void> pump(final ReadStream<M> rs, final EndableWriteStream<M> ws) {
rs.pause();
return Observable.defer(() -> {
ObservableFuture<Void> observableFuture = RxHelper.observableFuture();
Handler<Throwable> exceptionHandler = throwable -> {
try {
ws.drainHandler(null);
rs.handler(null);
} catch (Throwable e) {
observableFuture.fail(e);
return;
}
observableFuture.fail(throwable);
};
rs.exceptionHandler(exceptionHandler);
ws.exceptionHandler(exceptionHandler);
Handler<Void> drainHandler = event -> {
try {
rs.resume();
} catch (Throwable e) {
exceptionHandler.handle(e);
}
};
Handler<M> dataHandler = data -> {
try {
ws.write(data);
if (ws.writeQueueFull()) {
rs.pause();
ws.drainHandler(drainHandler);
}
} catch (Throwable e) {
exceptionHandler.handle(e);
}
};
ws.endHandler(observableFuture::complete);
rs.endHandler(event -> {
try {
ws.end();
} catch (Throwable e) {
exceptionHandler.handle(e);
}
});
try {
rs.handler(dataHandler);
rs.resume();
} catch (Throwable e) {
exceptionHandler.handle(e);
}
return observableFuture;
});
}
public static Observable<Void> close(AsyncFile asyncFile) {
return Observable.defer(() -> {
ObservableFuture<Void> rh = RxHelper.observableFuture();
asyncFile.close(rh.toHandler());
return rh;
});
}
}