Add /api/v1/instance, start work on ap_activity model, rework save/load files to use json helper functions, remove client_app model json template, implement notification model

master
teknomunk 1 year ago
parent 808f912b1e
commit 6706606cf8

@ -3,6 +3,8 @@
#include "http_server/http_request.h"
#include "json/json.h"
#include "model/activity.h"
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
@ -94,7 +96,7 @@ void process_inbox()
printf( "Inbox has %d items pending processing...\n", (head_pos - tail_pos) );
}
sleep(1);
sleep(30);
}
}

@ -1,21 +1,24 @@
#include "mastodon_api.h"
#include "http_server/http_request.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "form.h"
#include "json/json.h"
#include "model/status.h"
#include "model/account.h"
#include "model/notification.h"
#include "model/timeline.h"
#include "model/server.h"
#include "api/client_apps.h"
#include "api/status.h"
#include "api/notice.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
enum timeline_ids {
tli_owner = 0,
tli_public = 1,
@ -71,10 +74,13 @@ bool route_mastodon_api( struct http_request* req )
if( http_request_route_method( req, "POST" ) ) {
return handle_mastodon_api_apps(req);
}
}
if( http_request_route( req, "timelines/public" ) ) {
} else if( http_request_route( req, "timelines/public" ) ) {
return handle_timeline( req, tli_public );
} else if( http_request_route( req, "instance" ) ) {
http_request_send_headers( req, 200, "application/json", true );
FILE* f = http_request_get_response_body( req );
#include "src/view/api/instance_data.json.inc"
return true;
}
//*
@ -85,12 +91,13 @@ bool route_mastodon_api( struct http_request* req )
struct account* owner = account_from_id(0);
if( http_request_route( req, "notifications" ) ) {
struct notification note = {
.account_id = 1,
.status_id = 1,
};
show_notifications( req, &note, 1 );
return true;
struct notification* note = notification_from_id(0);
if( note ) {
show_notifications( req, note, 1 );
notification_free(note);
return true;
}
return false;
} else if( http_request_route( req, "filters" ) ) {
http_request_send_headers( req, 200, "application/json", true );
FILE* f = http_request_get_response_body( req );

@ -1 +1 @@
Subproject commit dd2f8484a1d2cafe8dee4ee1e3104664e3213716
Subproject commit 8853784e4d4cc3954c0bf12ad46ede4b1eabb56a

@ -26,5 +26,6 @@ struct account* account_new();
void account_free( struct account* a );
void account_save( struct account* a );
// TODO: move to controller/view and rename api_account_write_as_json
void account_write_as_json( struct account* a, FILE* f );

@ -0,0 +1,20 @@
#pragma once
struct ap_signature;
struct ap_activity
{
char* id;
char* type;
char* actor;
struct {
char** items;
int count;
} to;
char* object;
struct ap_signature* signature;
};
struct json_field_type;
extern struct json_field_type json_field_object_activity;

@ -33,16 +33,10 @@ static struct json_object_field client_app_layout[] = {
struct client_app* client_app_from_id( const char* client_id )
{
FILE* f = NULL;
struct client_app* app = NULL;
struct json_pull_parser* jpp = NULL;
char filename[512];
snprintf( filename, 512, "data/client_apps/%s.json", client_id );
f = fopen(filename,"r");
if( !f ) { goto failed; }
app = malloc(sizeof(struct client_app));
struct client_app* app = malloc(sizeof(struct client_app));
app->client.name = NULL;
app->client.id = strdup(client_id);
app->client.secret = NULL;
@ -50,19 +44,12 @@ struct client_app* client_app_from_id( const char* client_id )
app->redirect_uri = NULL;
app->access_token = NULL;
jpp = json_pull_parser_new( f );
if( !jpp ) { goto failed; }
if( !json_read_object_layout( jpp, client_app_layout, app ) ) { goto failed; }
if( !json_read_object_layout_from_file( filename, client_app_layout, app ) ) {
client_app_free(app);
return NULL;
}
cleanup:
json_pull_parser_release(jpp);
if( f ) { fclose(f); }
return app;
failed:
client_app_free(app);
app = NULL;
goto cleanup;
}
struct client_app* client_app_new( const char* client_name )
@ -96,16 +83,7 @@ void client_app_save( struct client_app* app )
char filename[512];
snprintf( filename, 512, "data/client_apps/%s.json", app->client.id );
char tmp_filename[512];
snprintf( tmp_filename, 512, "%s.tmp-%d", filename, rand() );
FILE* f = fopen(tmp_filename, "w" );
if( !f ) {
return;
}
#include "model/client_app.json.inc"
fclose(f);
rename( tmp_filename, filename );
json_write_object_layout_to_file( filename, "\t", client_app_layout, app );
}
void client_app_free( struct client_app* app )

@ -1,7 +0,0 @@
{
"secret": "%s{app->client.secret}",
"name": "%s{app->client.name}",
"auth_code": "%s{ safe(app->auth_code) }",
"redirect_uri": "%s{ safe(app->redirect_uri) }",
"access_token": "%s{ safe(app->access_token) }"
}

@ -1,12 +1,57 @@
#include "notification.h"
#include "json/json.h"
#include "json/layout.h"
#include "model/account.h"
#include "model/status.h"
#include "controller/api/status.h"
#include <stdlib.h>
#include <stddef.h>
static struct json_enum notification_type_enum[] = {
{ "favorite", 1 },
{ NULL, -1 },
};
static struct json_object_field notification_layout[] = {
{ "account_id", offsetof( struct notification, account_id ), true, &json_field_integer },
{ "status_id", offsetof( struct notification, status_id ), true, &json_field_integer },
{ "type", offsetof( struct notification, type ), true, &json_field_enum, notification_type_enum },
{ NULL }
};
struct notification* notification_from_id( int id )
{
struct notification* note = malloc(sizeof(struct notification));
char filename[512];
snprintf( filename, 512, "data/notices/%d.json", id );
if( !json_read_object_layout_from_file( filename, notification_layout, note ) ) {
free(note);
return NULL;
}
return note;
}
void notification_save( struct notification* note )
{
char filename[512];
snprintf( filename, 512, "data/notices/%d.json", note->id );
json_write_object_layout_to_file( filename, "\t", notification_layout, note );
}
void notification_free( struct notification* note )
{
free(note);
}
void notification_write_as_json( struct notification* n, FILE* f )
{
// TODO: move to controller/view
struct account* a = account_from_id( n->account_id );
struct account* owner = account_from_id( 0 );
struct status* s = status_from_id( n->status_id );

@ -1,12 +1,17 @@
#pragma once
#include <stdio.h>
#include <time.h>
#include <stdbool.h>
struct notification
{
unsigned int id;
unsigned int account_id;
unsigned int status_id;
time_t created_at;
bool is_muted;
bool is_seen;
int type;
};
@ -15,5 +20,10 @@ enum notification_type
nt_favorite = 1,
};
struct notification* notification_from_id( int id );
void notification_save( struct notification* note );
void notification_free( struct notification* note );
// TODO: move to controler/view
void notification_write_as_json( struct notification* n, FILE* f );

@ -1,11 +1,15 @@
{
"account": %( account_write_as_json(a,f); ),
"created_at": "2022-12-12T15:31:54.000Z",
"id": "%d{n->id}",
"pleroma": {
"is_muted": false,
"is_seen": false
},
"status": %( api_status_write_as_json(s,f); ),
"type": "favourite"
"account": %( account_write_as_json(a,f); ),
"created_at": "2022-12-12T15:31:54.000Z",
"id": "%d{n->id}",
"pleroma": {
"is_muted": false,
"is_seen": false
},
"status": %( api_status_write_as_json(s,f); ),
"type": "%(
switch(n->type) {
case nt_favorite: fprintf(f,"favourite"); break;
default: fprintf(f,"unknown-%d",n->type); break;
}; )"
}

