Major refactoring: HTTP client unification and project restructuring
Some checks failed
Gitea Actions Demo / Explore-Gitea-Actions (push) Failing after 13m53s

## HTTP Client Refactoring
- Create unified HttpClient module (src/http_client.rs)
- Refactor 24 files to use shared HTTP client
- Replace .unwrap() with proper error handling
- Eliminate code duplication in HTTP requests

## Project Restructuring
- Rename package: ai → aibot
- Add dual binary support: aibot (main) + ai (compatibility alias)
- Migrate config directory: ~/.config/ai/ → ~/.config/syui/ai/bot/
- Implement backward compatibility with automatic migration

## Testing Infrastructure
- Add unit tests for HttpClient
- Create test infrastructure with cargo-make
- Add test commands: test, test-quick, test-verbose

## Documentation
- Complete migration guide with step-by-step instructions
- Updated development guide with new structure
- HTTP client API reference documentation
- Comprehensive refactoring summary

## Files Changed
- Modified: 24 source files (HTTP client integration)
- Added: src/http_client.rs, src/alias.rs, src/tests/
- Added: 5 documentation files in docs/
- Added: migration setup script

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-06-06 23:47:12 +09:00
parent 998777d46a
commit a17d2c9d66
45 changed files with 1871 additions and 593 deletions

39
src/alias.rs Normal file
View File

@ -0,0 +1,39 @@
// Legacy alias: ai -> aibot
// This provides backward compatibility for existing scripts
use std::env;
use std::path::PathBuf;
use std::process::{Command, exit};
fn main() {
let args: Vec<String> = env::args().collect();
// Skip the first argument (program name) and pass the rest to aibot
let aibot_args: Vec<&str> = args.iter().skip(1).map(|s| s.as_str()).collect();
// Try to find aibot binary in the same directory as this binary
let current_exe = env::current_exe().unwrap_or_else(|_| PathBuf::from("ai"));
let mut aibot_path = current_exe.parent().unwrap_or(&PathBuf::from(".")).to_path_buf();
aibot_path.push("aibot");
// First try relative path, then try PATH
let mut cmd = if aibot_path.exists() {
Command::new(&aibot_path)
} else {
Command::new("aibot")
};
cmd.args(&aibot_args);
match cmd.status() {
Ok(status) => {
exit(status.code().unwrap_or(1));
}
Err(e) => {
eprintln!("Error executing aibot: {}", e);
eprintln!("Make sure 'aibot' is installed and available in PATH");
eprintln!("Attempted path: {:?}", aibot_path);
exit(1);
}
}
}

View File

