/*******************************************************************************
* Copyright (c) 2015
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*******************************************************************************/
package jsettlers.network.infrastructure.channel.socket.delayed;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
/**
*
* @author Andreas Eberle
*
*/
public class DelayedOutputStream extends OutputStream {
private static final int BUFFER_LENGTH = 2000;
private final Thread thread;
private final ByteArrayOutputStream[] buffers = new ByteArrayOutputStream[BUFFER_LENGTH];
private final OutputStream out;
private boolean closed;
private int currWriteSlot = 200;
private int currReadSlot = 0;
public DelayedOutputStream(OutputStream out) {
this.out = out;
for (int i = 0; i < buffers.length; i++) {
buffers[i] = new ByteArrayOutputStream();
}
thread = new DelayedOutStreamWriter();
thread.setDaemon(true);
thread.start();
}
@Override
public void close() throws IOException {
closed = true;
thread.interrupt();
out.close();
}
@Override
public void write(int b) throws IOException {
buffers[currWriteSlot].write(b);
}
private final class DelayedOutStreamWriter extends Thread {
private static final int MIN_DELAY = 80;
private static final int MAX_DELAY = 120;
private static final int MAX_DELAY_STEP = 10;
private DelayedOutStreamWriter() {
super("delayedOutStreamWriter");
}
@Override
public void run() {
while (!closed) {
currWriteSlot = (currWriteSlot + 1) % BUFFER_LENGTH;
int currDist = (BUFFER_LENGTH + currWriteSlot - currReadSlot) % BUFFER_LENGTH;
int targetDistance = Math.min(MAX_DELAY,
Math.max(MIN_DELAY, (int) (currDist + Math.random() * MAX_DELAY_STEP * 2 - MAX_DELAY_STEP)));
// System.out.println("ssdsf");
if (targetDistance >= currDist) {
currReadSlot = (BUFFER_LENGTH + currReadSlot - (targetDistance - currDist)) % BUFFER_LENGTH;
} else {
for (int i = targetDistance; i < currDist; i++) {
writeNextSlot();
}
}
try {
Thread.sleep(1);
} catch (InterruptedException e) {
}
}
}
private void writeNextSlot() {
ByteArrayOutputStream currBuffer = buffers[currReadSlot];
currReadSlot = (currReadSlot + 1) % BUFFER_LENGTH;
try {
currBuffer.writeTo(DelayedOutputStream.this.out);
currBuffer.reset();
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
}