Revert "refactor (backend): it turns out that sending the entire note object was redundant"

This reverts commit 3b65ebcb3e.
This commit is contained in:
naskya 2024-04-22 01:47:56 +09:00
parent 3039458c4c
commit 2a30b4a536
No known key found for this signature in database
GPG key ID: 712D413B3A9FED5C
7 changed files with 98 additions and 6 deletions

View file

@ -1103,7 +1103,7 @@ export interface Webhook {
latestSentAt: Date | null latestSentAt: Date | null
latestStatus: number | null latestStatus: number | null
} }
export function addNoteToAntenna(antennaId: string, noteId: string): void export function addNoteToAntenna(antennaId: string, note: Note): void
/** Initializes Cuid2 generator. Must be called before any [create_id]. */ /** Initializes Cuid2 generator. Must be called before any [create_id]. */
export function initIdGenerator(length: number, fingerprint: string): void export function initIdGenerator(length: number, fingerprint: string): void
export function getTimestamp(id: string): number export function getTimestamp(id: string): number

View file

@ -1,20 +1,23 @@
use crate::database::{redis_conn, redis_key}; use crate::database::{redis_conn, redis_key};
use crate::service::stream::{publish_to_stream, Error, Stream}; use crate::service::stream::{publish_to_stream, Error, Stream};
use crate::model::entity::note;
use crate::util::id::get_timestamp; use crate::util::id::get_timestamp;
use redis::{streams::StreamMaxlen, Commands}; use redis::{streams::StreamMaxlen, Commands};
type Note = note::Model;
#[crate::export] #[crate::export]
pub fn add_note_to_antenna(antenna_id: String, note_id: &str) -> Result<(), Error> { pub fn add_note_to_antenna(antenna_id: String, note: &Note) -> Result<(), Error> {
redis_conn()?.xadd_maxlen( redis_conn()?.xadd_maxlen(
redis_key(format!("antennaTimeline:{}", antenna_id)), redis_key(format!("antennaTimeline:{}", antenna_id)),
StreamMaxlen::Approx(200), StreamMaxlen::Approx(200),
format!("{}-*", get_timestamp(note_id)), format!("{}-*", get_timestamp(&note.id)),
&[("note", note_id)], &[("note", &note.id)],
)?; )?;
publish_to_stream( publish_to_stream(
&Stream::Antenna { antenna_id }, &Stream::Antenna { antenna_id },
Some("note"), Some("note"),
Some(format!("{{ \"id\": \"{}\" }}", note_id)), Some(serde_json::to_string(note)?),
) )
} }

View file

@ -41,6 +41,8 @@ pub enum Stream {
pub enum Error { pub enum Error {
#[error("Redis error: {0}")] #[error("Redis error: {0}")]
RedisError(#[from] RedisError), RedisError(#[from] RedisError),
#[error("Json (de)serialization error: {0}")]
JsonError(#[from] serde_json::Error),
#[error("Value error: {0}")] #[error("Value error: {0}")]
ValueError(String), ValueError(String),
} }

View file

@ -178,6 +178,7 @@
"ts-loader": "9.5.1", "ts-loader": "9.5.1",
"ts-node": "10.9.2", "ts-node": "10.9.2",
"tsconfig-paths": "4.2.0", "tsconfig-paths": "4.2.0",
"type-fest": "4.15.0",
"typescript": "5.4.5", "typescript": "5.4.5",
"webpack": "^5.91.0", "webpack": "^5.91.0",
"ws": "8.16.0" "ws": "8.16.0"

View file

@ -0,0 +1,76 @@
// https://gist.github.com/tkrotoff/a6baf96eb6b61b445a9142e5555511a0
import type { Primitive } from "type-fest";
type NullToUndefined<T> = T extends null
? undefined
: T extends Primitive | Function | Date | RegExp
? T
: T extends Array<infer U>
? Array<NullToUndefined<U>>
: T extends Map<infer K, infer V>
? Map<K, NullToUndefined<V>>
: T extends Set<infer U>
? Set<NullToUndefined<U>>
: T extends object
? { [K in keyof T]: NullToUndefined<T[K]> }
: unknown;
type UndefinedToNull<T> = T extends undefined
? null
: T extends Primitive | Function | Date | RegExp
? T
: T extends Array<infer U>
? Array<UndefinedToNull<U>>
: T extends Map<infer K, infer V>
? Map<K, UndefinedToNull<V>>
: T extends Set<infer U>
? Set<NullToUndefined<U>>
: T extends object
? { [K in keyof T]: UndefinedToNull<T[K]> }
: unknown;
function _nullToUndefined<T>(obj: T): NullToUndefined<T> {
if (obj === null) {
return undefined as any;
}
if (typeof obj === "object") {
if (obj instanceof Map) {
obj.forEach((value, key) => obj.set(key, _nullToUndefined(value)));
} else {
for (const key in obj) {
obj[key] = _nullToUndefined(obj[key]) as any;
}
}
}
return obj as any;
}
function _undefinedToNull<T>(obj: T): UndefinedToNull<T> {
if (obj === undefined) {
return null as any;
}
if (typeof obj === "object") {
if (obj instanceof Map) {
obj.forEach((value, key) => obj.set(key, _undefinedToNull(value)));
} else {
for (const key in obj) {
obj[key] = _undefinedToNull(obj[key]) as any;
}
}
}
return obj as any;
}
/**
* Recursively converts all undefined values to null.
*
* @param obj object to convert
* @returns a copy of the object with all its undefined values converted to null
*/
export function undefinedToNull<T>(obj: T) {
return _undefinedToNull(structuredClone(obj));
}

View file

@ -62,6 +62,7 @@ import { Mutex } from "redis-semaphore";
import { langmap } from "@/misc/langmap.js"; import { langmap } from "@/misc/langmap.js";
import Logger from "@/services/logger.js"; import Logger from "@/services/logger.js";
import { inspect } from "node:util"; import { inspect } from "node:util";
import { undefinedToNull } from "@/prelude/undefined-to-null.js";
const logger = new Logger("create-note"); const logger = new Logger("create-note");
@ -398,7 +399,8 @@ export default async (
for (const antenna of await getAntennas()) { for (const antenna of await getAntennas()) {
checkHitAntenna(antenna, note, user).then((hit) => { checkHitAntenna(antenna, note, user).then((hit) => {
if (hit) { if (hit) {
addNoteToAntenna(antenna.id, note.id); // TODO: do this more sanely
addNoteToAntenna(antenna.id, undefinedToNull(note) as Note);
} }
}); });
} }

View file

@ -521,6 +521,9 @@ importers:
tsconfig-paths: tsconfig-paths:
specifier: 4.2.0 specifier: 4.2.0
version: 4.2.0 version: 4.2.0
type-fest:
specifier: 4.15.0
version: 4.15.0
typescript: typescript:
specifier: 5.4.5 specifier: 5.4.5
version: 5.4.5 version: 5.4.5
@ -16632,6 +16635,11 @@ packages:
engines: {node: '>=8'} engines: {node: '>=8'}
dev: true dev: true
/type-fest@4.15.0:
resolution: {integrity: sha512-tB9lu0pQpX5KJq54g+oHOLumOx+pMep4RaM6liXh2PKmVRFF+/vAtUP0ZaJ0kOySfVNjF6doBWPHhBhISKdlIA==}
engines: {node: '>=16'}
dev: true
/type-is@1.6.18: /type-is@1.6.18:
resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==} resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==}
engines: {node: '>= 0.6'} engines: {node: '>= 0.6'}