Implement timelines, make media and reactions data driven (reactions still need count/react pulled from data)

master
teknomunk 1 year ago
parent 16f4e1911e
commit 9d43a84d5b

@ -5,6 +5,7 @@
#include "http_server/http_request.h"
#include "model/status.h"
#include "model/account.h"
#include "model/timeline.h"
#include <stdio.h>
#include <stdlib.h>
@ -96,11 +97,12 @@ bool handle_post( struct http_request* req, struct account* a )
status_save_new(s);
/*
struct account* owner = account_from_id(0);
struct timeline* tl = account_get_home_timeline(owner);
timeline_insert_status( tl, s );
*/
// Add to owner timeline, public timeline and home timelines
for( int i = 0; i < 3; ++i ) {
struct timeline* tl = timeline_from_id(i);
timeline_add_post( tl, s );
timeline_free(tl);
}
http_request_send_headers( req, 200, "application/json", true );
FILE* f = http_request_get_response_body(req);

@ -23,12 +23,16 @@ bool handle_timeline( struct http_request* req, const char* which )
unsigned int limit = 100;
struct timeline* tl = timeline_from_id( 0 );
timeline_free(tl);
struct status* s = status_from_id(1);
struct status* ss[] = { s };
show_statuses( req, ss, 1 );
status_free(s);
struct status* ss[32];
int count = timeline_load_statuses( tl, 0, 32, ss );
show_statuses( req, ss, count );
for( int i = 0; i < count; ++i ) {
status_free( ss[i] );
}
timeline_free(tl);
return true;
}
@ -134,3 +138,4 @@ bool route_mastodon_api( struct http_request* req )
return false;
}

@ -1 +1 @@
Subproject commit b779f4b44fc35c54e9f77913e65af72b3d783b29
Subproject commit 3db4755b6c9544ea4c37ac33665eeba278e4d67e

@ -22,9 +22,11 @@ static const char* host()
}
static struct json_object_field status_layout[] = {
{ "account_id", offsetof( struct status, account_id ), true, &json_field_integer },
{ "sensitive", offsetof( struct status, sensitive ), true, &json_field_bool },
{ "content", offsetof( struct status, content ), true, &json_field_string },
{ "account_id", offsetof( struct status, account_id ), true, &json_field_integer },
{ "sensitive", offsetof( struct status, sensitive ), true, &json_field_bool },
{ "content", offsetof( struct status, content ), true, &json_field_string },
{ "media", offsetof( struct status, media ), false, &json_field_array_of, &json_field_string },
{ "reacts", offsetof( struct status, reacts ), false, &json_field_array_of, &json_field_string },
{ NULL }
};
@ -41,6 +43,7 @@ struct status* status_from_id( unsigned int id )
if( !jpp ) { return NULL; }
s = malloc(sizeof(struct status));
memset( s, 0, sizeof(*s) );
s->id = id;
s->account_id = -1;
@ -89,7 +92,6 @@ void status_save( struct status* s )
.indent = 0,
.indentation = "\t",
};
printf( "content:\n%s\n", s->content );
json_write_pretty_object_layout( &jw, status_layout, s );
fclose(jw.f);
@ -100,6 +102,16 @@ void status_free( struct status* s )
{
if( !s ) { return; }
for( int i = 0; i < s->media.count; ++i ) {
free(s->media.items[i]);
}
free(s->media.items);
for( int i = 0; i < s->reacts.count; ++i ) {
free(s->reacts.items[i]);
}
free(s->reacts.items);
free(s->content);
free(s);
}

@ -10,6 +10,16 @@ struct status
char* content;
bool sensitive;
struct {
char** items;
int count;
} media;
struct {
char** items;
int count;
} reacts;
};
struct status* status_from_id( unsigned int id );

