Coder Social home page Coder Social logo

katrix / ackcord Goto Github PK

View Code? Open in Web Editor NEW
111.0 7.0 15.0 24.51 MB

A Discord library for Scala using Akka

Home Page: https://ackcord.katsstuff.net/

License: MIT License

Scala 93.76% Batchfile 0.14% JavaScript 1.77% TypeScript 4.33%
discord discord-api scala akka discord-library hacktoberfest

ackcord's Introduction

AckCord

Do what you want, exactly how you want it.

AckCord is a Scala Discord library powered by sttp. AckCord's focus is on letting you choose the level of abstraction you want, without sacrificing speed. Want to work with the raw events from the gateway? Works for that. Maybe you don't want to bother with any of the underlying implementation and technicalities. Works for that too. Only interested in the REST requests? Pull in that module and ignore the rest. AckCord is fast, reactive, modular, and clean, focusing on letting you write good code.

AckCord 2.X is currently in early development, and artifacts have not yet been published.

Lastly, join our Discord server (we got cookies).

'

License

AckCord itself is licensed under the MIT license (see LICENSE). AckCord uses a lot of content from the official Discord API documentation (made by Discord) for its ScalaDocs, and as such, AckCord's ScalaDocs documentation is licensed under the Creative Commons Attribution-ShareAlike 4.0 License (see LICENSE-SCALADOC).

ackcord's People

Contributors

katrix avatar yomanz avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

ackcord's Issues

RawChannel has no entry in CacheTypeRegistry

18:05:21.518 [AckCord-akka.actor.default-dispatcher-14] DEBUG a.cachehandlers.CacheTypeRegistry - updater not found
java.lang.Exception: No updater found for class ackcord.data.raw.RawChannel
at ackcord.cachehandlers.CacheTypeRegistry.getWithData(CacheTypeRegistry.scala:64)
at ackcord.cachehandlers.CacheTypeRegistry.handleWithData(CacheTypeRegistry.scala:46)
at ackcord.cachehandlers.CacheTypeRegistry.updateData(CacheTypeRegistry.scala:49)
at ackcord.cachehandlers.CacheHandlers$$anon$22.$anonfun$handle$202(CacheHandlers.scala:662)
at ackcord.cachehandlers.CacheHandlers$$anon$22.$anonfun$handle$202$adapted(CacheHandlers.scala:662)
at ackcord.util.JsonSome.foreach(JsonOption.scala:100)
at ackcord.cachehandlers.CacheHandlers$$anon$22.handle(CacheHandlers.scala:662)
at ackcord.cachehandlers.CacheHandlers$$anon$22.handle(CacheHandlers.scala:574)
at ackcord.APIMessageCacheUpdate.process(cacheUpdates.scala:68)
at ackcord.CacheStreams$.$anonfun$cacheUpdater$2(CacheStreams.scala:254)
at akka.stream.impl.fusing.StatefulMapConcat$$anon$49.onPush(Ops.scala:2238)
at akka.stream.impl.fusing.GraphInterpreter.processPush(GraphInterpreter.scala:542)
at akka.stream.impl.fusing.GraphInterpreter.processEvent(GraphInterpreter.scala:496)
at akka.stream.impl.fusing.GraphInterpreter.execute(GraphInterpreter.scala:390)
at akka.stream.impl.fusing.GraphInterpreterShell.runBatch(ActorGraphInterpreter.scala:650)
at akka.stream.impl.fusing.GraphInterpreterShell$AsyncInput.execute(ActorGraphInterpreter.scala:521)
at akka.stream.impl.fusing.GraphInterpreterShell.processEvent(ActorGraphInterpreter.scala:625)
at akka.stream.impl.fusing.ActorGraphInterpreter.akka$stream$impl$fusing$ActorGraphInterpreter$$processEvent(ActorGraphInterpreter.scala:800)
at akka.stream.impl.fusing.ActorGraphInterpreter$$anonfun$receive$1.applyOrElse(ActorGraphInterpreter.scala:818)
at akka.actor.Actor.aroundReceive(Actor.scala:537)
at akka.actor.Actor.aroundReceive$(Actor.scala:535)
at akka.stream.impl.fusing.ActorGraphInterpreter.aroundReceive(ActorGraphInterpreter.scala:716)
at akka.actor.ActorCell.receiveMessage(ActorCell.scala:580)
at akka.actor.ActorCell.invoke(ActorCell.scala:548)
at akka.dispatch.Mailbox.processMailbox(Mailbox.scala:270)
at akka.dispatch.Mailbox.run(Mailbox.scala:231)
at akka.dispatch.Mailbox.exec(Mailbox.scala:243)
at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:373)
at java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1182)
at java.base/java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1655)
at java.base/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1622)
at java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:165)

I think it's because discord have added a new Channel type causing a RawChannel to get through.

It can be fixed by adding classOf[RawChannel] -> CacheUpdater.dummy[RawChannel](shouldBeIgnored = true) and classOf[RawChannel] -> CacheDeleter.dummy[RawChannel](shouldBeIgnored = true) to your own CacheTypeRegistry when creating Events.

DecodingFailure at .t: Invalid message type

Unfortunately I have no idea which message caused it. I'll try to add more details as soon as I discover some new details about it.

