Move some code into a post module

This commit is contained in:
Greg Shuflin
2025-07-21 19:13:19 -07:00
parent a80e84f0d3
commit b2dffd4df0
2 changed files with 189 additions and 108 deletions

View File

@@ -2,32 +2,12 @@ use clap::Parser;
use colored::*;
use futures_util::StreamExt;
use log::{debug, warn};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use tokio_tungstenite::{connect_async, tungstenite::protocol::Message};
#[derive(Debug, Deserialize, Serialize)]
struct Post {
kind: Option<String>,
#[serde(rename = "type")]
type_: Option<String>,
time_us: Option<u64>,
did: Option<String>,
commit: Option<CommitData>,
}
mod post;
#[derive(Debug, Deserialize, Serialize)]
struct CommitData {
#[serde(rename = "type")]
type_: Option<String>,
operation: Option<String>,
record: Option<RecordData>,
}
#[derive(Debug, Deserialize, Serialize)]
struct RecordData {
text: Option<String>,
}
use post::*;
#[derive(Parser, Debug)]
#[command(author, version, about, long_about = None)]
@@ -91,17 +71,6 @@ impl BlueskyFirehosePrinter {
colored::Color::TrueColor { r, g, b }
}
fn extract_post_text(&self, post: &Post) -> String {
if let Some(ref commit) = post.commit {
if let Some(ref record) = commit.record {
if let Some(ref text) = record.text {
return text.chars().take(200).collect();
}
}
}
format!("{:?}", post)
}
async fn connect_and_print(
&self,
websocket_url: &str,
@@ -126,79 +95,40 @@ impl BlueskyFirehosePrinter {
match serde_json::from_str::<Post>(&text) {
Ok(mut post) => {
// Handle missing fields
if post.kind.is_none() {
post.kind = post.type_.clone();
}
post.normalize();
// Apply filters
if !onlys.is_empty() {
if let Some(ref kind) = post.kind {
if !onlys.contains(kind) {
continue;
}
}
if !post.matches_only_filter(onlys) {
continue;
}
if let Some(ref kind) = post.kind {
if skips.contains(kind) {
continue;
}
if post.should_skip(skips) {
continue;
}
let ts = post.time_us.unwrap_or(0) / 10_000;
let ts = post.get_time_us().unwrap_or(0) / 10_000;
// Generate HSV color based on timestamp
let h = ((ts as f64 / 4.0) % 255.0) / 255.0 * 360.0;
let mut s = 0.8;
let mut v = 0.8;
let v;
let mut text = String::new();
// Apply commit type filters
if !post.matches_commit_type_filters(cfilters) {
continue;
}
// Handle commit type filtering and text extraction
if post.kind.as_deref() == Some("commit") {
if let Some(ref commit) = post.commit {
if let Some(ref commit_type) = commit.type_ {
// Apply commit type filters
if let Some(excludes) = cfilters.get("-") {
if excludes.iter().any(|w| commit_type.contains(w)) {
continue;
}
}
if let Some(includes) = cfilters.get("+") {
if !includes.iter().any(|w| commit_type.contains(w)) {
continue;
}
}
}
// Extract and filter text
let text = match post.extract_and_filter_text(fkeeps, fdrops) {
Some(text) => text,
None => continue, // Text was filtered out
};
if let Some(ref record) = commit.record {
if let Some(ref record_text) = record.text {
// Apply text filters
if !fdrops.is_empty() {
if fdrops.iter().any(|w| record_text.contains(w)) {
continue;
}
}
if !fkeeps.is_empty() {
if !fkeeps.iter().any(|w| record_text.contains(w)) {
continue;
}
}
text = record_text.clone();
// Adjust brightness based on text length
v = 1.0
- (text.len() as f64)
.ln()
.min(16.0 * 256.0_f64.ln())
/ (16.0 * 256.0_f64.ln());
} else {
text = format!("commit.record={:?}", record);
}
}
}
// Adjust color based on post type and text
if post.get_kind() == Some("commit") {
// Adjust brightness based on text length
v = post.calculate_text_brightness(&text);
} else {
text = self.extract_post_text(&post);
s = 0.8;
v = 120.0 / 255.0;
}
@@ -213,24 +143,15 @@ impl BlueskyFirehosePrinter {
// Print colored output
let hsv_str = format!("{:.1}:{:.1}:{:.1}", h / 360.0, s, v);
let _post_id = post
.did
.unwrap_or_else(|| format!("r:{}", rand::random::<f64>()));
let _post_id = post.get_post_id();
let type_str = post.type_.as_deref().unwrap_or("None");
let kind_str = post.kind.as_deref().unwrap_or("None");
let type_str = post.get_type().unwrap_or("None");
let kind_str = post.get_kind().unwrap_or("None");
if post.type_.as_deref() == Some("com") {
let commit_type = post
.commit
.as_ref()
.and_then(|c| c.type_.as_deref())
.unwrap_or("None");
let operation = post
.commit
.as_ref()
.and_then(|c| c.operation.as_deref())
.unwrap_or("None");
if post.get_type() == Some("com") {
let (commit_type, operation) = post.get_commit_info();
let commit_type = commit_type.unwrap_or("None");
let operation = operation.unwrap_or("None");
println!(
"{}{}|type:{}|{}{}{}|hsv:{} type:{} kind:{} commit.type={} operation={}",

160
src/post.rs Normal file
View File

@@ -0,0 +1,160 @@
use rand;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
#[derive(Debug, Deserialize, Serialize)]
pub struct Post {
kind: Option<String>,
#[serde(rename = "type")]
type_: Option<String>,
time_us: Option<u64>,
did: Option<String>,
commit: Option<CommitData>,
}
#[derive(Debug, Deserialize, Serialize)]
pub struct CommitData {
#[serde(rename = "type")]
type_: Option<String>,
operation: Option<String>,
record: Option<RecordData>,
}
#[derive(Debug, Deserialize, Serialize)]
pub struct RecordData {
text: Option<String>,
}
impl Post {
/// Normalize the post by ensuring kind field is set
pub fn normalize(&mut self) {
if self.kind.is_none() {
self.kind = self.type_.clone();
}
}
/// Get the type of this post
pub fn get_type(&self) -> Option<&str> {
self.type_.as_deref()
}
/// Get the kind of this post
pub fn get_kind(&self) -> Option<&str> {
self.kind.as_deref()
}
/// Get the timestamp in microseconds
pub fn get_time_us(&self) -> Option<u64> {
self.time_us
}
/// Get the DID or generate a random one
pub fn get_post_id(&self) -> String {
self.did
.clone()
.unwrap_or_else(|| format!("r:{}", rand::random::<f64>()))
}
/// Check if this post matches the "only" filter
pub fn matches_only_filter(&self, onlys: &[String]) -> bool {
if onlys.is_empty() {
return true;
}
if let Some(ref kind) = self.kind {
onlys.contains(kind)
} else {
false
}
}
/// Check if this post should be skipped
pub fn should_skip(&self, skips: &[String]) -> bool {
if let Some(ref kind) = self.kind {
skips.contains(kind)
} else {
false
}
}
/// Check if this post matches commit type filters
pub fn matches_commit_type_filters(&self, cfilters: &HashMap<String, Vec<String>>) -> bool {
if self.kind.as_deref() != Some("commit") {
return true; // Non-commit posts pass commit filters
}
if let Some(ref commit) = self.commit {
if let Some(ref commit_type) = commit.type_ {
// Apply commit type filters
if let Some(excludes) = cfilters.get("-") {
if excludes.iter().any(|w| commit_type.contains(w)) {
return false;
}
}
if let Some(includes) = cfilters.get("+") {
if !includes.iter().any(|w| commit_type.contains(w)) {
return false;
}
}
}
}
true
}
/// Check if this post matches text filters and return the extracted text
pub fn extract_and_filter_text(&self, fkeeps: &[String], fdrops: &[String]) -> Option<String> {
if self.kind.as_deref() == Some("commit") {
if let Some(ref commit) = self.commit {
if let Some(ref record) = commit.record {
if let Some(ref record_text) = record.text {
// Apply text filters
if !fdrops.is_empty() {
if fdrops.iter().any(|w| record_text.contains(w)) {
return None;
}
}
if !fkeeps.is_empty() {
if !fkeeps.iter().any(|w| record_text.contains(w)) {
return None;
}
}
return Some(record_text.clone());
} else {
return Some(format!("commit.record={:?}", record));
}
}
}
} else {
return Some(self.extract_text());
}
None
}
/// Get commit information for display
pub fn get_commit_info(&self) -> (Option<&str>, Option<&str>) {
if let Some(ref commit) = self.commit {
(commit.type_.as_deref(), commit.operation.as_deref())
} else {
(None, None)
}
}
/// Calculate color brightness based on text length
pub fn calculate_text_brightness(&self, text: &str) -> f64 {
1.0 - (text.len() as f64).ln().min(16.0 * 256.0_f64.ln()) / (16.0 * 256.0_f64.ln())
}
pub fn extract_text(&self) -> String {
if let Some(ref commit) = self.commit {
if let Some(ref record) = commit.record {
if let Some(ref text) = record.text {
return text.chars().take(200).collect();
}
}
}
format!("{:?}", self)
}
}