@ -8,35 +8,91 @@ use std::io::Write;
use std::path::Path;
pub fn data_file(s: &str) -> String {
let file = "/.config/ai/";
let mut f = shellexpand::tilde("~").to_string();
f.push_str(&file);
let path = Path::new(&f);
if path.is_dir() == false {
let _ = fs::create_dir_all(f.clone());
// 新しい設定ディレクトリ(優先)
let new_config_dir = "/.config/syui/ai/bot/";
let mut new_path = shellexpand::tilde("~").to_string();
new_path.push_str(&new_config_dir);
// 旧設定ディレクトリ(互換性のため)
let old_config_dir = "/.config/ai/";
let mut old_path = shellexpand::tilde("~").to_string();
old_path.push_str(&old_config_dir);
// 新しいディレクトリを作成
let new_dir = Path::new(&new_path);
if !new_dir.is_dir() {
let _ = fs::create_dir_all(new_path.clone());
}
match &*s {
"toml" => f + &"token.toml",
"json" => f + &"token.json",
"refresh" => f + &"refresh.toml",
_ => f + &"." + &s,
let filename = match &*s {
"toml" => "token.toml",
"json" => "token.json",
"refresh" => "refresh.toml",
_ => &format!(".{}", s),
};
let new_file = new_path.clone() + filename;
let old_file = old_path + filename;
// 新しいパスにファイルが存在する場合は新しいパスを使用
if Path::new(&new_file).exists() {
return new_file;
}
// 旧パスにファイルが存在し、新しいパスに存在しない場合は移行を試行
if Path::new(&old_file).exists() && !Path::new(&new_file).exists() {
if let Ok(_) = fs::copy(&old_file, &new_file) {
eprintln!("Migrated config file: {} -> {}", old_file, new_file);
return new_file;
}
}
// デフォルトは新しいパス
new_file
}
pub fn log_file(s: &str) -> String {
let file = "/.config/ai/txt/";
let mut f = shellexpand::tilde("~").to_string();
f.push_str(&file);
let path = Path::new(&f);
if path.is_dir() == false {
let _ = fs::create_dir_all(f.clone());
// 新しい設定ディレクトリ(優先)
let new_log_dir = "/.config/syui/ai/bot/txt/";
let mut new_path = shellexpand::tilde("~").to_string();
new_path.push_str(&new_log_dir);
// 旧設定ディレクトリ(互換性のため)
let old_log_dir = "/.config/ai/txt/";
let mut old_path = shellexpand::tilde("~").to_string();
old_path.push_str(&old_log_dir);
// 新しいディレクトリを作成
let new_dir = Path::new(&new_path);
if !new_dir.is_dir() {
let _ = fs::create_dir_all(new_path.clone());
}
match &*s {
"n1" => f + &"notify_cid.txt",
"n2" => f + &"notify_cid_run.txt",
"c1" => f + &"comment_cid.txt",
_ => f + &s,
let filename = match &*s {
"n1" => "notify_cid.txt",
"n2" => "notify_cid_run.txt",
"c1" => "comment_cid.txt",
_ => s,
};
let new_file = new_path.clone() + filename;
let old_file = old_path + filename;
// 新しいパスにファイルが存在する場合は新しいパスを使用
if Path::new(&new_file).exists() {
return new_file;
}
// 旧パスにファイルが存在し、新しいパスに存在しない場合は移行を試行
if Path::new(&old_file).exists() && !Path::new(&new_file).exists() {
if let Ok(_) = fs::copy(&old_file, &new_file) {
eprintln!("Migrated log file: {} -> {}", old_file, new_file);
return new_file;
}
}
// デフォルトは新しいパス
new_file
}
impl Token {

View File

@ -1,33 +1,21 @@
extern crate reqwest;
use crate::http_client::HttpClient;
use crate::data_toml;
use crate::data_refresh;
use crate::url;
use serde_json::json;
pub async fn post_request(rkey: String, col: String) -> String {
let token = data_refresh(&"access");
//let did = data_toml(&"did");
let handle = data_toml(&"handle");
let url = url(&"record_delete");
let client = HttpClient::new();
let post = Some(json!({
let post = json!({
"repo": handle.to_string(),
"rkey": rkey.to_string(),
"collection": col.to_string()
}));
});
let client = reqwest::Client::new();
let res = client
.post(url)
.json(&post)
.header("Authorization", "Bearer ".to_owned() + &token)
.send()
.await
.unwrap()
.text()
.await
.unwrap();
return res;
match client.post_json_with_auth(&url, &post).await {
Ok(response) => response,
Err(e) => format!("Error: {}", e),
}
}

View File

@ -1,22 +1,13 @@
extern crate reqwest;
//use crate::data_toml;
use crate::http_client::HttpClient;
use crate::url;
pub async fn get_request(user: String) -> String {
//let token = data_refresh(&"access");
let url = url(&"describe");
let base_url = url(&"describe");
let url = format!("{}?repo={}", base_url, user);
let client = HttpClient::new();
let client = reqwest::Client::new();
let res = client
.get(url)
.query(&[("repo", &user)])
//.header("Authorization", "Bearer ".to_owned() + &token)
.send()
.await
.unwrap()
.text()
.await
.unwrap();
return res;
match client.get(&url).await {
Ok(response) => response,
Err(e) => format!("Error: {}", e),
}
}

View File

@ -1,33 +1,13 @@
extern crate reqwest;
use crate::data_refresh;
use crate::http_client::HttpClient;
use crate::url;
pub async fn get_request(feed: String) -> String {
let token = data_refresh(&"access");
let url = url(&"feed_get");
let feed = feed.to_string();
//let col = "app.bsky.feed.generator".to_string();
let base_url = url(&"feed_get");
let url = format!("{}?feed={}", base_url, feed);
let client = HttpClient::new();
let client = reqwest::Client::new();
let res = client
.get(url)
.query(&[("feed", feed)])
//.query(&[("feed", feed), ("collection", col)])
.header("Authorization", "Bearer ".to_owned() + &token)
.send()
.await
.unwrap();
let status_ref = res.error_for_status_ref();
match status_ref {
Ok(_) => {
return res.text().await.unwrap();
}
Err(_e) => {
let e = "err".to_string();
return e;
}
match client.get_with_auth(&url).await {
Ok(response) => response,
Err(_) => "err".to_string(),
}
}

View File

@ -1,14 +1,12 @@
extern crate reqwest;
use crate::data_toml;
use crate::data_refresh;
use crate::url;
use crate::http_client::HttpClient;
use iso8601_timestamp::Timestamp;
use serde_json::json;
//use crate::data::Follow;
pub async fn post_request(u: String) -> String {
let token = data_refresh(&"access");
let did = data_toml(&"did");
let handle = data_toml(&"handle");
@ -18,7 +16,7 @@ pub async fn post_request(u: String) -> String {
let d = Timestamp::now_utc();
let d = d.to_string();
let post = Some(json!({
let post = json!({
"repo": handle.to_string(),
"did": did.to_string(),
"collection": col.to_string(),
@ -26,25 +24,19 @@ pub async fn post_request(u: String) -> String {
"subject": u.to_string(),
"createdAt": d.to_string(),
},
}));
});
let client = reqwest::Client::new();
let res = client
.post(url)
.json(&post)
.header("Authorization", "Bearer ".to_owned() + &token)
.send()
.await
.unwrap()
.text()
.await
.unwrap();
return res;
let client = HttpClient::new();
match client.post_json_with_auth(&url, &post).await {
Ok(response) => response,
Err(e) => {
eprintln!("Error following user: {}", e);
"err".to_string()
}
}
}
pub async fn delete_request(u: String, rkey: String) -> String {
let token = data_refresh(&"access");
let did = data_toml(&"did");
let handle = data_toml(&"handle");
@ -54,7 +46,7 @@ pub async fn delete_request(u: String, rkey: String) -> String {
let d = Timestamp::now_utc();
let d = d.to_string();
let post = Some(json!({
let post = json!({
"repo": handle.to_string(),
"did": did.to_string(),
"collection": col.to_string(),
@ -63,19 +55,14 @@ pub async fn delete_request(u: String, rkey: String) -> String {
"subject": u.to_string(),
"createdAt": d.to_string(),
},
}));
});
let client = reqwest::Client::new();
let res = client
.post(url)
.json(&post)
.header("Authorization", "Bearer ".to_owned() + &token)
.send()
.await
.unwrap()
.text()
.await
.unwrap();
return res;
let client = HttpClient::new();
match client.post_json_with_auth(&url, &post).await {
Ok(response) => response,
Err(e) => {
eprintln!("Error unfollowing user: {}", e);
"err".to_string()
}
}
}

View File

@ -1,24 +1,14 @@
extern crate reqwest;
use crate::data_refresh;
use crate::http_client::HttpClient;
use crate::url;
//use serde_json::json;
pub async fn get_request(actor: String, cursor: Option<String>) -> String {
let token = data_refresh(&"access");
let url = url(&"followers");
let base_url = url(&"followers");
let cursor = cursor.unwrap();
let url = format!("{}?actor={}&cursor={}", base_url, actor, cursor);
let client = HttpClient::new();
let client = reqwest::Client::new();
let res = client
.get(url)
.query(&[("actor", actor), ("cursor", cursor)])
.header("Authorization", "Bearer ".to_owned() + &token)
.send()
.await
.unwrap()
.text()
.await
.unwrap();
return res;
match client.get_with_auth(&url).await {
Ok(response) => response,
Err(e) => format!("Error: {}", e),
}
}

View File

@ -1,26 +1,14 @@
extern crate reqwest;
use crate::data_refresh;
use crate::http_client::HttpClient;
use crate::url;
//use serde_json::json;
pub async fn get_request(actor: String, cursor: Option<String>) -> String {
let token = data_refresh(&"access");
let url = url(&"follows");
let base_url = url(&"follows");
let cursor = cursor.unwrap();
//let cursor = "1682386039125::bafyreihwgwozmvqxcxrhbr65agcaa4v357p27ccrhzkjf3mz5xiozjvzfa".to_string();
//let cursor = "1682385956974::bafyreihivhux5m3sxbg33yruhw5ozhahwspnuqdsysbo57smzgptdcluem".to_string();
let url = format!("{}?actor={}&cursor={}", base_url, actor, cursor);
let client = HttpClient::new();
let client = reqwest::Client::new();
let res = client
.get(url)
.query(&[("actor", actor), ("cursor", cursor)])
//cursor.unwrap()
.header("Authorization", "Bearer ".to_owned() + &token)
.send()
.await
.unwrap()
.text()
.await
.unwrap();
return res;
match client.get_with_auth(&url).await {
Ok(response) => response,
Err(e) => format!("Error: {}", e),
}
}

View File

@ -1,19 +1,17 @@
extern crate reqwest;
use crate::http_client::HttpClient;
use crate::data_toml;
use crate::data_refresh;
use crate::url;
use iso8601_timestamp::Timestamp;
use serde_json::json;
pub async fn post_request(verify: String, id: i32, cp: i32, rank: i32, rare: String, col: String, author: String) -> String {
let token = data_refresh(&"access");
let did = data_toml(&"did");
let handle = data_toml(&"handle");
let url = url(&"record_create");
let d = Timestamp::now_utc();
let d = d.to_string();
let post = Some(json!({
let post = json!({
"repo": handle.to_string(),
"did": did.to_string(),
"collection": col.to_string(),
@ -26,19 +24,12 @@ pub async fn post_request(verify: String, id: i32, cp: i32, rank: i32, rare: Str
"verify": verify.to_string(),
"createdAt": d.to_string(),
},
}));
});
let client = reqwest::Client::new();
let res = client
.post(url)
.json(&post)
.header("Authorization", "Bearer ".to_owned() + &token)
.send()
.await
.unwrap()
.text()
.await
.unwrap();
return res;
let client = HttpClient::new();
match client.post_json_with_auth(&url, &post).await {
Ok(response) => response,
Err(e) => format!("Error: {}", e),
}
}

View File

@ -1,19 +1,17 @@
extern crate reqwest;
use crate::http_client::HttpClient;
use crate::data_toml;
use crate::data_refresh;
use crate::url;
use iso8601_timestamp::Timestamp;
use serde_json::json;
pub async fn post_request(col: String, img: String, id: i32, cp: i32, rank: i32, rare: String, user_handle: String, user_did: String) -> String {
let token = data_refresh(&"access");
let did = data_toml(&"did");
let handle = data_toml(&"handle");
let url = url(&"record_create");
let d = Timestamp::now_utc();
let d = d.to_string();
let link = "https://bsky.app/profile/yui.syui.ai".to_string();
let post = Some(json!({
let post = json!({
"repo": handle.to_string(),
"did": did.to_string(),
"collection": col.to_string(),
@ -40,19 +38,12 @@ pub async fn post_request(col: String, img: String, id: i32, cp: i32, rank: i32,
},
"createdAt": d.to_string(),
},
}));
});
let client = reqwest::Client::new();
let res = client
.post(url)
.json(&post)
.header("Authorization", "Bearer ".to_owned() + &token)
.send()
.await
.unwrap()
.text()
.await
.unwrap();
return res;
let client = HttpClient::new();
match client.post_json_with_auth(&url, &post).await {
Ok(response) => response,
Err(e) => format!("Error: {}", e),
}
}

View File

@ -1,18 +1,16 @@
extern crate reqwest;
use crate::http_client::HttpClient;
use crate::data_toml;
use crate::data_refresh;
use crate::url;
use iso8601_timestamp::Timestamp;
use serde_json::json;
pub async fn post_request(col: String, account: String) -> String {
let token = data_refresh(&"access");
let did = data_toml(&"did");
let handle = data_toml(&"handle");
let url = url(&"record_put");
let d = Timestamp::now_utc();
let d = d.to_string();
let post = Some(json!({
let post = json!({
"repo": handle.to_string(),
"did": did.to_string(),
"collection": col.to_string(),
@ -21,19 +19,12 @@ pub async fn post_request(col: String, account: String) -> String {
"account": account.to_string(),
"createdAt": d.to_string(),
},
}));
});
let client = reqwest::Client::new();
let res = client
.post(url)
.json(&post)
.header("Authorization", "Bearer ".to_owned() + &token)
.send()
.await
.unwrap()
.text()
.await
.unwrap();
return res;
let client = HttpClient::new();
match client.post_json_with_auth(&url, &post).await {
Ok(response) => response,
Err(e) => format!("Error: {}", e),
}
}

View File

@ -1,19 +1,17 @@
extern crate reqwest;
use crate::http_client::HttpClient;
use crate::data_toml;
use crate::data_refresh;
use crate::url;
use iso8601_timestamp::Timestamp;
use serde_json::json;
pub async fn post_request(col: String, username: String, login: bool, account: String) -> String {
let token = data_refresh(&"access");
let did = data_toml(&"did");
let handle = data_toml(&"handle");
let url = url(&"record_put");
let d = Timestamp::now_utc();
let d = d.to_string();
let post = Some(json!({
let post = json!({
"repo": handle.to_string(),
"did": did.to_string(),
"collection": col.to_string(),
@ -24,19 +22,12 @@ pub async fn post_request(col: String, username: String, login: bool, account: S
"account": account.to_string(),
"createdAt": d.to_string(),
},
}));
});
let client = reqwest::Client::new();
let res = client
.post(url)
.json(&post)
.header("Authorization", "Bearer ".to_owned() + &token)
.send()
.await
.unwrap()
.text()
.await
.unwrap();
return res;
let client = HttpClient::new();
match client.post_json_with_auth(&url, &post).await {
Ok(response) => response,
Err(e) => format!("Error: {}", e),
}
}

View File

@ -1,18 +1,16 @@
extern crate reqwest;
use crate::http_client::HttpClient;
use crate::data_toml;
use crate::data_refresh;
use crate::url;
use iso8601_timestamp::Timestamp;
use serde_json::json;
pub async fn post_request(col: String, user_name: String, user_did: String, user_handle: String, aiten: i32, limit: i32, chara: String, lv: i32, exp: i32, hp: i32, rank: i32, mode: i32, attach: i32, critical: i32, critical_d: i32) -> String {
let token = data_refresh(&"access");
let did = data_toml(&"did");
let handle = data_toml(&"handle");
let url = url(&"record_put");
let d = Timestamp::now_utc();
let d = d.to_string();
let post = Some(json!({
let post = json!({
"repo": handle.to_string(),
"did": did.to_string(),
"collection": col.to_string(),
@ -37,19 +35,12 @@ pub async fn post_request(col: String, user_name: String, user_did: String, user
"createdAt": d.to_string(),
"updatedAt": d.to_string(),
},
}));
});
let client = reqwest::Client::new();
let res = client
.post(url)
.json(&post)
.header("Authorization", "Bearer ".to_owned() + &token)
.send()
.await
.unwrap()
.text()
.await
.unwrap();
return res;
let client = HttpClient::new();
match client.post_json_with_auth(&url, &post).await {
Ok(response) => response,
Err(e) => format!("Error: {}", e),
}
}

114
src/http_client.rs Normal file
View File

@ -0,0 +1,114 @@
use reqwest::{Client, Error};
use serde::Serialize;
use crate::data_refresh;
pub struct HttpClient {
client: Client,
}
impl HttpClient {
pub fn new() -> Self {
Self {
client: Client::new(),
}
}
/// GET request with authentication
pub async fn get_with_auth(&self, url: &str) -> Result<String, Error> {
let token = data_refresh(&"access");
let response = self.client
.get(url)
.header("Authorization", format!("Bearer {}", token))
.send()
.await?
.text()
.await?;
Ok(response)
}
/// POST request with JSON body and authentication
pub async fn post_json_with_auth<T: Serialize>(&self, url: &str, json: &T) -> Result<String, Error> {
let token = data_refresh(&"access");
let response = self.client
.post(url)
.json(json)
.header("Authorization", format!("Bearer {}", token))
.send()
.await?
.text()
.await?;
Ok(response)
}
/// DELETE request with authentication
pub async fn delete_with_auth(&self, url: &str) -> Result<String, Error> {
let token = data_refresh(&"access");
let response = self.client
.delete(url)
.header("Authorization", format!("Bearer {}", token))
.send()
.await?
.text()
.await?;
Ok(response)
}
/// POST request without authentication (for login, etc.)
pub async fn post_json<T: Serialize>(&self, url: &str, json: &T) -> Result<String, Error> {
let response = self.client
.post(url)
.json(json)
.send()
.await?
.text()
.await?;
Ok(response)
}
/// GET request without authentication
pub async fn get(&self, url: &str) -> Result<String, Error> {
let response = self.client
.get(url)
.send()
.await?
.text()
.await?;
Ok(response)
}
/// POST request with custom headers
pub async fn post_with_headers<T: Serialize>(
&self,
url: &str,
json: &T,
headers: Vec<(&str, &str)>
) -> Result<String, Error> {
let mut request = self.client.post(url).json(json);
for (key, value) in headers {
request = request.header(key, value);
}
let response = request
.send()
.await?
.text()
.await?;
Ok(response)
}
}
impl Default for HttpClient {
fn default() -> Self {
Self::new()
}
}

View File

@ -1,23 +1,19 @@
extern crate reqwest;
use crate::http_client::HttpClient;
use crate::data_toml;
use crate::data_refresh;
use crate::url;
use serde_json::json;
use iso8601_timestamp::Timestamp;
pub async fn post_request(text: String, link: String) -> String {
let token = data_refresh(&"access");
let did = data_toml(&"did");
let handle = data_toml(&"handle");
let url = url(&"record_create");
let col = "app.bsky.feed.post".to_string();
let d = Timestamp::now_utc();
let d = d.to_string();
let post = Some(json!({
let post = json!({
"repo": handle.to_string(),
"did": did.to_string(),
"collection": col.to_string(),
@ -41,19 +37,12 @@ pub async fn post_request(text: String, link: String) -> String {
]
}
}
}));
});
let client = reqwest::Client::new();
let res = client
.post(url)
.json(&post)
.header("Authorization", "Bearer ".to_owned() + &token)
.send()
.await
.unwrap()
.text()
.await
.unwrap();
return res
let client = HttpClient::new();
match client.post_json_with_auth(&url, &post).await {
Ok(response) => response,
Err(e) => format!("Error: {}", e),
}
}

View File

@ -1,6 +1,5 @@
extern crate reqwest;
use crate::http_client::HttpClient;
use crate::data_toml;
use crate::data_refresh;
use crate::url;
use iso8601_timestamp::Timestamp;
use serde_json::json;
@ -12,17 +11,15 @@ pub async fn post_request(
uri: String,
itype: String,
) -> String {
let token = data_refresh(&"access");
let did = data_toml(&"did");
let handle = data_toml(&"handle");
let url = url(&"record_create");
let col = "app.bsky.feed.post".to_string();
let d = Timestamp::now_utc();
let d = d.to_string();
let post = Some(json!({
let post = json!({
"repo": handle.to_string(),
"did": did.to_string(),
"collection": col.to_string(),
@ -56,19 +53,12 @@ pub async fn post_request(
}
}
}
}));
});
let client = reqwest::Client::new();
let res = client
.post(url)
.json(&post)
.header("Authorization", "Bearer ".to_owned() + &token)
.send()
.await
.unwrap()
.text()
.await
.unwrap();
return res;
let client = HttpClient::new();
match client.post_json_with_auth(&url, &post).await {
Ok(response) => response,
Err(e) => format!("Error: {}", e),
}
}

View File

@ -1,23 +1,19 @@
extern crate reqwest;
use crate::http_client::HttpClient;
use crate::data_toml;
use crate::data_refresh;
use crate::url;
use serde_json::json;
use iso8601_timestamp::Timestamp;
pub async fn post_request(text: String, link: String) -> String {
let token = data_refresh(&"access");
let did = data_toml(&"did");
let handle = data_toml(&"handle");
let url = url(&"record_create");
let col = "app.bsky.feed.post".to_string();
let d = Timestamp::now_utc();
let d = d.to_string();
let post = Some(json!({
let post = json!({
"repo": handle.to_string(),
"did": did.to_string(),
"collection": col.to_string(),
@ -41,19 +37,12 @@ pub async fn post_request(text: String, link: String) -> String {
]
}
}
}));
});
let client = reqwest::Client::new();
let res = client
.post(url)
.json(&post)
.header("Authorization", "Bearer ".to_owned() + &token)
.send()
.await
.unwrap()
.text()
.await
.unwrap();
return res
let client = HttpClient::new();
match client.post_json_with_auth(&url, &post).await {
Ok(response) => response,
Err(e) => format!("Error: {}", e),
}
}

View File

@ -1,12 +1,10 @@
extern crate reqwest;
use crate::data_toml;
use crate::data_refresh;
use crate::url;
use crate::http_client::HttpClient;
use iso8601_timestamp::Timestamp;
use serde_json::json;
pub async fn post_request(cid: String, uri: String) -> String {
let token = data_refresh(&"access");
let did = data_toml(&"did");
let handle = data_toml(&"handle");
@ -16,7 +14,7 @@ pub async fn post_request(cid: String, uri: String) -> String {
let d = Timestamp::now_utc();
let d = d.to_string();
let post = Some(json!({
let post = json!({
"repo": handle.to_string(),
"did": did.to_string(),
"collection": col.to_string(),
@ -27,19 +25,14 @@ pub async fn post_request(cid: String, uri: String) -> String {
},
"createdAt": d.to_string(),
},
}));
});
let client = reqwest::Client::new();
let res = client
.post(url)
.json(&post)
.header("Authorization", "Bearer ".to_owned() + &token)
.send()
.await
.unwrap()
.text()
.await
.unwrap();
return res;
let client = HttpClient::new();
match client.post_json_with_auth(&url, &post).await {
Ok(response) => response,
Err(e) => {
eprintln!("Error liking post: {}", e);
"err".to_string()
}
}
}

View File

@ -27,6 +27,7 @@ pub mod describe;
pub mod follow;
pub mod followers;
pub mod follows;
pub mod http_client;
pub mod img_reply;
pub mod like;
pub mod mention;
@ -49,6 +50,9 @@ pub mod feed_get;
pub mod feed_watch;
pub mod delete_record;
#[cfg(test)]
mod tests;
fn main() {
let args: Vec<String> = env::args().collect();
let app = App::new(env!("CARGO_PKG_NAME"))

View File

@ -1,22 +1,18 @@
extern crate reqwest;
use crate::http_client::HttpClient;
use crate::data_toml;
use crate::data_refresh;
use crate::url;
use iso8601_timestamp::Timestamp;
use serde_json::json;
pub async fn post_request(col: String, text: String, at: String, udid: String, s: i32, e: i32) -> String {
let token = data_refresh(&"access");
let did = data_toml(&"did");
let handle = data_toml(&"handle");
let url = url(&"record_create");
//let col = "app.bsky.feed.post".to_string();
let d = Timestamp::now_utc();
let d = d.to_string();
let post = Some(json!({
let post = json!({
"did": did.to_string(),
"repo": handle.to_string(),
"collection": col.to_string(),
@ -39,19 +35,12 @@ pub async fn post_request(col: String, text: String, at: String, udid: String, s
}
]
},
}));
});
let client = reqwest::Client::new();
let res = client
.post(url)
.json(&post)
.header("Authorization", "Bearer ".to_owned() + &token)
.send()
.await
.unwrap()
.text()
.await
.unwrap();
return res;
let client = HttpClient::new();
match client.post_json_with_auth(&url, &post).await {
Ok(response) => response,
Err(e) => format!("Error: {}", e),
}
}

