обновляем алгоритмы + добавляем асинхранной вызов
This commit is contained in:
8
src/main/java/ru/dmitriymx/vkapi/Callback.java
Normal file
8
src/main/java/ru/dmitriymx/vkapi/Callback.java
Normal file
@@ -0,0 +1,8 @@
|
||||
package ru.dmitriymx.vkapi;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
public interface Callback {
|
||||
void call(JsonObject jsonObject);
|
||||
void error(Throwable throwable);
|
||||
}
|
||||
16
src/main/java/ru/dmitriymx/vkapi/TaskMethod.java
Normal file
16
src/main/java/ru/dmitriymx/vkapi/TaskMethod.java
Normal file
@@ -0,0 +1,16 @@
|
||||
package ru.dmitriymx.vkapi;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@Builder
|
||||
@RequiredArgsConstructor
|
||||
@Getter
|
||||
class TaskMethod {
|
||||
private final String method;
|
||||
private final Map<String, String> postData;
|
||||
private final Callback callback;
|
||||
}
|
||||
21
src/main/java/ru/dmitriymx/vkapi/Timer.java
Normal file
21
src/main/java/ru/dmitriymx/vkapi/Timer.java
Normal file
@@ -0,0 +1,21 @@
|
||||
package ru.dmitriymx.vkapi;
|
||||
|
||||
class Timer {
|
||||
private long lastTime;
|
||||
|
||||
void reset() {
|
||||
this.lastTime = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
boolean after(long expendedDiffTime) {
|
||||
return diff() >= expendedDiffTime;
|
||||
}
|
||||
|
||||
boolean before(long expendedDiffTime) {
|
||||
return diff() < expendedDiffTime;
|
||||
}
|
||||
|
||||
long diff() {
|
||||
return System.currentTimeMillis() - lastTime;
|
||||
}
|
||||
}
|
||||
@@ -5,106 +5,130 @@ import com.google.gson.JsonObject;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import ru.dmitriymx.vkapi.browser.ApacheBroswe;
|
||||
import ru.dmitriymx.vkapi.browser.Browser;
|
||||
import ru.dmitriymx.vkapi.browser.Response;
|
||||
import ru.dmitriymx.vkapi.longpoll.LongPollListener;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.StringJoiner;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.SynchronousQueue;
|
||||
|
||||
@Slf4j
|
||||
public class VkApi {
|
||||
public class VkApi implements Runnable {
|
||||
private static final String VKAPI_URL = "https://api.vk.com/method/";
|
||||
private final String accessToken;
|
||||
private final Browser browser;
|
||||
private final Gson gson;
|
||||
private final Gson gson = new Gson();
|
||||
@Getter
|
||||
@Setter
|
||||
private String apiVersion = "5.62";
|
||||
@Getter
|
||||
@Setter
|
||||
private long callPause = 1200L;
|
||||
private long lastTime;
|
||||
private int call = 0;
|
||||
private String apiVersion;
|
||||
|
||||
public VkApi(String accessToken, Browser browser) {
|
||||
if (accessToken == null || accessToken.trim().isEmpty()) {
|
||||
throw new RuntimeException("Access token don't be NULL or EMPTY!");
|
||||
private Timer timer = new Timer();
|
||||
private int countCallApiPerSecond = 0;
|
||||
|
||||
private BlockingQueue<TaskMethod> queueExecute = new SynchronousQueue<>();
|
||||
|
||||
public VkApi(String apiVersion, String accessToken) {
|
||||
this(apiVersion, accessToken, new ApacheBroswe());
|
||||
}
|
||||
|
||||
public VkApi(String apiVersion, String accessToken, Browser browser) {
|
||||
if (stringIsNullOrEmpty(apiVersion)) throw new IllegalArgumentException("API version don't be NULL or EMPTY!");
|
||||
if (stringIsNullOrEmpty(accessToken)) throw new IllegalArgumentException("Access token don't be NULL or EMPTY!");
|
||||
if (browser == null) throw new IllegalArgumentException("Browser don't be NULL or EMPTY!");
|
||||
|
||||
this.accessToken = accessToken;
|
||||
this.browser = browser;
|
||||
this.gson = new Gson();
|
||||
|
||||
timer.reset();
|
||||
}
|
||||
|
||||
public JsonObject execApi(String methodApi, Map<String, String> params) throws VkApiException {
|
||||
checkCalls();
|
||||
String url = VKAPI_URL + methodApi;
|
||||
String postData = paramsToString(params);
|
||||
|
||||
Response response;
|
||||
try {
|
||||
response = browser.post(url, postData);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
public JsonObject execApi(String methodApi, Map<String, String> params) throws IOException {
|
||||
if (timer.before(1000L) && countCallApiPerSecond >= 3) {
|
||||
safeSleep(timer.diff() + 100);
|
||||
timer.reset();
|
||||
countCallApiPerSecond = 0;
|
||||
} else if (timer.after(1000L)) {
|
||||
timer.reset();
|
||||
countCallApiPerSecond = 0;
|
||||
}
|
||||
|
||||
countCallApiPerSecond++;
|
||||
Response response = browser.post(VKAPI_URL + methodApi, paramsToString(params));
|
||||
chechResponse(response);
|
||||
|
||||
JsonObject jsonObject = gson.fromJson(response.getContent(), JsonObject.class);
|
||||
if (jsonObject.has("error")) {
|
||||
throw new VkApiException(jsonObject);
|
||||
return gson.fromJson(response.getContent(), JsonObject.class);
|
||||
}
|
||||
|
||||
return jsonObject;
|
||||
public void execApiAsync(String apiMethod, Map<String, String> params, Callback callback) {
|
||||
queueExecute.offer(TaskMethod.builder()
|
||||
.method(apiMethod)
|
||||
.postData(params)
|
||||
.callback(callback)
|
||||
.build());
|
||||
}
|
||||
|
||||
public JsonObject longExecApi(String server, String key, long ts, long wait) throws VkApiException {
|
||||
public LongPollListener getLongPollListener() throws IOException {
|
||||
JsonObject jsonObject = execApi("messages.getLongPollServer", Collections.singletonMap("need_pts", "1"));
|
||||
jsonObject = jsonObject.getAsJsonObject("response");
|
||||
|
||||
return new LongPollListener(
|
||||
this,
|
||||
jsonObject.get("server").getAsString(),
|
||||
jsonObject.get("key").getAsString(),
|
||||
jsonObject.get("ts").getAsLong()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
while(!Thread.currentThread().isInterrupted()) {
|
||||
try {
|
||||
TaskMethod task = queueExecute.take();
|
||||
|
||||
try {
|
||||
JsonObject jsonObject = execApi(task.getMethod(), task.getPostData());
|
||||
|
||||
if (task.getCallback() != null) {
|
||||
task.getCallback().call(jsonObject);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
if (task.getCallback() != null) {
|
||||
task.getCallback().error(e);
|
||||
} else {
|
||||
log.error(MessageFormat.format(
|
||||
"Error execute method \"{0}\"",
|
||||
task.getMethod()), e);
|
||||
}
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public JsonObject longExecApi(String server, String key, long ts, long wait) throws IOException {
|
||||
String url = String.format("https://%s?act=a_check&key=%s&ts=%d&wait=%d&mode=2&version=1",
|
||||
server, key, ts, wait
|
||||
);
|
||||
|
||||
Response response;
|
||||
try {
|
||||
response = browser.get(url);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
Response response = browser.get(url);
|
||||
chechResponse(response);
|
||||
|
||||
JsonObject jsonObject = gson.fromJson(response.getContent(), JsonObject.class);
|
||||
if (jsonObject.has("error")) {
|
||||
throw new VkApiException(jsonObject);
|
||||
}
|
||||
|
||||
return jsonObject;
|
||||
return gson.fromJson(response.getContent(), JsonObject.class);
|
||||
}
|
||||
|
||||
private String paramsToString(Map<String, String> params) {
|
||||
String collect = "";
|
||||
if (params != null && params.size() > 0) {
|
||||
collect = "&" + params.entrySet().stream()
|
||||
.map(entry -> entry.getKey() + "=" + entry.getValue())
|
||||
.collect(Collectors.joining("&"));
|
||||
}
|
||||
return "access_token=" + accessToken + "&v=" + apiVersion + collect;
|
||||
}
|
||||
final StringJoiner sj = new StringJoiner("&");
|
||||
sj.add("access_token=" + accessToken).add("v=" + apiVersion);
|
||||
params.forEach((key, value) -> sj.add(key + "=" + value));
|
||||
|
||||
private void checkCalls() {
|
||||
if (call >= 3) {
|
||||
long currTime = System.currentTimeMillis();
|
||||
long diff = currTime - lastTime;
|
||||
|
||||
if (diff <= callPause) {
|
||||
safeSleep(callPause);
|
||||
}
|
||||
|
||||
lastTime = System.currentTimeMillis();
|
||||
call = 0;
|
||||
} else {
|
||||
safeSleep(callPause/3);
|
||||
call++;
|
||||
}
|
||||
return sj.toString();
|
||||
}
|
||||
|
||||
private void chechResponse(Response response) {
|
||||
@@ -131,4 +155,8 @@ public class VkApi {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean stringIsNullOrEmpty(String string) {
|
||||
return string == null || string.isEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
package ru.dmitriymx.vkapi;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
public class VkApiException extends Exception {
|
||||
public VkApiException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public VkApiException(JsonObject jsonObject) {
|
||||
this(jsonObject.getAsJsonObject("error").get("error_msg").getAsString());
|
||||
}
|
||||
}
|
||||
@@ -2,12 +2,11 @@ package ru.dmitriymx.vkapi.longpoll;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonObject;
|
||||
import lombok.Setter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import ru.dmitriymx.vkapi.VkApi;
|
||||
import ru.dmitriymx.vkapi.VkApiException;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
@@ -19,6 +18,8 @@ class LPRunner implements Runnable {
|
||||
private final String server;
|
||||
private final String key;
|
||||
private long ts;
|
||||
@Setter
|
||||
private long timeOut;
|
||||
Map<Class<? extends Event>, List<EventListener>> mapListeners = new HashMap<>();
|
||||
|
||||
LPRunner(VkApi vkApi, String server, String key, long ts) {
|
||||
@@ -31,13 +32,10 @@ class LPRunner implements Runnable {
|
||||
@Override
|
||||
public void run() {
|
||||
while (!Thread.currentThread().isInterrupted()) {
|
||||
log.debug("next loop...");
|
||||
log.debug("next loop");
|
||||
|
||||
try {
|
||||
JsonObject jsonObject = vkApi.longExecApi(
|
||||
this.server, this.key, this.ts,
|
||||
25L
|
||||
);
|
||||
JsonObject jsonObject = vkApi.longExecApi(server, key, ts, timeOut);
|
||||
|
||||
JsonArray updates = jsonObject.getAsJsonArray("updates");
|
||||
if (updates.size() > 0) {
|
||||
@@ -47,8 +45,8 @@ class LPRunner implements Runnable {
|
||||
}
|
||||
|
||||
this.ts = jsonObject.get("ts").getAsLong();
|
||||
} catch (VkApiException e) {
|
||||
log.error("Oops!", e);
|
||||
} catch (IOException e) {
|
||||
log.error("Execute long poll error", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,33 +1,23 @@
|
||||
package ru.dmitriymx.vkapi.longpoll;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import ru.dmitriymx.vkapi.VkApi;
|
||||
import ru.dmitriymx.vkapi.VkApiException;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class LongPollListener {
|
||||
private Thread thread;
|
||||
private LPRunner lpRunner;
|
||||
private final Thread thread;
|
||||
private final LPRunner lpRunner;
|
||||
|
||||
public static LongPollListener create(VkApi vkApi) throws VkApiException {
|
||||
JsonObject jsonObject = vkApi.execApi("messages.getLongPollServer",
|
||||
Collections.singletonMap("need_pts", "1"));
|
||||
jsonObject = jsonObject.getAsJsonObject("response");
|
||||
|
||||
return new LongPollListener(
|
||||
vkApi,
|
||||
jsonObject.get("server").getAsString(),
|
||||
jsonObject.get("key").getAsString(),
|
||||
jsonObject.get("ts").getAsLong()
|
||||
);
|
||||
}
|
||||
|
||||
private LongPollListener(VkApi vkApi, String server, String key, long ts) {
|
||||
public LongPollListener(VkApi vkApi, String server, String key, long ts) {
|
||||
this.lpRunner = new LPRunner(vkApi, server, key, ts);
|
||||
this.thread = new Thread(this.lpRunner, "Long poll listener");
|
||||
}
|
||||
|
||||
public void setTimeOut(long timeOut) {
|
||||
lpRunner.setTimeOut(timeOut);
|
||||
}
|
||||
|
||||
public void start() {
|
||||
start(false);
|
||||
}
|
||||
@@ -43,6 +33,10 @@ public class LongPollListener {
|
||||
}
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
thread.interrupt();
|
||||
}
|
||||
|
||||
public void register(Class<? extends Event> clazz, EventListener listener) {
|
||||
List<EventListener> eventListeners = lpRunner.mapListeners.computeIfAbsent(clazz, list -> new ArrayList<>());
|
||||
eventListeners.add(listener);
|
||||
|
||||
Reference in New Issue
Block a user