egg-mode-rs / egg-mode

a twitter api crate for rust
https://crates.io/crates/egg-mode
Mozilla Public License 2.0
372 stars 65 forks source link

overhaul the `direct` module to use the new API #97

Closed QuietMisdreavus closed 4 years ago

QuietMisdreavus commented 4 years ago

Back in 2018, Twitter introduced the new Account Activity API for Direct Messages, and deprecated the previous DM endpoints. egg-mode was never updated to use this new API, so when the old endpoints were shut off later that year, users couldn't use egg-mode to send and receive DMs any more.

This PR updates egg-mode's Direct Message functionality to use the new API. The functionality has been updated to reflect the new capabilities they added. Notably, it's no longer necessary to merge two different timelines to get a complete view of a user's Direct Messages - now there's a single list call that returns everything from the last 30 days. Also, now there are many things that can be added to a DM when you send it, including media, so the old send function has been converted into a DraftMessage type, a la the DraftTweet type for creating a tweet. The changelog has been updated with the full list of updates.

Closes #67

QuietMisdreavus commented 4 years ago

I've opened this as a draft because i still want to do a complete docs pass over it. However, the code works based on personal testing, so i wanted to post it in case people wanted to see it ahead of time.

QuietMisdreavus commented 4 years ago

One thing i'm not certain about is the fact that i couldn't directly implement Deserialize for DirectMessage any more, due to the format returned by Twitter. The "source app" information is only referenced as a numeric ID, so to fully populate that you need to cross-reference that mapping separately. This poses a problem when integrating Direct Messages with the raw module, since now you can't ask response_json to load up a DM struct.

There are a couple ways i can see to get around this:

  1. Scrap the "source app" info and go back to deserializing directly into a DirectMessage. The info is only populated for messages sent by the authorized user, so it's not even that useful. There would still need to be hoops to jump through to load a DM, since the returned JSON looks different between show, list, and send, but it might still be possible. Mainly, i'm not sure whether you can implement it differently for T versus Vec<T> without running into coherence issues with serde's own Vec<T> implementation.
  2. Expose the direct::raw module, either as-is or re-exported under some new raw::types module. This would allow users to deserialize data the same way as egg-mode does at the moment - by loading into a SingleEvent or EventCursor, then converting over using TryFrom. This makes the loading process more complicated for the end-user, but still allows them to use the raw module and egg-mode's types, rather than having to drop all the way to plain JSON. This is the approach i'm leaning toward, but it would introduce more complicated mechanisms to deal with, so i avoided it in the initial work.
ThomAub commented 4 years ago

Hello,

I found egg-mode few days ago and it's really a nice and polish crate ! I saw the direct module was deprecated so I started to try to fix it but I'm still learning rust and only play a bit with this crate. I realize now that I should have commented the issue 67 before starting upon this, surely too hard for me, task :D

Reading the contributing guide I try to follow as much as possible your current implementation and at the moment:

I was also block by the fact that I cannot Deserialize DirectMessage for one Event and and array of Events. I will wait and see which option you go with.

Thanks again for this great crate :)

QuietMisdreavus commented 4 years ago

@ThomAub Yeah, the deserialization work turned out to be quite complicated! I wound up having to create a bunch of new types internally to match the over-the-wire representation, before converting them into the flattened structure i wanted to expose. I wound up not implementing Deserialize for DirectMessage directly at all, and exposing a separate set of types under the raw module to allow people to directly deserialize data if they needed.

Regarding the Cursor trait, i wound up ignoring that altogether, since the "cursor" structure used by the DM Account Activity API is fundamentally different - for one, it uses a string key, and for another, there's no "previous" cursor key that you can use to go backwards in the collection. For that reason, i wound up wrapping up that behavior in a Timeline structure that was similar-but-not-the-same as the one used for Tweets. Thanks for your interest and kind words!

QuietMisdreavus commented 4 years ago

There are a couple of API things this PR is missing (specifically, Welcome Messages and the initiated_via information) but i feel like this is a significant proportion of the API to merge and set aside for now. If i remember, i can add those things before this hits a release, but for now i think this is very useful on its own.