View File

@ -1,30 +1,13 @@
extern crate reqwest;
use crate::data_refresh;
use crate::http_client::HttpClient;
use crate::url;
//use serde_json::json;
pub async fn get_request(limit: i32) -> String {
let token = data_refresh(&"access");
let url = url(&"notify_list");
let base_url = url(&"notify_list");
let url = format!("{}?limit={}", base_url, limit);
let client = HttpClient::new();
let client = reqwest::Client::new();
let res = client
.get(url)
.query(&[("limit", limit)])
.header("Authorization", "Bearer ".to_owned() + &token)
.send()
.await
.unwrap();
let status_ref = res.error_for_status_ref();
match status_ref {
Ok(_) => {
return res.text().await.unwrap();
}
Err(_e) => {
let e = "err".to_string();
return e;
}
match client.get_with_auth(&url).await {
Ok(response) => response,
Err(_) => "err".to_string(),
}
}

View File

@ -1,27 +1,17 @@
extern crate reqwest;
use crate::data_refresh;
use crate::http_client::HttpClient;
use crate::url;
use serde_json::json;
pub async fn post_request(time: String) -> String {
let token = data_refresh(&"access");
let url = url(&"notify_update");
let client = HttpClient::new();
let post = Some(json!({
let post = json!({
"seenAt": time.to_string(),
}));
});
let client = reqwest::Client::new();
let res = client
.post(url)
.json(&post)
.header("Authorization", "Bearer ".to_owned() + &token)
.send()
.await
.unwrap()
.text()
.await
.unwrap();
return res;
match client.post_json_with_auth(&url, &post).await {
Ok(response) => response,
Err(e) => format!("Error: {}", e),
}
}

View File

@ -1,12 +1,10 @@
extern crate reqwest;
use crate::data_toml;
use crate::data_refresh;
use crate::url;
use crate::http_client::HttpClient;
use iso8601_timestamp::Timestamp;
use serde_json::json;
pub async fn post_request(text: String) -> String {
let token = data_refresh(&"access");
let did = data_toml(&"did");
let handle = data_toml(&"handle");
@ -16,7 +14,7 @@ pub async fn post_request(text: String) -> String {
let d = Timestamp::now_utc();
let d = d.to_string();
let post = Some(json!({
let post = json!({
"repo": handle.to_string(),
"did": did.to_string(),
"collection": col.to_string(),
@ -24,19 +22,14 @@ pub async fn post_request(text: String) -> String {
"text": text.to_string(),
"createdAt": d.to_string(),
},
}));
});
let client = reqwest::Client::new();
let res = client
.post(url)
.json(&post)
.header("Authorization", "Bearer ".to_owned() + &token)
.send()
.await
.unwrap()
.text()
.await
.unwrap();
return res;
let client = HttpClient::new();
match client.post_json_with_auth(&url, &post).await {
Ok(response) => response,
Err(e) => {
eprintln!("Error posting: {}", e);
"err".to_string()
}
}
}

View File

@ -1,22 +1,19 @@
extern crate reqwest;
use crate::http_client::HttpClient;
use crate::data_toml;
use crate::data_refresh;
use crate::url;
use iso8601_timestamp::Timestamp;
use serde_json::json;
pub async fn post_request(text: String, link: String, s: i32, e: i32) -> String {
let token = data_refresh(&"access");
let did = data_toml(&"did");
let handle = data_toml(&"handle");
let url = url(&"record_create");
let col = "app.bsky.feed.post".to_string();
let d = Timestamp::now_utc();
let d = d.to_string();
let post = Some(json!({
let post = json!({
"repo": handle.to_string(),
"did": did.to_string(),
"collection": col.to_string(),
@ -38,19 +35,12 @@ pub async fn post_request(text: String, link: String, s: i32, e: i32) -> String
}
],
},
}));
});
let client = reqwest::Client::new();
let res = client
.post(url)
.json(&post)
.header("Authorization", "Bearer ".to_owned() + &token)
.send()
.await
.unwrap()
.text()
.await
.unwrap();
return res;
let client = HttpClient::new();
match client.post_json_with_auth(&url, &post).await {
Ok(response) => response,
Err(e) => format!("Error: {}", e),
}
}

