Add mechanism to restrict the number of requests

Flirt4Free is finnicky with the amount of requests you can do. So we use
a mechanism to only allow 2 requests at a time and a cooldown of 500 ms
between requests.
This commit is contained in:
0xboobface 2019-05-11 15:03:15 +02:00
parent 6c9bff56fc
commit 35c8378d88
1 changed files with 161 additions and 99 deletions

View File

@ -8,6 +8,8 @@ import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
@ -53,10 +55,19 @@ public class Flirt4FreeModel extends AbstractModel {
private String userIdt = ""; private String userIdt = "";
private String userIp = "0.0.0.0"; private String userIp = "0.0.0.0";
private static Semaphore requestThrottle = new Semaphore(2, true);
private static volatile long lastRequest = 0;
private long lastOnlineRequest = 0;
@Override @Override
public boolean isOnline(boolean ignoreCache) throws IOException, ExecutionException, InterruptedException { public boolean isOnline(boolean ignoreCache) throws IOException, ExecutionException, InterruptedException {
if(ignoreCache) { long now = System.currentTimeMillis();
long timeSinceLastCheck = now - lastOnlineRequest;
if (ignoreCache && timeSinceLastCheck > TimeUnit.MINUTES.toMillis(1)) {
String url = "https://ws.vs3.com/rooms/check-model-status.php?model_name=" + getName(); String url = "https://ws.vs3.com/rooms/check-model-status.php?model_name=" + getName();
acquireSlot();
try {
Request request = new Request.Builder() Request request = new Request.Builder()
.url(url) .url(url)
.header("Accept", "*/*") .header("Accept", "*/*")
@ -72,9 +83,9 @@ public class Flirt4FreeModel extends AbstractModel {
return false; return false;
} }
JSONObject json = new JSONObject(body); JSONObject json = new JSONObject(body);
//LOG.debug("check model status: ", json.toString(2)); // LOG.debug("check model status: {}", json.toString(2));
online = Objects.equals(json.optString("status"), "online"); online = Objects.equals(json.optString("status"), "online");
id = json.getString("model_id"); id = String.valueOf(json.get("model_id"));
if (online) { if (online) {
try { try {
loadStreamUrl(); loadStreamUrl();
@ -87,11 +98,15 @@ public class Flirt4FreeModel extends AbstractModel {
throw new HttpException(response.code(), response.message()); throw new HttpException(response.code(), response.message());
} }
} }
} finally {
lastOnlineRequest = System.currentTimeMillis();
releaseSlot();
}
} }
return online; return online;
} }
private void loadModelInfo() throws IOException { private void loadModelInfo() throws IOException, InterruptedException {
String url = getSite().getBaseUrl() + "/webservices/chat-room-interface.php?a=login_room&model_id=" + id; String url = getSite().getBaseUrl() + "/webservices/chat-room-interface.php?a=login_room&model_id=" + id;
LOG.trace("Loading url {}", url); LOG.trace("Loading url {}", url);
Request request = new Request.Builder() Request request = new Request.Builder()
@ -138,7 +153,12 @@ public class Flirt4FreeModel extends AbstractModel {
MasterPlaylist masterPlaylist = null; MasterPlaylist masterPlaylist = null;
try { try {
if (withWebsocket) { if (withWebsocket) {
acquireSlot();
try {
loadStreamUrl(); loadStreamUrl();
} finally {
releaseSlot();
}
} }
masterPlaylist = getMasterPlaylist(); masterPlaylist = getMasterPlaylist();
} catch (InterruptedException e) { } catch (InterruptedException e) {
@ -168,6 +188,7 @@ public class Flirt4FreeModel extends AbstractModel {
.header("User-Agent", Config.getInstance().getSettings().httpUserAgent) .header("User-Agent", Config.getInstance().getSettings().httpUserAgent)
.header("X-Requested-With", "XMLHttpRequest") .header("X-Requested-With", "XMLHttpRequest")
.build(); .build();
acquireSlot();
try (Response response = getSite().getHttpClient().execute(req)) { try (Response response = getSite().getHttpClient().execute(req)) {
if (response.isSuccessful()) { if (response.isSuccessful()) {
InputStream inputStream = response.body().byteStream(); InputStream inputStream = response.body().byteStream();
@ -178,6 +199,8 @@ public class Flirt4FreeModel extends AbstractModel {
} else { } else {
throw new HttpException(response.code(), response.message()); throw new HttpException(response.code(), response.message());
} }
} finally {
releaseSlot();
} }
} }
@ -246,6 +269,7 @@ public class Flirt4FreeModel extends AbstractModel {
} }
} }
}); });
synchronized (monitor) { synchronized (monitor) {
monitor.wait(10_000); monitor.wait(10_000);
if (streamHost == null) { if (streamHost == null) {
@ -262,16 +286,20 @@ public class Flirt4FreeModel extends AbstractModel {
@Override @Override
public void receiveTip(Double tokens) throws IOException { public void receiveTip(Double tokens) throws IOException {
try {
// if(tokens < 50 || tokens > 750000) { // if(tokens < 50 || tokens > 750000) {
// throw new RuntimeException("Tip amount has to be between 50 and 750000"); // throw new RuntimeException("Tip amount has to be between 50 and 750000");
// } // }
// make sure we are logged in and all necessary model data is available // make sure we are logged in and all necessary model data is available
getSite().login(); getSite().login();
acquireSlot();
try { try {
loadStreamUrl(); loadStreamUrl();
} catch (InterruptedException e) { } catch (InterruptedException e) {
throw new IOException("Couldn't send tip", e); throw new IOException("Couldn't send tip", e);
} finally {
releaseSlot();
} }
// send the tip // send the tip
@ -312,10 +340,15 @@ public class Flirt4FreeModel extends AbstractModel {
throw new HttpException(response.code(), response.message()); throw new HttpException(response.code(), response.message());
} }
} }
} catch (InterruptedException e) {
throw new IOException("Couldn't acquire request slot", e);
}
} }
private String getUserIdt() throws IOException { private String getUserIdt() throws IOException, InterruptedException {
if (userIdt.isEmpty()) { if (userIdt.isEmpty()) {
acquireSlot();
try {
Request req = new Request.Builder() Request req = new Request.Builder()
.url(getUrl()) .url(getUrl())
.header("Accept", "*/*") .header("Accept", "*/*")
@ -336,6 +369,9 @@ public class Flirt4FreeModel extends AbstractModel {
throw new HttpException(response.code(), response.message()); throw new HttpException(response.code(), response.message());
} }
} }
} finally {
releaseSlot();
}
} }
return userIdt; return userIdt;
} }
@ -361,22 +397,31 @@ public class Flirt4FreeModel extends AbstractModel {
@Override @Override
public boolean follow() throws IOException { public boolean follow() throws IOException {
try {
return changeFavoriteStatus(true); return changeFavoriteStatus(true);
} catch (InterruptedException e) {
throw new IOException("Couldn't change follow status for model " + getName(), e);
}
} }
@Override @Override
public boolean unfollow() throws IOException { public boolean unfollow() throws IOException {
try { try {
isOnline(true); isOnline(true);
} catch (ExecutionException | InterruptedException e) {
throw new IOException("Couldn't rectrieve model id", e);
}
return changeFavoriteStatus(false); return changeFavoriteStatus(false);
} catch (ExecutionException | InterruptedException e) {
throw new IOException("Couldn't change follow status for model " + getName(), e);
}
} }
private boolean changeFavoriteStatus(boolean add) throws IOException { private boolean changeFavoriteStatus(boolean add) throws IOException, InterruptedException {
getSite().login(); getSite().login();
acquireSlot();
try {
loadModelInfo(); loadModelInfo();
} finally {
releaseSlot();
}
String url = getSite().getBaseUrl() + "/external.php?a=" + String url = getSite().getBaseUrl() + "/external.php?a=" +
(add ? "add_favorite" : "delete_favorite") + (add ? "add_favorite" : "delete_favorite") +
"&id=" + id + "&id=" + id +
@ -423,4 +468,21 @@ public class Flirt4FreeModel extends AbstractModel {
public void setOnline(boolean b) { public void setOnline(boolean b) {
online = b; online = b;
} }
private void acquireSlot() throws InterruptedException {
LOG.debug("Acquire: {}", requestThrottle.availablePermits());
requestThrottle.acquire();
long now = System.currentTimeMillis();
long millisSinceLastRequest = now - lastRequest;
if(millisSinceLastRequest < 500) {
LOG.debug("Sleeping: {}", (500-millisSinceLastRequest));
Thread.sleep(500 - millisSinceLastRequest);
}
}
private void releaseSlot() {
lastRequest = System.currentTimeMillis();
requestThrottle.release();
LOG.debug("Release: {}", requestThrottle.availablePermits());
}
} }