Issue
I am using telegrambots-spring-boot-starter v 5.2.0 and trying register my bot Here's my bot config:
bot.url=https://74e437885ee9.ngrok.io
bot.path=adam
@Slf4j
@Configuration
public class BotConfig {
@Value("${bot.url}")
private String BOT_URL;
@Bean
public SetWebhook setWebhookInstance() {
return SetWebhook.builder().url(BOT_URL).build();
}
// Create it as
@Bean
public AdamSmithBot adamSmithBot(SetWebhook setWebhookInstance) throws TelegramApiException {
AdamSmithBot adamSmithBot = new AdamSmithBot(setWebhookInstance);
// DefaultWebhook defaultWebhook = new DefaultWebhook();
// defaultWebhook.setInternalUrl(BOT_URL);
// defaultWebhook.registerWebhook(adamSmithBot);
TelegramBotsApi telegramBotsApi = new TelegramBotsApi(DefaultBotSession.class);
log.info("SetWebHook from AdamSmith bot {}", adamSmithBot.getSetWebhook());
telegramBotsApi.registerBot(adamSmithBot, adamSmithBot.getSetWebhook());
return adamSmithBot;
}
}
But it dont working, but when i send this request, it working perfectly and updates recieve to me https://api.telegram.org/MY_TOKEN_HERE/setWebhook?url=https://74e437885ee9.ngrok.io
I think my mistake in BotConfig,but i also publush my other clases bot and controller:
public class AdamSmithBot extends SpringWebhookBot {
@Value("${bot.token}")
private String TOKEN;
@Value("${bot.name}")
private String BOT_USERNAME;
@Value("${bot.path}")
private String BOT_PATH;
public AdamSmithBot(SetWebhook setWebhook) {
super(setWebhook);
}
public AdamSmithBot(DefaultBotOptions options, SetWebhook setWebhook) {
super(options, setWebhook);
}
@Override
public String getBotUsername() {
return BOT_USERNAME;
}
@Override
public String getBotToken() {
return TOKEN;
}
@Override
public BotApiMethod<?> onWebhookUpdateReceived(Update update) {
if (update.getMessage() != null && update.getMessage().hasText()) {
Long chatId = update.getMessage().getChatId();
try {
execute(new SendMessage(chatId.toString(), "HI HANDSOME " + update.getMessage().getText()));
} catch (TelegramApiException e) {
throw new IllegalStateException(e);
}
}
return null;
}
@Override
public String getBotPath() {
return "adam";
}
}
Controller:
@Slf4j
@RestController
public class WebHookBotRecieveController {
@Autowired
private AdamSmithBot adamSmithBot;
@PostMapping("/")
public void getUpdate(@RequestBody Update update){
log.info("some update recieved {}",update.toString());
adamSmithBot.onWebhookUpdateReceived(update);
}
@PostMapping("/callback/adam")
public void getUpdateWithDifferentUrl(@RequestBody Update update){
log.info("some update recieved {}",update.toString());
adamSmithBot.onWebhookUpdateReceived(update);
}
}
NOTE: I seemd some info here: https://github.com/rubenlagus/TelegramBots/wiki/How-To-Update
They do that: https://i.stack.imgur.com/9JKRT.png
But when i trying put DefaultWebhook class instead it produce NullPointerException What i made wrong?
EDIT : I refactored some code
@Value("${bot.url}") private String BOT_URL;
- where was null value (fixed),reloaded library, but now i have that exception:
Caused by: javax.ws.rs.ProcessingException: Failed to start Grizzly HTTP server: Cannot assign requested address: bind
at org.glassfish.jersey.grizzly2.httpserver.GrizzlyHttpServerFactory.createHttpServer(GrizzlyHttpServerFactory.java:270) ~[jersey-container-grizzly2-http-2.33.jar:na]
at org.glassfish.jersey.grizzly2.httpserver.GrizzlyHttpServerFactory.createHttpServer(GrizzlyHttpServerFactory.java:93) ~[jersey-container-grizzly2-http-2.33.jar:na]
at org.telegram.telegrambots.updatesreceivers.DefaultWebhook.startServer(DefaultWebhook.java:64) ~[telegrambots-5.2.0.jar:na]
at org.telegram.telegrambots.meta.TelegramBotsApi.<init>(TelegramBotsApi.java:50) ~[telegrambots-meta-5.2.0.jar:na]
at ru.website.selenium.bot.telegram.config.BotConfig.adamSmithBot(BotConfig.java:44) ~[classes/:na]
at ru.website.selenium.bot.telegram.config.BotConfig$$EnhancerBySpringCGLIB$$4eb8259d.CGLIB$adamSmithBot$0(<generated>) ~[classes/:na]
at ru.website.selenium.bot.telegram.config.BotConfig$$EnhancerBySpringCGLIB$$4eb8259d$$FastClassBySpringCGLIB$$1e185cfd.invoke(<generated>) ~[classes/:na]
at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:244) ~[spring-core-5.3.8.jar:5.3.8]
at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:331) ~[spring-context-5.3.8.jar:5.3.8]
at ru.website.selenium.bot.telegram.config.BotConfig$$EnhancerBySpringCGLIB$$4eb8259d.adamSmithBot(<generated>) ~[classes/:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:na]
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
at java.base/java.lang.reflect.Method.invoke(Method.java:566) ~[na:na]
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:154) ~[spring-beans-5.3.8.jar:5.3.8]
... 39 common frames omitted
Caused by: java.net.BindException: Cannot assign requested address: bind
at java.base/sun.nio.ch.Net.bind0(Native Method) ~[na:na]
at java.base/sun.nio.ch.Net.bind(Net.java:461) ~[na:na]
at java.base/sun.nio.ch.Net.bind(Net.java:453) ~[na:na]
at java.base/sun.nio.ch.ServerSocketChannelImpl.bind(ServerSocketChannelImpl.java:227) ~[na:na]
at java.base/sun.nio.ch.ServerSocketAdaptor.bind(ServerSocketAdaptor.java:80) ~[na:na]
at org.glassfish.grizzly.nio.transport.TCPNIOBindingHandler.bindToChannelAndAddress(TCPNIOBindingHandler.java:107) ~[grizzly-framework-2.4.4.jar:2.4.4]
at org.glassfish.grizzly.nio.transport.TCPNIOBindingHandler.bind(TCPNIOBindingHandler.java:64) ~[grizzly-framework-2.4.4.jar:2.4.4]
at org.glassfish.grizzly.nio.transport.TCPNIOTransport.bind(TCPNIOTransport.java:215) ~[grizzly-framework-2.4.4.jar:2.4.4]
at org.glassfish.grizzly.nio.transport.TCPNIOTransport.bind(TCPNIOTransport.java:195) ~[grizzly-framework-2.4.4.jar:2.4.4]
at org.glassfish.grizzly.nio.transport.TCPNIOTransport.bind(TCPNIOTransport.java:186) ~[grizzly-framework-2.4.4.jar:2.4.4]
at org.glassfish.grizzly.http.server.NetworkListener.start(NetworkListener.java:711) ~[grizzly-http-server-2.4.4.jar:2.4.4]
at org.glassfish.grizzly.http.server.HttpServer.start(HttpServer.java:256) ~[grizzly-http-server-2.4.4.jar:2.4.4]
at org.glassfish.jersey.grizzly2.httpserver.GrizzlyHttpServerFactory.createHttpServer(GrizzlyHttpServerFactory.java:267) ~[jersey-container-grizzly2-http-2.33.jar:na]
... 53 common frames omitted
Process finished with exit code 0
Solution
Okay, I get it, I didn't know that TelegramBotApi runs a grizzly server underneath and that was the reason for my mistakes For those who ever come here with the same problem, I will describe the solution : Let's start with the fact that for the test on localhost we need a public address , e.g. ngrok , then we have to do the following, start grizzli on , let's say port 80 (localhost), specify the correct ngrok url , and then run spring boot application on , let's say port 8080, examples in the code
For ex. ngrok forwarding: Forwarding http://b44ecce72666.ngrok.io -> http://localhost:8080 Forwarding https://b44ecce72666.ngrok.io -> http://localhost:8080
@Slf4j
@Configuration
public class BotConfig {
// @Value("${bot.url}")
// @NotNull
// @NotEmpty
// private String BOT_URL;
@Value("${bot.token}")
@NotNull
@NotEmpty
private String TOKEN;
@Value("${bot.name}")
@NotNull
@NotEmpty
private String BOT_USERNAME;
@Bean
public SetWebhook setWebhookInstance() {
return SetWebhook.builder().url("https://b44ecce72666.ngrok.io").build();
} // public address, now it is ngrok, in the future it will (i think) be the server address
// Create it as
@Bean
public AdamSmithBot adamSmithBot(SetWebhook setWebhookInstance) throws TelegramApiException {
AdamSmithBot adamSmithBot = new AdamSmithBot(setWebhookInstance);
adamSmithBot.setBOT_USERNAME(BOT_USERNAME);
adamSmithBot.setTOKEN(TOKEN);
adamSmithBot.setBOT_PATH("adam");
DefaultWebhook defaultWebhook = new DefaultWebhook();
defaultWebhook.setInternalUrl(
"http://localhost:80"); // the port to start the server, on the localhost computer, on the server it
// be the server address
// defaultWebhook.registerWebhook(adamSmithBot);
TelegramBotsApi telegramBotsApi = new TelegramBotsApi(DefaultBotSession.class, defaultWebhook);
log.info("SetWebHook from AdamSmith bot {}", setWebhookInstance);
adamSmithBot.getBotUsername();
telegramBotsApi.registerBot(adamSmithBot, setWebhookInstance);
return adamSmithBot;
}
}
Next is code of webhook bot:
@Slf4j
@Setter
public class AdamSmithBot extends SpringWebhookBot {
@Value("${bot.token}")
private String TOKEN;
@Value("${bot.name}")
private String BOT_USERNAME;
@Value("${bot.path}")
private String BOT_PATH;
@Autowired
private MainService mainService;
public AdamSmithBot(SetWebhook setWebhook) {
super(setWebhook);
}
public AdamSmithBot(DefaultBotOptions options, SetWebhook setWebhook) {
super(options, setWebhook);
}
@Override
public String getBotUsername() {
log.info("BOT_USERNAME FROM ADAM BOT {}",BOT_USERNAME);
return BOT_USERNAME;
}
@Override
public String getBotToken() {
return TOKEN;
}
@Override
public BotApiMethod<?> onWebhookUpdateReceived(Update update) { //All messages coming from the grizzly server will trigger this method
log.info("Message teext {}",update.toString());
if (update.getMessage() != null && update.getMessage().hasText()) {
Long chatId = update.getMessage().getChatId();
List<PartialBotApiMethod<Message>> listOfCommands= mainService.receiveUpdate(update);
listOfCommands.forEach(x->{
try {
if(x instanceof SendMessage){
execute((SendMessage)x);
}
if(x instanceof SendPhoto){
execute((SendPhoto) x);
}
} catch (TelegramApiException e) {
e.printStackTrace();
}
});
}
return null;
}
@Override
public String getBotPath() {
return "adam"; //any other path here
}
}
My code is excessive in some places, and too fancy, but it's not hard to figure out. If you have any suggestions on how to make it better, I'd love to hear them.
Answered By - handsome16
Answer Checked By - Mary Flores (JavaFixing Volunteer)