View File

@ -1,21 +1,15 @@
extern crate reqwest;
use crate::data_refresh;
use crate::url;
use crate::http_client::HttpClient;
pub async fn get_request(user: String) -> String {
let token = data_refresh(&"access");
let url = url(&"profile_get") + &"?handle=" + &user;
let client = reqwest::Client::new();
let res = client
.get(url)
.header("Authorization", "Bearer ".to_owned() + &token)
.send()
.await
.unwrap()
.text()
.await
.unwrap();
return res;
let client = HttpClient::new();
match client.get_with_auth(&url).await {
Ok(response) => response,
Err(e) => {
eprintln!("Error getting profile: {}", e);
"err".to_string()
}
}
}

View File

@ -1,28 +1,18 @@
extern crate reqwest;
use crate::http_client::HttpClient;
use crate::data_toml;
use crate::url;
pub async fn post_request() -> String {
let refresh = data_toml(&"refresh");
let url = url(&"session_refresh");
let client = HttpClient::new();
let client = reqwest::Client::new();
let res = client
.post(url)
.header("Authorization", "Bearer ".to_owned() + &refresh)
.send()
.await
.unwrap();
let status_ref = res.error_for_status_ref();
match status_ref {
Ok(_) => {
return res.text().await.unwrap();
}
Err(_e) => {
let e = "err".to_string();
return e;
}
let auth_header = format!("Bearer {}", refresh);
let headers = vec![("Authorization", auth_header.as_str())];
let empty_json = serde_json::json!({});
match client.post_with_headers(&url, &empty_json, headers).await {
Ok(response) => response,
Err(_) => "err".to_string(),
}
}

View File

@ -1,7 +1,6 @@
extern crate reqwest;
use crate::data_toml;
use crate::data_refresh;
use crate::url;
use crate::http_client::HttpClient;
use iso8601_timestamp::Timestamp;
use serde_json::json;
@ -12,7 +11,6 @@ pub async fn post_request(
cid_root: String,
uri_root: String,
) -> String {
let token = data_refresh(&"access");
let did = data_toml(&"did");
let handle = data_toml(&"handle");
@ -23,7 +21,7 @@ pub async fn post_request(
let d = Timestamp::now_utc();
let d = d.to_string();
let post = Some(json!({
let post = json!({
"repo": handle.to_string(),
"did": did.to_string(),
"collection": col.to_string(),
@ -41,19 +39,14 @@ pub async fn post_request(
}
}
},
}));
});
let client = reqwest::Client::new();
let res = client
.post(url)
.json(&post)
.header("Authorization", "Bearer ".to_owned() + &token)
.send()
.await
.unwrap()
.text()
.await
.unwrap();
return res;
let client = HttpClient::new();
match client.post_json_with_auth(&url, &post).await {
Ok(response) => response,
Err(e) => {
eprintln!("Error replying to post: {}", e);
"err".to_string()
}
}
}

