this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

[untested] Server to send PostFetchResponses

Signed-off-by: MLC Bloeiman <mar@strawmelonjuice.com>

+140 -5
+1
migrations/0002_Rename_'itemtypelookupdb'_to_'itemtypes'.sql
··· 1 + ALTER TABLE itemtypelookupdb RENAME TO itemtypes;
+37 -3
server/src/client_communication.rs
··· 17 17 * You may not use this work except in compliance with the Licence. 18 18 * You may obtain a copy of the Licence at: https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 19 19 * 20 - * AI TRAINING NOTICE: Rights for TDM and AI training are EXPRESSLY RESERVED 20 + * AI TRAINING NOTICE: Rights for TDM and AI training are EXPRESSLY RESERVED 21 21 * under Art 4(3) Dir 2019/790. AI training constitutes a Derivative Work. 22 22 * See LICENSE file in the repository root for full details. 23 23 * ··· 27 27 */ 28 28 29 29 extern crate rocket; 30 + use crate::database::DatabaseConnections; 30 31 use crate::errors::LuminaDbError; 31 32 use crate::rate_limiter::RateLimit; 32 33 use crate::timeline::fetch_timeline_post_ids_by_timeline_name; 33 34 use crate::user::User; 34 35 use crate::{ 35 36 AppState, LuminaError, authentication_error_elog, error_elog, http_code_elog, incoming_elog, 36 - info_elog, registration_error_elog, 37 + info_elog, registration_error_elog, warn_elog, 37 38 }; 38 39 use base64::Engine; 39 40 use base64::engine::general_purpose::STANDARD; ··· 56 57 let appstate = state.0.clone(); 57 58 appstate.event_logger.clone() 58 59 }; 60 + let db_pool = state.inner().0.db.get_postgres_pool(); 59 61 http_code_elog!(ev_log, 200, "/connection"); 60 62 use rocket::futures::{SinkExt, StreamExt}; 61 63 ··· 79 81 { 80 82 info_elog!( 81 83 ev_log, "Post was requested: {}", post_id); 82 - todo!("PostViewRequest not yet implemented!") 84 + 85 + match crate::database::operations::get_public_timelineitem(&db_pool,post_id).await { 86 + Ok(post) => { 87 + let _ = match post { 88 + crate::database::typedreturns::PostItem::TextPost{post_id,source_instance,content,timestamp}=> 89 + { 90 + info_elog!( 91 + ev_log, "Serving text post {}", post_id); 92 + stream 93 + .send(ws::Message::from(msgtojson(Message::TextPostDataSent { post_id, source_instance, content }))) 94 + .await} 95 + , 96 + crate::database::typedreturns::PostItem::MediaPost { post_id, source_instance, description, medias, timestamp } => { 97 + info_elog!(ev_log, "Serving media post {}", post_id); 98 + 99 + 100 + stream 101 + .send(ws::Message::from(msgtojson(Message::MediaPostDataSent { post_id, source_instance, description, medias }))) 102 + .await}, 103 + crate::database::typedreturns::PostItem::ArticlePost { post_id, source_instance,title, content, timestamp,author_id, } => { 104 + info_elog!(ev_log, "Serving article post {}", post_id); 105 + let timestamp = todo!("Convert timestamp to unix or Rfc3339 format here?"); 106 + stream 107 + .send(ws::Message::from(msgtojson(Message::ArticlePostDataSent { post_id, source_instance, title, content, timestamp, author_id }))) 108 + .await}, 109 + }; 110 + 111 + } 112 + Err(m) => { 113 + warn_elog!(ev_log, "Not serving {}, {m}.", post_id); 114 + } 115 + }; 116 + 83 117 } 84 118 Ok(Message::Introduction { client_kind, try_revive }) => { 85 119 match client_kind.as_str() {
+102 -2
server/src/database.rs
··· 10 10 * You may not use this work except in compliance with the Licence. 11 11 * You may obtain a copy of the Licence at: https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 12 12 * 13 - * AI TRAINING NOTICE: Rights for TDM and AI training are EXPRESSLY RESERVED 13 + * AI TRAINING NOTICE: Rights for TDM and AI training are EXPRESSLY RESERVED 14 14 * under Art 4(3) Dir 2019/790. AI training constitutes a Derivative Work. 15 15 * See LICENSE file in the repository root for full details. 16 16 * ··· 444 444 Ok(()) 445 445 } 446 446 447 - mod operations { 447 + pub(crate) mod operations { 448 + 449 + use std::str::FromStr; 450 + 451 + use anyhow::bail; 452 + use time::OffsetDateTime; 453 + use uuid::Uuid; 454 + 455 + use crate::timeline::GLOBAL_TIMELINE_ID; 456 + 448 457 use super::*; 449 458 /// List all users and their emails from the database, used for populating bloom filters on 450 459 ///startup ··· 469 478 res.push((rec.email, rec.username)); 470 479 } 471 480 Ok(res) 481 + } 482 + /// Returns a post if it is on any public timeline, including bubble timelines but excluding DM timelines. 483 + // (This because all bubble timelines are also published to the global timeline, for now) 484 + /// The answer from this is not necessarily safe for public API's, though it is yet unspecified how public API's would handle single postrequests. 485 + pub(crate) async fn get_public_timelineitem( 486 + pool: &PgPool, 487 + postid: Uuid, 488 + ) -> anyhow::Result<typedreturns::PostItem> { 489 + let gltl = Uuid::from_str(GLOBAL_TIMELINE_ID)?; 490 + let timeline_lookup = sqlx::query!( 491 + "SELECT * FROM timelines WHERE item_id = $1 AND tlid = $2", 492 + postid, 493 + gltl 494 + ) 495 + .fetch_optional(pool) 496 + .await?; 497 + let _ = if let None = timeline_lookup { 498 + bail!("No post was found on global timeline") 499 + }; 500 + let type_lookup = sqlx::query!("SELECT * FROM itemtypes WHERE item_id = $1", postid,) 501 + .fetch_one(pool) 502 + .await?; 503 + match type_lookup.itemtype.as_str() { 504 + "text" => { 505 + let post = sqlx::query!("SELECT * FROM post_text WHERE id = $1", postid,) 506 + .fetch_one(pool) 507 + .await?; 508 + let location = match (post.foreign_instance_id, post.foreign_post_id) { 509 + (Some(pid), Some(iid)) => (Uuid::from_str(pid.as_str())?, iid), 510 + _ => (postid, String::from("local")), 511 + }; 512 + anyhow::Ok(typedreturns::PostItem::TextPost { 513 + post_id: postid, 514 + source_instance: location.1, 515 + content: post.content, 516 + timestamp: post.created_at, 517 + }) 518 + } 519 + "media" => { 520 + todo!("Media post fetching not yet implemented."); 521 + } 522 + "article" => { 523 + todo!("Article post fetching not yet implemented."); 524 + } 525 + _ => { 526 + bail!("Unsupported post for the global timeline, something got mixed up here.") 527 + } 528 + } 529 + } 530 + } 531 + 532 + pub(crate) mod typedreturns { 533 + use time::OffsetDateTime; 534 + use uuid::Uuid; 535 + 536 + pub(crate) enum TimelineItem { 537 + Post(PostItem), 538 + } 539 + pub(crate) enum PostItem { 540 + ArticlePost { 541 + post_id: Uuid, 542 + /// Source instance. 'local' by default, hostname if external. 543 + source_instance: String, 544 + title: String, 545 + content: String, 546 + /// Timestamp of the moment of posting 547 + timestamp: OffsetDateTime, 548 + /// User id of poster, which is why the source_instance matters. 549 + /// This means that client will do a lookup and stores the user once it gets it. 550 + author_id: String, 551 + }, 552 + MediaPost { 553 + post_id: Uuid, 554 + /// Source instance. 'local' by default, hostname if external. 555 + source_instance: String, 556 + /// Media description 557 + description: String, 558 + /// Base64 encoded media strings, either webp or mp4. 559 + medias: Vec<String>, 560 + /// Timestamp of the moment of posting 561 + timestamp: OffsetDateTime, 562 + }, 563 + TextPost { 564 + post_id: Uuid, 565 + /// Source instance. 'local' by default, hostname (IID) if external. 566 + source_instance: String, 567 + /// Markdown content. 568 + content: String, 569 + /// Timestamp of the moment of posting 570 + timestamp: OffsetDateTime, 571 + }, 472 572 } 473 573 }