1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
//! Asynchronous client for [Misskey](https://github.com/syuilo/misskey).
//!
//! We provide four components in this crate:
//!
//! - Clients that handles the connection between Misskey. As Misskey provides HTTP and WebSocket
//!   interfaces to interact with, we have [`HttpClient`] and [`WebSocketClient`] implementations
//!   correspondingly.
//! - API bindings, including requests/responses of [endpoints][`endpoint`] and messages on
//!   [channels][`streaming::channel`].
//! - Abstraction that connects API datatypes and client implementations: [`Request`][`endpoint::Request`],
//!   [`ConnectChannelRequest`][`streaming::ConnectChannelRequest`], etc.
//! - High-level API for easier handling of various functionalities: [`ClientExt`] and others.
//!
//! # Examples
//!
//! Create a note:
//!
//! ```no_run
//! use misskey::prelude::*;
//! use misskey::HttpClient;
//!
//! # #[tokio::main]
//! # async fn main() -> anyhow::Result<()> {
//! let client = HttpClient::builder("https://your.instance.example/api/")
//!     .token("API_TOKEN")
//!     .build()?;
//!
//! client.create_note("Hello, Misskey").await?;
//! # Ok(())
//! # }
//! ```
//!
//! Automatically follow-back:
//!
//! ```no_run
//! use futures::stream::TryStreamExt;
//! use misskey::prelude::*;
//! use misskey::streaming::channel::main::MainStreamEvent;
//! use misskey::WebSocketClient;
//!
//! # #[tokio::main]
//! # async fn main() -> anyhow::Result<()> {
//! let client = WebSocketClient::builder("wss://your.instance.example/streaming")
//!     .token("YOUR_API_TOKEN")
//!     .connect()
//!     .await?;
//!
//! // Connect to the main stream.
//! // The main stream is a channel that streams events about the connected account.
//! let mut stream = client.main_stream().await?;
//!
//! // Wait for the next event in the main stream.
//! while let Some(event) = stream.try_next().await? {
//!     match event {
//!         // Check if the event is 'followed' and the user is not a bot
//!         MainStreamEvent::Followed(user) if !user.is_bot => {
//!             println!("followed from @{}", user.username);
//!
//!             // Follow back `user` if you haven't already.
//!             if !client.is_following(&user).await? {
//!                 client.follow(&user).await?;
//!             }
//!         }
//!         // other events are just ignored here
//!         _ => {}
//!    }
//! }
//! # Ok(())
//! # }
//! ```
//!
//! See the [example](https://github.com/coord-e/misskey-rs/tree/develop/example) directory for more examples.
//!
//! # Feature flags
//!
//! - `http-client`: Enables the HTTP client which is capable for uploading files.
//!   Enabled by default.
//! - `websocket-client`: Enables the WebSocket client which is capable for streaming.
//!   Enabled by default.
//! - `tokio-runtime`: Use the [tokio](https://tokio.rs) v0.3 runtime in the WebSocket client.
//!   Enabled by default.
//! - `tokio02-runtime`: Use the [tokio](https://tokio.rs) v0.2 runtime in the WebSocket client.
//! - `async-std-runtime`: Use the [async-std](https://async.rs) runtime in the WebSocket client.
//! - `aid`: Assume that the `aid` ID generation method is used in the targeted Misskey instance.
//!   Enabled by default.
//! - `meid`: Assume that the `meid` ID generation method is used in the targeted Misskey instance.
//! - `ulid`: Assume that the `ulid` ID generation method is used in the targeted Misskey instance.
//! - `objectid`: Assume that the `objectid` ID generation method is used in the targeted Misskey instance.
//! - and version flags, as described in [version flags section](#specifying-misskey-version).
//!
//! ## Specifying Misskey version
//!
//! We have a set of feature flags to specify the targeted Misskey version.
//! The latest one (`12-63-0`) is enabled as a default. You can opt-in to compile for prior
//! Misskey version by using `default-features = false` and the corresponding feature flag.
//!
//! For example, to compile for Misskey v12.33.0 with WebSocket client on async-std runtime, add
//! the following to your `Cargo.toml` file:
//!
//! ```toml
//! [dependencies.misskey]
//! version = "0.2"
//! default-features = false
//! features = ["12-31-0", "websocket-client", "async-std-runtime", "aid"]
//! ```
//!
//! | Feature                    | Supported Misskey versions (inclusive) | Tested Misskey version |
//! | -------------------------- | -------------------------------------- | ---------------------- |
//! | `12-63-0`                  | v12.63.0                               | v12.63.0               |
//! | `12-62-2`                  | v12.62.2                               | v12.62.2               |
//! | `12-62-0`                  | v12.62.0 ~ v12.62.1                    | v12.62.0               |
//! | `12-61-0`                  | v12.61.0 ~ v12.61.1                    | v12.61.0               |
//! | `12-60-0`                  | v12.60.0 ~ v12.60.1                    | v12.60.0               |
//! | `12-58-0`                  | v12.58.0 ~ v12.59.0                    | v12.58.0               |
//! | `12-57-0`                  | v12.57.0 ~ v12.57.4                    | v12.57.1               |
//! | `12-55-0`                  | v12.55.0 ~ v12.56.0                    | v12.55.0               |
//! | `12-51-0`                  | v12.51.0 ~ v12.54.0                    | v12.51.0               |
//! | `12-49-0`                  | v12.49.0 ~ v12.50.0                    | v12.49.0               |
//! | `12-48-0`                  | v12.48.0 ~ v12.48.3                    | v12.48.0               |
//! | `12-47-0`                  | v12.47.0 ~ v12.47.1                    | v12.47.1               |
//! | `12-42-0`                  | v12.42.0 ~ v12.46.0                    | v12.42.0               |
//! | `12-39-0`                  | v12.39.0 ~ v12.41.3                    | v12.39.0               |
//! | `12-37-0`                  | v12.37.0 ~ v12.38.1                    | v12.37.0               |
//! | `12-31-0`                  | v12.31.0 ~ v12.36.1                    | v12.31.0               |
//! | `12-29-0`                  | v12.29.0 ~ v12.30.0                    | v12.29.0               |
//! | `12-28-0`                  | v12.28.0                               | v12.28.0               |
//! | `12-27-0`                  | v12.27.0 ~ v12.27.1                    | v12.27.0               |
//! | `12-19-0`                  | v12.19.0 ~ v12.26.0                    | v12.20.0               |
//! | `12-13-0`                  | v12.13.0 ~ v12.18.1                    | v12.13.0               |
//! | `12-10-0`                  | v12.10.0 ~ v12.12.0                    | v12.10.0               |
//! | `12-9-0`                   | v12.9.0                                | v12.9.0                |
//! | `12-8-0`                   | v12.8.0                                | v12.8.0                |
//! | `12-5-0`                   | v12.5.0 ~ v12.7.1                      | v12.5.0                |
//! | (no version flag enabled)  | v12.0.0 ~ v12.4.1                      | v12.0.0                |
#![cfg_attr(docsrs, feature(doc_cfg))]
#![deny(missing_docs)]