View File

@ -1,6 +1,5 @@
extern crate reqwest;
use crate::http_client::HttpClient;
use crate::data_toml;
use crate::data_refresh;
use crate::url;
use iso8601_timestamp::Timestamp;
use serde_json::json;
@ -15,17 +14,15 @@ pub async fn post_request(
cid_root: String,
uri_root: String,
) -> String {
let token = data_refresh(&"access");
let did = data_toml(&"did");
let handle = data_toml(&"handle");
let url = url(&"record_create");
let col = "app.bsky.feed.post".to_string();
let d = Timestamp::now_utc();
let d = d.to_string();
let post = Some(json!({
let post = json!({
"repo": handle.to_string(),
"did": did.to_string(),
"collection": col.to_string(),
@ -57,19 +54,12 @@ pub async fn post_request(
}
],
},
}));
});
let client = reqwest::Client::new();
let res = client
.post(url)
.json(&post)
.header("Authorization", "Bearer ".to_owned() + &token)
.send()
.await
.unwrap()
.text()
.await
.unwrap();
return res;
let client = HttpClient::new();
match client.post_json_with_auth(&url, &post).await {
Ok(response) => response,
Err(e) => format!("Error: {}", e),
}
}

View File

@ -1,6 +1,5 @@
extern crate reqwest;
use crate::http_client::HttpClient;
use crate::data_toml;
use crate::data_refresh;
use crate::url;
use iso8601_timestamp::Timestamp;
use serde_json::json;
@ -16,17 +15,15 @@ pub async fn post_request(
title: String,
description: String,
) -> String {
let token = data_refresh(&"access");
let did = data_toml(&"did");
let handle = data_toml(&"handle");
let url = url(&"record_create");
let col = "app.bsky.feed.post".to_string();
let d = Timestamp::now_utc();
let d = d.to_string();
let post = Some(json!({
let post = json!({
"repo": handle.to_string(),
"did": did.to_string(),
"collection": col.to_string(),
@ -60,19 +57,12 @@ pub async fn post_request(
}
}
}
}));
});
let client = reqwest::Client::new();
let res = client
.post(url)
.json(&post)
.header("Authorization", "Bearer ".to_owned() + &token)
.send()
.await
.unwrap()
.text()
.await
.unwrap();
return res;
let client = HttpClient::new();
match client.post_json_with_auth(&url, &post).await {
Ok(response) => response,
Err(e) => format!("Error: {}", e),
}
}

