gizmo385 / discord.clj Goto Github PK
View Code? Open in Web Editor NEWA Clojure library for creating Discord bots
License: MIT License
A Clojure library for creating Discord bots
License: MIT License
When triggering the <prefix>help
command (auto-handled by the library), it sends two messages instead of one.
My core code is
(ns disclojure.core
(:gen-class)
(:require [discord.bot :as bot]))
(defn -main
"Boots the bot."
[& _]
(bot/start))
Is there a way to change the bot's config file location before starting it?
E.g. to instead load data/settings.json
.
Trying to set up a notifications bot using this library. Not sure if I'm missing an import or something?
(ns gcloud-monitoring.core
(:require [ring.adapter.jetty :refer [run-jetty]]
[ring.util.request]
[clojure.data.json :as json]
[discord.http]
[discord.bot :as bot]
[discord.types]))
(bot/create-bot "CloudNotifications"
"!"
(discord.types/configuration-auth)) => Execution error (NoClassDefFoundError) at org.eclipse.jetty.websocket.common.extensions.fragment.FragmentExtension/<init> (FragmentExtension.java:44).
Currently, when extensions are declared, information about those extensions, handlers, and their relevant documentation is maintained in a series of global atoms. This isn't ideal and can cause confusion (see #10) where extensions can be duplicated if files are reloaded without properly clearing out the global atoms.
Ideally, I think we should try and remove this from global state. At the moment, I don't have a great solution to this problem and would love input from others :)
Basically what the title says. I'm new to clojure, so I rely on documentation to understand where bugs are coming from. In my testing of this API, I've been running into seemingly simple bugs that I don't understand the nature of, and the lack current documentation definitely doesn't help.
When I get better, maybe I could help with documentation, but because it's done via the permlocked wiki, I can't controbute through a pull request or something.
If I try to call the close method on an instance of discord.bot.DiscordBot
, I get the error IllegalArgumentException No implementation of method: :close of protocol: #'gniazdo.core/Client found for class: clojure.lang.Atom clojure.core/-cache-protocol-fn (core_deftype.clj:583)
.
I believe the reason is that https://github.com/gizmo385/discord.clj/blob/master/src/discord/gateway.clj#L52 should deref the websocket atom with (ws/close @(:websocket this))
. I'd be happy to submit a PR, but it seems a little silly for such a small change.
Thanks for all the work you've put into this! ๐
I have a custom handler that handles a set of "formats".
I'd like to document them.
In bot.clj I found about register-extension-docs!
, which seems to be for this exact purpose, but... How do one actually use it?
I tried a primitive code with typings as (register-extension-docs! "" "")
(with actual values), but I get a HTTP 400 error, with the following body:
:body "{\"embed\": [\"fields\"]}"
(defn start
"Starts the bot asynchronously."
[]
(dosync
(bot/load-extension-folders!)
(ref
(bot/create-bot (config/get-bot-name) (config/get-prefix)))))
(defn stop
"Stops the bot."
[client]
(.close @client))
...
(bot/defcommand working
[client message]
"Posts the Star Wars Episode 1 'It's working' gif in the channel"
(bot/say "https://giphy.com/gifs/9K2nFglCAQClO"))
If I start a bot and call !working it responds perfectly. If I stop that bot and start another, when I call !working it posts the same response twice. If you do it again you get 3 responses and so on. Am I not stopping correctly? I'm relatively new to clojure (and nearly entirely new to discord.clj) so apologies if I'm missing something basic!
Also, thanks for making this!
I am getting an HTTP 400 quite randomly when I send some messages. Its reproducible at will though.
20-06-08 16:41:21 gimli ERROR [discord.client:77] - Error sending message:
clojure.lang.ExceptionInfo: clj-http: status 400
{:cached nil, :request-time 472, :repeatable? false,
:protocol-version {:name "HTTP", :major 1, :minor 1},
:streaming? true,
:http-client #object[org.apache.http.impl.client.InternalHttpClient 0x45bff638 "org.apache.http.impl.client.InternalHttpClient@45bff638"],
:chunked? false,
:type :clj-http.client/unexceptional-status,
:reason-phrase "Bad Request",
:headers {"x-envoy-upstream-service-time" "9",
"Server" "cloudflare",
"x-ratelimit-reset-after" "5",
"Via" "1.1 google",
"Content-Type" "application/json",
"Content-Length" "21",
"strict-transport-security" "max-age=31536000; includeSubDomains",
"x-ratelimit-limit" "5",
"x-ratelimit-remaining" "4",
"x-ratelimit-reset" "1591634487",
"x-ratelimit-bucket" "80c17d2f203122d936070c88c8d10f33",
"Connection" "close",
"cf-request-id" "033667e7180000df4b73824200000001",
"Set-Cookie" ["__cfduid=d646323f023029fc337c7d79d9e1eed701591634480; expires=Wed, 08-Jul-20 16:41:20 GMT; path=/; domain=.discordapp.com; HttpOnly; SameSite=Lax" "__cfruid=8b7f57ba621570e90aaa72ecff2886c33d034cd0-1591634481; path=/; domain=.discordapp.com; HttpOnly; Secure; SameSite=None"],
"Expect-CT" "max-age=604800, report-uri=\"https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct\"", "CF-Cache-Status" "DYNAMIC", "CF-RAY" "5a040f51c9dbdf4b-BOM", "Date" "Mon, 08 Jun 2020 16:41:21 GMT"
},
:orig-content-encoding nil,
:status 400,
:length 21,
:body "{\"embed\": [\"fields\"]}", :trace-redirects []
}
discord.http/logs-from
returns all results regardless of the limit supplied. I haven't checked this that thoroughly, I only had 16 messages and it returned all when I tried limit as 0, 1, 2, or 50.
My bot running on my prod machine, once disconnected stays offline forever
[discord.gateway:111] - Event of Type: :reconnect
[discord.gateway:258] - Closing Gateway websocket, not reconnecting (1001).
Exception in thread "async-dispatch-1" org.eclipse.jetty.websocket.api.WebSocketException: RemoteEndpoint unavailable, current state [CLOSED], expecting [OPEN or CONNECTED]
at org.eclipse.jetty.websocket.common.WebSocketSession.getRemote(WebSocketSession.java:299)
Once this happens, it would be nice if we could periodically try to reconnect and go back online when you could.
Once again, I'm new to clojure, so bear with me. I tried looking for logic errors, but there's so much that I don't understand, I'd have to come back with a better understanding of the language.
Here's my core file:
(ns devbot.core
(:require [discord.bot :as bot]
[discord.http :as http]
[discord.config :as config])
(:gen-class))
(defn say
"Repeats the message back to the user"
[client message]
(bot/say (:content message)))
(bot/defcommand ping [_ _]
"Ping!"
(bot/say "Pong!"))
(defn -main
"Creates a new discord bot and supplies a series of extensions to it."
[& args]
(let [bot-name (config/get-bot-name)
prefix (config/get-prefix)]
(bot/with-extensions bot-name prefix
:say say)))
Sorry about the formatting, IntelliJ was sorta mangling the tabbing and spacing.
I've been trying to test the use of inline command definitions and macros. In my testing, the bot worked perfectly with the say command, but not with the ping command. On top of that, standard builtins like the help
command doesn't work correctly with say, nor with any functions. The commands simply pass the bot by, with no exceptions or anything printed out onto the screen.
The docs only cover message receiving, but there are other events as well. Can the docs cover events like user joining/leaving server, bot joining/leaving server and other useful events as well?
The go-loops at https://github.com/gizmo385/discord.clj/blob/master/src/discord/client.clj#L63-L78 need to check for when their respective channels have been closed to stop recurring. As it is now, once these channels are closed, the go-loops will take nil values forever. To verify the behavior, you can do this at the repl:
=> (require '[clojure.core.async :as a])
nil
=> (def c (a/chan))
#'discord.core/c
=> (a/go-loop [] (let [v (a/<! c)] (println v) (recur)))
#object[clojure.core.async.impl.channels.ManyToManyChannel 0x55d32427 "clojure.core.async.impl.channels.ManyToManyChannel@55d32427"]
=> (a/>!! c "hello")
hello
true
=> (a/close! c)
nil
nil
nil
...
I'll put up a PR with what I think is a reasonable fix. Appreciate the work you've put into this project!
The server that hosts my bot that uses your library often disconnects. This causes an error above 1001. Right now the bot doesn't reconnect or exit the program. https://github.com/gizmo385/discord.clj/blob/master/src/discord/gateway.clj#L258 which causes my bot to hang and then i have to log into my server and restart it manually.
WARN [discord.gateway:259] - Closing Gateway websocket, not reconnecting (1006).
Exception in thread "async-dispatch-7" org.eclipse.jetty.websocket.api.WebSocketException: RemoteEndpoint unavailable, current state [CLOSED], expecting [OPEN or CONNECTED]
at org.eclipse.jetty.websocket.common.WebSocketSession.getRemote(WebSocketSession.java:299)
at gniazdo.core$connect_with_client$reify__11265.send_msg(core.clj:138)
at discord.gateway.DiscordGateway.send_message(gateway.clj:62)
at discord.gateway$send_heartbeat.invokeStatic(gateway.clj:204)
at discord.gateway$send_heartbeat.invoke(gateway.clj:202)
at discord.gateway$connect_to_gateway$fn__15913$state_machine__5591__auto____15932$fn__15934.invoke(gateway.clj:292)
at discord.gateway$connect_to_gateway$fn__15913$state_machine__5591__auto____15932.invoke(gateway.clj:292)
at clojure.core.async.impl.ioc_macros$run_state_machine.invokeStatic(ioc_macros.clj:973)
at clojure.core.async.impl.ioc_macros$run_state_machine.invoke(ioc_macros.clj:972)
at clojure.core.async.impl.ioc_macros$run_state_machine_wrapped.invokeStatic(ioc_macros.clj:977)
at clojure.core.async.impl.ioc_macros$run_state_machine_wrapped.invoke(ioc_macros.clj:975)
at clojure.core.async$ioc_alts_BANG_$fn__5794.invoke(async.clj:384)
at clojure.core.async$do_alts$fn__5740$fn__5743.invoke(async.clj:253)
at clojure.core.async.impl.channels.ManyToManyChannel$fn__509.invoke(channels.clj:265)
at clojure.lang.AFn.run(AFn.java:22)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
^C
I made the changes
(if (> 1001 status)
(do
(timbre/warnf "Socket closed for unexpected reason (%d): %s" status reason)
(timbre/warnf "Attempting to reconnect to websocket...")
(reconnect-gateway gateway))
(do (timbre/warnf "Closing Gateway websocket, not reconnecting (%d)." status)
(System/exit 1)))
which causes the program to exit if an abnormal error occurs.
WARN [discord.gateway:259] - Closing Gateway websocket, not reconnecting (1006).
Exception in thread "async-dispatch-6" org.eclipse.jetty.websocket.api.WebSocketException: RemoteEndpoint unavailable, current state [CLOSED], expecting [OPEN or CONNECTED]
at org.eclipse.jetty.websocket.common.WebSocketSession.getRemote(WebSocketSession.java:299)
at gniazdo.core$connect_with_client$reify__11265.send_msg(core.clj:138)
at discord.gateway.DiscordGateway.send_message(gateway.clj:62)
at discord.gateway$send_heartbeat.invokeStatic(gateway.clj:204)
at discord.gateway$send_heartbeat.invoke(gateway.clj:202)
at discord.gateway$connect_to_gateway$fn__15913$state_machine__5591__auto____15932$fn__15934.invoke(gateway.clj:293)
at discord.gateway$connect_to_gateway$fn__15913$state_machine__5591__auto____15932.invoke(gateway.clj:293)
at clojure.core.async.impl.ioc_macros$run_state_machine.invokeStatic(ioc_macros.clj:973)
at clojure.core.async.impl.ioc_macros$run_state_machine.invoke(ioc_macros.clj:972)
at clojure.core.async.impl.ioc_macros$run_state_machine_wrapped.invokeStatic(ioc_macros.clj:977)
at clojure.core.async.impl.ioc_macros$run_state_machine_wrapped.invoke(ioc_macros.clj:975)
at clojure.core.async$ioc_alts_BANG_$fn__5794.invoke(async.clj:384)
at clojure.core.async$do_alts$fn__5740$fn__5743.invoke(async.clj:253)
at clojure.core.async.impl.channels.ManyToManyChannel$fn__509.invoke(channels.clj:265)
at clojure.lang.AFn.run(AFn.java:22)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
2020-04-03 22:42:58.216:WARN:oejut.QueuedThreadPool:Thread-2: WebSocketClient@282234594{STOPPING,8<=8<=200,i=0,q=1} Couldn't stop Thread[WebSocketClient@282234594-13,5,main]
is it all right if i make a PR?
After closing the gateway (and its websocket), the heartbeat loop continues running, resulting in this error a bit afterwards:
Exception in thread "async-dispatch-9" org.eclipse.jetty.websocket.api.WebSocketException: RemoteEndpoint unavailable, current state [CLOSED], expecting [OPEN or CONNECTED]
at org.eclipse.jetty.websocket.common.WebSocketSession.getRemote(WebSocketSession.java:299)
at gniazdo.core$connect_with_client$reify__20760.send_msg(core.clj:138)
at discord.gateway.DiscordGateway.send_message(gateway.clj:62)
at discord.gateway$send_heartbeat.invokeStatic(gateway.clj:205)
at discord.gateway$send_heartbeat.invoke(gateway.clj:203)
at discord.gateway$connect_to_gateway$fn__25400$state_machine__13838__auto____25417$fn__25419.invoke(gateway.clj:292)
at discord.gateway$connect_to_gateway$fn__25400$state_machine__13838__auto____25417.invoke(gateway.clj:292)
at clojure.core.async.impl.ioc_macros$run_state_machine.invokeStatic(ioc_macros.clj:973)
at clojure.core.async.impl.ioc_macros$run_state_machine.invoke(ioc_macros.clj:972)
at clojure.core.async.impl.ioc_macros$run_state_machine_wrapped.invokeStatic(ioc_macros.clj:977)
at clojure.core.async.impl.ioc_macros$run_state_machine_wrapped.invoke(ioc_macros.clj:975)
at clojure.core.async.impl.ioc_macros$take_BANG_$fn__13856.invoke(ioc_macros.clj:986)
at clojure.core.async.impl.channels.ManyToManyChannel$fn__8788.invoke(channels.clj:265)
at clojure.lang.AFn.run(AFn.java:22)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
I'm happy to submit a PR fixing this if you'd like.
I'm looking to set up a reminder such that the bot will post a message to a specific channel on a specific server on a schedule.
I see that say
needs to be called within the context of build-handler-fn
and can't specify a channel directly. I also see that say*
looks like it can specify a channel but is private. I tried debugging to check out a message
's channel
and saw that it only had an id
. Could I potentially use that id or just save that entire channel
object if I tried to make a say
function that worked outside of build-handler-fn
?
Is there already a way to do what I'm looking for or maybe there's a better way to go about it?
Thanks!
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.