|
|
|
@ -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 );
|
|
|
|
|
}
|
|
|
|
|