View File

@ -1,12 +1,10 @@
extern crate reqwest;
use crate::data_toml;
use crate::data_refresh;
use crate::url;
use crate::http_client::HttpClient;
use iso8601_timestamp::Timestamp;
use serde_json::json;
pub async fn post_request(cid: String, uri: String) -> String {
let token = data_refresh(&"access");
let did = data_toml(&"did");
let handle = data_toml(&"handle");
@ -16,7 +14,7 @@ pub async fn post_request(cid: String, uri: String) -> String {
let d = Timestamp::now_utc();
let d = d.to_string();
let post = Some(json!({
let post = json!({
"repo": handle.to_string(),
"did": did.to_string(),
"collection": col.to_string(),
@ -27,19 +25,14 @@ pub async fn post_request(cid: String, uri: String) -> String {
},
"createdAt": d.to_string(),
},
}));
});
let client = reqwest::Client::new();
let res = client
.post(url)
.json(&post)
.header("Authorization", "Bearer ".to_owned() + &token)
.send()
.await
.unwrap()
.text()
.await
.unwrap();
return res;
let client = HttpClient::new();
match client.post_json_with_auth(&url, &post).await {
Ok(response) => response,
Err(e) => {
eprintln!("Error reposting: {}", e);
"err".to_string()
}
}
}