Valid login. Going to active. Response: HttpEntity.Strict(none/none,0 bytes total)
Error in stream: ackcord.gateway.GatewayJsonException: DecodingFailure at .t: Invalid message type
	at ackcord.gateway.GatewayHandlerGraphStage$$anonfun$1.applyOrElse(GatewayHandlerGraphStage.scala:217)
	at ackcord.gateway.GatewayHandlerGraphStage$$anonfun$1.applyOrElse(GatewayHandlerGraphStage.scala:215)
	at akka.stream.impl.fusing.Collect$$anon$6.$anonfun$wrappedPf$1(Ops.scala:242)
	at akka.stream.impl.fusing.SupervisedGraphStageLogic.withSupervision(Ops.scala:201)
	at akka.stream.impl.fusing.Collect$$anon$6.onPush(Ops.scala:244)
	at akka.stream.impl.fusing.GraphInterpreter.processPush(GraphInterpreter.scala:541)
	at akka.stream.impl.fusing.GraphInterpreter.execute(GraphInterpreter.scala:423)
	at akka.stream.impl.fusing.GraphInterpreterShell.runBatch(ActorGraphInterpreter.scala:625)
	at akka.stream.impl.fusing.GraphInterpreterShell$AsyncInput.execute(ActorGraphInterpreter.scala:502)
	at akka.stream.impl.fusing.GraphInterpreterShell.processEvent(ActorGraphInterpreter.scala:600)
	at akka.stream.impl.fusing.ActorGraphInterpreter.akka$stream$impl$fusing$ActorGraphInterpreter$$processEvent(ActorGraphInterpreter.scala:769)
	at akka.stream.impl.fusing.ActorGraphInterpreter.akka$stream$impl$fusing$ActorGraphInterpreter$$shortCircuitBatch(ActorGraphInterpreter.scala:759)
	at akka.stream.impl.fusing.ActorGraphInterpreter$$anonfun$receive$1.applyOrElse(ActorGraphInterpreter.scala:785)
	at akka.actor.Actor.aroundReceive(Actor.scala:535)
	at akka.actor.Actor.aroundReceive$(Actor.scala:533)
	at akka.stream.impl.fusing.ActorGraphInterpreter.aroundReceive(ActorGraphInterpreter.scala:691)
	at akka.actor.ActorCell.receiveMessage(ActorCell.scala:577)
	at akka.actor.ActorCell.invoke(ActorCell.scala:547)
	at akka.dispatch.Mailbox.processMailbox(Mailbox.scala:270)
	at akka.dispatch.Mailbox.run(Mailbox.scala:231)
	at akka.dispatch.Mailbox.exec(Mailbox.scala:243)
	at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:290)
	at java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1016)
	at java.base/java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1665)
	at java.base/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1598)
	at java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:183)
Caused by: io.circe.DecodingFailure$$anon$2: Invalid message type: DownField(t)

AckCord: 0.17.1

Ping command in example bot shouldn't take any arguments

I tried the example bot, successfully connected it to my discord server but none of the implemented command work (!ping etc), the only thing that work is when i private message the bot, it reply back to me.
Any ideas of what could be the problem ?
Thanks in advance.

Error in stage Upstream producer failed with exception, removing from MergeHub now

I have a bot running that has been printing this error several times, any suggestions to prevent it?

2020-07-12 09:59:25,391 [ERROR] from akka.actor.RepointableActorRef in AckCord-akka.actor.default-dispatcher-5272 - Error in stage [akka.stream.scaladsl.MergeHub$$anon$2@2b900b4e]: Upstream producer failed with exception, removing from MergeHub now
akka.http.scaladsl.model.ws.PeerClosedConnectionException: Peer closed connection with code 4000 'Unknown error.'
	at akka.http.impl.engine.ws.WebSocket$PrepareForUserHandler$$anon$1.onPush(WebSocket.scala:115)
	at akka.stream.impl.fusing.GraphInterpreter.processPush(GraphInterpreter.scala:541)
	at akka.stream.impl.fusing.GraphInterpreter.processEvent(GraphInterpreter.scala:495)
	... 20 common frames omitted
Wrapped by: akka.stream.scaladsl.MergeHub$ProducerFailed: Upstream producer failed with exception, removing from MergeHub now
	at akka.stream.scaladsl.MergeHub$$anon$2$$anon$3.onUpstreamFailure(Hub.scala:276)
	at akka.stream.impl.fusing.GraphInterpreter.processEvent(GraphInterpreter.scala:524)
	at akka.stream.impl.fusing.GraphInterpreter.execute(GraphInterpreter.scala:390)
	at akka.stream.impl.fusing.GraphInterpreterShell.runBatch(ActorGraphInterpreter.scala:624)
	at akka.stream.impl.fusing.ActorGraphInterpreter$SimpleBoundaryEvent.execute(ActorGraphInterpreter.scala:55)
	at akka.stream.impl.fusing.ActorGraphInterpreter$SimpleBoundaryEvent.execute$(ActorGraphInterpreter.scala:51)
	at akka.stream.impl.fusing.ActorGraphInterpreter$BatchingActorInputBoundary$OnNext.execute(ActorGraphInterpreter.scala:94)
	at akka.stream.impl.fusing.GraphInterpreterShell.processEvent(ActorGraphInterpreter.scala:599)
	at akka.stream.impl.fusing.ActorGraphInterpreter.akka$stream$impl$fusing$ActorGraphInterpreter$$processEvent(ActorGraphInterpreter.scala:768)
	at akka.stream.impl.fusing.ActorGraphInterpreter$$anonfun$receive$1.applyOrElse(ActorGraphInterpreter.scala:783)
	at akka.actor.Actor.aroundReceive(Actor.scala:534)
	at akka.actor.Actor.aroundReceive$(Actor.scala:532)
	at akka.stream.impl.fusing.ActorGraphInterpreter.aroundReceive(ActorGraphInterpreter.scala:690)
	at akka.actor.ActorCell.receiveMessage(ActorCell.scala:573)
	at akka.actor.ActorCell.invoke(ActorCell.scala:543)
	at akka.dispatch.Mailbox.processMailbox(Mailbox.scala:269)
	at akka.dispatch.Mailbox.run(Mailbox.scala:230)
	at akka.dispatch.Mailbox.exec(Mailbox.scala:242)
	at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:289)
	at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1056)
	at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1692)
	at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157)
