Make github request handling work, fix some things

This commit is contained in:
comp500 2019-06-01 16:26:15 +01:00
parent 2118a8fda1
commit fd87edd6ca
3 changed files with 135 additions and 10 deletions

View File

@ -1,25 +1,83 @@
package link.infra.packwiz.installer.request.handlers; package link.infra.packwiz.installer.request.handlers;
import java.net.URI; import java.net.URI;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class RequestHandlerGithub extends RequestHandlerZip { public class RequestHandlerGithub extends RequestHandlerZip {
public RequestHandlerGithub() {
super(true);
}
@Override
public URI getNewLoc(URI loc) {
return loc;
}
// TODO: is caching really needed, if HTTPURLConnection follows redirects correctly?
private Map<String, URI> zipUriMap = new HashMap<String, URI>();
final ReentrantReadWriteLock zipUriLock = new ReentrantReadWriteLock();
private static Pattern repoMatcherPattern = Pattern.compile("/([\\w.-]+/[\\w.-]+).*");
private String getRepoName(URI loc) {
Matcher matcher = repoMatcherPattern.matcher(loc.getPath());
matcher.matches();
return matcher.group(1);
}
@Override @Override
protected URI getZipUri(URI loc) throws Exception { protected URI getZipUri(URI loc) throws Exception {
// TODO Auto-generated method stub String repoName = getRepoName(loc);
return null; String branchName = getBranch(loc);
zipUriLock.readLock().lock();
URI zipUri = zipUriMap.get(repoName + "/" + branchName);
zipUriLock.readLock().unlock();
if (zipUri != null) {
return zipUri;
}
zipUri = new URI("https://api.github.com/repos/" + repoName + "/zipball/" + branchName);
zipUriLock.writeLock().lock();
// If another thread sets the value concurrently, use the value of the
// thread that first acquired the lock.
URI zipUriInserted = zipUriMap.putIfAbsent(repoName + "/" + branchName, zipUri);
if (zipUriInserted != null) {
zipUri = zipUriInserted;
}
zipUriLock.writeLock().unlock();
return zipUri;
}
private static Pattern branchMatcherPattern = Pattern.compile("/[\\w.-]+/[\\w.-]+/blob/([\\w.-]+).*");
private String getBranch(URI loc) {
Matcher matcher = branchMatcherPattern.matcher(loc.getPath());
matcher.matches();
return matcher.group(1);
} }
@Override @Override
protected URI getLocationInZip(URI loc) throws Exception { protected URI getLocationInZip(URI loc) throws Exception {
// TODO Auto-generated method stub String path = "/" + getRepoName(loc) + "/blob/" + getBranch(loc);
return null; return new URI(loc.getScheme(), loc.getAuthority(), path, null, null).relativize(loc);
} }
@Override @Override
public boolean matchesHandler(URI loc) { public boolean matchesHandler(URI loc) {
// TODO Auto-generated method stub String scheme = loc.getScheme();
return false; if (!(scheme.equals("http") || scheme.equals("https"))) {
return false;
}
if (!loc.getHost().equals("github.com")) {
return false;
}
// TODO: sanity checks, support for more github urls
return true;
} }
} }

View File

@ -17,7 +17,9 @@ public class RequestHandlerHTTP implements IRequestHandler {
@Override @Override
public InputStream getFileInputStream(URI loc) throws Exception { public InputStream getFileInputStream(URI loc) throws Exception {
URLConnection conn = loc.toURL().openConnection(); URLConnection conn = loc.toURL().openConnection();
conn.addRequestProperty("Accept", "application/octet-stream"); // TODO: when do we send specific headers??? should there be a way to signal this?
// github *sometimes* requires it, sometimes not!
//conn.addRequestProperty("Accept", "application/octet-stream");
// 30 second read timeout // 30 second read timeout
conn.setReadTimeout(30 * 1000); conn.setReadTimeout(30 * 1000);
return conn.getInputStream(); return conn.getInputStream();

View File

@ -10,11 +10,26 @@ import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.concurrent.locks.ReentrantLock; import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.function.Predicate;
import java.util.zip.ZipEntry; import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream; import java.util.zip.ZipInputStream;
public abstract class RequestHandlerZip extends RequestHandlerHTTP { public abstract class RequestHandlerZip extends RequestHandlerHTTP {
protected final boolean modeHasFolder;
public RequestHandlerZip(boolean modeHasFolder) {
this.modeHasFolder = modeHasFolder;
}
private String removeFolder(String name) {
if (modeHasFolder) {
return name.substring(name.indexOf("/")+1);
} else {
return name;
}
}
private class ZipReader { private class ZipReader {
private final ZipInputStream zis; private final ZipInputStream zis;
@ -43,10 +58,11 @@ public abstract class RequestHandlerZip extends RequestHandlerHTTP {
return null; return null;
} }
byte[] data = readCurrFile(); byte[] data = readCurrFile();
if (loc.equals(new URI(entry.getName()))) { URI fileLoc = new URI(removeFolder(entry.getName()));
if (loc.equals(fileLoc)) {
return data; return data;
} else { } else {
readFiles.put(loc, data); readFiles.put(fileLoc, data);
} }
} }
} }
@ -68,6 +84,31 @@ public abstract class RequestHandlerZip extends RequestHandlerHTTP {
return null; return null;
} }
public URI findInZip(Predicate<URI> matches) throws Exception {
filesLock.lock();
for (URI file : readFiles.keySet()) {
if (matches.test(file)) {
filesLock.unlock();
return file;
}
}
while (true) {
entry = zis.getNextEntry();
if (entry == null) {
filesLock.unlock();
return null;
}
byte[] data = readCurrFile();
URI fileLoc = new URI(removeFolder(entry.getName()));
readFiles.put(fileLoc, data);
if (matches.test(fileLoc)) {
filesLock.unlock();
return fileLoc;
}
}
}
} }
private final Map<URI, ZipReader> cache = new HashMap<URI, ZipReader>(); private final Map<URI, ZipReader> cache = new HashMap<URI, ZipReader>();
@ -91,7 +132,12 @@ public abstract class RequestHandlerZip extends RequestHandlerHTTP {
// Recheck, because unlocking read lock allows another thread to modify it // Recheck, because unlocking read lock allows another thread to modify it
zr = cache.get(zipUri); zr = cache.get(zipUri);
if (zr == null) { if (zr == null) {
zr = new ZipReader(super.getFileInputStream(zipUri)); InputStream str = super.getFileInputStream(zipUri);
if (str == null) {
cacheLock.writeLock().unlock();
return null;
}
zr = new ZipReader(str);
cache.put(zipUri, zr); cache.put(zipUri, zr);
} }
cacheLock.writeLock().unlock(); cacheLock.writeLock().unlock();
@ -100,4 +146,23 @@ public abstract class RequestHandlerZip extends RequestHandlerHTTP {
return zr.getFileInputStream(getLocationInZip(loc)); return zr.getFileInputStream(getLocationInZip(loc));
} }
protected URI findInZip(URI loc, Predicate<URI> matches) throws Exception {
URI zipUri = getZipUri(loc);
cacheLock.readLock().lock();
ZipReader zr = cache.get(zipUri);
cacheLock.readLock().unlock();
if (zr == null) {
cacheLock.writeLock().lock();
// Recheck, because unlocking read lock allows another thread to modify it
zr = cache.get(zipUri);
if (zr == null) {
zr = new ZipReader(super.getFileInputStream(zipUri));
cache.put(zipUri, zr);
}
cacheLock.writeLock().unlock();
}
return zr.findInZip(matches);
}
} }