Git Product home page Git Product logo

nostrum's People

Contributors

aely0 avatar awlexus avatar bcksl avatar bdanklin avatar brandthill avatar cedeno avatar cookkkie avatar daskycodes avatar dazeycm avatar jb3 avatar jchristgit avatar jirkavrba avatar jmajeski avatar jswny avatar kevinkjt2000 avatar kraigie avatar leastrio avatar mtvillwock avatar ovyerus avatar panoramix360 avatar pixelinc avatar ppraisethesun avatar realvidy avatar ruyili avatar skippi avatar th3-m4jor avatar thatsnomoon avatar unleashy avatar wkpatrick avatar z64 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  avatar  avatar  avatar  avatar  avatar  avatar

nostrum's Issues

Unhandled websocket message after application start

Version: github

Starting the application from iex -S mix (I used both the simple and the more complex samples), it shows the following warning.

16:04:21.780 [warn]  Unhandled websocket message: {:DOWN, #Reference<0.436806687.830210049.7920>, 
:process, #PID<0.242.0>, {:undef, [{:crypto, :rand_bytes, [16], []}, {:cow_ws, :key, 0, 
[file: 'src/cow_ws.erl', line: 63]}, {:gun_http, :ws_upgrade, 7, [file: 'src/gun_http.erl', line: 407]}, 
{:gun, :loop, 1, [file: 'src/gun.erl', line: 629]}, {:proc_lib, :init_p_do_apply, 3, [file: 'proc_lib.erl', line: 247]}]}}

This warning comes from here, and it does nothing, and so (or maybe not) it never connects.

When I edited the source to do the same thing as this pattern, it keeps on doing the reconnection and never succeeds.

16:28:28.656 [warn]  websocket caller received DOWN, attempting reconnect

16:28:28.656 [debug] WAITING 5454 BEFORE NEXT SHARD CONNECT

16:28:34.154 [warn]  websocket caller received DOWN, attempting reconnect

16:28:34.154 [debug] WAITING 5460 BEFORE NEXT SHARD CONNECT

...

This is curious because the hex version will succeed with no warnings.

Random(?) disconnects

Without any warning, I've been seeing the following in the logs:

17:41:26.324 [warn] websocket disconnected with reason {:remote, 1000, ""}, attempting reconnect
17:42:21.409 [warn] websocket disconnected with reason {:remote, 1000, ""}, attempting reconnect
17:43:16.475 [warn] websocket disconnected with reason {:remote, 1000, ""}, attempting reconnect
17:44:11.543 [warn] websocket disconnected with reason {:remote, 1000, ""}, attempting reconnect
17:45:06.617 [warn] websocket disconnected with reason {:remote, 1000, ""}, attempting reconnect
17:46:01.692 [warn] websocket disconnected with reason {:remote, 1000, ""}, attempting reconnect
17:46:56.802 [warn] websocket disconnected with reason {:remote, 1000, ""}, attempting reconnect
17:47:51.872 [warn] websocket disconnected with reason {:remote, 1000, ""}, attempting reconnect
17:48:46.942 [warn] websocket disconnected with reason {:remote, 1000, ""}, attempting reconnect
17:49:42.026 [warn] websocket disconnected with reason {:remote, 1000, ""}, attempting reconnect

Until today, it would eventually reconnect, but now it seems stuck in eternal attempt to reconnect. Does anyone have any insight on what might be happening?

Implement rest endpoints

This includes

  • Documentation
  • @spec's
  • Banged methods

Methods that have documentation have been tested and will adhere to their documentation. I can't make any guarantees for those without documentation.

TODO:

  • Guild
    • docs
    • @spec's
    • implementation
  • Channel
    • docs
    • @spec's
    • implementation
  • User
    • docs
    • @spec's
    • implementation
  • Invite
    • docs
    • @spec's
    • implementation
  • Voice
    • docs
    • @spec's
    • implementation
  • Webhook
    • docs
    • @spec's
    • implementation
  • Review endpoints to handle file uploading / url vs. json body handling
    • file uploading
    • url vs. json body

Example Consumer script won't post on discord channel?

Hi all,

So I found this lib over the weekend and I was trying out the example consumer program. The bot is connected, sees when someone is typing, but when I write "!ping" in the general channel it says "message created" in the debug logs but I don't see a message on the channel.