@ -30,34 +30,29 @@ static struct json_object_field status_layout[] = {
{ NULL }
};
void* allocate( size_t s )
{
void* ptr = malloc(s);
memset( ptr, 0, s );
return ptr;
}
struct status* status_from_id( unsigned int id )
{
struct status* s = NULL;
char filename[512];
snprintf( filename, 512, "data/statuses/%d.json", id );
FILE* f = fopen( filename, "r" );
if( !f ) { return NULL; }
struct json_pull_parser* jpp = json_pull_parser_new( f );
if( !jpp ) { return NULL; }
s = malloc(sizeof(struct status));
memset( s, 0, sizeof(*s) );
s = allocate(sizeof(struct status));
s->id = id;
s->account_id = -1;
if( !json_read_object_layout( jpp, status_layout, s ) ) { goto failed; }
cleanup:
json_pull_parser_release(jpp);
fclose(f);
if( !json_read_object_layout_from_file( filename, status_layout, s ) ) {
free(s);
return NULL;
}
return s;
failed:
//status_free(s);
s = NULL;
goto cleanup;
}
bool status_save_new( struct status* s )
@ -83,19 +78,9 @@ bool status_save_new( struct status* s )
void status_save( struct status* s )
{
char filename[512];
char tmp_filename[512+32];
snprintf( filename, 512, "data/statuses/%d.json", s->id );
snprintf( tmp_filename, 512+32, "%s.tmp", filename );
struct json_writer jw = {
.f = fopen( tmp_filename, "w" ),
.indent = 0,
.indentation = "\t",
};
json_write_pretty_object_layout( &jw, status_layout, s );
fclose(jw.f);
rename( tmp_filename, filename );
json_write_object_layout_to_file( filename, "\t", status_layout, s );
}
void status_free( struct status* s )

