You can use {@link #onThread(long)} to target specific threads on the channel. 39 | * 40 | * @param webhook 41 | * The webhook 42 | * 43 | * @throws NullPointerException 44 | * If the webhook is null or does not provide a token 45 | * 46 | * @return The D4JWebhookClient 47 | */ 48 | @NotNull 49 | public static D4JWebhookClient from(@NotNull discord4j.core.object.entity.Webhook webhook) { 50 | return WebhookClientBuilder.fromD4J(webhook).buildD4J(); 51 | } 52 | 53 | /** 54 | * Factory method to create a basic D4JWebhookClient with the provided id and token. 55 | * 56 | *
You can use {@link #onThread(long)} to target specific threads on the channel. 57 | * 58 | * @param id 59 | * The webhook id 60 | * @param token 61 | * The webhook token 62 | * 63 | * @throws java.lang.NullPointerException 64 | * If provided with null 65 | * 66 | * @return The D4JWebhookClient for the provided id and token 67 | */ 68 | @NotNull 69 | public static D4JWebhookClient withId(long id, @NotNull String token) { 70 | Objects.requireNonNull(token, "Token"); 71 | ScheduledExecutorService pool = ThreadPools.getDefaultPool(id, null, false); 72 | return new D4JWebhookClient(id, token, true, new OkHttpClient(), pool, AllowedMentions.all(), 0L); 73 | } 74 | 75 | /** 76 | * Factory method to create a basic D4JWebhookClient with the provided id and token. 77 | * 78 | *
You can use {@link #onThread(long)} to target specific threads on the channel.
79 | *
80 | * @param url
81 | * The url for the webhook
82 | *
83 | * @throws java.lang.NullPointerException
84 | * If provided with null
85 | * @throws java.lang.NumberFormatException
86 | * If no valid id is part o the url
87 | *
88 | * @return The D4JWebhookClient for the provided url
89 | */
90 | @NotNull
91 | public static D4JWebhookClient withUrl(@NotNull String url) {
92 | Objects.requireNonNull(url, "URL");
93 | Matcher matcher = WebhookClientBuilder.WEBHOOK_PATTERN.matcher(url);
94 | if (!matcher.matches()) {
95 | throw new IllegalArgumentException("Failed to parse webhook URL");
96 | }
97 | return withId(Long.parseUnsignedLong(matcher.group(1)), matcher.group(2));
98 | }
99 |
100 | @NotNull
101 | @Override
102 | public D4JWebhookClient onThread(final long threadId) {
103 | return new D4JWebhookClient(this, threadId);
104 | }
105 |
106 | /**
107 | * Sends the provided {@link MessageCreateSpec} to the webhook.
108 | *
109 | * @param callback
110 | * The callback used to specify the desired message settings
111 | *
112 | * @throws NullPointerException
113 | * If null is provided
114 | *
115 | * @return {@link Mono}
116 | *
117 | * @deprecated Replace wth {@link #send(MessageCreateSpec)}
118 | *
119 | * @see #isWait()
120 | * @see WebhookMessageBuilder#fromD4J(Consumer)
121 | */
122 | @NotNull
123 | @Deprecated
124 | @CheckReturnValue
125 | public Mono You can use {@link #onThread(long)} to target specific threads on the channel.
36 | *
37 | * @param webhook
38 | * The webhook
39 | *
40 | * @throws NullPointerException
41 | * If the webhook is null or does not provide a token
42 | *
43 | * @return The JDAWebhookClient
44 | */
45 | @NotNull
46 | public static JDAWebhookClient from(@NotNull net.dv8tion.jda.api.entities.Webhook webhook) {
47 | return WebhookClientBuilder.fromJDA(webhook).buildJDA();
48 | }
49 |
50 | /**
51 | * Factory method to create a basic JDAWebhookClient with the provided id and token.
52 | *
53 | * You can use {@link #onThread(long)} to target specific threads on the channel.
54 | *
55 | * @param id
56 | * The webhook id
57 | * @param token
58 | * The webhook token
59 | *
60 | * @throws java.lang.NullPointerException
61 | * If provided with null
62 | *
63 | * @return The JDAWebhookClient for the provided id and token
64 | */
65 | @NotNull
66 | public static JDAWebhookClient withId(long id, @NotNull String token) {
67 | Objects.requireNonNull(token, "Token");
68 | ScheduledExecutorService pool = ThreadPools.getDefaultPool(id, null, false);
69 | return new JDAWebhookClient(id, token, true, new OkHttpClient(), pool, AllowedMentions.all());
70 | }
71 |
72 | /**
73 | * Factory method to create a basic JDAWebhookClient with the provided id and token.
74 | *
75 | * You can use {@link #onThread(long)} to target specific threads on the channel.
76 | *
77 | * @param url
78 | * The url for the webhook
79 | *
80 | * @throws java.lang.NullPointerException
81 | * If provided with null
82 | * @throws java.lang.NumberFormatException
83 | * If no valid id is part o the url
84 | *
85 | * @return The JDAWebhookClient for the provided url
86 | */
87 | @NotNull
88 | public static JDAWebhookClient withUrl(@NotNull String url) {
89 | Objects.requireNonNull(url, "URL");
90 | Matcher matcher = WebhookClientBuilder.WEBHOOK_PATTERN.matcher(url);
91 | if (!matcher.matches()) {
92 | throw new IllegalArgumentException("Failed to parse webhook URL");
93 | }
94 | return withId(Long.parseUnsignedLong(matcher.group(1)), matcher.group(2));
95 | }
96 |
97 | @NotNull
98 | @Override
99 | public JDAWebhookClient onThread(long threadId) {
100 | return new JDAWebhookClient(this, threadId);
101 | }
102 |
103 | /**
104 | * Sends the provided {@link net.dv8tion.jda.api.entities.Message Message} to the webhook.
105 | *
106 | * @param message
107 | * The message to send
108 | *
109 | * @throws NullPointerException
110 | * If null is provided
111 | *
112 | * @return {@link CompletableFuture}
113 | *
114 | * @see #isWait()
115 | * @see WebhookMessageBuilder#fromJDA(Message)
116 | */
117 | @NotNull
118 | public CompletableFuture You can use {@link #onThread(long)} to target specific threads on the channel.
35 | *
36 | * @param webhook
37 | * The webhook
38 | *
39 | * @throws NullPointerException
40 | * If the webhook is null or does not provide a token
41 | *
42 | * @return The JavacordWebhookClient
43 | */
44 | @NotNull
45 | public static JavacordWebhookClient from(@NotNull org.javacord.api.entity.webhook.Webhook webhook) {
46 | return WebhookClientBuilder.fromJavacord(webhook).buildJavacord();
47 | }
48 |
49 | /**
50 | * Factory method to create a basic JavacordWebhookClient with the provided id and token.
51 | *
52 | * You can use {@link #onThread(long)} to target specific threads on the channel.
53 | *
54 | * @param id
55 | * The webhook id
56 | * @param token
57 | * The webhook token
58 | *
59 | * @throws java.lang.NullPointerException
60 | * If provided with null
61 | *
62 | * @return The JavacordWebhookClient for the provided id and token
63 | */
64 | @NotNull
65 | public static JavacordWebhookClient withId(long id, @NotNull String token) {
66 | Objects.requireNonNull(token, "Token");
67 | ScheduledExecutorService pool = ThreadPools.getDefaultPool(id, null, false);
68 | return new JavacordWebhookClient(id, token, true, new OkHttpClient(), pool, AllowedMentions.all());
69 | }
70 |
71 | /**
72 | * Factory method to create a basic JavacordWebhookClient with the provided id and token.
73 | *
74 | * You can use {@link #onThread(long)} to target specific threads on the channel.
75 | *
76 | * @param url
77 | * The url for the webhook
78 | *
79 | * @throws java.lang.NullPointerException
80 | * If provided with null
81 | * @throws java.lang.NumberFormatException
82 | * If no valid id is part o the url
83 | *
84 | * @return The JavacordWebhookClient for the provided url
85 | */
86 | @NotNull
87 | public static JavacordWebhookClient withUrl(@NotNull String url) {
88 | Objects.requireNonNull(url, "URL");
89 | Matcher matcher = WebhookClientBuilder.WEBHOOK_PATTERN.matcher(url);
90 | if (!matcher.matches()) {
91 | throw new IllegalArgumentException("Failed to parse webhook URL");
92 | }
93 | return withId(Long.parseUnsignedLong(matcher.group(1)), matcher.group(2));
94 | }
95 |
96 | @NotNull
97 | @Override
98 | public JavacordWebhookClient onThread(long threadId) {
99 | return new JavacordWebhookClient(this, threadId);
100 | }
101 |
102 | /**
103 | * Sends the provided {@link org.javacord.api.entity.message.Message Message} to the webhook.
104 | *
105 | * @param message
106 | * The message to send
107 | *
108 | * @throws NullPointerException
109 | * If null is provided
110 | *
111 | * @return {@link CompletableFuture}
112 | *
113 | * @see #isWait()
114 | * @see WebhookMessageBuilder#fromJavacord(org.javacord.api.entity.message.Message)
115 | */
116 | @NotNull
117 | public CompletableFuture Equivalent:
61 | * Equivalent:
81 | *
This does not actually contain the file but only meta-data
27 | * useful to retrieve the actual attachment.
28 | */
29 | public class ReadonlyAttachment implements JSONString {
30 | private final String url;
31 | private final String proxyUrl;
32 | private final String fileName;
33 | private final int width, height;
34 | private final int size;
35 | private final long id;
36 |
37 | public ReadonlyAttachment(
38 | @NotNull String url, @NotNull String proxyUrl, @NotNull String fileName,
39 | int width, int height, int size, long id) {
40 | this.url = url;
41 | this.proxyUrl = proxyUrl;
42 | this.fileName = fileName;
43 | this.width = width;
44 | this.height = height;
45 | this.size = size;
46 | this.id = id;
47 | }
48 |
49 | /**
50 | * The URL for this attachment
51 | *
52 | * @return The url
53 | */
54 | @NotNull
55 | public String getUrl() {
56 | return url;
57 | }
58 |
59 | /**
60 | * The proxy url for this attachment, this is used by the client
61 | * to generate previews of images.
62 | *
63 | * @return The proxy url
64 | */
65 | @NotNull
66 | @JSONPropertyName("proxy_url")
67 | public String getProxyUrl() {
68 | return proxyUrl;
69 | }
70 |
71 | /**
72 | * The name of this attachment
73 | *
74 | * @return The file name
75 | */
76 | @NotNull
77 | @JSONPropertyName("filename")
78 | public String getFileName() {
79 | return fileName;
80 | }
81 |
82 | /**
83 | * The approximated size of this embed in bytes
84 | *
85 | * @return The approximated size in bytes
86 | */
87 | public int getSize() {
88 | return size;
89 | }
90 |
91 | /**
92 | * Width of the attachment, this is only relevant to images and videos
93 | *
94 | * @return Width of this image, or -1 if not an image or video
95 | */
96 | public int getWidth() {
97 | return width;
98 | }
99 |
100 | /**
101 | * Height of the attachment, this is only relevant to images and videos
102 | *
103 | * @return Height of this image, or -1 if not an image or video
104 | */
105 | public int getHeight() {
106 | return height;
107 | }
108 |
109 | /**
110 | * The id of this attachment
111 | *
112 | * @return The idi
113 | */
114 | public long getId() {
115 | return id;
116 | }
117 |
118 | /**
119 | * JSON representation of this attachment
120 | *
121 | * @return The JSON representation
122 | */
123 | @Override
124 | public String toString() {
125 | return toJSONString();
126 | }
127 |
128 | @Override
129 | public String toJSONString() {
130 | return new JSONObject(this).toString();
131 | }
132 | }
133 |
--------------------------------------------------------------------------------
/src/main/java/club/minnced/discord/webhook/receive/ReadonlyEmbed.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2018-2020 Florian Spieß
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package club.minnced.discord.webhook.receive;
18 |
19 | import club.minnced.discord.webhook.send.WebhookEmbed;
20 | import org.jetbrains.annotations.NotNull;
21 | import org.jetbrains.annotations.Nullable;
22 | import org.json.JSONObject;
23 | import org.json.JSONPropertyName;
24 | import org.json.JSONString;
25 |
26 | import java.time.OffsetDateTime;
27 | import java.util.List;
28 |
29 | /**
30 | * Extension of {@link club.minnced.discord.webhook.send.WebhookEmbed}
31 | * with additional meta-data on receivable embeds.
32 | */
33 | public class ReadonlyEmbed extends WebhookEmbed {
34 | private final EmbedProvider provider;
35 | private final EmbedImage thumbnail, image;
36 | private final EmbedVideo video;
37 |
38 | public ReadonlyEmbed(
39 | @Nullable OffsetDateTime timestamp, @Nullable Integer color, @Nullable String description,
40 | @Nullable EmbedImage thumbnail, @Nullable EmbedImage image, @Nullable EmbedFooter footer,
41 | @Nullable EmbedTitle title, @Nullable EmbedAuthor author, @NotNull List
Used for services that are automatically embedded by discord when posting a link,
56 | * this includes services like youtube or twitter.
57 | *
58 | * @return Possibly-null embed provider
59 | */
60 | @Nullable
61 | public EmbedProvider getProvider() {
62 | return provider;
63 | }
64 |
65 | /**
66 | * The thumbnail of this embed.
67 | *
68 | * @return Possibly-null {@link club.minnced.discord.webhook.receive.ReadonlyEmbed.EmbedImage} for the thumbnail
69 | */
70 | @Nullable
71 | public EmbedImage getThumbnail() {
72 | return thumbnail;
73 | }
74 |
75 | /**
76 | * The image of this embed.
77 | *
78 | * @return Possibly-null {@link club.minnced.discord.webhook.receive.ReadonlyEmbed.EmbedImage} for the image
79 | */
80 | @Nullable
81 | public EmbedImage getImage() {
82 | return image;
83 | }
84 |
85 | /**
86 | * The video of this embed.
87 | *
This is a whitelisted feature only available for services like youtube
88 | * and is only populated for link embeds.
89 | *
90 | * @return Possibly-null {@link club.minnced.discord.webhook.receive.ReadonlyEmbed.EmbedVideo}
91 | */
92 | @Nullable
93 | public EmbedVideo getVideo() {
94 | return video;
95 | }
96 |
97 | /**
98 | * Reduces this embed to a simpler {@link club.minnced.discord.webhook.send.WebhookEmbed}
99 | * instance that can be used for sending, this is done implicitly
100 | * when trying to send an instance of a readonly-embed.
101 | *
102 | * @return The reduced embed instance
103 | */
104 | @Override
105 | @NotNull
106 | public WebhookEmbed reduced() {
107 | return new WebhookEmbed(
108 | getTimestamp(), getColor(), getDescription(),
109 | thumbnail == null ? null : thumbnail.getUrl(),
110 | image == null ? null : image.getUrl(),
111 | getFooter(), getTitle(), getAuthor(), getFields());
112 | }
113 |
114 | /**
115 | * JSON representation of this embed.
116 | *
Note that received embeds look different compared to sent ones.
117 | *
118 | * @return The JSON representation
119 | */
120 | @Override
121 | public String toString() {
122 | return toJSONString();
123 | }
124 |
125 | @Override
126 | public String toJSONString() {
127 | JSONObject base = new JSONObject(super.toJSONString());
128 | base.put("provider", provider)
129 | .put("thumbnail", thumbnail)
130 | .put("video", video)
131 | .put("image", image);
132 | if (getTitle() != null) {
133 | base.put("title", getTitle().getText());
134 | base.put("url", getTitle().getUrl());
135 | }
136 | return base.toString();
137 | }
138 |
139 | /**
140 | * POJO containing meta-data for an embed provider
141 | *
142 | * @see #getProvider()
143 | */
144 | public static class EmbedProvider implements JSONString {
145 | private final String name, url;
146 |
147 | public EmbedProvider(@Nullable String name, @Nullable String url) {
148 | this.name = name;
149 | this.url = url;
150 | }
151 |
152 | /**
153 | * The name of the provider, or {@code null} if none is set
154 | *
155 | * @return The name
156 | */
157 | @Nullable
158 | public String getName() {
159 | return name;
160 | }
161 |
162 | /**
163 | * The url of the provider, or {@code null} if none is set
164 | *
165 | * @return The url
166 | */
167 | @Nullable
168 | public String getUrl() {
169 | return url;
170 | }
171 |
172 | /**
173 | * JSON representation of this provider
174 | *
175 | * @return The JSON representation
176 | */
177 | @Override
178 | public String toString() {
179 | return toJSONString();
180 | }
181 |
182 | @Override
183 | public String toJSONString() {
184 | return new JSONObject(this).toString();
185 | }
186 | }
187 |
188 | /**
189 | * POJO containing meta-data about an embed video
190 | *
191 | * @see #getVideo()
192 | */
193 | public static class EmbedVideo implements JSONString {
194 | private final String url;
195 | private final int width, height;
196 |
197 | public EmbedVideo(@NotNull String url, int width, int height) {
198 | this.url = url;
199 | this.width = width;
200 | this.height = height;
201 | }
202 |
203 | /**
204 | * The URL fot this video
205 | *
206 | * @return The URL
207 | */
208 | @NotNull
209 | public String getUrl() {
210 | return url;
211 | }
212 |
213 | /**
214 | * The width of this video
215 | *
216 | * @return The width
217 | */
218 | public int getWidth() {
219 | return width;
220 | }
221 |
222 | /**
223 | * The height of this video
224 | *
225 | * @return The height
226 | */
227 | public int getHeight() {
228 | return height;
229 | }
230 |
231 | /**
232 | * JSON representation of this video
233 | *
234 | * @return The JSON representation
235 | */
236 | @Override
237 | public String toString() {
238 | return toJSONString();
239 | }
240 |
241 | @Override
242 | public String toJSONString() {
243 | return new JSONObject(this).toString();
244 | }
245 | }
246 |
247 | /**
248 | * POJO containing meta-data about an embed image component
249 | *
250 | * @see #getThumbnail()
251 | * @see #getImage()
252 | */
253 | public static class EmbedImage implements JSONString {
254 | private final String url, proxyUrl;
255 | private final int width, height;
256 |
257 | public EmbedImage(
258 | @NotNull String url, @NotNull String proxyUrl,
259 | int width, int height) {
260 | this.url = url;
261 | this.proxyUrl = proxyUrl;
262 | this.width = width;
263 | this.height = height;
264 | }
265 |
266 | /**
267 | * The URL fot this image
268 | *
269 | * @return The URL
270 | */
271 | @NotNull
272 | public String getUrl() {
273 | return url;
274 | }
275 |
276 | /**
277 | * The proxy url for this image, this is used
278 | * to render previews in the discord client.
279 | *
280 | * @return The proxy url
281 | */
282 | @NotNull
283 | @JSONPropertyName("proxy_url")
284 | public String getProxyUrl() {
285 | return proxyUrl;
286 | }
287 |
288 | /**
289 | * The width of this image
290 | *
291 | * @return The width
292 | */
293 | public int getWidth() {
294 | return width;
295 | }
296 |
297 | /**
298 | * The height of this image
299 | *
300 | * @return The height
301 | */
302 | public int getHeight() {
303 | return height;
304 | }
305 |
306 | /**
307 | * JSON representation of this provider
308 | *
309 | * @return The JSON representation
310 | */
311 | @Override
312 | public String toString() {
313 | return toJSONString();
314 | }
315 |
316 | @Override
317 | public String toJSONString() {
318 | return new JSONObject(this).toString();
319 | }
320 | }
321 | }
322 |
--------------------------------------------------------------------------------
/src/main/java/club/minnced/discord/webhook/receive/ReadonlyMessage.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2018-2020 Florian Spieß
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package club.minnced.discord.webhook.receive;
18 |
19 | import club.minnced.discord.webhook.send.WebhookMessage;
20 | import org.jetbrains.annotations.NotNull;
21 | import org.json.JSONObject;
22 | import org.json.JSONString;
23 |
24 | import java.util.List;
25 |
26 | /**
27 | * Readonly message representation used for responses
28 | * of {@link club.minnced.discord.webhook.WebhookClient} send methods.
29 | *
30 | * @see #toWebhookMessage()
31 | */
32 | public class ReadonlyMessage implements JSONString {
33 | private final long id;
34 | private final long channelId;
35 | private final boolean mentionsEveryone;
36 | private final boolean tts;
37 | private final int flags;
38 |
39 | private final ReadonlyUser author;
40 |
41 | private final String content;
42 | private final List
If this message is the beginning of a thread, then this is the thread id.
69 | *
70 | * @return The id
71 | */
72 | public long getId() {
73 | return id;
74 | }
75 |
76 | /**
77 | * The channel id for the channel this message was sent in
78 | *
79 | * @return The channel id
80 | */
81 | public long getChannelId() {
82 | return channelId;
83 | }
84 |
85 | /**
86 | * Whether this message mentioned everyone/here
87 | *
88 | * @return True, if this message mentioned everyone/here
89 | */
90 | public boolean isMentionsEveryone() {
91 | return mentionsEveryone;
92 | }
93 |
94 | /**
95 | * Whether this message used Text-to-Speech (TTS)
96 | *
97 | * @return True, if this message used TTS
98 | */
99 | public boolean isTTS() {
100 | return tts;
101 | }
102 |
103 | /**
104 | * The flags for this message.
105 | *
You can use {@link club.minnced.discord.webhook.MessageFlags} to determine which flags are set.
106 | *
107 | * @return The flags
108 | */
109 | public int getFlags() {
110 | return flags;
111 | }
112 |
113 | /**
114 | * The author of this message, represented by a {@link club.minnced.discord.webhook.receive.ReadonlyUser} instance.
115 | *
116 | * @return The author
117 | */
118 | @NotNull
119 | public ReadonlyUser getAuthor() {
120 | return author;
121 | }
122 |
123 | /**
124 | * The content of this message, this is displayed above embeds and attachments.
125 | *
126 | * @return The content
127 | */
128 | @NotNull
129 | public String getContent() {
130 | return content;
131 | }
132 |
133 | /**
134 | * The embeds in this message, a webhook can send up to 10 embeds
135 | * in one message. Additionally this contains embeds generated from links.
136 | *
137 | * @return List of embeds for this message
138 | */
139 | @NotNull
140 | public List
The attachments only contain meta-data and not the actual files.
148 | *
149 | * @return List of attachments
150 | */
151 | @NotNull
152 | public List
This will not contain all users when using an everyone/here mention,
159 | * it only contains directly mentioned users.
160 | *
161 | * @return List of mentioned users.
162 | */
163 | @NotNull
164 | public List
This can be used for sending.
181 | *
182 | * @return {@link club.minnced.discord.webhook.send.WebhookMessage}
183 | */
184 | @NotNull
185 | public WebhookMessage toWebhookMessage() {
186 | return WebhookMessage.from(this);
187 | }
188 |
189 | /**
190 | * JSON representation of this provider
191 | *
192 | * @return The JSON representation
193 | */
194 | @Override
195 | public String toString() {
196 | return toJSONString();
197 | }
198 |
199 | @Override
200 | public String toJSONString() {
201 | JSONObject json = new JSONObject();
202 | json.put("content", content)
203 | .put("embeds", embeds)
204 | .put("mentions", mentionedUsers)
205 | .put("mention_roles", mentionedRoles)
206 | .put("attachments", attachments)
207 | .put("author", author)
208 | .put("tts", tts)
209 | .put("id", Long.toUnsignedString(id))
210 | .put("channel_id", Long.toUnsignedString(channelId))
211 | .put("mention_everyone", mentionsEveryone);
212 | return json.toString();
213 | }
214 | }
215 |
--------------------------------------------------------------------------------
/src/main/java/club/minnced/discord/webhook/receive/ReadonlyUser.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2018-2020 Florian Spieß
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package club.minnced.discord.webhook.receive;
18 |
19 | import org.jetbrains.annotations.NotNull;
20 | import org.jetbrains.annotations.Nullable;
21 | import org.json.JSONObject;
22 | import org.json.JSONPropertyName;
23 | import org.json.JSONString;
24 |
25 | import java.util.Locale;
26 |
27 | /**
28 | * Readonly POJO of a discord user
29 | */
30 | public class ReadonlyUser implements JSONString {
31 | private final long id;
32 | private final short discriminator;
33 | private final boolean bot;
34 | private final String name;
35 | private final String avatar;
36 |
37 | public ReadonlyUser(long id, short discriminator, boolean bot, @NotNull String name, @Nullable String avatar) {
38 | this.id = id;
39 | this.discriminator = discriminator;
40 | this.bot = bot;
41 | this.name = name;
42 | this.avatar = avatar;
43 | }
44 |
45 | /**
46 | * The id of this user
47 | *
48 | * @return The id
49 | */
50 | public long getId() {
51 | return id;
52 | }
53 |
54 | /**
55 | * The 4 digit discriminator of this user
56 | *
This is show in the client after the {@code #} when viewing profiles.
57 | *
58 | * @return The discriminator
59 | */
60 | public String getDiscriminator() {
61 | return String.format(Locale.ROOT, "%04d", discriminator);
62 | }
63 |
64 | /**
65 | * Whether this is a bot or not, webhook authors are always bots.
66 | *
67 | * @return True, if this is a bot
68 | */
69 | public boolean isBot() {
70 | return bot;
71 | }
72 |
73 | /**
74 | * The name of this user, this is the username and not the guild-specific nickname.
75 | *
76 | * @return The name of this user
77 | */
78 | @NotNull
79 | @JSONPropertyName("username")
80 | public String getName() {
81 | return name;
82 | }
83 |
84 | /**
85 | * The avatar id of this user, or {@code null} if no avatar is set.
86 | *
87 | * @return The avatar id
88 | */
89 | @Nullable
90 | @JSONPropertyName("avatar_id")
91 | public String getAvatarId() {
92 | return avatar;
93 | }
94 |
95 | /**
96 | * JSON representation of this user
97 | *
98 | * @return THe JSON representation of this user
99 | */
100 | @Override
101 | public String toString() {
102 | return toJSONString();
103 | }
104 |
105 | @Override
106 | public String toJSONString() {
107 | return new JSONObject(this).toString();
108 | }
109 | }
110 |
--------------------------------------------------------------------------------
/src/main/java/club/minnced/discord/webhook/send/AllowedMentions.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2018-2020 Florian Spieß
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package club.minnced.discord.webhook.send;
18 |
19 | import org.jetbrains.annotations.NotNull;
20 | import org.json.JSONArray;
21 | import org.json.JSONObject;
22 | import org.json.JSONString;
23 |
24 | import java.util.Collection;
25 | import java.util.Collections;
26 | import java.util.HashSet;
27 | import java.util.Set;
28 |
29 | /**
30 | * Constructs a whitelist of allowed mentions for a message.
31 | * If any argument in this class is {@code null}, a {@link NullPointerException} will be thrown.
32 | *
33 | * Example
34 | * {@code
35 | * AllowedMentions mentions = new AllowedMentions()
36 | * .withUsers("86699011792191488", "107562988810027008")
37 | * .withParseEveryone(false)
38 | * .withParseRoles(false);
39 | *
40 | * // This will only mention the user with the id 86699011792191488 (Minn#6688)
41 | * // The @everyone will be ignored since the allowed mentions disabled it.
42 | * client.send(
43 | * new WebhookMessageBuilder()
44 | * .setAllowedMentions(mentions)
45 | * .setContent("Hello <@86699011792191488>! And hello @everyone else!")
46 | * .build()
47 | * );
48 | * }
49 | *
50 | * @see WebhookMessageBuilder#setAllowedMentions(AllowedMentions)
51 | * @see club.minnced.discord.webhook.WebhookClientBuilder#setAllowedMentions(AllowedMentions) WebhookClientBuilder#setAllowedMentions(AllowedMentions)
52 | *
53 | * @see #all()
54 | * @see #none()
55 | */
56 | public class AllowedMentions implements JSONString {
57 | /**
58 | * Parse all mentions.
59 | *
60 | * {@code
62 | * return new AllowedMentions()
63 | * .withParseEveryone(true)
64 | * .withParseRoles(true)
65 | * .withParseUsers(true);
66 | * }
67 | *
68 | * @return Every mention type will be parsed.
69 | */
70 | public static AllowedMentions all() {
71 | return new AllowedMentions()
72 | .withParseEveryone(true)
73 | .withParseRoles(true)
74 | .withParseUsers(true);
75 | }
76 |
77 | /**
78 | * Disable all mentions.
79 | *
80 | * {@code
82 | * return new AllowedMentions()
83 | * .withParseEveryone(false)
84 | * .withParseRoles(false)
85 | * .withParseUsers(false);
86 | * }
87 | *
88 | * @return No mentions will be parsed.
89 | */
90 | public static AllowedMentions none() {
91 | return new AllowedMentions()
92 | .withParseEveryone(false)
93 | .withParseRoles(false)
94 | .withParseUsers(false);
95 | }
96 |
97 | private boolean parseRoles, parseUsers, parseEveryone;
98 | private final Set
This will set {@link #withParseUsers(boolean)} to false.
104 | *
105 | * @param userId
106 | * The whitelist of users to mention
107 | *
108 | * @return AllowedMentions instance with applied whitelist
109 | */
110 | @NotNull
111 | public AllowedMentions withUsers(@NotNull String... userId)
112 | {
113 | Collections.addAll(users, userId);
114 | parseUsers = false;
115 | return this;
116 | }
117 |
118 | /**
119 | * Whitelist specified roles for mention.
120 | *
This will set {@link #withParseRoles(boolean)} to false.
121 | *
122 | * @param roleId
123 | * The whitelist of roles to mention
124 | *
125 | * @return AllowedMentions instance with applied whitelist
126 | */
127 | @NotNull
128 | public AllowedMentions withRoles(@NotNull String... roleId)
129 | {
130 | Collections.addAll(roles, roleId);
131 | parseRoles = false;
132 | return this;
133 | }
134 |
135 | /**
136 | * Whitelist specified users for mention.
137 | *
This will set {@link #withParseUsers(boolean)} to false.
138 | *
139 | * @param userId
140 | * The whitelist of users to mention
141 | *
142 | * @return AllowedMentions instance with applied whitelist
143 | */
144 | @NotNull
145 | public AllowedMentions withUsers(@NotNull Collection
This will set {@link #withParseRoles(boolean)} to false.
155 | *
156 | * @param roleId
157 | * The whitelist of roles to mention
158 | *
159 | * @return AllowedMentions instance with applied whitelist
160 | */
161 | @NotNull
162 | public AllowedMentions withRoles(@NotNull Collection
Setting this to {@code true} will clear the whitelist provided by {@link #withUsers(String...)}.
187 | *
188 | * @param allowParseUsers
189 | * True, if all user mentions should be parsed
190 | *
191 | * @return AllowedMentions instance with applied parsing rule
192 | */
193 | @NotNull
194 | public AllowedMentions withParseUsers(boolean allowParseUsers)
195 | {
196 | parseUsers = allowParseUsers;
197 | if (parseUsers)
198 | users.clear();
199 | return this;
200 | }
201 |
202 | /**
203 | * Whether to parse role mentions.
204 | *
Setting this to {@code true} will clear the whitelist provided by {@link #withRoles(String...)}.
205 | *
206 | * @param allowParseRoles
207 | * True, if all role mentions should be parsed
208 | *
209 | * @return AllowedMentions instance with applied parsing rule
210 | */
211 | @NotNull
212 | public AllowedMentions withParseRoles(boolean allowParseRoles)
213 | {
214 | parseRoles = allowParseRoles;
215 | if (parseRoles)
216 | roles.clear();
217 | return this;
218 | }
219 |
220 | @Override
221 | public String toJSONString() {
222 | JSONObject json = new JSONObject();
223 | json.put("parse", new JSONArray());
224 |
225 | if (!users.isEmpty())
226 | json.put("users", users);
227 | else if (parseUsers)
228 | json.accumulate("parse", "users");
229 |
230 | if (!roles.isEmpty())
231 | json.put("roles", roles);
232 | else if (parseRoles)
233 | json.accumulate("parse", "roles");
234 |
235 | if (parseEveryone)
236 | json.accumulate("parse", "everyone");
237 | return json.toString();
238 | }
239 | }
240 |
--------------------------------------------------------------------------------
/src/main/java/club/minnced/discord/webhook/send/MessageAttachment.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2018-2020 Florian Spieß
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package club.minnced.discord.webhook.send;
18 |
19 | import club.minnced.discord.webhook.IOUtil;
20 | import org.jetbrains.annotations.NotNull;
21 |
22 | import java.io.File;
23 | import java.io.FileInputStream;
24 | import java.io.IOException;
25 | import java.io.InputStream;
26 |
27 | /**
28 | * Internal representation of attachments for outgoing messages
29 | */
30 | public class MessageAttachment {
31 | private final String name;
32 | private final byte[] data;
33 |
34 | MessageAttachment(@NotNull String name, @NotNull byte[] data) {
35 | this.name = name;
36 | this.data = data;
37 | }
38 |
39 | MessageAttachment(@NotNull String name, @NotNull InputStream stream) throws IOException {
40 | this.name = name;
41 | try (InputStream data = stream) {
42 | this.data = IOUtil.readAllBytes(data);
43 | }
44 | }
45 |
46 | MessageAttachment(@NotNull String name, @NotNull File file) throws IOException {
47 | this(name, new FileInputStream(file));
48 | }
49 |
50 | @NotNull
51 | public String getName() {
52 | return name;
53 | }
54 |
55 | @NotNull
56 | public byte[] getData() {
57 | return data;
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/src/main/java/club/minnced/discord/webhook/send/WebhookEmbed.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2018-2020 Florian Spieß
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package club.minnced.discord.webhook.send;
18 |
19 | import org.jetbrains.annotations.NotNull;
20 | import org.jetbrains.annotations.Nullable;
21 | import org.json.JSONObject;
22 | import org.json.JSONPropertyIgnore;
23 | import org.json.JSONPropertyName;
24 | import org.json.JSONString;
25 |
26 | import java.time.OffsetDateTime;
27 | import java.util.Collections;
28 | import java.util.List;
29 | import java.util.Objects;
30 |
31 | /**
32 | * Reduced version of an {@link club.minnced.discord.webhook.receive.ReadonlyEmbed}
33 | * used for sending. A webhook can send up to {@value WebhookMessage#MAX_EMBEDS} embeds
34 | * in a single message.
35 | *
36 | * @see club.minnced.discord.webhook.send.WebhookEmbedBuilder
37 | */
38 | public class WebhookEmbed implements JSONString {
39 | /**
40 | * Max amount of fields an embed can hold (25)
41 | */
42 | public static final int MAX_FIELDS = 25;
43 |
44 | private final OffsetDateTime timestamp;
45 | private final Integer color;
46 |
47 | private final String description;
48 | private final String thumbnailUrl;
49 | private final String imageUrl;
50 |
51 | private final EmbedFooter footer;
52 | private final EmbedTitle title;
53 | private final EmbedAuthor author;
54 | private final List
The discord client displays this
97 | * in the correct timezone and locale of the viewing users.
98 | *
99 | * @return Possibly-null {@link java.time.OffsetDateTime} of the timestamp
100 | */
101 | @Nullable
102 | public OffsetDateTime getTimestamp() {
103 | return timestamp;
104 | }
105 |
106 | /**
107 | * The title of the embed, this is displayed
108 | * above the description and below the author.
109 | *
110 | * @return Possibly-null {@link club.minnced.discord.webhook.send.WebhookEmbed.EmbedTitle}
111 | */
112 | @Nullable
113 | @JSONPropertyIgnore
114 | public EmbedTitle getTitle() {
115 | return title;
116 | }
117 |
118 | /**
119 | * The rgb color of this embed.
120 | *
This is the colored line on the left-hand side of the embed.
121 | *
122 | * @return Possibly-null boxed integer of the color
123 | */
124 | @Nullable
125 | public Integer getColor() {
126 | return color;
127 | }
128 |
129 | /**
130 | * The description of this embed
131 | *
132 | * @return Possibly-null description
133 | */
134 | @Nullable
135 | public String getDescription() {
136 | return description;
137 | }
138 |
139 | /**
140 | * The footer of the embed.
141 | *
This is displayed at the very bottom of the embed, left to the timestamp.
142 | *
143 | * @return Possibly-null {@link club.minnced.discord.webhook.send.WebhookEmbed.EmbedFooter}
144 | */
145 | @Nullable
146 | public EmbedFooter getFooter() {
147 | return footer;
148 | }
149 |
150 | /**
151 | * The embed author.
152 | *
This is displayed at the very top of the embed,
153 | * even above the {@link #getTitle()}.
154 | *
155 | * @return Possibly-null {@link club.minnced.discord.webhook.send.WebhookEmbed.EmbedAuthor}
156 | */
157 | @Nullable
158 | public EmbedAuthor getAuthor() {
159 | return author;
160 | }
161 |
162 | /**
163 | * List of fields for this embed.
164 | *
And embed can have up to {@value MAX_FIELDS}.
165 | *
166 | * @return List of fields for this embed
167 | */
168 | @NotNull
169 | public List
An embed can have up to {@value MAX_FIELDS} fields.
227 | * A row of fields can be up 3 wide, or 2 when a thumbnail is configured.
228 | * To be displayed in the same row as other fields, the field has to be set to {@link #isInline() inline}.
229 | */
230 | public static class EmbedField implements JSONString {
231 | private final boolean inline;
232 | private final String name, value;
233 |
234 | /**
235 | * Creates a new embed field
236 | *
237 | * @param inline
238 | * Whether or not this should share a row with other fields
239 | * @param name
240 | * The name of the field
241 | * @param value
242 | * The value of the field
243 | *
244 | * @see club.minnced.discord.webhook.send.WebhookEmbedBuilder#addField(club.minnced.discord.webhook.send.WebhookEmbed.EmbedField)
245 | */
246 | public EmbedField(boolean inline, @NotNull String name, @NotNull String value) {
247 | this.inline = inline;
248 | this.name = Objects.requireNonNull(name);
249 | this.value = Objects.requireNonNull(value);
250 | }
251 |
252 | /**
253 | * Whether this field should share a row with other fields
254 | *
255 | * @return True, if this should be in the same row as other fields
256 | */
257 | public boolean isInline() {
258 | return inline;
259 | }
260 |
261 | /**
262 | * The name of this field.
263 | *
This is displayed above the value in a bold font.
264 | *
265 | * @return The name
266 | */
267 | @NotNull
268 | public String getName() {
269 | return name;
270 | }
271 |
272 | /**
273 | * The value of this field.
274 | *
This is displayed below the name in a regular font.
275 | *
276 | * @return The value
277 | */
278 | @NotNull
279 | public String getValue() {
280 | return value;
281 | }
282 |
283 | /**
284 | * JSON representation of this field
285 | *
286 | * @return The JSON representation
287 | */
288 | @Override
289 | public String toString() {
290 | return toJSONString();
291 | }
292 |
293 | @Override
294 | public String toJSONString() {
295 | return new JSONObject(this).toString();
296 | }
297 | }
298 |
299 | /**
300 | * POJO for an embed author.
301 | *
This can contain an icon (avatar), a name, and a url.
302 | * Often useful for posts from other platforms such as twitter/github.
303 | */
304 | public static class EmbedAuthor implements JSONString {
305 | private final String name, iconUrl, url;
306 |
307 | /**
308 | * Creates a new embed author
309 | *
310 | * @param name
311 | * The name of the author
312 | * @param iconUrl
313 | * The (nullable) icon url of the author
314 | * @param url
315 | * The (nullable) hyperlink of the author
316 | *
317 | * @see club.minnced.discord.webhook.send.WebhookEmbedBuilder#setAuthor(club.minnced.discord.webhook.send.WebhookEmbed.EmbedAuthor)
318 | */
319 | public EmbedAuthor(@NotNull String name, @Nullable String iconUrl, @Nullable String url) {
320 | this.name = Objects.requireNonNull(name);
321 | this.iconUrl = iconUrl;
322 | this.url = url;
323 | }
324 |
325 | /**
326 | * The name of the author, this is the only visible text of this component.
327 | *
328 | * @return The name
329 | */
330 | @NotNull
331 | public String getName() {
332 | return name;
333 | }
334 |
335 | /**
336 | * The iconUrl of this author.
337 | *
This is displayed left to the name, similar to messages in discord.
338 | *
339 | * @return Possibly-null iconUrl url
340 | */
341 | @Nullable
342 | @JSONPropertyName("icon_url")
343 | public String getIconUrl() {
344 | return iconUrl;
345 | }
346 |
347 | /**
348 | * The url of this author.
349 | *
This can be used to highlight the name as a hyperlink
350 | * to the platform's profile service.
351 | *
352 | * @return Possibly-null url
353 | */
354 | @Nullable
355 | public String getUrl() {
356 | return url;
357 | }
358 |
359 | /**
360 | * JSON representation of this author
361 | *
362 | * @return The JSON representation
363 | */
364 | @Override
365 | public String toString() {
366 | return toJSONString();
367 | }
368 |
369 | @Override
370 | public String toJSONString() {
371 | return new JSONObject(this).toString();
372 | }
373 | }
374 |
375 | /**
376 | * POJO for an embed footer.
377 | *
Useful to display meta-data about context such as
378 | * for a github comment a repository name/icon.
379 | */
380 | public static class EmbedFooter implements JSONString {
381 | private final String text, icon;
382 |
383 | /**
384 | * Creates a new embed footer
385 | *
386 | * @param text
387 | * The visible text of the footer
388 | * @param icon
389 | * The (nullable) icon url of the footer
390 | *
391 | * @see club.minnced.discord.webhook.send.WebhookEmbedBuilder#setFooter(club.minnced.discord.webhook.send.WebhookEmbed.EmbedFooter)
392 | */
393 | public EmbedFooter(@NotNull String text, @Nullable String icon) {
394 | this.text = Objects.requireNonNull(text);
395 | this.icon = icon;
396 | }
397 |
398 | /**
399 | * The visible text of the footer.
400 | *
401 | * @return The text
402 | */
403 | @NotNull
404 | public String getText() {
405 | return text;
406 | }
407 |
408 | /**
409 | * The url for the icon of this footer
410 | *
411 | * @return Possibly-null icon url
412 | */
413 | @Nullable
414 | @JSONPropertyName("icon_url")
415 | public String getIconUrl() {
416 | return icon;
417 | }
418 |
419 | /**
420 | * JSON representation of this footer
421 | *
422 | * @return The JSON representation
423 | */
424 | @Override
425 | public String toString() {
426 | return toJSONString();
427 | }
428 |
429 | @Override
430 | public String toJSONString() {
431 | return new JSONObject(this).toString();
432 | }
433 | }
434 |
435 | /**
436 | * POJO for an embed title.
437 | *
This is displayed above description and below the embed author.
438 | */
439 | public static class EmbedTitle {
440 | private final String text, url;
441 |
442 | /**
443 | * Creates a new embed title
444 | *
445 | * @param text
446 | * The visible text
447 | * @param url
448 | * The (nullable) hyperlink
449 | *
450 | * @see club.minnced.discord.webhook.send.WebhookEmbedBuilder#setTitle(club.minnced.discord.webhook.send.WebhookEmbed.EmbedTitle)
451 | */
452 | public EmbedTitle(@NotNull String text, @Nullable String url) {
453 | this.text = Objects.requireNonNull(text);
454 | this.url = url;
455 | }
456 |
457 | /**
458 | * The visible text of this title
459 | *
460 | * @return The visible text
461 | */
462 | @NotNull
463 | public String getText() {
464 | return text;
465 | }
466 |
467 | /**
468 | * The hyperlink for this title.
469 | *
470 | * @return Possibly-null url
471 | */
472 | @Nullable
473 | public String getUrl() {
474 | return url;
475 | }
476 |
477 | /**
478 | * JSON representation of this title
479 | *
480 | * @return The JSON representation
481 | */
482 | @Override
483 | public String toString() {
484 | return new JSONObject(this).toString();
485 | }
486 | }
487 | }
488 |
--------------------------------------------------------------------------------
/src/main/java/club/minnced/discord/webhook/util/ThreadPools.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2018-2020 Florian Spieß
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package club.minnced.discord.webhook.util;
18 |
19 | import java.util.concurrent.Executors;
20 | import java.util.concurrent.ScheduledExecutorService;
21 | import java.util.concurrent.ThreadFactory;
22 |
23 | public class ThreadPools { // internal utils
24 | public static ScheduledExecutorService getDefaultPool(long id, ThreadFactory factory, boolean isDaemon) {
25 | return Executors.newSingleThreadScheduledExecutor(factory == null ? new DefaultWebhookThreadFactory(id, isDaemon) : factory);
26 | }
27 |
28 | public static final class DefaultWebhookThreadFactory implements ThreadFactory {
29 | private final long id;
30 | private final boolean isDaemon;
31 |
32 | public DefaultWebhookThreadFactory(long id, boolean isDaemon) {
33 | this.id = id;
34 | this.isDaemon = isDaemon;
35 | }
36 |
37 | @Override
38 | public Thread newThread(Runnable r) {
39 | final Thread thread = new Thread(r, "Webhook-RateLimit Thread WebhookID: " + id);
40 | thread.setDaemon(isDaemon);
41 | return thread;
42 | }
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/main/java/club/minnced/discord/webhook/util/WebhookErrorHandler.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2018-2020 Florian Spieß
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package club.minnced.discord.webhook.util;
18 |
19 | import club.minnced.discord.webhook.WebhookClient;
20 | import org.jetbrains.annotations.NotNull;
21 | import org.jetbrains.annotations.Nullable;
22 | import org.slf4j.LoggerFactory;
23 |
24 | /**
25 | * Used to dynamically handle errors for webhook requests in {@link WebhookClient}
26 | *
If not explicitly configured, this uses {@link #DEFAULT}.
27 | *
28 | * @see WebhookClient#setDefaultErrorHandler(WebhookErrorHandler)
29 | * @see WebhookClient#setErrorHandler(WebhookErrorHandler)
30 | */
31 | @FunctionalInterface
32 | public interface WebhookErrorHandler {
33 | /**
34 | * The default error handling which simply logs the exception using SLF4J
35 | */
36 | WebhookErrorHandler DEFAULT = (client, message, throwable) -> LoggerFactory.getLogger(WebhookClient.class).error(message, throwable);
37 |
38 | /**
39 | * Implements error handling, must not throw anything!
40 | *
41 | * @param client
42 | * The {@link WebhookClient} instance which encountered the exception
43 | * @param message
44 | * The context message used for logging
45 | * @param throwable
46 | * The encountered exception, or null if the error is only a context message
47 | */
48 | void handle(@NotNull WebhookClient client, @NotNull String message, @Nullable Throwable throwable);
49 | }
50 |
--------------------------------------------------------------------------------
/src/test/java/root/IOTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2018-2020 Florian Spieß
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package root;
18 |
19 | import club.minnced.discord.webhook.IOUtil;
20 | import org.junit.*;
21 |
22 | import java.io.File;
23 | import java.io.FileInputStream;
24 | import java.io.IOException;
25 | import java.nio.file.Files;
26 | import java.nio.file.StandardOpenOption;
27 | import java.util.concurrent.ThreadLocalRandom;
28 |
29 | public class IOTest {
30 | public static String CONTENT;
31 | private File tempFile;
32 |
33 | @BeforeClass
34 | public static void randomContent() {
35 | ThreadLocalRandom random = ThreadLocalRandom.current();
36 | int size = random.nextInt(4098);
37 | StringBuilder builder = new StringBuilder(size);
38 | for (int i = 0; i < size; i++) {
39 | builder.append(random.nextInt());
40 | }
41 | CONTENT = builder.toString();
42 | }
43 |
44 | @Before
45 | public void setup() throws IOException {
46 | tempFile = File.createTempFile("test", "Data");
47 | Files.write(tempFile.toPath(), CONTENT.getBytes(), StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING);
48 | }
49 |
50 | @After
51 | public void cleanup() {
52 | tempFile.delete();
53 | }
54 |
55 | @Test
56 | public void readAll() throws IOException {
57 | String content = new String(IOUtil.readAllBytes(new FileInputStream(tempFile)));
58 | Assert.assertEquals(CONTENT, content);
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/src/test/java/root/IOTestUtil.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2018-2020 Florian Spieß
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package root;
18 |
19 | import okhttp3.*;
20 | import okio.Buffer;
21 | import okio.Timeout;
22 |
23 | import java.io.ByteArrayOutputStream;
24 | import java.io.IOException;
25 | import java.nio.charset.StandardCharsets;
26 | import java.util.Collections;
27 | import java.util.HashMap;
28 | import java.util.Map;
29 | import java.util.regex.Matcher;
30 | import java.util.regex.Pattern;
31 | import java.util.zip.GZIPOutputStream;
32 |
33 | @SuppressWarnings("deprecation")
34 | public class IOTestUtil {
35 |
36 | public static boolean isMultiPart(RequestBody body) {
37 | return getBoundary(body) != null;
38 | }
39 |
40 | public static String readRequestBody(RequestBody body) throws IOException {
41 | Buffer sink = new Buffer();
42 | body.writeTo(sink);
43 | ByteArrayOutputStream bos = new ByteArrayOutputStream();
44 | sink.copyTo(bos);
45 | return new String(bos.toByteArray(), 0, bos.size(), StandardCharsets.UTF_8);
46 | }
47 |
48 | private static final Pattern CONTENT_DISPOSITION_PATTERN =
49 | Pattern.compile("^Content-Disposition: form-data; name=\"([^\"]+)\"(?:; filename=\"([^\"]+)\")?$");
50 | private static final String validFileContent = "Content-Type: application/octet-stream; charset=utf-8";
51 |
52 | public static Map