akka.stream.scaladsl.MergeHub$ProducerFailed: Upstream producer failed with exception, removing from MergeHub now
	at akka.stream.scaladsl.MergeHub$$anon$2$$anon$3.onUpstreamFailure(Hub.scala:276)
	at akka.stream.impl.fusing.GraphInterpreter.processEvent(GraphInterpreter.scala:524)
	at akka.stream.impl.fusing.GraphInterpreter.execute(GraphInterpreter.scala:390)
	at akka.stream.impl.fusing.GraphInterpreterShell.runBatch(ActorGraphInterpreter.scala:624)
	at akka.stream.impl.fusing.ActorGraphInterpreter$SimpleBoundaryEvent.execute(ActorGraphInterpreter.scala:55)
	at akka.stream.impl.fusing.ActorGraphInterpreter$SimpleBoundaryEvent.execute$(ActorGraphInterpreter.scala:51)
	at akka.stream.impl.fusing.ActorGraphInterpreter$BatchingActorInputBoundary$OnNext.execute(ActorGraphInterpreter.scala:94)
	at akka.stream.impl.fusing.GraphInterpreterShell.processEvent(ActorGraphInterpreter.scala:599)
	at akka.stream.impl.fusing.ActorGraphInterpreter.akka$stream$impl$fusing$ActorGraphInterpreter$$processEvent(ActorGraphInterpreter.scala:768)
	at akka.stream.impl.fusing.ActorGraphInterpreter$$anonfun$receive$1.applyOrElse(ActorGraphInterpreter.scala:783)
	at akka.actor.Actor.aroundReceive(Actor.scala:534)
	at akka.actor.Actor.aroundReceive$(Actor.scala:532)
	at akka.stream.impl.fusing.ActorGraphInterpreter.aroundReceive(ActorGraphInterpreter.scala:690)
	at akka.actor.ActorCell.receiveMessage(ActorCell.scala:573)
	at akka.actor.ActorCell.invoke(ActorCell.scala:543)
	at akka.dispatch.Mailbox.processMailbox(Mailbox.scala:269)
	at akka.dispatch.Mailbox.run(Mailbox.scala:230)
	at akka.dispatch.Mailbox.exec(Mailbox.scala:242)
	at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:289)
	at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1056)
	at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1692)
	at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157)
Caused by: akka.http.scaladsl.model.ws.PeerClosedConnectionException: Peer closed connection with code 4000 'Unknown error.'
	at akka.http.impl.engine.ws.WebSocket$PrepareForUserHandler$$anon$1.onPush(WebSocket.scala:115)
	at akka.stream.impl.fusing.GraphInterpreter.processPush(GraphInterpreter.scala:541)
	at akka.stream.impl.fusing.GraphInterpreter.processEvent(GraphInterpreter.scala:495)
	... 20 common frames omitted
2020-07-12 10:04:25,392 [INFO] from ackcord.DiscordShard$ in AckCord-akka.actor.default-dispatcher-5627 - Gateway handler shut down. Restarting in 5 minutes

Example not compiling

I tried coping the example package, on my project, and there is a lot imports that does not work anymore. Events also have wrong usage.

ERROR: actor name [GatewayHandler] is not unique!

Another error I got, which looks like a race condition occurring somewhere on the actor creation.

Also, do you have any plans to release the latest fixes anytime soon? Thanks.

2020-07-12 10:09:25,415 [ERROR] from akka.actor.SupervisorStrategy in AckCord-akka.actor.default-dispatcher-5634 - actor name [GatewayHandler] is not unique!
akka.actor.InvalidActorNameException: actor name [GatewayHandler] is not unique!
	at akka.actor.dungeon.ChildrenContainer$NormalChildrenContainer.reserve(ChildrenContainer.scala:134)
	at akka.actor.dungeon.Children.reserveChild(Children.scala:139)
	at akka.actor.dungeon.Children.reserveChild$(Children.scala:137)
	at akka.actor.ActorCell.reserveChild(ActorCell.scala:408)
	at akka.actor.dungeon.Children.makeChild(Children.scala:291)
	at akka.actor.dungeon.Children.actorOf(Children.scala:47)
	at akka.actor.dungeon.Children.actorOf$(Children.scala:46)
	at akka.actor.ActorCell.actorOf(ActorCell.scala:408)
	at akka.actor.typed.internal.adapter.ActorRefFactoryAdapter$.spawn(ActorRefFactoryAdapter.scala:41)
	at akka.actor.typed.internal.adapter.ActorContextAdapter.spawn(ActorContextAdapter.scala:66)
	at ackcord.DiscordShard$.$anonfun$shard$1(DiscordShard.scala:124)
	at akka.actor.typed.internal.BehaviorImpl$ReceiveMessageBehavior.receive(BehaviorImpl.scala:152)
	at akka.actor.typed.Behavior$.interpret(Behavior.scala:274)
	at akka.actor.typed.Behavior$.interpretMessage(Behavior.scala:230)
	at akka.actor.typed.internal.adapter.ActorAdapter.handleMessage(ActorAdapter.scala:119)
	at akka.actor.typed.internal.adapter.ActorAdapter.aroundReceive(ActorAdapter.scala:105)
	at akka.actor.ActorCell.receiveMessage(ActorCell.scala:573)
	at akka.actor.ActorCell.invoke(ActorCell.scala:543)
	at akka.dispatch.Mailbox.processMailbox(Mailbox.scala:269)
	at akka.dispatch.Mailbox.run(Mailbox.scala:230)
	at akka.dispatch.Mailbox.exec(Mailbox.scala:242)
	at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:289)
	at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1056)
	at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1692)
	at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157)
