io.github.biezhi.tgbot.TelegramBot Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of telegram-bot-api Show documentation
Show all versions of telegram-bot-api Show documentation
Telegram bot library by Java
The newest version!
package io.github.biezhi.tgbot;
import com.google.gson.Gson;
import io.github.biezhi.request.Request;
import io.github.biezhi.tgbot.api.File;
import io.github.biezhi.tgbot.api.FileApi;
import io.github.biezhi.tgbot.api.Message;
import io.github.biezhi.tgbot.api.Update;
import io.github.biezhi.tgbot.request.*;
import io.github.biezhi.tgbot.response.BotResponse;
import io.github.biezhi.tgbot.response.GetMeResponse;
import io.github.biezhi.tgbot.response.GetUpdatesResponse;
import lombok.extern.slf4j.Slf4j;
import java.io.ByteArrayInputStream;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
import static java.net.Proxy.Type.HTTP;
/**
* Telegram机器人
*
* @author biezhi
* @date 2017/9/30
*/
@Slf4j
public class TelegramBot {
private Gson gson = new Gson();
private String token;
private Proxy proxy;
private FileApi fileApi;
private volatile boolean startUpdates;
private volatile boolean stopUpdates;
private Map> mappings = new HashMap<>();
private Options options = Options.builder().build();
private ExecutorService executorService = Executors.newFixedThreadPool(options.getExecutorPoolSize());
public TelegramBot(String token) {
this.token = token;
this.fileApi = new FileApi(token);
}
/**
* 设置自定义配置
*
* @param options
* @return
*/
public TelegramBot options(Options options) {
this.options = options;
this.executorService = Executors.newFixedThreadPool(options.getExecutorPoolSize());
return this;
}
/**
* 启动机器人后发的消息
*
* @param consumer
* @return
*/
public TelegramBot onStart(Consumer consumer) {
return this.onCmd("/start", consumer);
}
/**
* 输入 /help 指令后
*
* @param consumer
* @return
*/
public TelegramBot onHelp(Consumer consumer) {
return this.onCmd("/help", consumer);
}
/**
* 监听指令
*
* @param cmdText 指令文本
* @param consumer 处理器
* @return
*/
public TelegramBot onCmd(String cmdText, Consumer consumer) {
if (mappings.containsKey(cmdText)) {
throw new BotException("请不要重复监听相同指令.");
}
mappings.put(cmdText, consumer);
if (!startUpdates) {
startUpdates = true;
GetUpdates getUpdates = new GetUpdates();
this.getUpdates(getUpdates);
}
return this;
}
/**
* 设置代理
*
* @param host 代理主机
* @param port 代理端口
* @return
*/
public TelegramBot useProxy(String host, int port) {
this.proxy = new java.net.Proxy(HTTP, new InetSocketAddress(host, port));
return this;
}
/**
* 设置代理
*
* @param proxy
* @return
*/
public TelegramBot useProxy(Proxy proxy) {
this.proxy = proxy;
return this;
}
/**
* 返回 GetMe
*
* @return
*/
public GetMeResponse getMe() {
GetMe request = new GetMe();
return this.execute(request);
}
/**
* 发送文本消息
*
* @param message
* @param text
*/
public void text(Message message, String text) {
this.text(message.chatId(), text);
}
/**
* 发送文本消息
*
* @param chatId
* @param message
*/
public void text(String chatId, String message) {
SendMessage sendMessage = new SendMessage(chatId, message);
this.execute(sendMessage);
}
/**
* 发送图片
*
* @param message
* @param photos
*/
public void photo(Message message, String... photos) {
this.photo(message.chatId(), photos);
}
/**
* 发送图片
*
* @param chatId
* @param photos 这里是图片的URL链接,多个用逗号相隔开
*/
public void photo(String chatId, String... photos) {
for (String photo : photos) {
SendPhoto sendPhoto = new SendPhoto(chatId, photo);
this.execute(sendPhoto);
}
}
/**
* 发送图片
*
* @param message
* @param file
*/
public void photo(Message message, java.io.File file) {
SendPhoto sendPhoto = new SendPhoto(message.chatId(), file);
this.execute(sendPhoto);
}
private void getUpdates(GetUpdates request) {
if (stopUpdates) {
return;
}
this.executeAsync(request, new Callback() {
@Override
public void onSuccess(GetUpdates request, GetUpdatesResponse response) {
if (!response.isOk() || response.getResult() == null || response.getResult().size() <= 0) {
sleep();
getUpdates(request);
return;
}
List updates = response.getResult();
if (!mappings.isEmpty()) {
Set texts = mappings.keySet();
updates.stream()
.map(Update::getMessage)
.filter(message -> texts.contains(message.getText()))
.forEach(message -> mappings.get(message.getText()).accept(message));
int offset = lastUpdateId(updates) + 1;
request = request.offset(offset);
}
sleep();
getUpdates(request);
}
@Override
public void onFailure(GetUpdates request, Throwable e) {
log.error("调用API出现异常", e);
sleep();
getUpdates(request);
}
});
}
private int lastUpdateId(List updates) {
if (null == updates || updates.isEmpty()) {
return 0;
}
return updates.get(updates.size() - 1).getUpdate_id();
}
/**
* 休眠,单位毫秒
*/
private void sleep() {
try {
TimeUnit.MILLISECONDS.sleep(options.getDuration());
} catch (InterruptedException e) {
log.error("休眠出现异常", e);
}
}
/**
* 同步执行请求
*
* @param request
* @param
* @param
* @return
* @throws Exception
*/
public R execute(T request) {
if (null == token || "".equals(token)) {
throw new BotException("请确认您机器人Token已填写");
}
String url = String.format(Const.API_URL + "%s/%s", token, request.getMethod());
if (options.isDebug()) {
log.info("Request : {}", url);
log.info("Params : {}", this.toJson(request.getParameters()));
}
String body;
Request httpRequest = Request.post(url)
.useProxy(this.proxy)
.contentType("application/json")
.connectTimeout(30_000)
.readTimeout(10_000);
if (request.isMultipart()) {
request.getParameters().forEach((key, value) -> {
if (value instanceof byte[]) {
httpRequest.part(key.toString(), request.getFileName(), request.getContentType(), new ByteArrayInputStream((byte[]) value));
} else if (value instanceof java.io.File) {
httpRequest.part(key.toString(), request.getFileName(), request.getContentType(), (java.io.File) value);
} else {
httpRequest.part(key.toString(), value.toString());
}
});
body = httpRequest.body();
} else {
body = httpRequest.send(this.toJson(request.getParameters()).getBytes()).body();
}
if (options.isDebug()) {
log.info("Response: {}", body);
}
R response = gson.fromJson(body, request.getResponseType());
return response;
}
/**
* 异步执行一个请求
*
* @param request 请求对象
* @param 请求类型
* @param 响应类型
* @return
*/
public void executeAsync(T request, Callback callback) {
CompletableFuture.supplyAsync(() -> {
R response = this.execute(request);
return response;
}, executorService).whenComplete((r, throwable) -> {
if (null == throwable) {
callback.onSuccess(request, r);
} else {
callback.onFailure(request, throwable);
}
});
// executorService.submit(() -> {
// try {
// R response = this.execute(request);
// callback.onSuccess(request, response);
// } catch (Exception e) {
// callback.onFailure(request, e);
// }
// });
}
public String getFullFilePath(File file) {
return fileApi.getFullFilePath(file.getFile_path());
}
public void stop() {
this.stopUpdates = true;
}
public void await() {
try {
Thread.currentThread().join();
} catch (InterruptedException e) {
log.error("Join异常", e);
}
}
public String toJson(Object bean) {
return gson.toJson(bean);
}
}