@ -3,25 +3,31 @@
#include "json/json.h"
#include "json/layout.h"
#include "model/status.h"
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
enum {
STATUSES_PER_BLOCK = 256,
};
static struct json_object_field timeline_block_layout[] = {
{ "status_ids", offsetof( struct timeline, status_ids ), true, &json_field_array_of, &json_field_integer },
{ NULL },
};
struct timeline* timeline_load_block( int id, unsigned int head, unsigned int block )
struct timeline* timeline_block_load( int id, unsigned int head, unsigned int block )
{
struct timeline* tl = NULL;
char filename[512];
FILE* f = NULL;
struct json_pull_parser* jpp = NULL;
printf( "timeline_load_block( %d, %u, %u )\n", id, head, block );
printf( "timeline_block_load( %d, %u, %u )\n", id, head, block );
snprintf( filename, 512, "data/timelines/%d/%u.json", id, block );
snprintf( filename, 512, "data/accounts/%d/timeline/%u.json", id, block );
f = fopen(filename,"r");
if( !f ) { goto failed; }
@ -37,10 +43,6 @@ struct timeline* timeline_load_block( int id, unsigned int head, unsigned int bl
if( !json_read_object_layout( jpp, timeline_block_layout, tl ) ) { goto failed; }
for( int i = 0; i < tl->status_ids.count; ++i ) {
printf( "tl->status_ids[%d] = %d\n", i, tl->status_ids.items[i] );
}
cleanup:
json_pull_parser_release(jpp);
fclose(f);
@ -51,10 +53,11 @@ failed:
goto cleanup;
}
struct timeline* timeline_from_id( int id )
{
char filename[512];
snprintf( filename, 512, "data/timelines/%d/HEAD", id );
snprintf( filename, 512, "data/accounts/%d/timeline/HEAD", id );
FILE* f = fopen(filename,"r");
unsigned int head = 0;
@ -63,7 +66,7 @@ struct timeline* timeline_from_id( int id )
fclose(f);
}
return timeline_load_block( id, head, head );
return timeline_block_load( id, head, head );
}
struct timeline* timeline_new()
{
@ -75,3 +78,78 @@ void timeline_free( struct timeline* tl )
free(tl->status_ids.items);
free(tl);
}
int timeline_load_statuses( struct timeline* tl, int offset_from_head, int count, struct status** result )
{
// TODO: take offset_from_head into account to get starting position
if( count > tl->status_ids.count ) {
count = tl->status_ids.count;
}
printf( "count=%d\n", count );
int found = 0;
for( int i = count - 1; i >= 0; --i ) {
result[found] = status_from_id( tl->status_ids.items[i] );
if( result[found] ) {
found += 1;
} else {
printf( "Couldn't load status with id %d\n", tl->status_ids.items[i] );
}
}
return found;
}
void timeline_add_post( struct timeline* tl, struct status* s )
{
if( tl->head != tl->block ) {
struct timeline* tl_head = timeline_block_load( tl->id, tl->head, tl->head );
timeline_add_post( tl_head, s );
timeline_free( tl_head );
return;
}
if( tl->status_ids.count >= STATUSES_PER_BLOCK ) {
int new_head = tl->head + 1;
int id = tl->id;
char filename[512];
snprintf( filename, 512, "data/accounts/%d/timeline/HEAD", id );
char tmp_filename[512+32];
snprintf( tmp_filename, 512+32, "%s.tmp", filename );
FILE* head = fopen( filename, "w" );
fprintf( head, "%d", new_head + 1 );
fclose(head);
rename( tmp_filename, filename );
tl = malloc(sizeof(struct timeline));
tl->status_ids.count = 0;
tl->status_ids.items = NULL;
tl->id = id;
tl->head = new_head;
tl->block = new_head;
timeline_add_post( tl, s );
timeline_free(tl);
return;
}
tl->status_ids.count += 1;
tl->status_ids.items = realloc( tl->status_ids.items, sizeof(int) * tl->status_ids.count );
tl->status_ids.items[ tl->status_ids.count - 1 ] = s->id;
char filename[512];
snprintf( filename, 512, "data/accounts/%d/timeline/%u.json", tl->id, tl->block );
char tmp_filename[512+32];
snprintf( tmp_filename, 512+32, "%s.tmp", filename );
FILE* f = fopen( tmp_filename, "w" );
struct json_writer jw = {
.f = f,
.indent = 0,
.indentation = "\t",
};
json_write_pretty_object_layout( &jw, timeline_block_layout, tl );
fclose(f);
rename( tmp_filename, filename );
}

@ -1,5 +1,7 @@
#pragma once
struct status;
struct timeline_block_ref
{
int starting_offset;
@ -22,3 +24,6 @@ struct timeline* timeline_from_id( int id );
struct timeline* timeline_new();
void timeline_free( struct timeline* tl );
int timeline_load_statuses( struct timeline* tl, int offset_from_head, int count, struct status** result );
void timeline_add_post( struct timeline* tl, struct status* s );

@ -12,19 +12,21 @@
"in_reply_to_account_id": null,
"in_reply_to_id": null,
"language": null,
"media_attachments": [ {
"blurhash": "eRH.A}xs0Kxv00xYR,R+t5R+9Gt6xaNG%%2-;xaM{NGRjD%%Rjs:xaxu",
"description": null,
"id": "1248813041",
"pleroma": {
"mime_type": "image/png"
},
"preview_url": "https://i.poastcdn.org/0ce6abff5d4838b9af4033a2567d94033b9b62a15aae394e7e48b5f597db76de.png",
"remote_url": "https://i.poastcdn.org/0ce6abff5d4838b9af4033a2567d94033b9b62a15aae394e7e48b5f597db76de.png",
"text_url": "https://i.poastcdn.org/0ce6abff5d4838b9af4033a2567d94033b9b62a15aae394e7e48b5f597db76de.png",
"type": "image",
"url": "https://i.poastcdn.org/0ce6abff5d4838b9af4033a2567d94033b9b62a15aae394e7e48b5f597db76de.png"
} ],
"media_attachments": [%( for( int i = 0; i < s->media.count; ++i ) { )
{
"blurhash": "eRH.A}xs0Kxv00xYR,R+t5R+9Gt6xaNG%%2-;xaM{NGRjD%%Rjs:xaxu",
"description": null,
"id": "1248813041",
"pleroma": {
"mime_type": "image/png"
},
"preview_url": "%s{s->media.items[i]}",
"remote_url": "%s{s->media.items[i]}",
"text_url": "%s{s->media.items[i]}",
"type": "image",
"url": "%s{s->media.items[i]}"
}%s{ i < s->media.count - 1 ? "," : "" }
%( } )],
"mentions": [],
"muted": false,
"pinned": false,
@ -34,11 +36,13 @@
},
"conversation_id": 2935699,
"direct_conversation_id": null,
"emoji_reactions": [ {
"emoji_reactions": [%( for( int i = 0; i < s->reacts.count; ++i ) { )
{
"count": 1,
"me": false,
"name": "😆"
} ],
}
%( } )],
"expires_at": null,
"in_reply_to_account_acct": null,
"local": false,

Loading…
Cancel
Save