Function bodies 355 total
default function · rust · L26-L31 (6 LOC)crates/nostrweet-blossom/src/lib.rs
fn default() -> Self {
Self {
max_attempts: DEFAULT_MAX_ATTEMPTS,
base_delay: Duration::from_millis(DEFAULT_RETRY_DELAY_MS),
}
}new function · rust · L63-L65 (3 LOC)crates/nostrweet-blossom/src/lib.rs
fn new(client: Client) -> Self {
Self { client }
}head function · rust · L69-L91 (23 LOC)crates/nostrweet-blossom/src/lib.rs
fn head<'a>(
&'a self,
url: &'a str,
headers: HeaderMap,
) -> BoxFuture<'a, Result<BlossomHttpResponse>> {
Box::pin(async move {
let response = self
.client
.head(url)
.headers(headers)
.send()
.await
.with_context(|| format!("HEAD {url} failed"))?;
let status = response.status();
let headers = response.headers().clone();
let body = response.bytes().await?.to_vec();
Ok(BlossomHttpResponse {
status,
headers,
body,
})
})
}put function · rust · L92-L117 (26 LOC)crates/nostrweet-blossom/src/lib.rs
fn put<'a>(
&'a self,
url: &'a str,
headers: HeaderMap,
body: Vec<u8>,
) -> BoxFuture<'a, Result<BlossomHttpResponse>> {
Box::pin(async move {
let response = self
.client
.put(url)
.headers(headers)
.body(body)
.send()
.await
.with_context(|| format!("PUT {url} failed"))?;
let status = response.status();
let headers = response.headers().clone();
let body = response.bytes().await?.to_vec();
Ok(BlossomHttpResponse {
status,
headers,
body,
})
})
}new function · rust · L129-L141 (13 LOC)crates/nostrweet-blossom/src/lib.rs
pub fn new(servers: Vec<BlossomUrl>) -> Result<Self> {
let client = Client::builder()
.timeout(Duration::from_secs(DEFAULT_TIMEOUT_SECS))
.build()
.context("Failed to build Blossom HTTP client")?;
let http = Arc::new(ReqwestBlossomHttp::new(client));
Ok(Self {
servers,
http,
auth_header: None,
retry: RetryConfig::default(),
})
}with_auth_header function · rust · L142-L146 (5 LOC)crates/nostrweet-blossom/src/lib.rs
pub fn with_auth_header(mut self, header: impl Into<String>) -> Self {
self.auth_header = Some(header.into());
self
}with_retry_config function · rust · L147-L151 (5 LOC)crates/nostrweet-blossom/src/lib.rs
pub fn with_retry_config(mut self, retry: RetryConfig) -> Self {
self.retry = retry;
self
}Repobility · severity-and-effort ranking · https://repobility.com
upload_url function · rust · L152-L163 (12 LOC)crates/nostrweet-blossom/src/lib.rs
fn upload_url(server: &BlossomUrl) -> Result<String> {
let base = server.as_str();
let normalized = if base.ends_with('/') {
base.to_string()
} else {
format!("{base}/")
};
let url = format!("{normalized}upload");
HttpUrl::parse(&url).context("Invalid Blossom upload URL")?;
Ok(url)
}upload_single function · rust · L164-L203 (40 LOC)crates/nostrweet-blossom/src/lib.rs
async fn upload_single(&self, asset: &MediaAsset) -> Result<HttpUrl> {
let sha256 = sha256_hex(&asset.bytes);
let content_len = asset.bytes.len();
for server in &self.servers {
let upload_url = Self::upload_url(server)?;
let mut headers = HeaderMap::new();
insert_header(&mut headers, "x-content-length", content_len.to_string())?;
insert_header(&mut headers, "x-content-type", &asset.content_type)?;
insert_header(&mut headers, "x-sha-256", &sha256)?;
let head_resp = self.http.head(&upload_url, headers).await?;
if !head_resp.status.is_success() {
warn!(
"Blossom HEAD request failed with status {}",
head_resp.status
);
continue;
}
let invoice = head_resp
.headers
.get("X-Lightning")
.and_then(|value| value.to_str().ok(upload_with_retries function · rust · L204-L252 (49 LOC)crates/nostrweet-blossom/src/lib.rs
async fn upload_with_retries(
&self,
upload_url: &str,
asset: &MediaAsset,
invoice: Option<&str>,
) -> Result<HttpUrl> {
let max_attempts = self.retry.max_attempts.max(1);
let mut attempt = 0;
loop {
attempt += 1;
debug!(
"Uploading media asset {} (attempt {}/{})",
asset.name, attempt, max_attempts
);
let mut headers = HeaderMap::new();
insert_header(&mut headers, "content-type", &asset.content_type)?;
if let Some(auth_header) = &self.auth_header {
insert_header(&mut headers, "authorization", auth_header)?;
}
if let Some(invoice) = invoice {
insert_header(&mut headers, "x-lightning", invoice)?;
}
let response = self
.http
.put(upload_url, headers, asset.bytes.clone())
.await?;
iupload_media function · rust · L257-L269 (13 LOC)crates/nostrweet-blossom/src/lib.rs
async fn upload_media(&self, assets: &[MediaAsset]) -> Result<Vec<HttpUrl>> {
if self.servers.is_empty() {
bail!("No Blossom servers provided for media upload");
}
let mut uploaded = Vec::with_capacity(assets.len());
for asset in assets {
let url = self.upload_single(asset).await?;
uploaded.push(url);
}
Ok(uploaded)
}sha256_hex function · rust · L271-L276 (6 LOC)crates/nostrweet-blossom/src/lib.rs
fn sha256_hex(bytes: &[u8]) -> String {
let mut hasher = Sha256::new();
hasher.update(bytes);
format!("{:x}", hasher.finalize())
}extract_url function · rust · L277-L295 (19 LOC)crates/nostrweet-blossom/src/lib.rs
fn extract_url(json: &Value) -> Option<String> {
if let Some(url) = json.get("url").and_then(|value| value.as_str()) {
return Some(url.to_string());
}
let tags = json
.get("nip94_event")
.and_then(|event| event.get("tags"))
.and_then(|tags| tags.as_array())?;
for tag in tags {
let arr = tag.as_array()?;
if arr.first()?.as_str()? == "url" {
return arr.get(1)?.as_str().map(str::to_string);
}
}
None
}retry_delay function · rust · L296-L304 (9 LOC)crates/nostrweet-blossom/src/lib.rs
fn retry_delay(headers: &HeaderMap, fallback: Duration) -> Duration {
headers
.get(RETRY_AFTER)
.and_then(|value| value.to_str().ok())
.and_then(|value| value.parse::<u64>().ok())
.map(Duration::from_secs)
.unwrap_or(fallback)
}insert_header function · rust · L305-L313 (9 LOC)crates/nostrweet-blossom/src/lib.rs
fn insert_header(headers: &mut HeaderMap, name: &str, value: impl AsRef<str>) -> Result<()> {
let name = HeaderName::from_bytes(name.as_bytes())
.with_context(|| format!("Invalid header name {name}"))?;
let value = HeaderValue::from_str(value.as_ref())
.with_context(|| format!("Invalid header value for {name}"))?;
headers.insert(name, value);
Ok(())
}About: code-quality intelligence by Repobility · https://repobility.com
server function · rust · L359-L495 (137 LOC)crates/nostrweet-blossom/src/lib.rs
fn server(&self) -> MockBlossomServer {
let mut state = self.state.lock().expect("lock mock state");
state.next_id += 1;
let base_url = format!("http://mock-{}.test", state.next_id);
let server_state = Arc::new(Mutex::new(StateData::default()));
state
.servers
.insert(base_url.clone(), Arc::clone(&server_state));
MockBlossomServer {
base_url,
state: server_state,
}
}
fn server_state(&self, url: &str) -> Result<Arc<Mutex<StateData>>> {
let base = base_url(url)?;
let state = self.state.lock().expect("lock mock state");
state
.servers
.get(&base)
.cloned()
.ok_or_else(|| anyhow!("Unknown mock server for {base}"))
}
}
impl BlossomHttp for MockHttp {
fn head<'a>(
&'a self,
userver_state function · rust · L372-L381 (10 LOC)crates/nostrweet-blossom/src/lib.rs
fn server_state(&self, url: &str) -> Result<Arc<Mutex<StateData>>> {
let base = base_url(url)?;
let state = self.state.lock().expect("lock mock state");
state
.servers
.get(&base)
.cloned()
.ok_or_else(|| anyhow!("Unknown mock server for {base}"))
}head function · rust · L385-L411 (27 LOC)crates/nostrweet-blossom/src/lib.rs
fn head<'a>(
&'a self,
url: &'a str,
headers: HeaderMap,
) -> BoxFuture<'a, Result<BlossomHttpResponse>> {
Box::pin(async move {
let state = self.server_state(url)?;
let mut state = state.lock().expect("lock server state");
state
.head_requests
.push(record_request(headers, Vec::new()));
let mut response_headers = HeaderMap::new();
if let Some(invoice) = &state.head_invoice {
response_headers.insert(
HeaderName::from_static("x-lightning"),
HeaderValue::from_str(invoice).expect("valid invoice header"),
);
}
Ok(BlossomHttpResponse {
status: StatusCode::OK,
headers: response_headers,
body: Vec::new(),
})
put function · rust · L412-L432 (21 LOC)crates/nostrweet-blossom/src/lib.rs
fn put<'a>(
&'a self,
url: &'a str,
headers: HeaderMap,
body: Vec<u8>,
) -> BoxFuture<'a, Result<BlossomHttpResponse>> {
Box::pin(async move {
let state = self.server_state(url)?;
let mut state = state.lock().expect("lock server state");
state.put_requests.push(record_request(headers, body));
let response = state.put_responses.pop_front().unwrap_or(MockResponse {
status: StatusCode::INTERNAL_SERVER_ERROR,
headers: Vec::new(),
body: Vec::new(),
});
Ok(response.into_http_response())
})
}into_http_response function · rust · L436-L450 (15 LOC)crates/nostrweet-blossom/src/lib.rs
fn into_http_response(self) -> BlossomHttpResponse {
let mut headers = HeaderMap::new();
for (name, value) in self.headers {
let name = name.to_ascii_lowercase();
let header_name =
HeaderName::from_bytes(name.as_bytes()).expect("valid header name");
let header_value = HeaderValue::from_str(&value).expect("valid header value");
headers.insert(header_name, header_value);
}
BlossomHttpResponse {
status: self.status,
headers,
body: self.body,
}
}blossom_url function · rust · L454-L456 (3 LOC)crates/nostrweet-blossom/src/lib.rs
fn blossom_url(&self) -> BlossomUrl {
BlossomUrl::parse(&self.base_url).expect("valid base url")
}set_invoice function · rust · L457-L461 (5 LOC)crates/nostrweet-blossom/src/lib.rs
fn set_invoice(&self, invoice: &str) {
let mut state = self.state.lock().expect("lock state");
state.head_invoice = Some(invoice.to_string());
}queue_response function · rust · L462-L466 (5 LOC)crates/nostrweet-blossom/src/lib.rs
fn queue_response(&self, response: MockResponse) {
let mut state = self.state.lock().expect("lock state");
state.put_responses.push_back(response);
}All rows above produced by Repobility · https://repobility.com
state function · rust · L467-L470 (4 LOC)crates/nostrweet-blossom/src/lib.rs
fn state(&self) -> Arc<Mutex<StateData>> {
self.state.clone()
}record_request function · rust · L472-L485 (14 LOC)crates/nostrweet-blossom/src/lib.rs
fn record_request(headers: HeaderMap, body: Vec<u8>) -> RecordedRequest {
let mut header_map = HashMap::new();
for (name, value) in headers.iter() {
if let Ok(value) = value.to_str() {
header_map.insert(name.as_str().to_ascii_lowercase(), value.to_string());
}
}
RecordedRequest {
headers: header_map,
body,
}
}fetch_media_assets function · rust · L40-L42 (3 LOC)crates/nostrweet-cli/src/main.rs
async fn fetch_media_assets(&self, data_dir: &Path, tweet: &Tweet) -> Result<Vec<MediaAsset>> {
fetch_media_assets(data_dir, tweet).await
}new function · rust · L64-L70 (7 LOC)crates/nostrweet-cli/src/main.rs
async fn new(keys: &Keys, relays: &[String], data_dir: &Path) -> Result<Self> {
let client = build_nostr_client(keys, relays).await?;
Ok(Self {
client,
data_dir: data_dir.to_path_buf(),
})
}publish_event function · rust · L74-L92 (19 LOC)crates/nostrweet-cli/src/main.rs
async fn publish_event(
&self,
draft: &NostrEventDraft,
keys: &Keys,
) -> Result<NostrEventResult> {
let event = build_event_from_draft(draft, keys).await?;
save_nostr_event_json(&self.data_dir, &event)?;
let output = self
.client
.send_event(&event)
.await
.context("Failed to publish Nostr event")?;
Ok(NostrEventResult {
event_id: NostrEventId::parse(&output.val.to_hex())?,
event_json: Some(
serde_json::to_string_pretty(&event).context("Failed to serialize Nostr event")?,
),
})
}find_event_by_tweet function · rust · L93-L100 (8 LOC)crates/nostrweet-cli/src/main.rs
async fn find_event_by_tweet(
&self,
tweet_id: &TweetId,
keys: &Keys,
) -> Result<Option<nostr_sdk::Event>> {
find_existing_event(&self.client, tweet_id, keys).await
}profile_exists function · rust · L101-L109 (9 LOC)crates/nostrweet-cli/src/main.rs
async fn profile_exists(&self, pubkey: &nostr_sdk::PublicKey) -> Result<bool> {
let filter = Filter::new().author(*pubkey).kind(Kind::Metadata).limit(1);
let events = self
.client
.fetch_events(filter, Duration::from_secs(10))
.await?;
Ok(!events.is_empty())
}publish_profile function · rust · L110-L123 (14 LOC)crates/nostrweet-cli/src/main.rs
async fn publish_profile(&self, metadata: Metadata, keys: &Keys) -> Result<nostr_sdk::EventId> {
let event = EventBuilder::metadata(&metadata)
.sign(keys)
.await
.context("Failed to sign metadata event")?;
save_nostr_event_json(&self.data_dir, &event)?;
let output = self
.client
.send_event(&event)
.await
.context("Failed to publish profile event")?;
Ok(*output.id())
}Methodology: Repobility · https://repobility.com/research/state-of-ai-code-2026/
update_relay_list function · rust · L124-L147 (24 LOC)crates/nostrweet-cli/src/main.rs
async fn update_relay_list(&self, relays: &[String], keys: &Keys) -> Result<()> {
let relay_list: Vec<(nostr_sdk::RelayUrl, Option<RelayMetadata>)> = relays
.iter()
.filter_map(|relay| match nostr_sdk::RelayUrl::parse(relay) {
Ok(url) => Some((url, None)),
Err(_) => None,
})
.collect();
if relay_list.is_empty() && !relays.is_empty() {
bail!("No valid relay URLs provided");
}
let event = EventBuilder::relay_list(relay_list)
.sign(keys)
.await
.context("Failed to sign relay list event")?;
let _ = self
.client
.send_event(&event)
.await
.context("Failed to publish relay list event")?;
Ok(())
}main function · rust · L435-L443 (9 LOC)crates/nostrweet-cli/src/main.rs
async fn main() -> Result<()> {
dotenv().ok();
init_logging();
let cli = Cli::parse();
if cli.verbose {
debug!("Verbose mode enabled");
}
run(cli).await
}init_logging function · rust · L444-L456 (13 LOC)crates/nostrweet-cli/src/main.rs
fn init_logging() {
let filter = if std::env::var("RUST_LOG").is_ok() {
EnvFilter::from_default_env()
} else {
EnvFilter::new("info")
};
tracing_subscriber::registry()
.with(fmt::layer().with_writer(std::io::stderr))
.with(filter)
.init();
}run function · rust · L457-L595 (139 LOC)crates/nostrweet-cli/src/main.rs
async fn run(cli: Cli) -> Result<()> {
let data_dir = resolve_data_dir(&cli)?;
let bearer_token = require_bearer_token(&cli, command_needs_bearer_token(&cli.command))?;
let mnemonic = require_mnemonic(&cli, command_needs_mnemonic(&cli.command))?;
let _ = cli.verbose;
match cli.command {
Commands::ListTweets => list_tweets(&data_dir).await,
Commands::ClearCache { force } => clear_cache(&data_dir, force),
Commands::FetchProfile { username } => {
fetch_profile(&data_dir, bearer_token.as_deref().unwrap(), &username).await
}
Commands::FetchTweet {
tweet_url_or_id,
skip_profiles,
} => {
fetch_tweet(
&data_dir,
bearer_token.as_deref().unwrap(),
&tweet_url_or_id,
skip_profiles,
)
.await
}
Commands::UserTweets {
username,
count,
days,
resolve_data_dir function · rust · L596-L602 (7 LOC)crates/nostrweet-cli/src/main.rs
fn resolve_data_dir(cli: &Cli) -> Result<PathBuf> {
let fallback = std::env::var("NOSTRWEET_OUTPUT_DIR")
.ok()
.map(PathBuf::from);
resolve_data_dir_with_fallback(cli, fallback)
}resolve_data_dir_with_fallback function · rust · L603-L610 (8 LOC)crates/nostrweet-cli/src/main.rs
fn resolve_data_dir_with_fallback(cli: &Cli, fallback: Option<PathBuf>) -> Result<PathBuf> {
let data_dir = cli.data_dir.clone().or(fallback).context(
"Data directory not specified. Please set --data-dir or NOSTRWEET_DATA_DIR environment variable",
)?;
ensure_data_dir_exists(&data_dir)?;
Ok(data_dir)
}ensure_data_dir_exists function · rust · L611-L617 (7 LOC)crates/nostrweet-cli/src/main.rs
fn ensure_data_dir_exists(path: &Path) -> Result<()> {
if !path.exists() {
std::fs::create_dir_all(path).context("Failed to create data directory")?;
}
Ok(())
}command_needs_bearer_token function · rust · L618-L627 (10 LOC)crates/nostrweet-cli/src/main.rs
fn command_needs_bearer_token(command: &Commands) -> bool {
matches!(
command,
Commands::FetchProfile { .. }
| Commands::FetchTweet { .. }
| Commands::UserTweets { .. }
| Commands::Daemon { .. }
)
}Repobility · severity-and-effort ranking · https://repobility.com
command_needs_mnemonic function · rust · L628-L639 (12 LOC)crates/nostrweet-cli/src/main.rs
fn command_needs_mnemonic(command: &Commands) -> bool {
matches!(
command,
Commands::PostTweetToNostr { .. }
| Commands::PostUserToNostr { .. }
| Commands::PostTweet { .. }
| Commands::PostProfileToNostr { .. }
| Commands::UpdateRelayList { .. }
| Commands::Daemon { .. }
)
}require_bearer_token function · rust · L640-L650 (11 LOC)crates/nostrweet-cli/src/main.rs
fn require_bearer_token(cli: &Cli, required: bool) -> Result<Option<String>> {
if required {
let token = cli.bearer_token.clone().context(
"Twitter bearer token not specified. Please set --bearer-token or TWITTER_BEARER_TOKEN environment variable",
)?;
Ok(Some(token))
} else {
Ok(cli.bearer_token.clone())
}
}require_mnemonic function · rust · L651-L663 (13 LOC)crates/nostrweet-cli/src/main.rs
fn require_mnemonic(cli: &Cli, required: bool) -> Result<Option<String>> {
if required {
let mnemonic = cli.mnemonic.clone().ok_or_else(|| {
anyhow::anyhow!(
"Mnemonic not provided. Please use --mnemonic flag or NOSTRWEET_MNEMONIC environment variable."
)
})?;
Ok(Some(mnemonic))
} else {
Ok(cli.mnemonic.clone())
}
}list_tweets function · rust · L664-L700 (37 LOC)crates/nostrweet-cli/src/main.rs
async fn list_tweets(data_dir: &Path) -> Result<()> {
let storage = FileStorage::new(data_dir)?;
let summaries = storage.list_tweets().await?;
println!("Found {} tweets in {}", summaries.len(), data_dir.display());
println!("{:-^80}", "");
for summary in summaries {
let tweet = summary.tweet;
let author_display = if !tweet.author.username.as_str().is_empty() {
match tweet.author.name.as_ref().filter(|name| !name.is_empty()) {
Some(name) => format!(
"{name} (@{username})",
username = tweet.author.username.as_str()
),
None => format!("@{username}", username = tweet.author.username.as_str()),
}
} else if let Some(author_id) = &tweet.author_id {
format!("ID: {author_id}")
} else {
"Unknown".to_string()
};
let time_str = format_timestamp(summary.modified_at);
let first_line = twformat_timestamp function · rust · L701-L716 (16 LOC)crates/nostrweet-cli/src/main.rs
fn format_timestamp(timestamp: UnixTimestamp) -> String {
let Ok(raw) = i64::try_from(timestamp.value()) else {
return "Unknown".to_string();
};
let Ok(parsed) = OffsetDateTime::from_unix_timestamp(raw) else {
return "Unknown".to_string();
};
let Ok(format) = format_description::parse("[year]-[month]-[day] [hour]:[minute]:[second]")
else {
return "Unknown".to_string();
};
parsed
.format(&format)
.unwrap_or_else(|_| "Unknown".to_string())
}clear_cache function · rust · L717-L757 (41 LOC)crates/nostrweet-cli/src/main.rs
fn clear_cache(data_dir: &Path, force: bool) -> Result<()> {
if !force {
print!(
"Are you sure you want to delete all cached tweets and media from {path}? [y/N] ",
path = data_dir.display()
);
io::stdout().flush().context("Failed to flush stdout")?;
let mut input = String::new();
io::stdin()
.read_line(&mut input)
.context("Failed to read user input")?;
if !input.trim().eq_ignore_ascii_case("y") {
return Ok(());
}
}
let entries = std::fs::read_dir(data_dir).context("Failed to read output directory")?;
let mut deleted_count = 0;
for entry in entries {
let entry = entry.context("Failed to read directory entry")?;
let path = entry.path();
let removed = if path.is_file() {
std::fs::remove_file(&path)
} else if path.is_dir() {
std::fs::remove_dir_all(&path)
} else {
continue;
sanitize_filename function · rust · L762-L765 (4 LOC)crates/nostrweet-cli/src/main.rs
fn sanitize_filename(value: &str) -> String {
value.replace(['\\', '/'], "_")
}media_extension_from_content_type function · rust · L766-L778 (13 LOC)crates/nostrweet-cli/src/main.rs
fn media_extension_from_content_type(content_type: &str) -> Option<&'static str> {
match content_type {
"image/jpeg" => Some("jpg"),
"image/png" => Some("png"),
"image/gif" => Some("gif"),
"image/webp" => Some("webp"),
"video/mp4" => Some("mp4"),
"video/quicktime" => Some("mov"),
"video/webm" => Some("webm"),
_ => None,
}
}About: code-quality intelligence by Repobility · https://repobility.com
extension_from_url function · rust · L779-L786 (8 LOC)crates/nostrweet-cli/src/main.rs
fn extension_from_url(url: &HttpUrl) -> Option<String> {
url.as_str()
.split('?')
.next()
.and_then(|value| value.rsplit('.').next())
.map(|ext| ext.to_lowercase())
}content_type_from_extension function · rust · L787-L799 (13 LOC)crates/nostrweet-cli/src/main.rs
fn content_type_from_extension(ext: &str) -> Option<&'static str> {
match ext {
"jpg" | "jpeg" => Some("image/jpeg"),
"png" => Some("image/png"),
"gif" => Some("image/gif"),
"webp" => Some("image/webp"),
"mp4" => Some("video/mp4"),
"mov" => Some("video/quicktime"),
"webm" => Some("video/webm"),
_ => None,
}
}select_media_variant function · rust · L807-L815 (9 LOC)crates/nostrweet-cli/src/main.rs
fn select_media_variant(media: &Media) -> Option<MediaVariant> {
media
.variants
.iter()
.filter_map(|variant| variant.bit_rate.map(|br| (br, variant)))
.max_by_key(|(br, _)| *br)
.map(|(_, variant)| variant.clone())
}page 1 / 8next ›