mirror of
https://github.com/VolmitSoftware/Iris.git
synced 2025-07-18 18:23:06 +00:00
Download utils
This commit is contained in:
parent
89642e71b5
commit
e364959d25
322
src/main/java/com/volmit/iris/util/network/DL.java
Normal file
322
src/main/java/com/volmit/iris/util/network/DL.java
Normal file
@ -0,0 +1,322 @@
|
||||
/*
|
||||
* Iris is a World Generator for Minecraft Bukkit Servers
|
||||
* Copyright (c) 2021 Arcane Arts (Volmit Software)
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.volmit.iris.util.network;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
|
||||
import com.volmit.iris.util.collection.KSet;
|
||||
import com.volmit.iris.util.io.IO;
|
||||
import com.volmit.iris.util.scheduling.ChronoLatch;
|
||||
|
||||
public abstract class DL
|
||||
{
|
||||
protected File d;
|
||||
protected URL u;
|
||||
protected ChronoLatch latch;
|
||||
protected KSet<DownloadFlag> flags;
|
||||
protected MeteredOutputStream o;
|
||||
protected DownloadState state;
|
||||
protected int timeout;
|
||||
protected long size;
|
||||
protected long start;
|
||||
protected long downloaded;
|
||||
protected long currentChunk;
|
||||
protected long lastChunk;
|
||||
protected long bps;
|
||||
protected int bufferSize;
|
||||
protected long lastPull;
|
||||
protected DownloadMonitor m;
|
||||
|
||||
public DL(URL u, File d, DownloadFlag...downloadFlags)
|
||||
{
|
||||
this.d = d;
|
||||
this.u = u;
|
||||
size = -1;
|
||||
lastPull = -1;
|
||||
downloaded = 0;
|
||||
bufferSize = 8192 * 32;
|
||||
currentChunk = 0;
|
||||
lastChunk = -1;
|
||||
bps = -1;
|
||||
start = -1;
|
||||
timeout = 10000;
|
||||
state = DownloadState.NEW;
|
||||
flags = new KSet<>();
|
||||
latch = new ChronoLatch(500);
|
||||
|
||||
for(DownloadFlag i : downloadFlags)
|
||||
{
|
||||
flags.add(i);
|
||||
}
|
||||
}
|
||||
|
||||
public void monitor(DownloadMonitor m)
|
||||
{
|
||||
this.m = m;
|
||||
}
|
||||
|
||||
public void update()
|
||||
{
|
||||
if(m != null)
|
||||
{
|
||||
m.onUpdate(state, getProgress(), getElapsed(), getTimeLeft(), bps, getDiskBytesPerSecond(), size, downloaded, bufferSize, getBufferUse());
|
||||
}
|
||||
}
|
||||
|
||||
public boolean hasFlag(DownloadFlag f)
|
||||
{
|
||||
return flags.contains(f);
|
||||
}
|
||||
|
||||
public boolean isState(DownloadState s)
|
||||
{
|
||||
return state.equals(s);
|
||||
}
|
||||
|
||||
protected void state(DownloadState s)
|
||||
{
|
||||
this.state = s;
|
||||
update();
|
||||
}
|
||||
|
||||
public int getBufferSize()
|
||||
{
|
||||
return bufferSize;
|
||||
}
|
||||
|
||||
public void start() throws IOException
|
||||
{
|
||||
if(!isState(DownloadState.NEW))
|
||||
{
|
||||
throw new DownloadException("Cannot start download while " + state.toString());
|
||||
}
|
||||
|
||||
state(DownloadState.STARTING);
|
||||
|
||||
if(hasFlag(DownloadFlag.CALCULATE_SIZE))
|
||||
{
|
||||
size = calculateSize();
|
||||
}
|
||||
|
||||
start = System.currentTimeMillis();
|
||||
downloaded = 0;
|
||||
bps = 0;
|
||||
lastChunk = System.currentTimeMillis();
|
||||
o = new MeteredOutputStream(new FileOutputStream(d), 100);
|
||||
openStream();
|
||||
state(DownloadState.DOWNLOADING);
|
||||
}
|
||||
|
||||
protected abstract long download() throws IOException;
|
||||
|
||||
protected abstract void openStream() throws IOException;
|
||||
|
||||
protected abstract void closeStream() throws IOException;
|
||||
|
||||
public void downloadChunk() throws IOException
|
||||
{
|
||||
if(!isState(DownloadState.DOWNLOADING))
|
||||
{
|
||||
throw new DownloadException("Cannot download while " + state.toString());
|
||||
}
|
||||
|
||||
long d = download();
|
||||
lastPull = d;
|
||||
|
||||
if(d < 0)
|
||||
{
|
||||
finishDownload();
|
||||
return;
|
||||
}
|
||||
|
||||
downloaded += d;
|
||||
currentChunk += d;
|
||||
|
||||
double chunkTime = (double)(System.currentTimeMillis() - lastChunk) / 1000D;
|
||||
bps = (long) ((double)currentChunk / chunkTime);
|
||||
|
||||
if(latch.flip())
|
||||
{
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
public double getBufferUse()
|
||||
{
|
||||
return (double)lastPull / (double)bufferSize;
|
||||
}
|
||||
|
||||
private void finishDownload() throws IOException
|
||||
{
|
||||
if(!isState(DownloadState.NEW))
|
||||
{
|
||||
throw new DownloadException("Cannot finish download while " + state.toString());
|
||||
}
|
||||
|
||||
closeStream();
|
||||
o.close();
|
||||
state(DownloadState.COMPLETE);
|
||||
}
|
||||
|
||||
public long getElapsed()
|
||||
{
|
||||
return System.currentTimeMillis() - start;
|
||||
}
|
||||
|
||||
public long getRemaining()
|
||||
{
|
||||
return size - downloaded;
|
||||
}
|
||||
|
||||
public long getTimeLeft()
|
||||
{
|
||||
return (long) (((double)getRemaining() / (double)bps) * 1000D);
|
||||
}
|
||||
|
||||
public long getDiskBytesPerSecond()
|
||||
{
|
||||
if(o == null)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
return o.getBps();
|
||||
}
|
||||
|
||||
public long getBytesPerSecond()
|
||||
{
|
||||
return bps;
|
||||
}
|
||||
|
||||
public double getProgress()
|
||||
{
|
||||
return hasProgress() ? ((double)downloaded / (double)size) : -1D;
|
||||
}
|
||||
|
||||
public boolean hasProgress()
|
||||
{
|
||||
return size > 0;
|
||||
}
|
||||
|
||||
private long calculateSize() throws IOException
|
||||
{
|
||||
URLConnection c = u.openConnection();
|
||||
c.setConnectTimeout((int) timeout);
|
||||
c.setReadTimeout((int) timeout);
|
||||
c.connect();
|
||||
return c.getContentLengthLong();
|
||||
}
|
||||
|
||||
public enum DownloadFlag
|
||||
{
|
||||
CALCULATE_SIZE
|
||||
}
|
||||
|
||||
public enum DownloadState
|
||||
{
|
||||
NEW,
|
||||
STARTING,
|
||||
DOWNLOADING,
|
||||
FINALIZING,
|
||||
COMPLETE,
|
||||
FAILED
|
||||
}
|
||||
|
||||
public static class ThrottledDownload extends Download
|
||||
{
|
||||
private long mbps;
|
||||
|
||||
public ThrottledDownload(URL u, File d, long mbps, DownloadFlag... downloadFlags) {
|
||||
super(u, d, downloadFlags);
|
||||
this.mbps = mbps;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected long download() throws IOException
|
||||
{
|
||||
if(getBytesPerSecond() > mbps)
|
||||
{
|
||||
try
|
||||
{
|
||||
Thread.sleep(40);
|
||||
}
|
||||
|
||||
catch (InterruptedException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return IO.transfer(in, o, 8192, mbps/20);
|
||||
}
|
||||
|
||||
return IO.transfer(in, o, 8192, bufferSize);
|
||||
}
|
||||
}
|
||||
|
||||
public static class DoubleBufferedDownload extends Download
|
||||
{
|
||||
protected BufferedOutputStream os;
|
||||
|
||||
public DoubleBufferedDownload(URL u, File d, DownloadFlag... downloadFlags)
|
||||
{
|
||||
super(u, d, downloadFlags);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void openStream() throws IOException
|
||||
{
|
||||
os = new BufferedOutputStream(o, 8192*16);
|
||||
in = new BufferedInputStream(u.openStream(), 8192*16);
|
||||
buf = new byte[8192 * 2];
|
||||
}
|
||||
}
|
||||
|
||||
public static class Download extends DL
|
||||
{
|
||||
protected InputStream in;
|
||||
protected byte[] buf;
|
||||
public Download(URL u, File d, DownloadFlag... downloadFlags) {
|
||||
super(u, d, downloadFlags);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected long download() throws IOException
|
||||
{
|
||||
return IO.transfer(in, o, buf, bufferSize);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void openStream() throws IOException {
|
||||
in = u.openStream();
|
||||
buf = new byte[8192];
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void closeStream() throws IOException {
|
||||
in.close();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Iris is a World Generator for Minecraft Bukkit Servers
|
||||
* Copyright (c) 2021 Arcane Arts (Volmit Software)
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.volmit.iris.util.network;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class DownloadException extends IOException
|
||||
{
|
||||
private static final long serialVersionUID = 5137918663903349839L;
|
||||
|
||||
public DownloadException() {
|
||||
super();
|
||||
}
|
||||
|
||||
public DownloadException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public DownloadException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public DownloadException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Iris is a World Generator for Minecraft Bukkit Servers
|
||||
* Copyright (c) 2021 Arcane Arts (Volmit Software)
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.volmit.iris.util.network;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface DownloadMonitor
|
||||
{
|
||||
public void onUpdate(DL.DownloadState state, double progress, long elapsed, long estimated, long bps, long iobps, long size, long downloaded, long buffer, double bufferuse);
|
||||
}
|
@ -0,0 +1,120 @@
|
||||
/*
|
||||
* Iris is a World Generator for Minecraft Bukkit Servers
|
||||
* Copyright (c) 2021 Arcane Arts (Volmit Software)
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.volmit.iris.util.network;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
public class MeteredInputStream extends InputStream
|
||||
{
|
||||
private InputStream os;
|
||||
private long written;
|
||||
private long totalWritten;
|
||||
private long since;
|
||||
private boolean auto;
|
||||
private long interval;
|
||||
private long bps;
|
||||
|
||||
public MeteredInputStream(InputStream os, long interval)
|
||||
{
|
||||
this.os = os;
|
||||
written = 0;
|
||||
totalWritten = 0;
|
||||
auto = true;
|
||||
this.interval = interval;
|
||||
bps = 0;
|
||||
since = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
public MeteredInputStream(InputStream os)
|
||||
{
|
||||
this(os, 100);
|
||||
auto = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read() throws IOException
|
||||
{
|
||||
written++;
|
||||
totalWritten++;
|
||||
|
||||
if(auto && System.currentTimeMillis() - getSince() > interval)
|
||||
{
|
||||
pollRead();
|
||||
}
|
||||
|
||||
return os.read();
|
||||
}
|
||||
|
||||
public long getSince()
|
||||
{
|
||||
return since;
|
||||
}
|
||||
|
||||
public long getRead()
|
||||
{
|
||||
return written;
|
||||
}
|
||||
|
||||
public long pollRead()
|
||||
{
|
||||
long w = written;
|
||||
written = 0;
|
||||
double secondsElapsedSince = (double) (System.currentTimeMillis() - since) / 1000.0;
|
||||
bps = (long) ((double) w / secondsElapsedSince);
|
||||
since = System.currentTimeMillis();
|
||||
|
||||
return w;
|
||||
}
|
||||
|
||||
public void close() throws IOException
|
||||
{
|
||||
os.close();
|
||||
}
|
||||
|
||||
public boolean isAuto()
|
||||
{
|
||||
return auto;
|
||||
}
|
||||
|
||||
public void setAuto(boolean auto)
|
||||
{
|
||||
this.auto = auto;
|
||||
}
|
||||
|
||||
public long getInterval()
|
||||
{
|
||||
return interval;
|
||||
}
|
||||
|
||||
public void setInterval(long interval)
|
||||
{
|
||||
this.interval = interval;
|
||||
}
|
||||
|
||||
public long getTotalRead()
|
||||
{
|
||||
return totalWritten;
|
||||
}
|
||||
|
||||
public long getBps()
|
||||
{
|
||||
return bps;
|
||||
}
|
||||
}
|
@ -0,0 +1,118 @@
|
||||
/*
|
||||
* Iris is a World Generator for Minecraft Bukkit Servers
|
||||
* Copyright (c) 2021 Arcane Arts (Volmit Software)
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.volmit.iris.util.network;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
public class MeteredOutputStream extends OutputStream
|
||||
{
|
||||
private OutputStream os;
|
||||
private long written;
|
||||
private long totalWritten;
|
||||
private long since;
|
||||
private boolean auto;
|
||||
private long interval;
|
||||
private long bps;
|
||||
|
||||
public MeteredOutputStream(OutputStream os, long interval)
|
||||
{
|
||||
this.os = os;
|
||||
written = 0;
|
||||
totalWritten = 0;
|
||||
auto = true;
|
||||
this.interval = interval;
|
||||
bps = 0;
|
||||
since = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
public MeteredOutputStream(OutputStream os)
|
||||
{
|
||||
this(os, 100);
|
||||
auto = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(int b) throws IOException
|
||||
{
|
||||
os.write(b);
|
||||
written++;
|
||||
totalWritten++;
|
||||
|
||||
if(auto && System.currentTimeMillis() - getSince() > interval)
|
||||
{
|
||||
pollWritten();
|
||||
}
|
||||
}
|
||||
|
||||
public long getSince()
|
||||
{
|
||||
return since;
|
||||
}
|
||||
|
||||
public long getWritten()
|
||||
{
|
||||
return written;
|
||||
}
|
||||
|
||||
public long pollWritten()
|
||||
{
|
||||
long w = written;
|
||||
written = 0;
|
||||
double secondsElapsedSince = (double) (System.currentTimeMillis() - since) / 1000.0;
|
||||
bps = (long) ((double) w / secondsElapsedSince);
|
||||
since = System.currentTimeMillis();
|
||||
return w;
|
||||
}
|
||||
|
||||
public void close() throws IOException
|
||||
{
|
||||
os.close();
|
||||
}
|
||||
|
||||
public boolean isAuto()
|
||||
{
|
||||
return auto;
|
||||
}
|
||||
|
||||
public void setAuto(boolean auto)
|
||||
{
|
||||
this.auto = auto;
|
||||
}
|
||||
|
||||
public long getInterval()
|
||||
{
|
||||
return interval;
|
||||
}
|
||||
|
||||
public void setInterval(long interval)
|
||||
{
|
||||
this.interval = interval;
|
||||
}
|
||||
|
||||
public long getTotalWritten()
|
||||
{
|
||||
return totalWritten;
|
||||
}
|
||||
|
||||
public long getBps()
|
||||
{
|
||||
return bps;
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user