Am I missing something obvious here? I granted all permissions to the bot to see if it worked (my example server that nobody uses so it's okay).

member chunk payloads are never handled

Here we're creating a stream and then never enumerating through it.

Additionally, we probably want to modify the user and guild cache to take in a list to improve performance, instead of calling these functions for each member.

no function clause matching in Nostrum.Api.handle_request_with_decode/2 raised on `add_member_to_guild/3` function when member already exists

I'm getting a no function clause matching in Nostrum.Api.handle_request_with_decode/2 exception being raised on the add_member_to_guild/3 function when that member already exists on the server.

The Discord API docs indicate that a 204 No Content status code is sent back in this scenario with an empty body. In this case, the function clause is being called with the following arguments:

  1. {:ok}
  2. {:struct, Nostrum.Struct.Guild.Member}

and the following function clauses were attempted:

defp handle_request_with_decode({:error, _} = error, _type)
defp handle_request_with_decode({:ok, body}, type)

The error is being raised at line 2571

I've tried it on both the stable version 0.1 and the development version (currently on the development version) but the error persists in both. 😞

Api.get_guild_members/2 results to a GenServer Ratelimiter error

Using the method, it crashes with this output:

15:13:43.092 [error] GenServer Ratelimiter terminating
** (Poison.SyntaxError) Unexpected token at position 0: <
    (poison) lib/poison/parser.ex:57: Poison.Parser.parse!/2
    (poison) lib/poison.ex:83: Poison.decode!/2
    (nostrum) lib/nostrum/api/ratelimiter.ex:110: Nostrum.Api.Ratelimiter.format_response/1
    (nostrum) lib/nostrum/api/ratelimiter.ex:33: Nostrum.Api.Ratelimiter.handle_call/3
    (stdlib) gen_server.erl:636: :gen_server.try_handle_call/4
    (stdlib) gen_server.erl:665: :gen_server.handle_msg/6
    (stdlib) proc_lib.erl:247: :proc_lib.init_p_do_apply/3
Last message (from #PID<0.233.0>): {:queue, %{body: %{limit: 1..100}, headers: [{"content-type", "application/json"}], method: :get, options: [], route: "/guilds/260291356562423809/members/"}, nil}
State: []
Client #PID<0.233.0> is alive
    (stdlib) gen.erl:169: :gen.do_call/4
    (elixir) lib/gen_server.ex:734: GenServer.call/3
    (nostrum) lib/nostrum/api.ex:907: Nostrum.Api.get_guild_members/2
    (test_discord_bot) lib/test_discord_bot.ex:54: ExampleConsumer.handle_event/2
    (nostrum) lib/nostrum/consumer.ex:176: Nostrum.Consumer.do_event/3
    (nostrum) lib/nostrum/consumer.ex:170: Nostrum.Consumer.handle_events/3
    (gen_stage) lib/gen_stage.ex:2543: GenStage.consumer_dispatch/7
    (gen_stage) lib/gen_stage.ex:2083: GenStage.handle_info/2

HTTPoison is crashing trying to parse this:

<!DOCTYPE html>
<html lang=en>
  <meta charset=utf-8>
  <meta name=viewport content="initial-scale=1, minimum-scale=1, width=device-width">
  <title>Error 400 (Bad Request)!!1</title>
  <style>
    *{margin:0;padding:0}html,code{font:15px/22px arial,sans-serif}html{background:#fff;color:#222;padding:15px}body{margin:7% auto 0;max-width:390px;min-height:180px;padding:30px 0 15px}* > body{background:url(//www.google.com/images/errors/robot.png) 100% 5px no-repeat;padding-right:205px}p{margin:11px 0 22px;overflow:hidden}ins{color:#777;text-decoration:none}a img{border:0}@media screen and (max-width:772px){body{background:none;margin-top:0;max-width:none;padding-right:0}}#logo{background:url(//www.google.com/images/branding/googlelogo/1x/googlelogo_color_150x54dp.png) no-repeat;margin-left:-5px}@media only screen and (min-resolution:192dpi){#logo{background:url(//www.google.com/images/branding/googlelogo/2x/googlelogo_color_150x54dp.png) no-repeat 0% 0%/100% 100%;-moz-border-image:url(//www.google.com/images/branding/googlelogo/2x/googlelogo_color_150x54dp.png) 0}}@media only screen and (-webkit-min-device-pixel-ratio:2){#logo{background:url(//www.google.com/images/branding/googlelogo/2x/googlelogo_color_150x54dp.png) no-repeat;-webkit-background-size:100% 100%}}#logo{display:inline-block;height:54px;width:150px}
  </style>
  <a href=//www.google.com/><span id=logo aria-label=Google></span></a>
  <p><b>400.</b> <ins>That’s an error.</ins>
  <p>Your client has issued a malformed or illegal request.  <ins>That’s all we know.</ins>

and I can't understand why Google is returning the error.

Warnings produced by elixir 1.7.4

HI,

Elixir 1.7.4 generates the following warnings when compiling

warning: variable "index_by" is unused
lib/nostrum/util.ex:222

warning: variable "type" is unused
lib/nostrum/util.ex:222

Update version guidance in Intro.md

The Intro doc says to use the git master of nostrum, instead of a released version.

The version of this library hosted on Hex is severely outdated. Once the dependency
[gun](https://github.com/ninenines/gun) has a 2.0 release, a new package will be
released with the most up to date Elixir version (1.6.4 as of the time of this writing).

In the meantime it is recommended you use the version hosted on GitHub.

However, the 0.3.0 release replaced gun with websockex. Is it still advised to use the dev version? Or can I use nostrum 0.3.2 without causing extra trouble for myself?

websocket state should be a struct

Currently the state of the websocket-controlling process is just stored as a map. We should instead store this as a struct so it can be properly documented as well as provide the guarantees of a struct.

The current state documentation can be found here.

User permanently stops receiving events if HEARTBEAT_ACK is not received in time

04:01:43.677 [warn]  HEARTBEAT_ACK not received in time, disconnecting
04:03:31.167 [warn]  Unhandled websocket message: {:DOWN, #Reference<0.2512857106.1813512198.243387>, :process, #PID<0.232.0>, {:shutdown, :nxdomain}}

If the user loses internet for a couple minutes and does not receive a HEARTBEAT_ACK in time, then the user will no longer receive events. This is even if the user reconnects his or her internet.

Expected: Even if losing internet for hours of time, lib user will start receiving events again after reconnecting to the internet.
Observed: Lib user no longer receives any events after the gun process shuts down. Even if the user reconnects to the internet.

Steps to reproduce:

  1. Start the nostrum application in developer mode.
  2. Once the gun process starts, disconnect from the internet.
  3. Wait until the aforementioned errors pop up.
  4. Reconnect to the internet.
  5. End result is that no events are received.

I'm thinking it's likely because we instruct gun to shutdown if we don't receive a HEARTBEAT_ACK in time. From what it looks like, we also never ask for gun to reopen its connection.

Credit to barkerja#9999 for bringing up the issue on the nostrum DAPI channel.

Add kick support.

Currently, to the best of my knowledge, Nostrum doesn't support kicking a user from a guild. It supports banning however.

Could kick support be added to the roadmap for addition to Nostrum, or is there a limitation of Discord's API with regards to kicking a user?

Thanks 😄

duplicate heartbeats

Overtime it seems like heartbeats are being duplicated. On my testing bot with a couple weeks uptime there were two heartbeat acks within 5 seconds of each other, when they should be ~40s apart.

nostrum crashes on receiving particular event types

  1. iex -S mix
  2. let bot join server
  3. kick bot out of server
  4. application exits!

sample log (from where bot gets kicked): gist

In dispatch.ex 's GUILD_DELETE pattern, it tries to get a p.unavailable boolean.
But from the Discord document it says unavailable is true or not set. (hey is that what we call a boolean!?)

whether the guild is unavailable, should always be true. if not set, this signifies that the user was removed from the guild

So the dot-access method might be the very first problem here.

Example how to listen to a channel?

Can someone point to an example where the example describes listening to a channel and replying?

Having troubles trying to get the hedwig discord adapter working.

Does Nostrum app start automatically when included as dependency?

Hi

is it possible to have to include nostrum in extra_applications rather than have it start automatically just because its listed as a dependency.

The reason - i use the same code base on multiple nodes but only want to run nostrum on one. My code explicity starts the applications it needs and not the ones that node does not. Despite this nostrum seems to be running regardless i.e. on call nodes.

REST ratelimiter (probably) broken

From bucket.ex:

def lookup_bucket(route) do
  route_time = :ets.lookup(:ratelimit_buckets, route)
  global_time = :ets.lookup(:ratelimit_buckets, "GLOBAL")

  Enum.max([route_time, global_time])
end

Intuitively, it seems like this ends up doing something to the effect of

iex(1)> Enum.max([{"route", 5, 1234567890, 2}, {"GLOBAL", 10, 1234567890, 4}])
{"route", 5, 1234567890, 2}

which probably isn't right.

Also you told me to open this issue https://i.imgur.com/ff4xy3T.png

Re-implement the ability to define custom consumers

Right now it's not possible to define customer consumers properly. You can see #126 for some discussion on the matter.

To properly implement this, if the config option is true, we should disable the cache supervisor as well as the gen_stage stages besides the producers. We might also want to consider creating a utility function so users can more easily subscribe to our producers, or mention the name of the producer somewhere in the docs.

member_update from guild_server can't merge newmember with nil

** (exit) exited in: GenServer.call(#PID<0.491.0>, {:update, :member, 248859295414878208, %{guild_id: 248859295414878208, nick: nil, roles: [277668776382693376], user: %{avatar: "309b5063d0797a362a9d697c5fc67920", discriminator: "9796", id: 222244646317850624, username: "mcred"}}}, 5000)
    ** (EXIT) an exception was raised:
        ** (BadMapError) expected a map, got: nil
            (stdlib) :maps.merge(nil, %{guild_id: 248859295414878208, nick: nil, roles: [277668776382693376], user: %{avatar: "309b5063d0797a362a9d697c5fc67920", discriminator: "9796", id: 222244646317850624, username: "mcred"}})
            (nostrum) lib/nostrum/cache/guild/guild_server.ex:390: Nostrum.Cache.Guild.GuildServer.handle_call/3
            (stdlib) gen_server.erl:636: :gen_server.try_handle_call/4
            (stdlib) gen_server.erl:665: :gen_server.handle_msg/6
            (stdlib) proc_lib.erl:247: :proc_lib.init_p_do_apply/3

I have frequently this issue with member update, the member is not already in cache so the update is generating an exception crashing my consumer

ZLib issue

Seems very similar to #35

22:26:44.468 [info]  websocket closed, attempting reconnect

22:26:44.470 [error] GenServer #PID<0.800.0> terminating
** (stop) :data_error
    :zlib.inflateEnd_nif(#Reference<0.2579208287.1398407170.85146>)
    (nostrum) lib/nostrum/shard/session.ex:133: Nostrum.Shard.Session.handle_info/2
    (stdlib) gen_server.erl:633: :gen_server.try_dispatch/4
    (stdlib) gen_server.erl:703: :gen_server.handle_msg/6
    (stdlib) proc_lib.erl:247: :proc_lib.init_p_do_apply/3
Last message: {:gun_down, #PID<0.803.0>, :ws, :closed, [], []}
State: %{gateway: 'gateway.discord.gg', gun_pid: #PID<0.803.0>, heartbeat_ack: true, producer_pid: #PID<0.801.0>, reconnect_attempts: 0, seq: 22, session: "2f2a3e582935ec8bb82d20bdf207446a", shard_num: 0, shard_pid: #PID<0.800.0>, token: "<CENSORED>", zlib_buffer: "", zlib_ctx: #Reference<0.2579208287.1398407170.85146>}

22:26:44.471 [info]  GenStage consumer #PID<0.857.0> is stopping after receiving cancel from producer #PID<0.802.0> with reason: {:data_error, [{:zlib, :inflateEnd_nif, [#Reference<0.2579208287.1398407170.85146>], []}, {Nostrum.Shard.Session, :handle_info, 2, [file: 'lib/nostrum/shard/session.ex', line: 133]}, {:gen_server, :try_dispatch, 4, [file: 'gen_server.erl', line: 633]}, {:gen_server, :handle_msg, 6, [file: 'gen_server.erl', line: 703]}, {:proc_lib, :init_p_do_apply, 3, [file: 'proc_lib.erl', line: 247]}]}

Voice state updates not handled

While the lib doesn't currently support voice, it would still be proper to handle voice state updates. The logic to do so should be here, and the docs for it are here.

The voice server update event should also probably be implemented. And is located nearby the referenced material.

This would close #26 and #22 I guess. 🙃

Switch to nostrum_struct utility

We're currently writing a lot of code to define the functions needed to work with structs:
defstruct - To define the struct.
p_encode - To decode poison results to structs
to_struct - To decode websocket payloads to structs

Work has been done on creating a single macro that encapsulates the above methods, it can be found here.

TODO:

  • Add struct definition to macro
  • Change all struct files to use new macro

update api to v7

In the new v7 api the way errors are returned is very different and way better. You could consider looking into this to provide better information about failed requests.

Nostrum.Consumer should be generalized to allow full utilization of GenStage capabilities

Right now, the Nostrum.Consumer behaviour specifies the GenStage behaviour with the :consumer type. Ideally, it would also support the :producer_consumer type (and handle_events would in that case pass its event objects in its return value), allowing other modules using the GenStage behaviour to subscribe directly to Nostrum.Consumer (or whatever would be named under this scheme, whether that name becomes something more general and it's parameterized or whether a Nostrum.ProducerConsumer behaviour is introduced alongside it).

Info about the OTP and Gun requierements

In the README there is currently a note about OTP 20:

This means in order to run your bot, you will need the Gun 2.0 rc, as the latest release is for OTP 19 and will not run on OTP 20.

Looking at the Gun repository, the latest version seems to be 1.0-pre and not 2.0-rc.
Is there a typo in the README or am I missing something?

According to the Gun doc, requirements for version 1.0 is OTP 18+.

Message cache

Nostrum currently caches guilds, channels, and users. I think that a message cache would prove useful to some bots. Some examples from mine:

  • a mod log checking the message cache for deleted / edited messages
  • searching past messages for something specific

This is not a common thing across bots, and having the message cache opt-in (maybe through another module) would be the best approach, since bots with a lot of channels will end up with very high memory usage.
As far as I'm aware, these are decent methods of caching messages:

  • per-guild (cache max. n messages per guild before dropping old messages)
  • per-channel (cache max. n messages per channel before dropping old messages)

I currently use an Agent to accomplish caching on a per-channel basis: https://github.com/jchristgit/Bolt/blob/master/lib/bolt/message_cache.ex
It's very dumb but it does its job. An ETS table might be better suited, but I've never used ETS directly, so I wouldn't know ...

My question: is something like this planned for nostrum, would it be a "nice-to-have", or is the library supposed to keep the implementation of this up to the user?

improve logging

There are some cases where we're probably using the wrong logging levels, and more place where we could have logging that we don't.

Creating an issue to ensure it's addressed. 🙃

Gateway ratelimiting

Currently there is no ratelimiting on requests sent over the gateway.

It would be somewhat trivial to implement ratelimiting using GenStage, such that only x amount of events are sent in a given time frame.

For Consideration

If we decide to use GenStage, there are a couple things we need to consider

Differing ratelimits

Different types of messages have different ratelimits that we need to respect. This makes it a little more complicated as we need to do some sort of partitioning and/or spawn multiple consumers.

Priority

We want to be able to give certain messages a priority over others (I.E. we want to handle heartbeats before we send member requests). Given that we will likely not be storing demand in memory, we can develop some kind of naive priority queue to handle this for us.

TODO:

  • Implement
    • Differing ratelimits
    • Priority

User/Nick State Issues

I am noticing when a nickname is reset on a server (meaning the nick is nil), the GUILD_MEMBER_UPDATE event payload received still contains the old nick in the new member payload.

Mentioning a mentionable role in a message results in an error

Hi,

I've a problem sending mentionable roles in a message. E.g. the message <@&123456> where 123456 is the id of a mentionable role, will result in the following error:

18:19:14.063 [error] GenServer #PID<0.240.0> terminating
** (BadMapError) expected a map, got: "123456"
    (elixir) lib/map.ex:424: Map.get("123456", "avatar", nil)
    (poison) lib/poison/decoder.ex:53: anonymous fn/3 in Poison.Decode.transform_struct/4
    (stdlib) lists.erl:1263: :lists.foldl/3
    (poison) lib/poison/decoder.ex:52: Poison.Decode.transform_struct/4
    (poison) lib/poison/decoder.ex:24: anonymous fn/5 in Poison.Decode.transform/4
    (elixir) lib/enum.ex:1826: Enum."-reduce/3-lists^foldl/2-0-"/3
    (poison) lib/poison/decoder.ex:24: Poison.Decode.transform/4
    (poison) lib/poison/decoder.ex:68: anonymous fn/6 in Poison.Decode.do_transform_struct/4

Here is a minimal project that reproduces the error: https://github.com/gerritwalther/nostrum_role_test.
It requires permission to create a role in the discord channel, but you can easily refactor it to use an existing role.

As far as I can see the problem occurs when handling the response from the Discord channel and Nostrum tries to decode the response with poison: https://github.com/kraigie/nostrum/blob/master/lib/nostrum/api.ex#L1755

Tell me if I can help to solve the problem, but my Elixir knowledge isn't that solid yet.

Inconsistent documentation in the Api module

Like #49 , this is another issue for tracking changes that we do while working on fixing the Api. After the Api work is done, all Api functions should have the following documentation format:

  • Each @doc attribute should use the ~S sigil.
  • Each section is to be separated by a line break.
  • Each code blocked section will use fenced code block markdown with the backtick symbols (`) instead of indentation. It will also specify the elixir language.
  • The first section contains the endpoint's purpose. It will not have a header.
  • The second section contains the endpoint's required permissions and fired gateway events (if applicable). It will not have a header. Endpoint specific details may go here if applicable.
  • The third section contains the function's return values. It should be kept simple. It will not have a header.
  • The fourth section contains the endpoint's JSON params, if applicable. It will have a header. The header will be labeled as "Options". This section will also mention any required options as a final section note.
  • The fifth section contains the function's examples. This section should disclose confusion on how the function can be used. It will contain a header.
    • Alternatively, if a function will point to another function for examples, the example section will be
      moved beneath the return value section. In this case, the example will not have a header.

Here an example template for the create_guild_emoji/2 function.

@doc ~S"""
Creates a new emoji for the given guild.

This endpoint requires the `MANAGE_EMOJIS` permission. It fires the `GUILD_EMOJIS_UPDATE` event.

If successful, returns `{:ok, emoji}`. Otherwise, returns a `t:Nostrum.Api.error/0`.

## Options

  * `:name` (string) - name of the emoji
  * `:image` (base64 data URI) - the 128x128 emoji image. Maximum size of 256kb
  * `:roles` (list of `t:Nostrum.Struct.Snowflake.t/0`) - roles for which this emoji will be whitelisted
    (default: [])

  `:name` and `:image` are always required.

## Examples

```Elixir
image = "data:image/png;base64,YXl5IGJieSB1IGx1a2luIDQgc3VtIGZ1az8="

Nostrum.Api.create_guild_emoji(43189401384091, name: "nostrum", image: image, roles: [])
```
"""

An example for delete_own_reaction/3:

@doc ~S"""
Deletes a reaction made by the user.

If succesful, returns `{:ok}`. Otherwise, returns `t:Nostrum.Api.error/0`.

See `create_reaction/3` for similar examples.
"""

Concerns and Solutions

  1. Some API functions, like Nostrum.Api.get_user/1 are obsolete due to nostrum already having a cache. Shouldn't we document that these functions are obsolete?

We will be addressing this by mentioning the cache and its usage in the Api module doc.

Known inconsistencies

  • User related Api functions.

Cache get() methods take keyword list

Cache get methods take keyword list for just one argument. It makes it harder to use pipes:

msg.channel_id |> ChannelCache.get! doesn't work and I have to use msg.channel_id |> (&ChannelCache.get! id: &1).()

There is method that takes whole message, but it works only for normal get() and not for banged get!() :(

'Bad record mac' error still an issue with correct 'gun' dependency

In the README it's stated that you have to fetch the 'dd1bfe4d6f9fb277781d922aa8bbb5648b3e6756' ref of gun to make the library work with OTP 20.

Doing so and then using the master branch (no ref/tag specified) of nostrum seems to have the same issue as without the supposed fix.

I'm running Elixir 1.5.2, OTP 20 and the specified dependency specifications. Any ideas on why this still seems to be an issue?

Here is the error message, for posterity's sake:

==> pomoshtnik_discord
Compiling 2 files (.ex)
Generated pomoshtnik_discord app

20:35:18.626 [error] SSL: :cipher: ssl_alert.erl:88:Fatal error: bad record mac


20:35:18.629 [error] SSL: :cipher: ssl_alert.erl:88:Fatal error: bad record mac


20:35:18.652 [error] SSL: :cipher: ssl_alert.erl:88:Fatal error: bad record mac


20:35:18.671 [error] SSL: :cipher: ssl_alert.erl:88:Fatal error: bad record mac


20:35:18.695 [error] SSL: :cipher: ssl_alert.erl:88:Fatal error: bad record mac


20:35:18.725 [error] SSL: :cipher: ssl_alert.erl:88:Fatal error: bad record mac


=INFO REPORT==== 14-Oct-2017::20:35:18 ===
    application: logger
    exited: stopped
    type: temporary
** (Mix) Could not start application nostrum: Nostrum.start(:normal, []) returned an error: shutdown: failed to start child: Nostrum.Shard.Supervisor
    ** (EXIT) shutdown: failed to start child: 0
        ** (EXIT) shutdown: failed to start child: Nostrum.Shard.Session
            ** (EXIT) an exception was raised:
                ** (ErlangError) Erlang error: {:gone, {:tls_alert, 'bad record mac'}}
                    (gun) /home/gonz/code/elixir/pomoshtnik/deps/gun/src/gun.erl:596: :gun.retry/2
                    (gun) /home/gonz/code/elixir/pomoshtnik/deps/gun/src/gun.erl:528: :gun.proc_lib_hack/5
                    (stdlib) proc_lib.erl:247: :proc_lib.init_p_do_apply/3

Here is the lock-file:

%{"certifi": {:hex, :certifi, "1.0.0", "1c787a85b1855ba354f0b8920392c19aa1d06b0ee1362f9141279620a5be2039", [], [], "hexpm"},
  "cowlib": {:git, "https://github.com/ninenines/cowlib", "bd37be4d3b065600c3b76b492535e76e5d413fc1", [ref: "master"]},
  "gen_stage": {:hex, :gen_stage, "0.12.2", "e0e347cbb1ceb5f4e68a526aec4d64b54ad721f0a8b30aa9d28e0ad749419cbb", [], [], "hexpm"},
  "gun": {:git, "https://github.com/ninenines/gun.git", "dd1bfe4d6f9fb277781d922aa8bbb5648b3e6756", [ref: "dd1bfe4d6f9fb277781d922aa8bbb5648b3e6756"]},
  "hackney": {:hex, :hackney, "1.7.1", "e238c52c5df3c3b16ce613d3a51c7220a784d734879b1e231c9babd433ac1cb4", [], [{:certifi, "1.0.0", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "4.0.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "1.0.1", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "1.0.2", [hex: :mimerl, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "1.1.1", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}], "hexpm"},
  "httpoison": {:hex, :httpoison, "0.11.1", "d06c571274c0e77b6cc50e548db3fd7779f611fbed6681fd60a331f66c143a0b", [], [{:hackney, "~> 1.7.0", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm"},
  "idna": {:hex, :idna, "4.0.0", "10aaa9f79d0b12cf0def53038547855b91144f1bfcc0ec73494f38bb7b9c4961", [], [], "hexpm"},
  "metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [], [], "hexpm"},
  "mimerl": {:hex, :mimerl, "1.0.2", "993f9b0e084083405ed8252b99460c4f0563e41729ab42d9074fd5e52439be88", [], [], "hexpm"},
  "nostrum": {:git, "https://github.com/Kraigie/nostrum", "06af555ea07fc09b340740eb7c10345551be8799", []},
  "poison": {:hex, :poison, "3.1.0", "d9eb636610e096f86f25d9a46f35a9facac35609a7591b3be3326e99a0484665", [], [], "hexpm"},
  "ranch": {:git, "https://github.com/ninenines/ranch", "70f9696b6c35d029ac7bce67485713aee3983917", [ref: "master"]},
  "slack": {:hex, :slack, "0.12.0", "a305f87adca043e056a86f92151d085a8c359718f9c4ca7f1d1012d67b75db8a", [], [{:httpoison, "~> 0.11", [hex: :httpoison, repo: "hexpm", optional: false]}, {:poison, "~> 3.0", [hex: :poison, repo: "hexpm", optional: false]}, {:websocket_client, "~> 1.2.4", [hex: :websocket_client, repo: "hexpm", optional: false]}], "hexpm"},
  "ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.1", "28a4d65b7f59893bc2c7de786dec1e1555bd742d336043fe644ae956c3497fbe", [], [], "hexpm"},
  "websocket_client": {:hex, :websocket_client, "1.2.4", "14ec1ca4b6d247b44ccd9a80af8f6ca98328070f6c1d52a5cb00bc9d939d63b8", [], [], "hexpm"}}

SSL: :cipher: ssl_alert.erl:88:Fatal error: bad record mac

I'm not sure there is much you can do about this, or if some hex package needs updating, but after upgrading to OpenSSL v1.1.0f I have been unable to start a nostrum bot. Here is a log of what it looks like when I attempt to start:

$ iex -S mix
Erlang/OTP 20 [erts-9.0] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:10] [hipe] [kernel-poll:false]

14:42:25.005 [error] SSL: :cipher: ssl_alert.erl:88:Fatal error: bad record mac


14:41:22.743 [error] SSL: :cipher: ssl_alert.erl:88:Fatal error: bad record mac


14:41:22.767 [error] SSL: :cipher: ssl_alert.erl:88:Fatal error: bad record mac


14:41:22.794 [error] SSL: :cipher: ssl_alert.erl:88:Fatal error: bad record mac


14:41:22.815 [error] SSL: :cipher: ssl_alert.erl:88:Fatal error: bad record mac


14:41:22.831 [info]  Application nostrum exited: Nostrum.start(:normal, []) returned an error: shutdown: failed to start child: Nostrum.Shard.Supervisor
    ** (EXIT) shutdown: failed to start child: 0
        ** (EXIT) shutdown: failed to start child: Nostrum.Shard.Session
            ** (EXIT) normal

14:41:22.831 [info]  Application gun exited: :stopped

14:41:22.831 [info]  Application ranch exited: :stopped

14:41:22.831 [info]  Application cowlib exited: :stopped

14:41:22.831 [info]  Application httpoison exited: :stopped

14:41:22.831 [info]  Application hackney exited: :stopped

14:41:22.831 [info]  Application metrics exited: :stopped

14:41:22.831 [info]  Application ssl_verify_fun exited: :stopped

14:41:22.831 [info]  Application certifi exited: :stopped

14:41:22.831 [info]  Application mimerl exited: :stopped

14:41:22.831 [info]  Application idna exited: :stopped

14:41:22.831 [info]  Application poison exited: :stopped

14:41:22.831 [info]  Application gen_stage exited: :stopped

=INFO REPORT==== 19-Jul-2017::14:41:22 ===
    application: logger
    exited: stopped
    type: temporary
** (Mix) Could not start application nostrum: Nostrum.start(:normal, []) returned an error: shutdown: failed to start child: Nostrum.Shard.Supervisor
    ** (EXIT) shutdown: failed to start child: 0
        ** (EXIT) shutdown: failed to start child: Nostrum.Shard.Session
            ** (EXIT) normal

Again, I've not really seen anything like this so I have no idea if this is an issue I created during the update to v1.1.0f or not. Any insight will be wonderful.

You can see the source of my code here: https://github.com/KumaKaiNi/discord-kuma

Thank you!

Allow more than one api client per application/move config out of config.exs

Reading from config.exs is bad practice for a library in general, but this both prehibits nostrum from being used to create a hedwig adapter and for a large spectrum of use-cases, including, for example, discord bots as a service, where users can input their own token, etc, and set up a bot under a custom bot account for their server.

Implement Snowflake.from_time

Generating snowflake values has a few use cases:

  • Fetching channel history before/after/around a certain time, when an existing message ID isn't known
  • Filtering messages out of a collection older than two weeks for bulk deletion
  • If search is ever exposed to bots, the search API uses snowflakes as well for its time filters
  • For sending nonce in creating messages

ZLib Issue

The bot randomly disconnected, and upon reconnect this appeared:

21:32:36.595 [info]  websocket closed, attempting reconnect

21:32:36.992 [info]  WAITING 5251 BEFORE NEXT SHARD CONNECT

21:32:37.045 [error] GenServer #PID<0.304.0> terminating
** (stop) :data_error
    zlib.erl:558: :zlib.call/3
    zlib.erl:270: :zlib.inflate/2
    (nostrum) lib/nostrum/shard/session.ex:101: Nostrum.Shard.Session.handle_info/2
    (stdlib) gen_server.erl:616: :gen_server.try_dispatch/4
    (stdlib) gen_server.erl:686: :gen_server.handle_msg/6
    (stdlib) proc_lib.erl:247: :proc_lib.init_p_do_apply/3
Last message: {:gun_ws, #PID<0.307.0>, {:binary, <<120, 156, 36, 204, 77, 14, 68, 64, 16, 197, 241, 231, 35, 22, 150, 18, 23, 176, 239, 51, 73, 153, 42, 180, 180, 70, 171, 24, 179, 118, 18, 55, 213, 19, 155, 151, 223, 219, 252, 47, 5, 144, 51, 18, 254, 35, 101, ...>>}}
State: %{gateway: 'gateway.discord.gg', gun_pid: #PID<0.307.0>,
21:32:37.046 [info]  GenStage consumer #PID<0.313.0> is stopping after receiving cancel from producer #PID<0.306.0> with reason: {:data_error,
 [{:zlib, :call, 3, [file: 'zlib.erl', line: 558]},
  {:zlib, :inflate, 2, [file: 'zlib.erl', line: 270]},
  {Nostrum.Shard.Session, :handle_info, 2,
   [file: 'lib/nostrum/shard/session.ex', line: 101]},
  {:gen_server, :try_dispatch, 4, [file: 'gen_server.erl', line: 616]},
  {:gen_server, :handle_msg, 6, [file: 'gen_server.erl', line: 686]},
  {:proc_lib, :init_p_do_apply, 3, [file: 'proc_lib.erl', line: 247]}]}

relevant line would be:

   |> :zlib.inflate(new_buffer)

Channel Updates Issue

Is there a known issue with the CHANNEL_UPDATE event when it's triggered by a permission overwrite? The consumer crashes when this occurs:

15:34:05.436 [error] GenServer #PID<0.437.0> terminating
** (stop) exited in: GenServer.call(#PID<0.435.0>, {:update, :channel, %Nostrum.Struct.Channel{application_id: nil, bitrate: nil, guild_id: 105713369939480576, icon: nil, id: 419255918199439363, last_message_id: 458680159143460864, last_pin_timestamp: nil, name: "bot-testing", nsfw: false, owner_id: nil, parent_id: nil, permission_overwrites: [%Nostrum.Struct.Overwrite{allow: 0, deny: 1024, id: 105713369939480576, name: nil}, %Nostrum.Struct.Overwrite{allow: 805829713, deny: 0, id: 168192499293224960, name: nil}], position: 24, recipients: nil, topic: nil, type: 0, user_limit: nil}}, 5000)
    ** (EXIT) an exception was raised:
        ** (Protocol.UndefinedError) protocol Enumerable not implemented for %Nostrum.Struct.Overwrite{allow: 0, deny: 1024, id: 105713369939480576, name: nil}. This protocol is implemented for: DBConnection.PrepareStream, DBConnection.Stream, Date.Range, File.Stream, Function, GenEvent.Stream, HashDict, HashSet, IO.Stream, List, Map, MapSet, Postgrex.Stream, Range, Stream
            (elixir) /private/tmp/elixir-20180316-64850-zsrybb/elixir-1.6.4/lib/elixir/lib/enum.ex:1: Enumerable.impl_for!/1
            (elixir) /private/tmp/elixir-20180316-64850-zsrybb/elixir-1.6.4/lib/elixir/lib/enum.ex:141: Enumerable.reduce/3
            (elixir) lib/enum.ex:1911: Enum.reverse/1
            (elixir) lib/enum.ex:2588: Enum.to_list/1
            (elixir) lib/map.ex:192: Map.new/2
            (nostrum) lib/nostrum/struct/overwrite.ex:44: Nostrum.Struct.Overwrite.to_struct/1
            (elixir) lib/enum.ex:1294: Enum."-map/2-lists^map/1-0-"/2
            (elixir) lib/map.ex:571: Map.update/4
Last message: {:DOWN, #Reference<0.1399560593.7340038.203953>, :process, #PID<0.436.0>, {{%Protocol.UndefinedError{description: "", protocol: Enumerable, value: %Nostrum.Struct.Overwrite{allow: 0, deny: 1024, id: 105713369939480576, name: nil}}, [{Enumerable, :impl_for!, 1, [file: '/private/tmp/elixir-20180316-64850-zsrybb/elixir-1.6.4/lib/elixir/lib/enum.ex', line: 1]}, {Enumerable, :reduce, 3, [file: '/private/tmp/elixir-20180316-64850-zsrybb/elixir-1.6.4/lib/elixir/lib/enum.ex', line: 141]}, {Enum, :reverse, 1, [file: 'lib/enum.ex', line: 1911]}, {Enum, :to_list, 1, [file: 'lib/enum.ex', line: 2588]}, {Map, :new, 2, [file: 'lib/map.ex', line: 192]}, {Nostrum.Struct.Overwrite, :to_struct, 1, [file: 'lib/nostrum/struct/overwrite.ex', line: 44]}, {Enum, :"-map/2-lists^map/1-0-", 2, [file: 'lib/enum.ex', line: 1294]}, {Map, :update, 4, [file: 'lib/map.ex', line: 571]}]}, {GenServer, :call, [#PID<0.435.0>, {:update, :channel, %Nostrum.Struct.Channel{application_id: nil, bitrate: nil, guild_id: 105713369939480576, icon: nil, id: 419255918199439363, last_message_id: 458680159143460864, last_pin_timestamp: nil, name: "bot-testing", nsfw: false, owner_id: nil, parent_id: nil, permission_overwrites: [%Nostrum.Struct.Overwrite{allow: 0, deny: 1024, id: 105713369939480576, name: nil}, %Nostrum.Struct.Overwrite{allow: 805829713, deny: 0, id: 168192499293224960, name: nil}], position: 24, recipients: nil, topic: nil, type: 0, user_limit: nil}}, 5000]}}}
State: %ConsumerSupervisor{args: [UsmcBot.Handler, []], children: %{}, max_restarts: 3, max_seconds: 5, mod: Nostrum.Consumer, name: {#PID<0.437.0>, Nostrum.Consumer}, producers: %{}, restarting: 0, restarts: [], strategy: :one_for_one, template: {UsmcBot.Handler, {UsmcBot.Handler, :start_link, []}, :transient, 5000, :worker, [UsmcBot.Handler]}}

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.