akka.actor.InvalidActorNameException: actor name [GatewayHandler] is not unique!
	at akka.actor.dungeon.ChildrenContainer$NormalChildrenContainer.reserve(ChildrenContainer.scala:134)
	at akka.actor.dungeon.Children.reserveChild(Children.scala:139)
	at akka.actor.dungeon.Children.reserveChild$(Children.scala:137)
	at akka.actor.ActorCell.reserveChild(ActorCell.scala:408)
	at akka.actor.dungeon.Children.makeChild(Children.scala:291)
	at akka.actor.dungeon.Children.actorOf(Children.scala:47)
	at akka.actor.dungeon.Children.actorOf$(Children.scala:46)
	at akka.actor.ActorCell.actorOf(ActorCell.scala:408)
	at akka.actor.typed.internal.adapter.ActorRefFactoryAdapter$.spawn(ActorRefFactoryAdapter.scala:41)
	at akka.actor.typed.internal.adapter.ActorContextAdapter.spawn(ActorContextAdapter.scala:66)
	at ackcord.DiscordShard$.$anonfun$shard$1(DiscordShard.scala:124)
	at akka.actor.typed.internal.BehaviorImpl$ReceiveMessageBehavior.receive(BehaviorImpl.scala:152)
	at akka.actor.typed.Behavior$.interpret(Behavior.scala:274)
	at akka.actor.typed.Behavior$.interpretMessage(Behavior.scala:230)
	at akka.actor.typed.internal.adapter.ActorAdapter.handleMessage(ActorAdapter.scala:119)
	at akka.actor.typed.internal.adapter.ActorAdapter.aroundReceive(ActorAdapter.scala:105)
	at akka.actor.ActorCell.receiveMessage(ActorCell.scala:573)
	at akka.actor.ActorCell.invoke(ActorCell.scala:543)
	at akka.dispatch.Mailbox.processMailbox(Mailbox.scala:269)
	at akka.dispatch.Mailbox.run(Mailbox.scala:230)
	at akka.dispatch.Mailbox.exec(Mailbox.scala:242)
	at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:289)
	at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1056)
	at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1692)
	at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157)
