diff --git a/README.md b/README.md index e9feeea2..e30c31a1 100644 --- a/README.md +++ b/README.md @@ -93,6 +93,12 @@ This library use [Telegram bot API](https://core.telegram.org/bots), you can fin ## Questions or Suggestions Feel free to create issues [here](https://github.com/rubenlagus/TelegramBots/issues) as you need or join the [chat](https://telegram.me/JavaBotsApi) +## Powered by Intellij +

+ +

+ + ## License MIT License diff --git a/TelegramBots.wiki/Using-Http-Proxy.md b/TelegramBots.wiki/Using-Http-Proxy.md index 502f145e..0b7d4c0a 100644 --- a/TelegramBots.wiki/Using-Http-Proxy.md +++ b/TelegramBots.wiki/Using-Http-Proxy.md @@ -31,7 +31,7 @@ public class MyBot extends AbilityBot { Now you are able to set up your proxy -#### without authentication +#### Without authentication ```java public class Main { @@ -51,13 +51,12 @@ public class Main { TelegramBotsApi botsApi = new TelegramBotsApi(); // Set up Http proxy - DefaultBotOptions botOptions = ApiContext.getInstance(DefaultBotOptions.class); + DefaultBotOptions botOptions = ApiContext.getInstance(DefaultBotOptions.class); - HttpHost httpHost = new HttpHost(PROXY_HOST, PROXY_PORT); - - RequestConfig requestConfig = RequestConfig.custom().setProxy(httpHost).setAuthenticationEnabled(false).build(); - botOptions.setRequestConfig(requestConfig); - botOptions.setHttpProxy(httpHost); + botOptions.setProxyHost(PROXY_HOST); + botOptions.setProxyPort(PROXY_PORT); + // Select proxy type: [HTTP|SOCKS4|SOCKS5] (default: NO_PROXY) + botOptions.setProxyType(DefaultBotOptions.ProxyType.SOCKS5); // Register your newly created AbilityBot MyBot bot = new MyBot(BOT_TOKEN, BOT_NAME, botOptions); @@ -89,25 +88,26 @@ public class Main { public static void main(String[] args) { try { + // Create the Authenticator that will return auth's parameters for proxy authentication + Authenticator.setDefault(new Authenticator() { + @Override + protected PasswordAuthentication getPasswordAuthentication() { + return new PasswordAuthentication(PROXY_USER, PROXY_PASSWORD.toCharArray()); + } + }); + ApiContextInitializer.init(); // Create the TelegramBotsApi object to register your bots TelegramBotsApi botsApi = new TelegramBotsApi(); // Set up Http proxy - DefaultBotOptions botOptions = ApiContext.getInstance(DefaultBotOptions.class); + DefaultBotOptions botOptions = ApiContext.getInstance(DefaultBotOptions.class); - CredentialsProvider credsProvider = new BasicCredentialsProvider(); - credsProvider.setCredentials( - new AuthScope(PROXY_HOST, PROXY_PORT), - new UsernamePasswordCredentials(PROXY_USER, PROXY_PASSWORD)); - - HttpHost httpHost = new HttpHost(PROXY_HOST, PROXY_PORT); - - RequestConfig requestConfig = RequestConfig.custom().setProxy(httpHost).setAuthenticationEnabled(true).build(); - botOptions.setRequestConfig(requestConfig); - botOptions.setCredentialsProvider(credsProvider); - botOptions.setHttpProxy(httpHost); + botOptions.setProxyHost(PROXY_HOST); + botOptions.setProxyPort(PROXY_PORT); + // Select proxy type: [HTTP|SOCKS4|SOCKS5] (default: NO_PROXY) + botOptions.setProxyType(DefaultBotOptions.ProxyType.SOCKS5); // Register your newly created AbilityBot MyBot bot = new MyBot(BOT_TOKEN, BOT_NAME, botOptions); @@ -119,4 +119,6 @@ public class Main { } } } -``` \ No newline at end of file +``` + +If you need something more complex than one proxy, then you can create more complex Authenticator that will check host and other parameters of proxy and return auth values based on them (for more information see code of java.net.Authenticator class) diff --git a/jetbrains.png b/jetbrains.png new file mode 100644 index 00000000..15024609 Binary files /dev/null and b/jetbrains.png differ diff --git a/pom.xml b/pom.xml index 4b5ea1dc..9bfeb45f 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ org.telegram Bots pom - 3.6.1 + 3.6.2 telegrambots diff --git a/telegrambots-abilities/pom.xml b/telegrambots-abilities/pom.xml index 716b8bd6..9ccbcd17 100644 --- a/telegrambots-abilities/pom.xml +++ b/telegrambots-abilities/pom.xml @@ -5,7 +5,7 @@ 4.0.0 org.telegram telegrambots-abilities - 3.6.1 + 3.6.2 jar Telegram Ability Bot diff --git a/telegrambots-extensions/pom.xml b/telegrambots-extensions/pom.xml index 35d22cd6..b28a6f6d 100644 --- a/telegrambots-extensions/pom.xml +++ b/telegrambots-extensions/pom.xml @@ -5,7 +5,7 @@ 4.0.0 org.telegram telegrambotsextensions - 3.6.1 + 3.6.2 jar Telegram Bots Extensions diff --git a/telegrambots-meta/pom.xml b/telegrambots-meta/pom.xml index a37020bc..2e813f79 100644 --- a/telegrambots-meta/pom.xml +++ b/telegrambots-meta/pom.xml @@ -5,7 +5,7 @@ 4.0.0 org.telegram telegrambots-meta - 3.6.1 + 3.6.2 jar Telegram Bots Meta diff --git a/telegrambots-spring-boot-starter/README.md b/telegrambots-spring-boot-starter/README.md index 8bb3f2a8..34b2cff5 100644 --- a/telegrambots-spring-boot-starter/README.md +++ b/telegrambots-spring-boot-starter/README.md @@ -25,7 +25,7 @@ Usage **Gradle** ```gradle - compile "org.telegram:telegrambots-spring-boot-starter:3.6" + compile "org.telegram:telegrambots-spring-boot-starter:3.6.1" ``` Motivation @@ -39,8 +39,6 @@ Your main spring boot class should look like this: ```java @SpringBootApplication -//Add this annotation to enable automatic bots initializing -@EnableTelegramBots public class YourApplicationMainClass { public static void main(String[] args) { diff --git a/telegrambots-spring-boot-starter/pom.xml b/telegrambots-spring-boot-starter/pom.xml index 72ed3705..e3dee763 100644 --- a/telegrambots-spring-boot-starter/pom.xml +++ b/telegrambots-spring-boot-starter/pom.xml @@ -5,7 +5,7 @@ 4.0.0 org.telegram telegrambots-spring-boot-starter - 3.6.1 + 3.6.2 jar Telegram Bots Spring Boot Starter @@ -60,7 +60,7 @@ UTF-8 UTF-8 3.6.1 - 1.5.10.RELEASE + 2.0.2.RELEASE @@ -75,24 +75,41 @@ spring-boot ${spring-boot.version} + org.springframework.boot spring-boot-autoconfigure ${spring-boot.version} + + + org.springframework.boot + spring-boot-test + ${spring-boot.version} + test + + + org.assertj + assertj-core + test + 3.9.1 + + org.mockito mockito-all 2.0.2-beta test + junit junit 4.11 test + diff --git a/telegrambots-spring-boot-starter/src/main/java/org/telegram/telegrambots/starter/EnableTelegramBots.java b/telegrambots-spring-boot-starter/src/main/java/org/telegram/telegrambots/starter/EnableTelegramBots.java deleted file mode 100644 index 68c4acf9..00000000 --- a/telegrambots-spring-boot-starter/src/main/java/org/telegram/telegrambots/starter/EnableTelegramBots.java +++ /dev/null @@ -1,10 +0,0 @@ -package org.telegram.telegrambots.starter; - -import org.springframework.context.annotation.Import; - -/** - * Imports configuration #TelegramBotStarterConfiguration in spring context. - */ -@Import(TelegramBotStarterConfiguration.class) -public @interface EnableTelegramBots { -} diff --git a/telegrambots-spring-boot-starter/src/main/java/org/telegram/telegrambots/starter/TelegramBotInitializer.java b/telegrambots-spring-boot-starter/src/main/java/org/telegram/telegrambots/starter/TelegramBotInitializer.java new file mode 100644 index 00000000..5348ae7c --- /dev/null +++ b/telegrambots-spring-boot-starter/src/main/java/org/telegram/telegrambots/starter/TelegramBotInitializer.java @@ -0,0 +1,45 @@ +package org.telegram.telegrambots.starter; + +import java.util.List; +import java.util.Objects; + +import org.springframework.beans.factory.InitializingBean; +import org.telegram.telegrambots.TelegramBotsApi; +import org.telegram.telegrambots.exceptions.TelegramApiException; +import org.telegram.telegrambots.generics.LongPollingBot; +import org.telegram.telegrambots.generics.WebhookBot; + +/** + * Receives all beand which are #LongPollingBot and #WebhookBot and register them in #TelegramBotsApi. + */ +public class TelegramBotInitializer implements InitializingBean { + + private final TelegramBotsApi telegramBotsApi; + private final List longPollingBots; + private final List webHookBots; + + public TelegramBotInitializer(TelegramBotsApi telegramBotsApi, + List longPollingBots, + List webHookBots) { + Objects.requireNonNull(telegramBotsApi); + Objects.requireNonNull(longPollingBots); + Objects.requireNonNull(webHookBots); + this.telegramBotsApi = telegramBotsApi; + this.longPollingBots = longPollingBots; + this.webHookBots = webHookBots; + } + + @Override + public void afterPropertiesSet() throws Exception { + try { + for (LongPollingBot bot : longPollingBots) { + telegramBotsApi.registerBot(bot); + } + for (WebhookBot bot : webHookBots) { + telegramBotsApi.registerBot(bot); + } + } catch (TelegramApiException e) { + throw new RuntimeException(e); + } + } +} diff --git a/telegrambots-spring-boot-starter/src/main/java/org/telegram/telegrambots/starter/TelegramBotStarterConfiguration.java b/telegrambots-spring-boot-starter/src/main/java/org/telegram/telegrambots/starter/TelegramBotStarterConfiguration.java index 11e66af3..86ef0c33 100644 --- a/telegrambots-spring-boot-starter/src/main/java/org/telegram/telegrambots/starter/TelegramBotStarterConfiguration.java +++ b/telegrambots-spring-boot-starter/src/main/java/org/telegram/telegrambots/starter/TelegramBotStarterConfiguration.java @@ -1,70 +1,37 @@ package org.telegram.telegrambots.starter; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.telegram.telegrambots.TelegramBotsApi; -import org.telegram.telegrambots.exceptions.TelegramApiRequestException; -import org.telegram.telegrambots.generics.LongPollingBot; -import org.telegram.telegrambots.generics.WebhookBot; - -import javax.annotation.PostConstruct; +import java.util.Collections; import java.util.List; import java.util.Optional; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.telegram.telegrambots.TelegramBotsApi; +import org.telegram.telegrambots.generics.LongPollingBot; +import org.telegram.telegrambots.generics.WebhookBot; + /** - * Receives all beand which are #LongPollingBot and #WebhookBot and register them in #TelegramBotsApi. * #TelegramBotsApi added to spring context as well */ @Configuration +@ConditionalOnProperty(prefix="telegrambots",name = "enabled", havingValue = "true", matchIfMissing = true) public class TelegramBotStarterConfiguration { - - - private final List longPollingBots; - private final List webHookBots; - - private TelegramBotsApi telegramBotsApi; - - @Autowired - public void setTelegramBotsApi(TelegramBotsApi telegramBotsApi) { - this.telegramBotsApi = telegramBotsApi; - } - - public TelegramBotStarterConfiguration(@Autowired(required = false) List longPollingBots, - @Autowired(required = false) List webHookBots) { - - this.longPollingBots = longPollingBots; - this.webHookBots = webHookBots; - } - - @PostConstruct - public void registerBots() { - Optional.ofNullable(longPollingBots).ifPresent(bots -> { - bots.forEach(bot -> { - try { - telegramBotsApi.registerBot(bot); - } catch (TelegramApiRequestException e) { - throw new RuntimeException(e); - } - }); - }); - - Optional.ofNullable(webHookBots).ifPresent(bots -> { - bots.forEach(bot -> { - try { - telegramBotsApi.registerBot(bot); - } catch (TelegramApiRequestException e) { - throw new RuntimeException(e); - } - }); - }); - } - - + @Bean @ConditionalOnMissingBean(TelegramBotsApi.class) - public TelegramBotsApi telegramBotsApi() { + public TelegramBotsApi telegramBotsApi() { return new TelegramBotsApi(); } + + @Bean + @ConditionalOnMissingBean + public TelegramBotInitializer telegramBotInitializer(TelegramBotsApi telegramBotsApi, + Optional> longPollingBots, + Optional> webHookBots) { + return new TelegramBotInitializer(telegramBotsApi, + longPollingBots.orElseGet(Collections::emptyList), + webHookBots.orElseGet(Collections::emptyList)); + } } diff --git a/telegrambots-spring-boot-starter/src/main/resources/META-INF/spring.factories b/telegrambots-spring-boot-starter/src/main/resources/META-INF/spring.factories new file mode 100644 index 00000000..71b3a84d --- /dev/null +++ b/telegrambots-spring-boot-starter/src/main/resources/META-INF/spring.factories @@ -0,0 +1 @@ +org.springframework.boot.autoconfigure.EnableAutoConfiguration=org.telegram.telegrambots.starter.TelegramBotStarterConfiguration \ No newline at end of file diff --git a/telegrambots-spring-boot-starter/src/test/java/org/telegram/telegrambots/starter/TestTelegramBotStarterConfiguration.java b/telegrambots-spring-boot-starter/src/test/java/org/telegram/telegrambots/starter/TestTelegramBotStarterConfiguration.java index 00a1e7cf..d8723664 100644 --- a/telegrambots-spring-boot-starter/src/test/java/org/telegram/telegrambots/starter/TestTelegramBotStarterConfiguration.java +++ b/telegrambots-spring-boot-starter/src/test/java/org/telegram/telegrambots/starter/TestTelegramBotStarterConfiguration.java @@ -1,66 +1,99 @@ package org.telegram.telegrambots.starter; -import com.google.common.collect.Lists; -import org.junit.Rule; + +import static org.assertj.core.api.Assertions.assertThat; + import org.junit.Test; -import org.mockito.Answers; -import org.mockito.Mock; -import org.mockito.junit.MockitoJUnit; -import org.mockito.junit.MockitoRule; +import static org.mockito.Mockito.*; +import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; import org.telegram.telegrambots.TelegramBotsApi; -import org.telegram.telegrambots.exceptions.TelegramApiRequestException; import org.telegram.telegrambots.generics.LongPollingBot; import org.telegram.telegrambots.generics.WebhookBot; -import static org.mockito.Matchers.any; -import static org.mockito.Mockito.*; - public class TestTelegramBotStarterConfiguration { - @Mock - private TelegramBotsApi telegramBotsApi; + private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() + .withConfiguration(AutoConfigurations.of(MockTelegramBotsApi.class, TelegramBotStarterConfiguration.class)); - @Rule - public MockitoRule mockitoRule = MockitoJUnit.rule(); + @Test + public void createMockTelegramBotsApiWithDefaultSettings() { + this.contextRunner.run((context) -> { + assertThat(context).hasSingleBean(TelegramBotsApi.class); + assertThat(context).hasSingleBean(TelegramBotInitializer.class); + assertThat(context).doesNotHaveBean(LongPollingBot.class); + assertThat(context).doesNotHaveBean(WebhookBot.class); + verifyNoMoreInteractions(context.getBean(TelegramBotsApi.class)); + }); + } + + @Test + public void createOnlyLongPollingBot() { + this.contextRunner.withUserConfiguration(LongPollingBotConfig.class) + .run((context) -> { + assertThat(context).hasSingleBean(LongPollingBot.class); + assertThat(context).doesNotHaveBean(WebhookBot.class); + + TelegramBotsApi telegramBotsApi = context.getBean(TelegramBotsApi.class); + + verify(telegramBotsApi, times(1)).registerBot( context.getBean(LongPollingBot.class) ); + verifyNoMoreInteractions(telegramBotsApi); + }); + } + + @Test + public void createOnlyWebhookBot() { + this.contextRunner.withUserConfiguration(WebhookBotConfig.class) + .run((context) -> { + assertThat(context).hasSingleBean(WebhookBot.class); + assertThat(context).doesNotHaveBean(LongPollingBot.class); + + TelegramBotsApi telegramBotsApi = context.getBean(TelegramBotsApi.class); + + verify(telegramBotsApi, times(1)).registerBot( context.getBean(WebhookBot.class) ); + verifyNoMoreInteractions(telegramBotsApi); + }); + } + + @Test + public void createLongPoolingBotAndWebhookBot() { + this.contextRunner.withUserConfiguration(LongPollingBotConfig.class, WebhookBotConfig.class) + .run((context) -> { + assertThat(context).hasSingleBean(LongPollingBot.class); + assertThat(context).hasSingleBean(WebhookBot.class); - @Test - public void TestRegisterBotsWithLongPollingBots() throws TelegramApiRequestException { - when(telegramBotsApi.registerBot(any(LongPollingBot.class))).then(Answers.RETURNS_MOCKS.get()); - LongPollingBot longPollingBot = mock(LongPollingBot.class); - TelegramBotStarterConfiguration configuration = new TelegramBotStarterConfiguration(Lists.newArrayList(longPollingBot), null); - configuration.setTelegramBotsApi(telegramBotsApi); + TelegramBotsApi telegramBotsApi = context.getBean(TelegramBotsApi.class); + + verify(telegramBotsApi, times(1)).registerBot( context.getBean(LongPollingBot.class) ); + verify(telegramBotsApi, times(1)).registerBot( context.getBean(WebhookBot.class) ); + //verifyNoMoreInteractions(telegramBotsApi); + }); + } - configuration.registerBots(); + @Configuration + static class MockTelegramBotsApi{ - verify(telegramBotsApi, times(1)).registerBot(longPollingBot); - verifyNoMoreInteractions(telegramBotsApi); - } - - @Test - public void TestRegisterBotsWithWebhookBots() throws TelegramApiRequestException { - doNothing().when(telegramBotsApi).registerBot(any(WebhookBot.class)); - WebhookBot webhookBot = mock(WebhookBot.class); - TelegramBotStarterConfiguration configuration = new TelegramBotStarterConfiguration(null, Lists.newArrayList(webhookBot)); - configuration.setTelegramBotsApi(telegramBotsApi); - - configuration.registerBots(); - - verify(telegramBotsApi, times(1)).registerBot(webhookBot); - verifyNoMoreInteractions(telegramBotsApi); - } - - @Test - public void TestRegisterBotsWithLongPollingBotsAndWebhookBots() throws TelegramApiRequestException { - doNothing().when(telegramBotsApi).registerBot(any(WebhookBot.class)); - LongPollingBot longPollingBot = mock(LongPollingBot.class); - WebhookBot webhookBot = mock(WebhookBot.class); - TelegramBotStarterConfiguration configuration = new TelegramBotStarterConfiguration(Lists.newArrayList(longPollingBot), Lists.newArrayList(webhookBot)); - configuration.setTelegramBotsApi(telegramBotsApi); - - configuration.registerBots(); - - verify(telegramBotsApi, times(1)).registerBot(longPollingBot); - verify(telegramBotsApi, times(1)).registerBot(webhookBot); - verifyNoMoreInteractions(telegramBotsApi); - } + @Bean + public TelegramBotsApi telegramBotsApi() { + return mock(TelegramBotsApi.class); + } + } + + @Configuration + static class LongPollingBotConfig{ + @Bean + public LongPollingBot longPollingBot() { + return mock(LongPollingBot.class); + } + } + + @Configuration + static class WebhookBotConfig{ + @Bean + public WebhookBot webhookBot() { + return mock(WebhookBot.class); + } + } } diff --git a/telegrambots/pom.xml b/telegrambots/pom.xml index 95d1f3e3..aceeb9d2 100644 --- a/telegrambots/pom.xml +++ b/telegrambots/pom.xml @@ -5,7 +5,7 @@ 4.0.0 org.telegram telegrambots - 3.6.1 + 3.6.2 jar Telegram Bots diff --git a/telegrambots/src/main/java/org/telegram/telegrambots/bots/DefaultAbsSender.java b/telegrambots/src/main/java/org/telegram/telegrambots/bots/DefaultAbsSender.java index 400ab4b9..11b69995 100644 --- a/telegrambots/src/main/java/org/telegram/telegrambots/bots/DefaultAbsSender.java +++ b/telegrambots/src/main/java/org/telegram/telegrambots/bots/DefaultAbsSender.java @@ -6,14 +6,11 @@ import org.apache.http.HttpEntity; import org.apache.http.client.config.RequestConfig; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpPost; -import org.apache.http.conn.ssl.NoopHostnameVerifier; import org.apache.http.entity.BufferedHttpEntity; import org.apache.http.entity.ContentType; import org.apache.http.entity.StringEntity; import org.apache.http.entity.mime.MultipartEntityBuilder; import org.apache.http.impl.client.CloseableHttpClient; -import org.apache.http.impl.client.HttpClientBuilder; -import org.apache.http.impl.client.ProxyAuthenticationStrategy; import org.apache.http.util.EntityUtils; import org.telegram.telegrambots.api.methods.BotApiMethod; import org.telegram.telegrambots.api.methods.groupadministration.SetChatPhoto; @@ -33,13 +30,13 @@ import org.telegram.telegrambots.updateshandlers.SentCallback; import java.io.IOException; import java.io.Serializable; +import java.net.InetSocketAddress; import java.net.MalformedURLException; import java.net.URL; import java.nio.charset.StandardCharsets; import java.util.List; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; import static org.telegram.telegrambots.Constants.SOCKET_TIMEOUT; @@ -56,7 +53,7 @@ public abstract class DefaultAbsSender extends AbsSender { protected final ExecutorService exe; private final ObjectMapper objectMapper = new ObjectMapper(); private final DefaultBotOptions options; - private volatile CloseableHttpClient httpclient; + private volatile CloseableHttpClient httpClient; private volatile RequestConfig requestConfig; protected DefaultAbsSender(DefaultBotOptions options) { @@ -64,10 +61,10 @@ public abstract class DefaultAbsSender extends AbsSender { this.exe = Executors.newFixedThreadPool(options.getMaxThreads()); this.options = options; - httpclient = TelegramHttpClientBuilder.build(options); + httpClient = TelegramHttpClientBuilder.build(options); + configureHttpContext(); requestConfig = options.getRequestConfig(); - if (requestConfig == null) { requestConfig = RequestConfig.copy(RequestConfig.custom().build()) .setSocketTimeout(SOCKET_TIMEOUT) @@ -76,6 +73,22 @@ public abstract class DefaultAbsSender extends AbsSender { } } + private void configureHttpContext() { + + if (options.getProxyType() != DefaultBotOptions.ProxyType.NO_PROXY) { + InetSocketAddress socksaddr = new InetSocketAddress(options.getProxyHost(), options.getProxyPort()); + options.getHttpContext().setAttribute("socketAddress", socksaddr); + } + + if (options.getProxyType() == DefaultBotOptions.ProxyType.SOCKS4) { + options.getHttpContext().setAttribute("socksVersion", 4); + } + if (options.getProxyType() == DefaultBotOptions.ProxyType.SOCKS5) { + options.getHttpContext().setAttribute("socksVersion", 5); + } + + } + /** * Returns the token of the bot to be able to perform Telegram Api Requests * @return Token of the bot @@ -734,7 +747,7 @@ public abstract class DefaultAbsSender extends AbsSender { } private String sendHttpPostRequest(HttpPost httppost) throws IOException { - try (CloseableHttpResponse response = httpclient.execute(httppost)) { + try (CloseableHttpResponse response = httpClient.execute(httppost, options.getHttpContext())) { HttpEntity ht = response.getEntity(); BufferedHttpEntity buf = new BufferedHttpEntity(ht); return EntityUtils.toString(buf, StandardCharsets.UTF_8); diff --git a/telegrambots/src/main/java/org/telegram/telegrambots/bots/DefaultBotOptions.java b/telegrambots/src/main/java/org/telegram/telegrambots/bots/DefaultBotOptions.java index f965ab91..95ac515b 100644 --- a/telegrambots/src/main/java/org/telegram/telegrambots/bots/DefaultBotOptions.java +++ b/telegrambots/src/main/java/org/telegram/telegrambots/bots/DefaultBotOptions.java @@ -1,8 +1,8 @@ package org.telegram.telegrambots.bots; -import org.apache.http.HttpHost; -import org.apache.http.client.CredentialsProvider; import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.protocol.HttpClientContext; +import org.apache.http.protocol.HttpContext; import org.telegram.telegrambots.ApiConstants; import org.telegram.telegrambots.generics.BotOptions; import org.telegram.telegrambots.updatesreceivers.ExponentialBackOff; @@ -18,17 +18,27 @@ import java.util.List; public class DefaultBotOptions implements BotOptions { private int maxThreads; ///< Max number of threads used for async methods executions (default 1) private RequestConfig requestConfig; + private volatile HttpContext httpContext; private ExponentialBackOff exponentialBackOff; private Integer maxWebhookConnections; private String baseUrl; private List allowedUpdates; + private ProxyType proxyType; + private String proxyHost; + private int proxyPort; - private CredentialsProvider credentialsProvider; - private HttpHost httpProxy; + public enum ProxyType { + NO_PROXY, + HTTP, + SOCKS4, + SOCKS5 + } public DefaultBotOptions() { maxThreads = 1; baseUrl = ApiConstants.BASE_URL; + httpContext = HttpClientContext.create(); + proxyType = ProxyType.NO_PROXY; } @Override @@ -56,6 +66,14 @@ public class DefaultBotOptions implements BotOptions { return maxWebhookConnections; } + public HttpContext getHttpContext() { + return httpContext; + } + + public void setHttpContext(HttpContext httpContext) { + this.httpContext = httpContext; + } + public void setMaxWebhookConnections(Integer maxWebhookConnections) { this.maxWebhookConnections = maxWebhookConnections; } @@ -88,19 +106,27 @@ public class DefaultBotOptions implements BotOptions { this.exponentialBackOff = exponentialBackOff; } - public CredentialsProvider getCredentialsProvider() { - return credentialsProvider; + public ProxyType getProxyType() { + return proxyType; } - public void setCredentialsProvider(CredentialsProvider credentialsProvider) { - this.credentialsProvider = credentialsProvider; + public void setProxyType(ProxyType proxyType) { + this.proxyType = proxyType; } - public HttpHost getHttpProxy() { - return httpProxy; + public String getProxyHost() { + return proxyHost; } - public void setHttpProxy(HttpHost httpProxy) { - this.httpProxy = httpProxy; + public void setProxyHost(String proxyHost) { + this.proxyHost = proxyHost; + } + + public int getProxyPort() { + return proxyPort; + } + + public void setProxyPort(int proxyPort) { + this.proxyPort = proxyPort; } } diff --git a/telegrambots/src/main/java/org/telegram/telegrambots/bots/TelegramWebhookBot.java b/telegrambots/src/main/java/org/telegram/telegrambots/bots/TelegramWebhookBot.java index 9b2ff0ec..e926ece4 100644 --- a/telegrambots/src/main/java/org/telegram/telegrambots/bots/TelegramWebhookBot.java +++ b/telegrambots/src/main/java/org/telegram/telegrambots/bots/TelegramWebhookBot.java @@ -3,12 +3,10 @@ package org.telegram.telegrambots.bots; import org.apache.http.HttpEntity; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpPost; -import org.apache.http.conn.ssl.NoopHostnameVerifier; import org.apache.http.entity.BufferedHttpEntity; import org.apache.http.entity.ContentType; import org.apache.http.entity.mime.MultipartEntityBuilder; import org.apache.http.impl.client.CloseableHttpClient; -import org.apache.http.impl.client.HttpClientBuilder; import org.apache.http.util.EntityUtils; import org.json.JSONArray; import org.json.JSONException; diff --git a/telegrambots/src/main/java/org/telegram/telegrambots/facilities/TelegramHttpClientBuilder.java b/telegrambots/src/main/java/org/telegram/telegrambots/facilities/TelegramHttpClientBuilder.java index fb911c04..38a3a17a 100644 --- a/telegrambots/src/main/java/org/telegram/telegrambots/facilities/TelegramHttpClientBuilder.java +++ b/telegrambots/src/main/java/org/telegram/telegrambots/facilities/TelegramHttpClientBuilder.java @@ -1,10 +1,19 @@ package org.telegram.telegrambots.facilities; +import org.apache.http.config.Registry; +import org.apache.http.config.RegistryBuilder; +import org.apache.http.conn.HttpClientConnectionManager; +import org.apache.http.conn.socket.ConnectionSocketFactory; import org.apache.http.conn.ssl.NoopHostnameVerifier; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClientBuilder; -import org.apache.http.impl.client.ProxyAuthenticationStrategy; +import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; +import org.apache.http.ssl.SSLContexts; import org.telegram.telegrambots.bots.DefaultBotOptions; +import org.telegram.telegrambots.facilities.proxysocketfactorys.HttpConnectionSocketFactory; +import org.telegram.telegrambots.facilities.proxysocketfactorys.HttpSSLConnectionSocketFactory; +import org.telegram.telegrambots.facilities.proxysocketfactorys.SocksSSLConnectionSocketFactory; +import org.telegram.telegrambots.facilities.proxysocketfactorys.SocksConnectionSocketFactory; import java.util.concurrent.TimeUnit; @@ -16,22 +25,30 @@ public class TelegramHttpClientBuilder { public static CloseableHttpClient build(DefaultBotOptions options) { HttpClientBuilder httpClientBuilder = HttpClientBuilder.create() .setSSLHostnameVerifier(new NoopHostnameVerifier()) + .setConnectionManager(createConnectionManager(options)) .setConnectionTimeToLive(70, TimeUnit.SECONDS) .setMaxConnTotal(100); - - if (options.getHttpProxy() != null) { - - httpClientBuilder.setProxy(options.getHttpProxy()); - - if (options.getCredentialsProvider() != null) { - httpClientBuilder - .setProxyAuthenticationStrategy(new ProxyAuthenticationStrategy()) - .setDefaultCredentialsProvider(options.getCredentialsProvider()); - } - - } - return httpClientBuilder.build(); } + private static HttpClientConnectionManager createConnectionManager(DefaultBotOptions options) { + Registry registry; + switch (options.getProxyType()) { + case NO_PROXY: + return null; + case HTTP: + registry = RegistryBuilder. create() + .register("http", new HttpConnectionSocketFactory()) + .register("https", new HttpSSLConnectionSocketFactory(SSLContexts.createSystemDefault())).build(); + return new PoolingHttpClientConnectionManager(registry); + case SOCKS4: + case SOCKS5: + registry = RegistryBuilder. create() + .register("http", new SocksConnectionSocketFactory()) + .register("https", new SocksSSLConnectionSocketFactory(SSLContexts.createSystemDefault())).build(); + return new PoolingHttpClientConnectionManager(registry); + } + return null; + } + } diff --git a/telegrambots/src/main/java/org/telegram/telegrambots/facilities/proxysocketfactorys/HttpConnectionSocketFactory.java b/telegrambots/src/main/java/org/telegram/telegrambots/facilities/proxysocketfactorys/HttpConnectionSocketFactory.java new file mode 100644 index 00000000..d06f17ce --- /dev/null +++ b/telegrambots/src/main/java/org/telegram/telegrambots/facilities/proxysocketfactorys/HttpConnectionSocketFactory.java @@ -0,0 +1,33 @@ +package org.telegram.telegrambots.facilities.proxysocketfactorys; + +import org.apache.http.HttpHost; +import org.apache.http.conn.socket.PlainConnectionSocketFactory; +import org.apache.http.protocol.HttpContext; + +import java.io.IOException; +import java.net.InetSocketAddress; +import java.net.Proxy; +import java.net.Socket; + +public class HttpConnectionSocketFactory extends PlainConnectionSocketFactory { + @Override + public Socket createSocket(final HttpContext context) throws IOException { + InetSocketAddress socketAddress = (InetSocketAddress) context.getAttribute("socketAddress"); + Proxy proxy = new Proxy(Proxy.Type.HTTP, socketAddress); + return new Socket(proxy); + } + + @Override + public Socket connectSocket( + int connectTimeout, + Socket socket, + HttpHost host, + InetSocketAddress remoteAddress, + InetSocketAddress localAddress, + HttpContext context) throws IOException { + String hostName = host.getHostName(); + int port = remoteAddress.getPort(); + InetSocketAddress unresolvedRemote = InetSocketAddress.createUnresolved(hostName, port); + return super.connectSocket(connectTimeout, socket, host, unresolvedRemote, localAddress, context); + } +} diff --git a/telegrambots/src/main/java/org/telegram/telegrambots/facilities/proxysocketfactorys/HttpSSLConnectionSocketFactory.java b/telegrambots/src/main/java/org/telegram/telegrambots/facilities/proxysocketfactorys/HttpSSLConnectionSocketFactory.java new file mode 100644 index 00000000..2c97e934 --- /dev/null +++ b/telegrambots/src/main/java/org/telegram/telegrambots/facilities/proxysocketfactorys/HttpSSLConnectionSocketFactory.java @@ -0,0 +1,40 @@ +package org.telegram.telegrambots.facilities.proxysocketfactorys; + +import org.apache.http.HttpHost; +import org.apache.http.conn.ssl.NoopHostnameVerifier; +import org.apache.http.conn.ssl.SSLConnectionSocketFactory; +import org.apache.http.protocol.HttpContext; + +import javax.net.ssl.SSLContext; +import java.io.IOException; +import java.net.InetSocketAddress; +import java.net.Proxy; +import java.net.Socket; + +public class HttpSSLConnectionSocketFactory extends SSLConnectionSocketFactory { + + public HttpSSLConnectionSocketFactory(final SSLContext sslContext) { + super(sslContext, new NoopHostnameVerifier()); + } + + @Override + public Socket createSocket(final HttpContext context) throws IOException { + InetSocketAddress socketAddress = (InetSocketAddress) context.getAttribute("socketAddress"); + Proxy proxy = new Proxy(Proxy.Type.HTTP, socketAddress); + return new Socket(proxy); + } + + @Override + public Socket connectSocket( + int connectTimeout, + Socket socket, + HttpHost host, + InetSocketAddress remoteAddress, + InetSocketAddress localAddress, + HttpContext context) throws IOException { + String hostName = host.getHostName(); + int port = remoteAddress.getPort(); + InetSocketAddress unresolvedRemote = InetSocketAddress.createUnresolved(hostName, port); + return super.connectSocket(connectTimeout, socket, host, unresolvedRemote, localAddress, context); + } +} diff --git a/telegrambots/src/main/java/org/telegram/telegrambots/facilities/proxysocketfactorys/SocksConnectionSocketFactory.java b/telegrambots/src/main/java/org/telegram/telegrambots/facilities/proxysocketfactorys/SocksConnectionSocketFactory.java new file mode 100644 index 00000000..d2b29a5e --- /dev/null +++ b/telegrambots/src/main/java/org/telegram/telegrambots/facilities/proxysocketfactorys/SocksConnectionSocketFactory.java @@ -0,0 +1,37 @@ +package org.telegram.telegrambots.facilities.proxysocketfactorys; + + +import org.apache.http.HttpHost; +import org.apache.http.conn.socket.PlainConnectionSocketFactory; +import org.apache.http.protocol.HttpContext; +import sun.net.SocksProxy; + +import java.io.IOException; +import java.net.InetSocketAddress; +import java.net.Proxy; +import java.net.Socket; + +public class SocksConnectionSocketFactory extends PlainConnectionSocketFactory { + + @Override + public Socket createSocket(final HttpContext context) throws IOException { + InetSocketAddress socksaddr = (InetSocketAddress) context.getAttribute("socketAddress"); + int socksVersion = (Integer) context.getAttribute("socksVersion"); + Proxy proxy = SocksProxy.create(socksaddr, socksVersion); + return new Socket(proxy); + } + + @Override + public Socket connectSocket( + int connectTimeout, + Socket socket, + HttpHost host, + InetSocketAddress remoteAddress, + InetSocketAddress localAddress, + HttpContext context) throws IOException { + String hostName = host.getHostName(); + int port = remoteAddress.getPort(); + InetSocketAddress unresolvedRemote = InetSocketAddress.createUnresolved(hostName, port); + return super.connectSocket(connectTimeout, socket, host, unresolvedRemote, localAddress, context); + } +} diff --git a/telegrambots/src/main/java/org/telegram/telegrambots/facilities/proxysocketfactorys/SocksSSLConnectionSocketFactory.java b/telegrambots/src/main/java/org/telegram/telegrambots/facilities/proxysocketfactorys/SocksSSLConnectionSocketFactory.java new file mode 100644 index 00000000..cbd46b6a --- /dev/null +++ b/telegrambots/src/main/java/org/telegram/telegrambots/facilities/proxysocketfactorys/SocksSSLConnectionSocketFactory.java @@ -0,0 +1,43 @@ +package org.telegram.telegrambots.facilities.proxysocketfactorys; + +import org.apache.http.HttpHost; +import org.apache.http.conn.ssl.NoopHostnameVerifier; +import org.apache.http.conn.ssl.SSLConnectionSocketFactory; +import org.apache.http.protocol.HttpContext; +import sun.net.SocksProxy; + +import javax.net.ssl.SSLContext; +import java.io.IOException; +import java.net.InetSocketAddress; +import java.net.Proxy; +import java.net.Socket; + + +public class SocksSSLConnectionSocketFactory extends SSLConnectionSocketFactory { + + public SocksSSLConnectionSocketFactory(final SSLContext sslContext) { + super(sslContext, new NoopHostnameVerifier()); + } + + @Override + public Socket createSocket(final HttpContext context) throws IOException { + InetSocketAddress socksaddr = (InetSocketAddress) context.getAttribute("socketAddress"); + int socksVersion = (Integer) context.getAttribute("socksVersion"); + Proxy proxy = SocksProxy.create(socksaddr, socksVersion); + return new Socket(proxy); + } + + @Override + public Socket connectSocket( + int connectTimeout, + Socket socket, + HttpHost host, + InetSocketAddress remoteAddress, + InetSocketAddress localAddress, + HttpContext context) throws IOException { + String hostName = host.getHostName(); + int port = remoteAddress.getPort(); + InetSocketAddress unresolvedRemote = InetSocketAddress.createUnresolved(hostName, port); + return super.connectSocket(connectTimeout, socket, host, unresolvedRemote, localAddress, context); + } +} diff --git a/telegrambots/src/main/java/org/telegram/telegrambots/updatesreceivers/DefaultBotSession.java b/telegrambots/src/main/java/org/telegram/telegrambots/updatesreceivers/DefaultBotSession.java index 6e6b56b9..bac2eef3 100644 --- a/telegrambots/src/main/java/org/telegram/telegrambots/updatesreceivers/DefaultBotSession.java +++ b/telegrambots/src/main/java/org/telegram/telegrambots/updatesreceivers/DefaultBotSession.java @@ -6,13 +6,10 @@ import org.apache.http.HttpEntity; import org.apache.http.client.config.RequestConfig; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpPost; -import org.apache.http.conn.ssl.NoopHostnameVerifier; import org.apache.http.entity.BufferedHttpEntity; import org.apache.http.entity.ContentType; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.CloseableHttpClient; -import org.apache.http.impl.client.HttpClientBuilder; -import org.apache.http.impl.client.ProxyAuthenticationStrategy; import org.apache.http.util.EntityUtils; import org.json.JSONException; import org.telegram.telegrambots.ApiConstants; @@ -32,7 +29,6 @@ import java.nio.charset.StandardCharsets; import java.security.InvalidParameterException; import java.util.*; import java.util.concurrent.ConcurrentLinkedDeque; -import java.util.concurrent.TimeUnit; import static org.telegram.telegrambots.Constants.SOCKET_TIMEOUT; @@ -245,7 +241,7 @@ public class DefaultBotSession implements BotSession { httpPost.setConfig(requestConfig); httpPost.setEntity(new StringEntity(objectMapper.writeValueAsString(request), ContentType.APPLICATION_JSON)); - try (CloseableHttpResponse response = httpclient.execute(httpPost)) { + try (CloseableHttpResponse response = httpclient.execute(httpPost, options.getHttpContext())) { HttpEntity ht = response.getEntity(); BufferedHttpEntity buf = new BufferedHttpEntity(ht); String responseContent = EntityUtils.toString(buf, StandardCharsets.UTF_8);