View File

@ -1,28 +1,12 @@
extern crate reqwest;
use crate::data_refresh;
use crate::http_client::HttpClient;
use crate::url;
pub async fn get_request() -> String {
let token = data_refresh(&"access");
let url = url(&"session_get");
let client = HttpClient::new();
let client = reqwest::Client::new();
let res = client
.get(url)
.header("Authorization", "Bearer ".to_owned() + &token)
.send()
.await
.unwrap();
let status_ref = res.error_for_status_ref();
match status_ref {
Ok(_) => {
return res.text().await.unwrap();
}
Err(_e) => {
let e = "err".to_string();
return e;
}
match client.get_with_auth(&url).await {
Ok(response) => response,
Err(_) => "err".to_string(),
}
}

View File

@ -0,0 +1,24 @@
use crate::http_client::HttpClient;
#[test]
fn test_http_client_creation() {
let _client = HttpClient::new();
// HttpClientが正しく作成されることを確認
let _client2 = HttpClient::default();
}
#[tokio::test]
async fn test_http_client_error_handling() {
let client = HttpClient::new();
// 無効なURLでエラーが返ることを確認
let result = client.get("http://invalid-url-that-does-not-exist.local").await;
assert!(result.is_err());
}
// モジュールが正しくコンパイルされることを確認
#[test]
fn test_module_imports() {
// モジュールが存在することを確認
assert!(true);
}

2
src/tests/mod.rs Normal file
View File

@ -0,0 +1,2 @@
#[cfg(test)]
mod http_client_tests;

View File

@ -1,27 +1,14 @@
extern crate reqwest;
use crate::data_refresh;
use crate::http_client::HttpClient;
use crate::url;
pub async fn get_request(actor: String) -> String {
let token = data_refresh(&"access");
let url = url(&"record_list");
let actor = actor.to_string();
//let cursor = cursor.unwrap();
let base_url = url(&"record_list");
let col = "app.bsky.feed.post".to_string();
let client = reqwest::Client::new();
let res = client
.get(url)
.query(&[("repo", actor), ("collection", col)])
//.query(&[("actor", actor),("cursor", cursor)])
.header("Authorization", "Bearer ".to_owned() + &token)
.send()
.await
.unwrap()
.text()
.await
.unwrap();
let url = format!("{}?repo={}&collection={}", base_url, actor, col);
let client = HttpClient::new();
return res;
match client.get_with_auth(&url).await {
Ok(response) => response,
Err(e) => format!("Error: {}", e),
}
}

View File

@ -1,25 +1,17 @@
extern crate reqwest;
use crate::http_client::HttpClient;
use std::collections::HashMap;
pub async fn post_request(handle: String, pass: String, host: String) -> String {
let url = "https://".to_owned()
+ &host.to_string()
+ &"/xrpc/com.atproto.server.createSession".to_string();
let url = format!("https://{}/xrpc/com.atproto.server.createSession", host);
let mut map = HashMap::new();
map.insert("identifier", &handle);
map.insert("password", &pass);
let client = reqwest::Client::new();
let res = client
.post(url)
.json(&map)
.send()
.await
.unwrap()
.text()
.await
.unwrap();
return res;
let client = HttpClient::new();
match client.post_json(&url, &map).await {
Ok(response) => response,
Err(e) => format!("Error: {}", e),
}
}