2020-07-12 10:09:25,425 [INFO] from akka.actor.LocalActorRef in AckCord-akka.actor.default-dispatcher-5629 - Message [scala.util.Success] wrapped in [akka.actor.typed.internal.AdaptMessage] to Actor[akka://AckCord/system/DiscordClient/Shard0/GatewayHandler#51704895] was not delivered. [1] dead letters encountered. If this is not an expected behavior then Actor[akka://AckCord/system/DiscordClient/Shard0/GatewayHandler#51704895] may have terminated unexpectedly. This logging can be turned off or adjusted with configuration settings 'akka.log-dead-letters' and 'akka.log-dead-letters-during-shutdown'.

Components not being registered

At some point after the latest SNAPSHOT was released, the AutoButtonHandler class was changed to inherit another class.

registeredComponents.addHandler(identifier, this)
and
def unregisterButtonHandler(): Unit = registeredComponents.removeHandler(this) were removed from this class when this was done.

The function isn't required but the addHandler is as the components dont get registered elsewhere.

I'd PR it back in but not sure if you want it added elsewhere.

When a user send a message I want to reply to the message and send a DM

Hey guys,

Thank you for the library its been working greet so far.
Just wondering how would some one reply to a user message in a channel by DM?

req.user.getDMChannel(req.cache) match { case Some(channel) => client.requestsHelper.runMany( req.textChannel.sendMessage(s"Ill DM you @${req.user.username}"), channel.sendMessage("Sup") )(req.cache)

This works great if the user already has an DM window open with the bot but creating a new window for a DM is a tricky situation I cannot seem to solve.

Removing a bot leads to an error parsing such message

Basically, just kick the bot out and this message gets printed:

	a.DiscordShard$ - Failed to parse payload for GUILD_DELETE: DecodingFailure at .d.unavailable: Attempt to decode value on failed cursor
Json traces:(Failed: .d,{"id":"729034246169296896"})
(Succeeded: ,{"t":"GUILD_DELETE","s":5,"op":0,"d":{"id":"729034246169296896"}})
io.circe.DecodingFailure$$anon$2: Attempt to decode value on failed cursor: DownField(unavailable),DownField(d)
io.circe.DecodingFailure$$anon$2: Attempt to decode value on failed cursor: DownField(unavailable),DownField(d)

Ban Reason does not get URL-Encoded

Using the latest 0.13.0, the route for bans does not get properly encoded.

Steps to reproduce

  • Send a CreateGuildBan request with a space in the reason (someMember.ban(Some(1), Some("Best Reason Evar")))

Expected Results

The REST-Call succeeds (provided permissions etc.)

Actual Results

akka.http.scaladsl.model.IllegalUriException: Illegal URI reference: Invalid input ' ', expected raw-query-char, '#' or 'EOI' (line 1, column 114): https://discordapp.com/api/v6/guilds/<guildid>/bans/<userid>?delete-message-days=1&reason=Best Reason Evar
                                                                                                                 ^
	at akka.http.scaladsl.model.IllegalUriException$.apply(ErrorInfo.scala:74)
	at akka.http.scaladsl.model.Uri$.fail(Uri.scala:823)
	at akka.http.impl.model.parser.UriParser.fail(UriParser.scala:81)
	at akka.http.impl.model.parser.UriParser.parseUriReference(UriParser.scala:46)
	at akka.http.scaladsl.model.Uri$.apply(Uri.scala:217)
	at akka.http.scaladsl.model.Uri$.apply(Uri.scala:189)
	at ackcord.requests.Routes$QueryRoute.$anonfun$$plus$qmark$2(Routes.scala:117)
	at scala.Function$.$anonfun$uncurried$1(Function.scala:50)
	at scala.Function2.$anonfun$tupled$1(Function2.scala:53)
	at ackcord.requests.Routes$QueryRouteFunction.$anonfun$toRequest$2(Routes.scala:170)
	at shapeless.ops.FnFromProductInstances$$anon$5.$anonfun$apply$5(fnfromproduct.scala:89)
	at ackcord.requests.CreateGuildBan.route(guildRequests.scala:504)
	at ackcord.requests.RequestStreams$.$anonfun$ratelimitFlow$1(RequestStreams.scala:158)
	at akka.stream.impl.fusing.MapAsyncUnordered$$anon$31.onPush(Ops.scala:1375)
	โ€ฆ```

DeleteMessage Sink shuts down after one command

This is more a request for help, than a bug (I think...you tell me).

I'm trying to also delete the original command message when it has been processed successfully and a response has been generated.
To that end I adapted the code from the core example in the following way:

class SayAsCmd(requests: RequestHelper) extends Actor with ActorLogging {
  import SayAsCmd._

  implicit val askTimeout = Timeout(5.seconds)
  implicit val system: ActorSystem = context.system;
  import requests.mat;
  import context.dispatcher;

  private val messageGraph = Sink.fromGraph(GraphDSL.create() { implicit builder =>
    import GraphDSL.Implicits._;

    val unzip = builder.add(Unzip[DeleteMessage[NotUsed], List[CreateMessage[NotUsed]]]);

    val msgSink = requests.sinkIgnore[RawMessage, NotUsed];
    val deleteSink = requests.sinkIgnore[NotUsed, NotUsed];

    unzip.out0.log("DELETE MSG", dm => dm.messageId) ~> deleteSink;
    unzip.out1.mapConcat(identity).log("REPLY MSG", cm => cm.bodyForLogging) ~> msgSink;
    SinkShape.of(unzip.in)
  });

  private val msgQueue = Source.queue[(ActorRef, SayAsMessage, ChannelId, MessageId)](32, OverflowStrategy.backpressure)
    .mapAsyncUnordered(parallelism = 1000)((t: (ActorRef, SayAsMessage, ChannelId, MessageId)) =>
      (t._1 ? t._2).mapTo[List[CreateMessageData]].map(l => (DeleteMessage(t._3, t._4) -> l.map(CreateMessage(t._3, _)))))
    .to(messageGraph).run();

  private val serverHandlers = mutable.Map.empty[GuildId, ActorRef];
  private val fallbackHandler = context.actorOf(Props(new SayAsActor(None)));

  override def receive: Receive = {
    case InitAck => {
      log.debug("Got Init");
      sendAck(sender);
    }
    case ParsedCmd(msg, cmd @ CharacterArgs.Register(name, avatar), _, _) => {
      log.debug(s"Received register command: $cmd");
      routeToHandler(msg, RegisterCharacter(name, avatar));
    }
    case ParsedCmd(msg, cmd @ CharacterArgs.Unregister(name), _, _) => {
      log.debug(s"Received unregister command: $cmd");
      routeToHandler(msg, UnregisterCharacter(name));
    }
    case ParsedCmd(msg, cmd @ CharacterArgs.ListAll, _, _) => {
      log.debug(s"Received list command: $cmd");
      routeToHandler(msg, ListCharacters);
    }
    case ParsedCmd(msg, cmd @ SayArgs.Say(author, content), _, _) => {
      log.debug(s"Received sayas command: $cmd");
      routeToHandler(msg, SayAs(author, content));
    }
    case x => {
      log.warning(s"Received unexpected message: $x");
      sendAck(sender);
    }
  }

  def routeToHandler(orig: Message, msg: SayAsMessage): Unit = {
    // TODO routing
    val msgSender = sender();
    msgQueue.offer((fallbackHandler, msg, orig.channelId, orig.id)).onComplete(_ => sendAck(msgSender))
  }
  def sendAck(sender: ActorRef): Unit = sender ! SayAsCmd.Ack;
}

This approach works for the first command after I start the bot, and afterwards the delete path seems to shut down and only the reply path works. (I added the log elements to the flow graph and the last message from the delete flow is [DELETE MSG] Downstream finished.)

a) Is this intended behaviour?
b) How do I work around it?
c) Is there a better way to sink both CreateMessage and DeleteMessage events into the requests queue, without splitting the stream like this?

user param doesn't work

using ackcord.interactions.commands.SlashCommandControllerBase#user in 0.18.0-SNAPSHOT i get "This interaction failed"
looks like ackcord.data.ApplicationCommandOptionTypeE#userRegex is wrong as it appears to be just a string:

      "options" : [                         
        {                                   
          "value" : "844577457944133652",   
          "type" : 6,                       
          "name" : "username"               
        }                                 
      ],                                    

Member add/update events not being triggered

I have an app that expects the APIMessage.GuildMemberAdd/APIMessage.GuildMemberUpdate events, but since I updated to 0.17.0-M1, I haven't been getting them, I tried 0.17.0-M2 without luck.

module not found: com.sedmelluq#lavaplayer;1.3.10

It seems the public source for the lavaplayer is 404'ing (I think), here's the full error:

[warn] 	module not found: com.sedmelluq#lavaplayer;1.3.10
[warn] ==== local: tried
[warn]   C:\Users\*****\.ivy2\local\com.sedmelluq\lavaplayer\1.3.10\ivys\ivy.xml
[warn] ==== public: tried
[warn]   https://repo1.maven.org/maven2/com/sedmelluq/lavaplayer/1.3.10/lavaplayer-1.3.10.pom
[warn] ==== local-preloaded-ivy: tried
[warn]   C:\Users\*****\.sbt\preloaded\com.sedmelluq\lavaplayer\1.3.10\ivys\ivy.xml
[warn] ==== local-preloaded: tried
[warn]   file:/C:/Users/*****/.sbt/preloaded/com/sedmelluq/lavaplayer/1.3.10/lavaplayer-1.3.10.pom
[warn] 	::::::::::::::::::::::::::::::::::::::::::::::
[warn] 	::          UNRESOLVED DEPENDENCIES         ::
[warn] 	::::::::::::::::::::::::::::::::::::::::::::::
[warn] 	:: com.sedmelluq#lavaplayer;1.3.10: not found
[warn] 	::::::::::::::::::::::::::::::::::::::::::::::
[warn] 
[warn] 	Note: Unresolved dependencies path:
[warn] 		com.sedmelluq:lavaplayer:1.3.10
[warn] 		  +- net.katsstuff:ackcord-lavaplayer_2.12:0.12.0
[warn] 		  +- net.katsstuff:ackcord-lavaplayer-core_2.12:0.12.0 (C:\Users\*****\IdeaProjects\Connect4\build.sbt#L10-11)
[warn] 		  +- default:connect4_2.12:0.1

Rate Limiter never releases once rate limit is hit

AckCord Version: 0.16.1

This issue is occurring through the use of Requests#singleFuture so it's possible that there is just a bug with how rate limits get updated through this flow. I'm still trying to get acquainted with the code and debug the issue.

Expected behavior:

Rate limit is hit for a specific bucket. All requests for the bucket are queued and then sent in order when the rate limit times out.

Actual behavior:

Rate limit is hit for a specific bucket. All subsequent requests for that bucket are queued but never sent as long as the same Ratelimiter actor lives.

Unable to load module in build.sbt

I add libraryDependencies += "net.katsstuff" %% "ackcord" % "0.10" to the file and I got the error:

[info] Updating ...
[warn] 	module not found: net.katsstuff#ackcord-core_2.12;0.10
[warn] ==== local: tried
[warn]   C:\*****\*****\.ivy2\local\net.katsstuff\ackcord-core_2.12\0.10\ivys\ivy.xml
[warn] ==== public: tried
[warn]   https://repo1.maven.org/maven2/net/katsstuff/ackcord-core_2.12/0.10/ackcord-core_2.12-0.10.pom
[warn] ==== local-preloaded-ivy: tried
[warn]   C:\Users\torik\.sbt\preloaded\net.katsstuff\ackcord-core_2.12\0.10\ivys\ivy.xml
[warn] ==== local-preloaded: tried
[warn]   file:/C:/*****/*****/.sbt/preloaded/net/katsstuff/ackcord-core_2.12/0.10/ackcord-core_2.12-0.10.pom
[warn] 	::::::::::::::::::::::::::::::::::::::::::::::
[warn] 	::          UNRESOLVED DEPENDENCIES         ::
[warn] 	::::::::::::::::::::::::::::::::::::::::::::::
[warn] 	:: net.katsstuff#ackcord-core_2.12;0.10: not found
[warn] 	::::::::::::::::::::::::::::::::::::::::::::::
[warn]
[warn] 	Note: Unresolved dependencies path:
[warn] 		net.katsstuff:ackcord-core_2.12:0.10 (F:\workspace\Scala\********\build.sbt#L7-8)
[warn] 		  +- default:tobenotbot_2.12:0.1
[error] sbt.librarymanagement.ResolveException: unresolved dependency: net.katsstuff#ackcord-core_2.12;0.10: not found
 (Stack Trace).....

I'm still learning on both how to use the API thru the example and making the bot, so I suppose I might be missing some steps here.

P/s: Apparently, our discord invite is expired

Requests should by default drop null values

The RequestDSL in the high-level command API gets stuck attempting to call channel.fetchMessages or any of its variants, preventing the bot from executing further portions of the DSL, as well as any other commands.

cmd: ParsedCmd[Int] => {
    for {
        channel <- {
            println("A")
            maybePure(cmd.msg.tGuildChannel)
        }
        messages <- {
            println("B")
            channel.fetchMessagesBefore(cmd.msg.id, limit = Some(cmd.args))
        }
        _ <- {
            println("C")
            channel.bulkDelete(messages.map(q => q.id))
        }
    } yield ()
}

will only print

A
B

and immediately following the bot will not respond to future commands.

Autocomplete errors if the user doesn't enter anything

When running the command:
image

ackcord.requests.HttpException: HttpMethod(POST) https://discord.com/api/v9/interactions/<<ID>>/<<TOKEN>>/callback: 400, Bad Request {"code": 50035, "errors": {"data": {"choices": {"0": {"name": {"_errors": [{"code": "BASE_TYPE_REQUIRED", "message": "This field is required"}]}}, "1": {"name": {"_errors": [{"code": "BASE_TYPE_REQUIRED", "message": "This field is required"}]}}, "2": {"name": {"_errors": [{"code": "BASE_TYPE_REQUIRED", "message": "This field is required"}]}}}}}, "message": "Invalid Form Body"}
	at ackcord.requests.RequestStreams$.$anonfun$requestParser$3(RequestStreams.scala:228)
	at scala.concurrent.impl.Promise$Transformation.run(Promise.scala:467)
	at akka.dispatch.BatchingExecutor$AbstractBatch.processBatch(BatchingExecutor.scala:63)
	at akka.dispatch.BatchingExecutor$BlockableBatch.$anonfun$run$1(BatchingExecutor.scala:100)
	at scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.scala:18)
	at scala.concurrent.BlockContext$.withBlockContext(BlockContext.scala:94)
	at akka.dispatch.BatchingExecutor$BlockableBatch.run(BatchingExecutor.scala:100)
	at akka.dispatch.TaskInvocation.run(AbstractDispatcher.scala:49)
	at akka.dispatch.ForkJoinExecutorConfigurator$AkkaForkJoinTask.exec(ForkJoinExecutorConfigurator.scala:48)
	at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:289)
	at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1056)
	at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1692)
	at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:175)

Adding an entry fixes it:
image

[Suggestion?] A Higher-leveled /modular command framework for AckCord

Other Discord libraries feature command frameworks that provide utilities that abstract over implementation details and/or boilerplate (usually using a decorator, annotation or some kind of off-handing mechanism) for example: [discord.py's commands extension]
(https://discordpy.readthedocs.io/en/rewrite/ext/commands/commands.html) which provides an easier and cleaner interface with the library.

In AckCord, The ping command is in itself quite verbose.

  def registerParsedCommand[F[_] : Monad : Streamable](commands: CommandsHelper[F]): Unit = {
    commands.registerCmd[NotUsed, Id](
      refiner = CmdInfo[F](prefix = GeneralCommands, aliases = Seq("ping"), filters = Seq(CmdFilter.NonBot, CmdFilter.InGuild)),
      description = Some(CmdDescription("Ping", "Check if the bot is alive"))
    ) { cmd: ParsedCmd[F, NotUsed] =>
      println(s"Received ping command")
    }

where-as using something such as an annotation macro (to avoid the using runtime-reflection) allows the
implementation to be quite clean and concise (this is just an example).

@Command(aliases = Seq("ping"), desc = "Check if the bot is alive")
def ping(/* some context parameter */) =
    println("Recieved ping command")

which would generate code similar to the former without any of the verbosity.

I am not experienced in writing libraries that wrap around APIs but I do appreciate the work that is being put on AckCord and do not bear any ill will towards anyone working on the project but it is rather difficult to write all that when using vim/vsc (IntelliJ also has problems resolving methods such as channel#sendMessage) :p

Verifier IndexOutOfBoundsException issues

This issue seems to be happening frequently:

In this example, content was empty as I was sending embeds which is a valid body.

java.lang.IndexOutOfBoundsException: null

    at java.base/java.lang.String.codePointCount(String.java:1607)

    at ackcord.util.Verifier$.stringLength(Verifier.scala:102)

    at ackcord.util.Verifier$.requireLength(Verifier.scala:18)

    at ackcord.requests.CreateMessageData.<init>(channelRequests.scala:319)

    at ackcord.syntax.package$TextChannelSyntax$.sendMessage$extension(syntax.scala:120)

This comes from within ackcord when parsing from discord so there's not much I can do to patch it on my end.

java.lang.String
in codePointCount at line 1610
ackcord.util.Verifier$
in stringLength at line 102
ackcord.util.Verifier$
in requireLength at line 18
ackcord.data.EmbedField
in <init> at line 784
ackcord.data.DiscordProtocol$$anon$26
in apply at line 192
io.circe.SeqDecoder
in apply at line 17
io.circe.Decoder$$anon$39
in tryDecode at line 930
ackcord.data.DiscordProtocol$$anon$33
in apply at line 213
io.circe.SeqDecoder
in apply at line 17
io.circe.Decoder$$anon$39
in tryDecode at line 930
io.circe.ACursor
in as at line 211
ackcord.util.JsonOption$
in $anonfun$decodeRestOption$1 at line 33
io.circe.Decoder$$anon$19
in tryDecode at line 526
io.circe.ACursor
in as at line 211
io.circe.ACursor
in get at line 218
ackcord.gateway.GatewayProtocol$
in $anonfun$rawPartialMessageDecoder$15 at line 235

Weird exception logged for no reason

I'm getting an exception logged, which seems related to another one due to missing permissions, this occurred while trying to send a message:

ackcord.requests.HttpException: 403, Forbidden {"message": "Missing Access", "code": 50001}
	at ackcord.requests.RequestStreams$.$anonfun$requestParser$3(RequestStreams.scala:303)
	at scala.concurrent.impl.Promise$Transformation.run(Promise.scala:430)
	at akka.dispatch.BatchingExecutor$AbstractBatch.processBatch(BatchingExecutor.scala:55)
	at akka.dispatch.BatchingExecutor$BlockableBatch.$anonfun$run$1(BatchingExecutor.scala:92)
	at scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.scala:18)
	at scala.concurrent.BlockContext$.withBlockContext(BlockContext.scala:94)
	at akka.dispatch.BatchingExecutor$BlockableBatch.run(BatchingExecutor.scala:92)
	at akka.dispatch.TaskInvocation.run(AbstractDispatcher.scala:47)
	at akka.dispatch.ForkJoinExecutorConfigurator$AkkaForkJoinTask.exec(ForkJoinExecutorConfigurator.scala:47)
	at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:289)
	at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1056)
	at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1692)
	at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157)

Weird exception:

java.util.NoSuchElementException: head of empty stream
	at akka.stream.scaladsl.Sink$.$anonfun$head$3(Sink.scala:197)
	at scala.Option.getOrElse(Option.scala:201)
	at akka.stream.scaladsl.Sink$.$anonfun$head$2(Sink.scala:197)
	at scala.concurrent.impl.Promise$Transformation.run(Promise.scala:430)
	at scala.concurrent.ExecutionContext$parasitic$.execute(ExecutionContext.scala:164)
	at scala.concurrent.impl.Promise$Transformation.submitWithValue(Promise.scala:392)
	at scala.concurrent.impl.Promise$DefaultPromise.submitWithValue(Promise.scala:302)
	at scala.concurrent.impl.Promise$DefaultPromise.tryComplete0(Promise.scala:249)
	at scala.concurrent.impl.Promise$DefaultPromise.tryComplete(Promise.scala:242)
	at scala.concurrent.Promise.trySuccess(Promise.scala:99)
	at scala.concurrent.Promise.trySuccess$(Promise.scala:99)
	at scala.concurrent.impl.Promise$DefaultPromise.trySuccess(Promise.scala:104)
	at akka.stream.impl.HeadOptionStage$$anon$3.onUpstreamFinish(Sinks.scala:235)
	at akka.stream.impl.fusing.GraphInterpreter.processEvent(GraphInterpreter.scala:523)
	at akka.stream.impl.fusing.GraphInterpreter.execute(GraphInterpreter.scala:390)
	at akka.stream.impl.fusing.GraphInterpreterShell.runBatch(ActorGraphInterpreter.scala:624)
	at akka.stream.impl.fusing.GraphInterpreterShell$AsyncInput.execute(ActorGraphInterpreter.scala:501)
	at akka.stream.impl.fusing.GraphInterpreterShell.processEvent(ActorGraphInterpreter.scala:599)
	at akka.stream.impl.fusing.ActorGraphInterpreter.akka$stream$impl$fusing$ActorGraphInterpreter$$processEvent(ActorGraphInterpreter.scala:768)
	at akka.stream.impl.fusing.ActorGraphInterpreter.akka$stream$impl$fusing$ActorGraphInterpreter$$shortCircuitBatch(ActorGraphInterpreter.scala:758)
	at akka.stream.impl.fusing.ActorGraphInterpreter$$anonfun$receive$1.applyOrElse(ActorGraphInterpreter.scala:784)
	at akka.actor.Actor.aroundReceive(Actor.scala:534)
	at akka.actor.Actor.aroundReceive$(Actor.scala:532)
	at akka.stream.impl.fusing.ActorGraphInterpreter.aroundReceive(ActorGraphInterpreter.scala:690)
	at akka.actor.ActorCell.receiveMessage(ActorCell.scala:573)
	at akka.actor.ActorCell.invoke(ActorCell.scala:543)
	at akka.dispatch.Mailbox.processMailbox(Mailbox.scala:269)
	at akka.dispatch.Mailbox.run(Mailbox.scala:230)
	at akka.dispatch.Mailbox.exec(Mailbox.scala:242)
	at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:289)
	at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1056)
	at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1692)
	at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157)
java.util.NoSuchElementException: head of empty stream
	at akka.stream.scaladsl.Sink$.$anonfun$head$3(Sink.scala:197)
	at scala.Option.getOrElse(Option.scala:201)
	at akka.stream.scaladsl.Sink$.$anonfun$head$2(Sink.scala:197)
	at scala.concurrent.impl.Promise$Transformation.run(Promise.scala:430)
	at scala.concurrent.ExecutionContext$parasitic$.execute(ExecutionContext.scala:164)
	at scala.concurrent.impl.Promise$Transformation.submitWithValue(Promise.scala:392)
	at scala.concurrent.impl.Promise$DefaultPromise.submitWithValue(Promise.scala:302)
	at scala.concurrent.impl.Promise$DefaultPromise.tryComplete0(Promise.scala:249)
	at scala.concurrent.impl.Promise$DefaultPromise.tryComplete(Promise.scala:242)
	at scala.concurrent.Promise.trySuccess(Promise.scala:99)

[Suggestion?] A Higher-leveled /modular command framework for AckCord

Other Discord libraries feature command frameworks that provide utilities that abstract over implementation details and/or boilerplate (usually using a decorator, annotation or some kind of off-handing mechanism) for example: [discord.py's commands extension]
(https://discordpy.readthedocs.io/en/rewrite/ext/commands/commands.html) which provides an easier and cleaner interface with the library.

In AckCord, The ping command is in itself quite verbose.

def registerRawCommand[F[_] : Monad : Streamable](client: DiscordClient[F], commands: CommandsHelper[F]): Unit = {
  commands.onRawCmd {
    client.withCache[SourceRequest, RawCmd[F]] { implicit c => {
      case RawCmd(message, Prefix, "echo", args, _) =>
        import client.sourceRequesterRunner._
        for {
          channel <- liftOptionT(message.tGuildChannel[F])
          _ <- run(channel.sendMessage(s"ECHO: ${args.mkString(" ")}"))
        } yield ()
      case _ => client.sourceRequesterRunner.unit
    }
    }
  }
}

where-as using something such as an annotation macro (to avoid the using runtime-reflection)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.