@ -21,15 +21,13 @@ static struct json_object_field timeline_block_layout[] = {
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_block_load( %d, %u, %u )\n", id, head, block );
char filename[512];
snprintf( filename, 512, "data/accounts/%d/timeline/%u.json", id, block );
f = fopen(filename,"r");
if( !f ) { goto failed; }
tl = malloc(sizeof(struct timeline));
tl->id = id;
@ -38,19 +36,12 @@ struct timeline* timeline_block_load( int id, unsigned int head, unsigned int bl
tl->status_ids.items = NULL;
tl->status_ids.count = 0;
jpp = json_pull_parser_new( f );
if( !jpp ) { goto failed; }
if( !json_read_object_layout( jpp, timeline_block_layout, tl ) ) { goto failed; }
if( !json_read_object_layout_from_file( filename, timeline_block_layout, tl ) ) {
free(tl);
return tl;
}
cleanup:
json_pull_parser_release(jpp);
fclose(f);
return tl;
failed:
timeline_free(tl);
tl = NULL;
goto cleanup;
}
@ -141,15 +132,7 @@ void timeline_add_post( struct timeline* tl, struct status* s )
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 );
json_write_object_layout_to_file( filename, "\t", timeline_block_layout, tl );
}

@ -0,0 +1,84 @@
{
"approval_required":false,
"avatar_upload_limit":2000000,
"background_image":"https://pl.polaris-1.work/images/city.jpg",
"background_upload_limit":4000000,
"banner_upload_limit":4000000,
"description":"Apogee: A Single-User ActivityPub Server",
"description_limit":5000,
"email":"teknomunk@protonmail.com",
"languages":["en"],
"max_toot_chars":5000,
"pleroma":{
"metadata":{
"account_activation_required":false,
"features":[
"pleroma_api",
"mastodon_api"
%( /*
"mastodon_api_streaming",
"polls",
"pleroma_explicit_addressing",
"shareable_emoji_packs",
"multifetch",
"pleroma:api/v1/notifications:include_types_filter",
"chat",
"shout",
"relay",
"pleroma_emoji_reactions",
"pleroma_chat_messages"
*/ )
],
"federation":{
"enabled":false,
"exclusions":false,
"mrf_hashtag":{
"federated_timeline_removal":[],
"reject":[],
"sensitive":["nsfw"]
},
"mrf_object_age":{
"actions":["delist","strip_followers"],
"threshold":604800
},
"mrf_policies":["ObjectAgePolicy","TagPolicy","HashtagPolicy"],
"quarantined_instances":[]
},
"fields_limits":{
"max_fields":10,
"max_remote_fields":20,
"name_length":512,
"value_length":2048
},
"post_formats":[
"text/plain",
"text/markdown",
"text/bbcode",
"text/html"
]
},
"stats":{"mau":1},
"vapid_public_key":"BIAQBuhbJJ-kSDSy3lfx9amo0iMk4jG4e4OSwJi4-N908lHWspxLy2p7sACjyW8dtJkLUSP00midXnaOIZxOVTo"
},
"poll_limits":{
"max_expiration":31536000,
"max_option_chars":200,
"max_options":20,
"min_expiration":0
},
"registrations":false,
"shout_limit":5000,
"stats":{
"domain_count":0,
"status_count":5,
"user_count":1
},
"thumbnail":"https://pl.polaris-1.work/media/27313e491a834971b8d868e121fcf3e279b109dca0351b87310a2a367b3a6237.png",
"title":"%s{g_server_name}",
"upload_limit":1600000000,
"uri":"https:/%s{g_server_name}",
"urls":{
%(/*"streaming_api":"wss://pl.polaris-1.work"*/)
},
"version":"0.1alpha"
}
Loading…
Cancel
Save