pub mod endpoint {
    //! API endpoints.
    //!
    //! Each endpoint is implemented under modules named by replacing `/` with `::` and `-` with `_` in the endpoint name.
    //! For example, `notes/local-timeline` is implemented under [`notes::local_timeline`] and
    //! `drive/files/create` is implemented under [`drive::files::create`].
    //!
    //! All request types implement [`Request`].
    //! We dispatch it actually and get the [response][`Request::Response`]
    //! using [`Client::request`][`crate::Client::request`].
    //!
    //! # Example
    //!
    //! Create a note using `/api/notes/create`:
    //!
    //! ```no_run
    //! # use misskey::{Client, HttpClient};
    //! # #[tokio::main]
    //! # async fn main() -> anyhow::Result<()> {
    //! # let client = HttpClient::with_token("http://your.instance.example/api/".parse()?, "API_TOKEN")?;
    //! client
    //!     .request(
    //!         // Each endpoint implementation has a corresponding `Request` type.
    //!         // We can dispatch an API call by passing `Request` to `Client::request` method.
    //!         // Here, we build a `Request` to `notes/create` using a `Request::builder()`.
    //!         misskey::endpoint::notes::create::Request::builder()
    //!             .text("Hello, Misskey")
    //!             .build(),
    //!     )
    //!     // Asynchronously wait for the response.
    //!     // `Client::request` method returns `Result<ApiResult<T>>`.
    //!     // The returned `Result` may contain an error happened on our side
    //!     // (e.g. networking failure or deserialization error)
    //!     .await?
    //!     // Convert `ApiResult<T>` to `Result<T, ApiError>` using `ApiResult::into_result`.
    //!     // `ApiError` is an error which is returned from Misskey API.
    //!     .into_result()?;
    //! # Ok(())
    //! # }
    //! ```
    //!
    //! Get your own information from `/api/i`:
    //!
    //! ```no_run
    //! # use misskey::{Client, HttpClient};
    //! # #[tokio::main]
    //! # async fn main() -> anyhow::Result<()> {
    //! # let client = HttpClient::with_token("http://your.instance.example/api/".parse()?, "API_TOKEN")?;
    //!     let me = client
    //!         .request(misskey::endpoint::i::Request::default())
    //!         .await?
    //!         .into_result()?;
    //!     println!("{:?}", me);
    //! # Ok(())
    //! # }
    //! ```

    // Because the `docsrs` cfg flag does not propagate to `misskey-api`, we're dealing with this
    // by specifying `no_inline` as a workaround.
    #[doc(no_inline)]
    pub use misskey_api::endpoint::*;
    pub use misskey_api::{OffsetPaginationRequest, PaginationRequest};
    pub use misskey_core::{Request, UploadFileRequest};
}

pub mod streaming {
    //! Streaming API.
    //!
    //! # Example
    //!
    //! Stream the notes in the local timeline:
    //!
    //! ```no_run
    //! use futures::stream::StreamExt;
    //! use misskey::streaming::channel::local_timeline::{self, LocalTimelineEvent};
    //! # use misskey::WebSocketClient;
    //! # #[tokio::main]
    //! # async fn main() -> anyhow::Result<()> {
    //! # let client = WebSocketClient::builder("wss://your.instance.example/streaming")
    //! #     .token("API_TOKEN")
    //! #     .connect()
    //! #     .await?;
    //!
    //! // Connect to the local timeline channel.
    //! let mut stream = client.channel(local_timeline::Request::default()).await?;
    //!
    //! loop {
    //!     // Wait for the next note using `next` method from `StreamExt`.
    //!     let LocalTimelineEvent::Note(note) = stream.next().await.unwrap()?;
    //!     println!("{:?}", note);
    //! }
    //! # Ok(())
    //! # }
    //! ```
    //!
    //! Capture the note:
    //!
    //! ```no_run
    //! use futures::stream::StreamExt;
    //! use misskey::model::{note::Note, id::Id};
    //! use misskey::streaming::note::NoteUpdateEvent;
    //! # use misskey::WebSocketClient;
    //! # #[tokio::main]
    //! # async fn main() -> anyhow::Result<()> {
    //! # let client = WebSocketClient::builder("wss://your.instance.example/streaming")
    //! #     .token("API_TOKEN")
    //! #     .connect()
    //! #     .await?;
    //!
    //! let mut stream = client.subnote("NOTE_ID_TO_WATCH").await?;
    //!
    //! loop {
    //!     // Wait for the event note using `next` method from `StreamExt`.
    //!     let event = stream.next().await.unwrap()?;
    //!
    //!     match event {
    //!        NoteUpdateEvent::Reacted { reaction, user_id } => {
    //!           println!("{:?} added {:?}", user_id, reaction);
    //!        }
    //!        NoteUpdateEvent::Unreacted { reaction, user_id } => {
    //!           println!("{:?} removed {:?}", user_id, reaction);
    //!        }
    //!        NoteUpdateEvent::Deleted { deleted_at } => {
    //!           println!("deleted at {:?}", deleted_at);
    //!        }
    //!        NoteUpdateEvent::PollVoted { choice, user_id } => {
    //!           println!("{:?} voted to {}", user_id, choice);
    //!        }
    //!     }
    //! }
    //! # Ok(())
    //! # }
    //! ```
    //!
    //! Monitor newly added emojis:
    //!
    //! ```no_run
    //! use futures::stream::StreamExt;
    //! use misskey::streaming::emoji::EmojiAddedEvent;
    //! # use misskey::WebSocketClient;
    //! # #[tokio::main]
    //! # async fn main() -> anyhow::Result<()> {
    //! # let client = WebSocketClient::builder("wss://your.instance.example/streaming")
    //! #     .token("API_TOKEN")
    //! #     .connect()
    //! #     .await?;
    //!
    //! // Connect to the broadcast stream.
    //! let mut stream = client.broadcast::<EmojiAddedEvent>().await?;
    //!
    //! loop {
    //!     let emoji = stream.next().await.unwrap()?.emoji;
    //!     println!("Emoji {} is added", emoji.name);
    //! }
    //! # Ok(())
    //! # }
    //! ```

