All Downloads are FREE. Search and download functionalities are using the official Maven repository.

ru.codeoff.bots.sdk.utils.vkapi.Executor Maven / Gradle / Ivy

package ru.codeoff.bots.sdk.utils.vkapi;

import ru.codeoff.bots.sdk.utils.vkapi.calls.CallAsync;
import ru.codeoff.bots.sdk.utils.vkapi.calls.CallSync;
import ru.codeoff.bots.sdk.utils.vkapi.calls.Call;
import ru.codeoff.bots.sdk.utils.web.Connection;
import org.json.JSONArray;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.IntStream;

import static ru.codeoff.bots.sdk.clients.Client.sheduler;

/**
 * Best way to use VK API: you can call up to 25 vk api methods by call execute once
 * Because without execute you only can call up to 3 methods per second
 * 

* See more: link */ public class Executor { private static final Logger LOG = LoggerFactory.getLogger(Executor.class); /** * We can call 'execute' method no more than three times per second. * 1000/3 ~ 333 milliseconds */ private static final int delay = 335; /** * Queue of requests */ private volatile List queue = new ArrayList<>(); private final String URL = "https://api.vk.com/method/execute?code="; private final String accessToken; private final String V = "&v=" + 5.68; /** * Init executor *

* All requests called directly by using client.api().call(...) * or indirectly (by calling methods that will use VK API) will be queued. * Every 350 milliseconds first 25 requests from queue will be executed. * VK response will be returned to the callback. *

* Important: * * @param accessToken Method 'execute' will be called using this access_token. * @see API#callSync(String, Object) requests made by this method wont be queued, be careful. * And responses of callSync seems like {"response":{...}} and all are instances of JSONObject. * but from method 'execute' will be returned "response" object directly (can be integer, boolean etc). */ public Executor(String accessToken) { this.accessToken = "&access_token=" + accessToken; sheduler.scheduleWithFixedDelay(this::executing, 0, delay, TimeUnit.MILLISECONDS); } /** * Method that makes 'execute' requests * with first 25 calls from queue. */ private void executing() { List tmpQueue = new ArrayList<>(); int count = 0; for (Iterator iterator = queue.iterator(); iterator.hasNext() && count < 25; count++) { tmpQueue.add(iterator.next()); } queue.removeAll(tmpQueue); StringBuilder calls = new StringBuilder(); calls.append('['); for (int i = 0; i < count; i++) { String codeTmp = codeForExecute(tmpQueue.get(i)); calls.append(codeTmp); if (i < count - 1) { calls.append(','); } } calls.append(']'); String code = calls.toString(); // Execute if (count > 0) { String vkCallQuery = null; try { vkCallQuery = URL + URLEncoder.encode("return " + code + ";", "UTF-8") + accessToken + V; } catch (UnsupportedEncodingException ignored) { } JSONObject response = new JSONObject(Connection.getRequestResponse(vkCallQuery)); if (response.has("execute_errors")) { try { LOG.error("Errors when executing " + URLDecoder.decode(code, "UTF-8") + ", error: {}", response.get("execute_errors").toString()); } catch (UnsupportedEncodingException ignored) { } } if (!response.has("response")) { LOG.error("No 'response' object when executing code, VK response: {}", response); tmpQueue.forEach(call -> call.getCallback().onResponse("false")); return; } JSONArray responses = response.getJSONArray("response"); IntStream.range(0, count).forEachOrdered(i -> tmpQueue.get(i).getCallback().onResponse(responses.get(i))); try { Thread.sleep(delay); } catch (InterruptedException ignored) { } } } /** * Method that makes string in json format from call object. * * @param call Call object * @return String 'API.method.name({param:value})' * @see Call * @see CallAsync * @see CallSync */ public String codeForExecute(Call call) { return "API." + call.getMethodName() + '(' + call.getParams().toString() + ')'; } /** * Method that puts all requests in a queue. * * @param call Call to be executed. */ public void execute(CallAsync call) { queue.add(call); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy