2024-04-23 13:21:26 +00:00
|
|
|
+++
|
|
|
|
date = "2022-02-06"
|
|
|
|
tags = ["rust", "mastodon"]
|
|
|
|
title = "mammutのexampleをまとめてみる"
|
|
|
|
slug = "rust-mammut"
|
|
|
|
+++
|
|
|
|
|
|
|
|
mastodon apiのrust libである[mammut](https://docs.rs/mammut/latest/mammut/)ですが、exampleがあるとわかりやすいと思ったので、作ってみました。
|
|
|
|
|
|
|
|
まず、mastodonへのrequestはこんな感じになります。
|
|
|
|
|
|
|
|
```sh
|
|
|
|
curl -H "Content-Type: application/json" -X POST -Ss https://$host/oauth/token \
|
|
|
|
-d "{
|
|
|
|
\"client_id\": \"$client_id\",
|
|
|
|
\"client_secret\": \"$client_secret\",
|
|
|
|
\"grant_type\": \"password\",
|
|
|
|
\"username\": \"$username\",
|
|
|
|
\"password\": \"$password\",
|
|
|
|
\"scope\": \"$scope\"
|
|
|
|
}"
|
|
|
|
```
|
|
|
|
|
|
|
|
mammutでは`Data`として認証に必要な要素がまとめられてますので、各種要素を入れて`Mastodon::from_data(data)`すると認証できます。
|
|
|
|
|
|
|
|
```toml:Cargo.toml
|
|
|
|
[package]
|
|
|
|
name = "test"
|
|
|
|
version = "0.0.1"
|
|
|
|
|
|
|
|
[dependencies]
|
|
|
|
dotenv = "0.15"
|
|
|
|
mammut = "0.13.0"
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
```rust:src/main.rs
|
|
|
|
extern crate mammut;
|
|
|
|
extern crate dotenv;
|
|
|
|
|
|
|
|
use std::env;
|
|
|
|
use mammut::{Data, Mastodon};
|
|
|
|
|
|
|
|
fn main() -> mammut::Result<()> {
|
|
|
|
|
|
|
|
let data = Data {
|
|
|
|
base: env::var("BASE").unwrap().into(),
|
|
|
|
client_id: env::var("CLIENT_ID").unwrap().into(),
|
|
|
|
client_secret: env::var("CLIENT_SECRET").unwrap().into(),
|
|
|
|
redirect: env::var("REDIRECT").unwrap().into(),
|
|
|
|
token: env::var("TOKEN").unwrap().into(),
|
|
|
|
};
|
|
|
|
|
|
|
|
let mastodon = Mastodon::from_data(data);
|
|
|
|
let t = mastodon.verify_credentials();
|
|
|
|
println!("{:?}", t);
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
```sh:.env
|
|
|
|
export TOKEN=''
|
|
|
|
export CLIENT_ID=''
|
|
|
|
export CLIENT_SECRET=''
|
|
|
|
export REDIRECT=''
|
2024-04-23 13:28:33 +00:00
|
|
|
export BASE='https://mstdn.syui.ai'
|
2024-04-23 13:21:26 +00:00
|
|
|
```
|
|
|
|
|
|
|
|
```sh
|
|
|
|
$ cargo run
|
|
|
|
$ ./target/debug/test
|
|
|
|
```
|
|
|
|
|
|
|
|
Data : https://docs.rs/mammut/latest/mammut/struct.Data.html
|
|
|
|
|
|
|
|
### src/data
|
|
|
|
|
|
|
|
ちなみに、`struct Data`はmammutが用意してるので、作る必要がありませんが、ファイルを分けて、何度も呼び出す場合、下記のようになります。`env`をやめて`config`にtokenなどを書いて読み込む例です。
|
|
|
|
|
|
|
|
なお、`edition`を`2021`にすることで、様々な記法を省略できたりします。
|
|
|
|
|
|
|
|
```toml:Cargo.toml
|
|
|
|
[package]
|
|
|
|
name = "test"
|
|
|
|
version = "0.0.1"
|
|
|
|
edition = "2021"
|
|
|
|
|
|
|
|
[dependencies]
|
|
|
|
dotenv = "0.15"
|
|
|
|
mammut = "0.13.0"
|
|
|
|
serde_derive = "*"
|
|
|
|
serde = "*"
|
|
|
|
config = { git = "https://github.com/mehcode/config-rs", branch = "master" }
|
|
|
|
```
|
|
|
|
|
|
|
|
```rust:src/data.rs
|
|
|
|
use config::{Config, ConfigError, File};
|
|
|
|
use serde_derive::Deserialize;
|
|
|
|
use std::borrow::Cow;
|
|
|
|
|
|
|
|
#[derive(Debug, Deserialize)]
|
|
|
|
#[allow(unused)]
|
|
|
|
pub struct Data {
|
|
|
|
pub base: Cow<'static, str>,
|
|
|
|
pub token: Cow<'static, str>,
|
|
|
|
pub client_id: Cow<'static, str>,
|
|
|
|
pub client_secret: Cow<'static, str>,
|
|
|
|
pub redirect: Cow<'static, str>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Data {
|
|
|
|
pub fn new() -> Result<Self, ConfigError> {
|
|
|
|
let s = Config::builder()
|
|
|
|
.add_source(File::with_name("config"))
|
|
|
|
.build()?;
|
|
|
|
s.try_deserialize()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
```rust:src/main.rs
|
|
|
|
pub mod data;
|
|
|
|
use data::Data as Datas;
|
|
|
|
use mammut::{Data, Mastodon};
|
|
|
|
|
|
|
|
fn token() -> Mastodon {
|
|
|
|
let data = Datas::new().unwrap();
|
|
|
|
let data = Data {
|
|
|
|
base: data.base,
|
|
|
|
token: data.token,
|
|
|
|
client_id: data.client_id,
|
|
|
|
client_secret: data.client_secret,
|
|
|
|
redirect: data.redirect,
|
|
|
|
};
|
|
|
|
let t = Mastodon::from_data(data);
|
|
|
|
return t;
|
|
|
|
}
|
|
|
|
|
|
|
|
fn main() {
|
|
|
|
let mastodon = token();
|
|
|
|
let t = mastodon.verify_credentials();
|
|
|
|
println!("{:#?}", t);
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
```sh:config.toml
|
|
|
|
token = ""
|
|
|
|
client_id = ""
|
|
|
|
client_secret = ""
|
|
|
|
redirect = "localhost"
|
2024-04-23 13:28:33 +00:00
|
|
|
base = "https://mstdn.syui.ai"
|
2024-04-23 13:21:26 +00:00
|
|
|
```
|
|
|
|
|
|
|
|
```sh
|
|
|
|
$ cargo run
|
|
|
|
```
|
|
|
|
|
|
|
|
### home dir
|
|
|
|
|
|
|
|
ここからは簡潔に紹介します。
|
|
|
|
|
|
|
|
`$HOME`を使うには`shellexpand`が便利です。
|
|
|
|
|
|
|
|
```rust:Cargo.toml
|
|
|
|
[dependencies]
|
|
|
|
shellexpand = "*"
|
|
|
|
```
|
|
|
|
|
|
|
|
```rust
|
|
|
|
impl Data {
|
|
|
|
pub fn new() -> Result<Self, ConfigError> {
|
|
|
|
let d = shellexpand::tilde("~") + "/.config/msr/config.toml";
|
|
|
|
let s = Config::builder()
|
|
|
|
.add_source(File::with_name(&d))
|
|
|
|
.add_source(config::Environment::with_prefix("APP"))
|
|
|
|
.build()?;
|
|
|
|
s.try_deserialize()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
### toot post
|
|
|
|
|
|
|
|
```rust
|
|
|
|
fn post() {
|
|
|
|
let mastodon = token();
|
|
|
|
let message = "test".to_string();
|
|
|
|
let status_b = StatusBuilder::new(format!("{}", message));
|
|
|
|
let post = mastodon.new_status(status_b);
|
|
|
|
println!("{:?}", post);
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
### timeline
|
|
|
|
|
|
|
|
```rust
|
|
|
|
fn timeline() -> mammut::Result<()> {
|
|
|
|
let mastodon = token();
|
|
|
|
let t = mastodon.get_home_timeline()?.initial_items;
|
|
|
|
println!("{:?}", t);
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
### toot delete
|
|
|
|
|
|
|
|
```rust
|
|
|
|
#[allow(unused_must_use)]
|
|
|
|
fn delete() -> mammut::Result<()> {
|
|
|
|
let mastodon = token();
|
|
|
|
let id = &mastodon.get_home_timeline()?.initial_items[0].id;
|
|
|
|
mastodon.delete_status(id);
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
### upload media
|
|
|
|
|
|
|
|
`media_ids`が必要になるので、手順としては、画像をmastodonのmedia serverにuploadする処理と、その出力にある`media_ids`をtootとしてpostする処理が必要になります。
|
|
|
|
|
|
|
|
```rust
|
|
|
|
use mammut::{Data, Mastodon, StatusBuilder, MediaBuilder};
|
|
|
|
|
|
|
|
fn media() {
|
|
|
|
let mastodon = token();
|
|
|
|
let file = "./test.png".to_string();
|
|
|
|
let t = mastodon.media(file.into());
|
|
|
|
println!("{:?}", t);
|
|
|
|
let id = t.as_ref().unwrap();
|
|
|
|
let mid = Some(vec![id.id.to_string()]);
|
|
|
|
let status = "#media".to_string();
|
|
|
|
let status_b = StatusBuilder {
|
|
|
|
status: status,
|
|
|
|
in_reply_to_id: None,
|
|
|
|
media_ids: mid,
|
|
|
|
sensitive: None,
|
|
|
|
spoiler_text: None,
|
|
|
|
visibility: None,
|
|
|
|
};
|
|
|
|
let post = mastodon.new_status(status_b);
|
|
|
|
println!("{:?}", post);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
StatusBuilder : https://docs.rs/mammut/0.11.0/mammut/status_builder/struct.StatusBuilder.html
|
|
|
|
|
|
|
|
`text`も同時に投稿するのはこっち。
|
|
|
|
|
|
|
|
|
|
|
|
```rust
|
|
|
|
use std::borrow::Cow;
|
|
|
|
|
|
|
|
let text = "test";
|
|
|
|
let s = Cow::Owned(String::from(text));
|
|
|
|
let status_b = StatusBuilder {
|
|
|
|
status: s,
|
|
|
|
in_reply_to_id: None,
|
|
|
|
media_ids: mid,
|
|
|
|
sensitive: None,
|
|
|
|
spoiler_text: None,
|
|
|
|
visibility: None,
|
|
|
|
};
|
|
|
|
```
|
|
|
|
|
|
|
|
ref : https://github.com/syui/msr
|