    // Because the `docsrs` cfg flag does not propagate to `misskey-api`, we're dealing with this
    // by specifying `no_inline` as a workaround.
    #[doc(no_inline)]
    pub use misskey_api::streaming::*;
    pub use misskey_core::streaming::*;
}

pub mod model {
    //! Object types used in API.

    pub use misskey_api::model::*;
    pub use misskey_api::{Entity, EntityRef, PaginationItem};
    pub use misskey_core::model::*;
}

pub use misskey_core::streaming::StreamingClient;
pub use misskey_core::{Client, UploadFileClient};

#[cfg(feature = "http-client")]
#[cfg_attr(docsrs, doc(cfg(feature = "http-client")))]
pub mod http {
    //! Asynchronous HTTP-based client.

    pub use misskey_http::*;
}

#[cfg(feature = "http-client")]
#[cfg_attr(docsrs, doc(cfg(feature = "http-client")))]
pub use http::HttpClient;

#[cfg(feature = "websocket-client")]
#[cfg_attr(docsrs, doc(cfg(feature = "websocket-client")))]
pub mod websocket {
    //! Asynchronous WebSocket-based client.
    //!
    //! The underlying async runtime is determined by the feature flags.
    //! The [tokio](https://tokio.rs) runtime is enabled by default. For details, see the [feature flags section](../index.html#feature-flags).

    pub use misskey_websocket::*;
}

#[cfg(feature = "websocket-client")]
#[cfg_attr(docsrs, doc(cfg(feature = "websocket-client")))]
pub use websocket::WebSocketClient;

pub use misskey_util::{builder, pager, Error, TimelineCursor, TimelineRange};
pub use misskey_util::{ClientExt, StreamingClientExt, UploadFileClientExt};

/// Prelude for crates using `misskey-rs`.
///
/// This module provides a set of useful re-exports, including helper traits.
/// The standard usage of this module is to import its entire contents as follows:
///
/// ```
/// use misskey::prelude::*;
/// ```
pub mod prelude {
    pub use crate::Client;
    #[doc(no_inline)]
    pub use crate::ClientExt as _;
    pub use crate::StreamingClient;
    #[doc(no_inline)]
    pub use crate::StreamingClientExt as _;
    pub use crate::UploadFileClient;
    #[doc(no_inline)]
    pub use crate::UploadFileClientExt as _;
}