1
0
hugo/content/blog/2022-02-06-mammut.md

267 lines
5.8 KiB
Markdown
Raw Normal View History

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