perl L10N and Perl Templates

FossilOrigin-Name: 06ed73d30ae11c7651dcb87e4b78f9ef7b297b386f8ff0bbd087e22628bc9a68
This commit is contained in:
nekobit 2022-07-22 22:41:07 +00:00
parent 004b47ad07
commit 772db3ce28
8 changed files with 313 additions and 83 deletions

View file

@ -8,25 +8,23 @@ SRC = $(wildcard src/*.c)
OBJ = $(patsubst %.c,%.o,$(SRC))
HEADERS = $(wildcard src/*.h) config.h
PAGES_DIR = static
PERL_DIR = perl
TMPL_DIR = templates
PAGES = $(wildcard $(PAGES_DIR)/*.tmpl)
PERLS = $(wildcard $(PERL_DIR)/*.pl)
TMPLS = $(wildcard $(TMPL_DIR)/*.tt)
PAGES_CMP = $(patsubst %.tmpl,%.ctmpl,$(PAGES))
PAGES_C = $(patsubst %.tmpl, %.c,$(PAGES))
PAGES_C_OBJ = $(patsubst %.c,%.o,$(PAGES_C))
PERLS_C = $(patsubst %.pl,%.cpl,$(PERLS))
TMPLS_C = $(patsubst %.tt,%.ctt,$(TMPLS))
DIST = dist/
PREFIX ?= /usr/local
TARGET = treebird
$(info $(PERLS) and $(PERLS_C))
MASTODONT_URL = https://fossil.nekobit.net/mastodont-c
all: $(MASTODONT_DIR) dep_build $(TARGET)
apache: all apache_start
$(TARGET): filec template $(PERLS_C) $(PAGES_CMP) $(PAGES_C) $(PAGES_C_OBJ) $(OBJ) $(HEADERS)
$(TARGET): filec template $(TMPLS_C) $(TMPLS) $(PAGES_CMP) $(PAGES_C) $(PAGES_C_OBJ) $(OBJ) $(HEADERS)
$(CC) -o $(TARGET) $(OBJ) $(PAGES_C_OBJ) $(LDFLAGS)
template: src/template/main.o
@ -41,11 +39,11 @@ emojitoc: scripts/emoji-to.o
# Redirect stdout and stderr into separate contents as a hack
# Let bash do the work :)
$(PAGES_DIR)/%.ctmpl: $(PAGES_DIR)/%.tmpl
$(PAGES_DIR)/%.ctmpl: $(PAGES_DIR)/%.tmpl $(TMPLS)
./template $< $(notdir $*) 2> $(PAGES_DIR)/$(notdir $*).c 1> $@
$(PERL_DIR)/%.cpl: $(PERL_DIR)/%.pl
./filec $< data_$(notdir $*)_pl > $@
$(TMPL_DIR)/%.ctt: $(TMPL_DIR)/%.tt
./filec $< data_$(notdir $*)_tt > $@
$(MASTODONT_DIR):
cd ..; fossil clone $(MASTODONT_URL) || true
@ -71,6 +69,7 @@ dep_build:
clean:
rm -f $(OBJ) src/file-to-c/main.o
rm -f $(PAGES_CMP)
rm -f $(TMPLS_C)
rm -f filec
make -C $(MASTODONT_DIR) clean

89
perl/l10n.pm Normal file
View file

@ -0,0 +1,89 @@
package l10n;
our @EXPORT = qw( %L10N );
our %L10N = (
EN_US => {
APP_NAME => 'Treebird',
HOME => 'Home',
LOCAL => 'Local',
FEDERATED => 'Federated',
NOTIFICATIONS => 'Notifications',
LISTS => 'Lists',
FAVOURITES => 'Favorites',
BOOKMARKS => 'Bookmarks',
DIRECT => 'Direct',
CONFIG => 'Config',
SEARCH_PLACEHOLDER => 'Search',
SEARCH_BUTTON => 'Search',
GENERAL => 'General',
ACCOUNT => 'Account',
JAVASCRIPT => 'JavaScript',
CFG_QUICK_ACTIONS => 'Quick actions - Likes, Boosts, etc done in the background',
CFG_QUICK_REPLY => 'Quick reply - Replies don\'t require redirects',
LIVE_STATUSES => 'Live statuses - Statuses fetch on the fly',
APPEARANCE => 'Appearance',
VARIANT => 'Variant',
THEME_TREEBIRD20 => 'Treebird - Default, simple theme',
THEME_TREEBIRD30 => 'Treebird 3.0 - Flat, modern theme',
COLOR_SCHEME => 'Color Scheme',
LIGHT => 'Light',
DARK => 'Dark',
SAVE => 'Save',
ACCT_MENU => 'Menu',
SUBSCRIBE => 'Subscribe',
UNSUBSCRIBE => 'Unsubscribe',
BLOCK => 'Block',
UNBLOCK => 'Unblock',
MUTE => 'Mute',
UNMUTE => 'Unmute',
TAB_STATUSES => 'Statuses',
TAB_FOLLOWING => 'Following',
TAB_FOLLOWERS => 'Followers',
TAB_SCROBBLES => 'Scrobbles',
TAB_MEDIA => 'Media',
TAB_PINNED => 'Pinned',
FOLLOWS_YOU => 'Follows you!',
FOLLOW => 'Follow',
FOLLOW_PENDING => 'Follow pending',
FOLLOWING => 'Following!',
BLOCKED => 'You are blocked by this user.',
REPLY => 'Reply',
REPEAT => 'Repeat',
LIKE => 'Like',
QUICK => 'Quick',
VIEW => 'View',
IN_REPLY_TO => 'In reply to',
PAGE_NOT_FOUND => 'Content not found',
STATUS_NOT_FOUND => 'Status not found',
ACCOUNT_NOT_FOUND => 'Account not found',
VIS_PUBLIC => 'Public',
VIS_UNLISTED => 'Unlisted',
VIS_PRIVATE => 'Private',
VIS_DIRECT => 'Direct',
VIS_LOCAL => 'Local',
VIS_LIST => 'List',
LOGIN => 'Login',
REGISTER => 'Register',
USERNAME => 'Username',
PASSWORD => 'Password',
LOGIN_BTN => 'Login',
LOGIN_HEADER => 'Login / Register',
LOGIN_FAIL => 'Couldn\'t login',
NOTIF_LIKED => 'liked your status',
NOTIF_REACTED_WITH => 'reacted with %s',
NOTIF_REPEATED => 'repeated your status',
NOTIF_FOLLOW => 'followed you',
NOTIF_FOLLOW_REQUEST => 'wants to follow you',
NOTIF_POLL => 'poll results',
NOTIF_COMPACT_LIKED => 'liked',
NOTIF_COMPACT_REACTED_WITH => 'reacted',
NOTIF_COMPACT_REPEATED => 'repeated',
NOTIF_COMPACT_FOLLOW => 'followed',
COMPACT_FOLLOW_REQUEST => 'wants to follow',
NOTIF_COMPACT_POLL => 'poll',
},
# TODO bring over Spanish and Chinese
);
return 1;

View file

@ -1,10 +1,31 @@
use strict;
use warnings;
# Modules
use Template;
use l10n;
my $template = Template->new(
{
INTERPOLATE => 1,
POST_CHOMP => 1,
EVAL_PERL => 1,
TRIM => 1
});
sub base_page
{
my ($ssn, $data) = @_;
my $result;
my $vars = {
# L10N => L10N,
prefix => '',
lang => sub { $l10n::L10N{'EN_US'}{shift(@_)} },
};
$template->process(\$data, $vars, \$result) ||
return $template->error();
2 * 2;
$result;
}
print "Hello from Perl\n";

View file

@ -33,14 +33,23 @@
// Files
#include "../static/index.ctmpl"
#include "../static/quick_login.ctmpl"
#include "../templates/main.ctt"
#define BODY_STYLE "style=\"background:url('%s');\""
void render_base_page(struct base_page* page, FCGX_Request* req, struct session* ssn, mastodont_t* api)
{
dSP;
ENTER;
SAVETMPS;
PUSHMARK(SP);
HV* session_hv = perlify_session(ssn);
XPUSHs(sv_2mortal(newRV_inc((SV*)session_hv)));
XPUSHs(sv_2mortal(newSVpv(data_main_tt, 0)));
struct mstdnt_args m_args;
set_mstdnt_args(&m_args, ssn);
char* cookie = GET_ENV("HTTP_COOKIE", req);
enum l10n_locale locale = l10n_normalize(ssn->config.lang);
char* theme_str = NULL;
const char* login_string = "<a href=\"login\" id=\"login-header\">Login / Register</a>";
@ -58,62 +67,62 @@ void render_base_page(struct base_page* page, FCGX_Request* req, struct session*
#define SIDEBAR_CSS_LEN 128
char sidebar_css[SIDEBAR_CSS_LEN];
if (keyint(ssn->cookies.logged_in))
login_string = "";
/* if (keyint(ssn->cookies.logged_in)) */
/* login_string = ""; */
if (ssn->config.background_url)
{
easprintf(&background_url_css, BODY_STYLE, ssn->config.background_url);
}
/* if (ssn->config.background_url) */
/* { */
/* easprintf(&background_url_css, BODY_STYLE, ssn->config.background_url); */
/* } */
// If user is logged in
if (keystr(ssn->cookies.logged_in) && keystr(ssn->cookies.access_token))
{
account_sidebar_str = construct_account_sidebar(&(ssn->acct), NULL);
/* // If user is logged in */
/* if (keystr(ssn->cookies.logged_in) && keystr(ssn->cookies.access_token)) */
/* { */
/* account_sidebar_str = construct_account_sidebar(&(ssn->acct), NULL); */
// Get / Show notifications on sidebar
if (ssn->config.notif_embed)
{
main_sidebar_str = (char*)sidebar_embed;
}
else {
struct mstdnt_get_notifications_args args = {
.exclude_types = 0,
.account_id = NULL,
.exclude_visibilities = 0,
.include_types = 0,
.with_muted = 1,
.max_id = NULL,
.min_id = NULL,
.since_id = NULL,
.offset = 0,
.limit = 8,
};
/* // Get / Show notifications on sidebar */
/* if (ssn->config.notif_embed) */
/* { */
/* main_sidebar_str = (char*)sidebar_embed; */
/* } */
/* else { */
/* struct mstdnt_get_notifications_args args = { */
/* .exclude_types = 0, */
/* .account_id = NULL, */
/* .exclude_visibilities = 0, */
/* .include_types = 0, */
/* .with_muted = 1, */
/* .max_id = NULL, */
/* .min_id = NULL, */
/* .since_id = NULL, */
/* .offset = 0, */
/* .limit = 8, */
/* }; */
if (mastodont_get_notifications(api,
&m_args,
&args,
&storage,
&notifs,
&notifs_len) == 0)
{
main_sidebar_str = construct_notifications_compact(ssn, api, notifs, notifs_len, NULL);
}
/* if (mastodont_get_notifications(api, */
/* &m_args, */
/* &args, */
/* &storage, */
/* &notifs, */
/* &notifs_len) == 0) */
/* { */
/* main_sidebar_str = construct_notifications_compact(ssn, api, notifs, notifs_len, NULL); */
/* } */
mstdnt_cleanup_notifications(notifs, notifs_len);
mastodont_storage_cleanup(&storage);
}
}
else {
// Construct small login page
struct quick_login_template tdata = {
.prefix = config_url_prefix,
.username = L10N[locale][L10N_USERNAME],
.password = L10N[locale][L10N_PASSWORD],
.login = L10N[locale][L10N_LOGIN_BTN],
};
main_sidebar_str = tmpl_gen_quick_login(&tdata, NULL);
}
/* mstdnt_cleanup_notifications(notifs, notifs_len); */
/* mastodont_storage_cleanup(&storage); */
/* } */
/* } */
/* else { */
/* // Construct small login page */
/* struct quick_login_template tdata = { */
/* .prefix = config_url_prefix, */
/* .username = L10N[locale][L10N_USERNAME], */
/* .password = L10N[locale][L10N_PASSWORD], */
/* .login = L10N[locale][L10N_LOGIN_BTN], */
/* }; */
/* main_sidebar_str = tmpl_gen_quick_login(&tdata, NULL); */
/* } */
// Combine into sidebar
easprintf(&sidebar_str, "%s%s",
@ -180,27 +189,37 @@ void render_base_page(struct base_page* page, FCGX_Request* req, struct session*
.source_link_str = "Source code",
};
size_t len;
char* data = tmpl_gen_index(&index_tmpl, &len);
// char* data = tmpl_gen_index(&index_tmpl, &len);
if (!data)
{
perror("malloc");
goto cleanup;
}
/* if (!data) */
/* { */
/* perror("malloc"); */
/* goto cleanup; */
/* } */
// Run function
PUTBACK;
call_pv("base_page", G_SCALAR);
SPAGAIN;
char* data = POPp;
send_result(req, NULL, "text/html", data, len);
send_result(req, NULL, "text/html", data, 0);
// Cleanup
/* cleanup_all: */
free(data);
// free(data);
cleanup:
free(sidebar_str);
if (main_sidebar_str != sidebar_embed) free(main_sidebar_str);
free(account_sidebar_str);
free(background_url_css);
free(instance_str);
free(theme_str);
/* free(sidebar_str); */
/* if (main_sidebar_str != sidebar_embed) free(main_sidebar_str); */
/* free(account_sidebar_str); */
/* free(background_url_css); */
/* free(instance_str); */
/* free(theme_str); */
PUTBACK;
FREETMPS;
LEAVE;
}
void send_result(FCGX_Request* req, char* status, char* content_type, char* data, size_t data_len)
@ -216,7 +235,7 @@ void send_result(FCGX_Request* req, char* status, char* content_type, char* data
"Content-Length: %d\r\n\r\n",
status ? status : "200 OK",
content_type ? content_type : "text/html",
data_len + 1);
data_len);
#ifdef SINGLE_THREADED
puts(data);
#else

View file

@ -18,13 +18,13 @@
#ifndef BASE_PAGE_H
#define BASE_PAGE_H
#include "session.h"
#include <fcgi_stdio.h>
#include <fcgiapp.h>
#include <mastodont.h>
#include "l10n.h"
#include "local_config.h"
#include "path.h"
#include "session.h"
enum base_category
{

View file

@ -47,10 +47,14 @@
#include "local_config_set.h"
#include "global_cache.h"
#include "conversations.h"
#include "../perl/main.cpl"
#define THREAD_COUNT 20
// Allow dynamic loading for Perl
static void xs_init (pTHX);
EXTERN_C void boot_DynaLoader (pTHX_ CV* cv);
/*******************
* Path handling *
******************/
@ -194,6 +198,12 @@ static void* cgi_start(void* arg)
return NULL;
}
EXTERN_C void xs_init(pTHX)
{
char *file = __FILE__;
newXS("DynaLoader::boot_DynaLoader", boot_DynaLoader, file);
}
int main(int argc, char **argv, char **env)
{
// Global init
@ -205,9 +215,9 @@ int main(int argc, char **argv, char **env)
perl = perl_alloc();
perl_construct(perl);
//char* perl_argv[] = { "", "-e", data_main_pl, NULL };
char* perl_argv[] = { "", "perl/main.pl", NULL };
char* perl_argv[] = { "", "-I", "perl/", "perl/main.pl", NULL };
perl_parse(perl, NULL, (sizeof(perl_argv) / sizeof(perl_argv[0])) - 1, perl_argv, (char**)NULL);
perl_parse(perl, xs_init, (sizeof(perl_argv) / sizeof(perl_argv[0])) - 1, perl_argv, (char**)NULL);
PL_exit_flags |= PERL_EXIT_DESTRUCT_END;
perl_run(perl);

5
templates/main.ctt Normal file

File diff suppressed because one or more lines are too long

87
templates/main.tt Normal file
View file

@ -0,0 +1,87 @@
<!DOCTYPE html>
<html {{ %s : background_url }}>
<head>
<meta charset="utf-8">
<title>{{ %s : title }}</title>
<link rel="icon" type="image/png" href="/favicon.png">
<link rel="stylesheet" type="text/css" href="/treebird.css">
{{ %s : theme_str }}
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="{{ %s : title }} is a decentralized social media platform">
<style>
{{ %s : sidebar_css }}
</style>
</head>
<body>
<div id="main-page">
<header id="navbar">
<label for="leftbar-show">
<svg class="leftbar-btn navbar-btn" xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="#000000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="3" y1="12" x2="21" y2="12"></line><line x1="3" y1="6" x2="21" y2="6"></line><line x1="3" y1="18" x2="21" y2="18"></line></svg>
</label>
<a href="{{ %s : prefix }}/"><img src="/treebird_logo.png" height="42"></a>
<span class="info">{{ %s : name }}</span>
<label for="rightbar-show">
<svg class="rightbar-btn navbar-btn" xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="#000000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M22 17H2a3 3 0 0 0 3-3V9a7 7 0 0 1 14 0v5a3 3 0 0 0 3 3zm-8.27 4a2 2 0 0 1-3.46 0"></path></svg>
</label>
<label for="searchbar-show">
<svg class="search-btn-show" xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="#000000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"></circle><line x1="21" y1="21" x2="16.65" y2="16.65"></line></svg>
</label>
<input type="checkbox" class="hidden" id="searchbar-show">
<div id="navbar-right-container">
<div id="navbar-right">
{{ %s : sidebar_cnt }}
<!-- Searchbox -->
<form action="{{ %s : prefix }}/search" method="get">
<input type="text" class="group group-left group-inputbox" placeholder="[% lang('SEARCH_PLACEHOLDER') %]" id="searchbox" name="q"><!-- i hate HTML
--><input type="submit" class="btn group group-right" value="[% lang('SEARCH_BUTTON') %]">
</form>
</div>
</div>
</header>
<input type="checkbox" id="leftbar-show" class="hidden">
<input type="checkbox" id="rightbar-show" class="hidden">
<table id="content" class="ui-table">
<!-- Navigation -->
<tr>
<td id="leftbar" class="sidebar">
<ul>
<li><a class="sidebarbtn {{ %s : active_home }}" href="$prefix/">[% lang('HOME') %]</a></li>
<li><a class="sidebarbtn {{ %s : active_local }}" href="$prefix/local/">[% lang('LOCAL') %]</a></li>
<li><a class="sidebarbtn {{ %s : active_federated }}" href="$prefix/federated/">[% lang('FEDERATED') %]</a></li>
<li><a class="sidebarbtn {{ %s : active_notifications }}" href="$prefix/notifications">[% lang('NOTIFICATIONS') %]</a></li>
<li><a class="sidebarbtn {{ %s : active_lists }}" href="$prefix/lists">[% lang('LISTS') %]</a></li>
<li><a class="sidebarbtn {{ %s : active_favourites }}" href="$prefix/favourites">[% lang('FAVOURITES') %]</a></li>
<li><a class="sidebarbtn {{ %s : active_bookmarks }}" href="$prefix/bookmarks">[% lang('BOOKMARKS') %]</a></li>
<li><a class="sidebarbtn {{ %s : active_direct }}" href="$prefix/direct">[% lang('DIRECT') %]</a></li>
<li><a class="sidebarbtn {{ %s : active_chats }}" href="$prefix/chats">Chats</a></li>
<li><a class="sidebarbtn {{ %s : active_config }}" href="$prefix/config">[% lang('CONFIG') %]</a></li>
</ul>
{{ %s : sidebar_leftbar }}
{{ %s : instance_panel }}
<div class="mini-links">
<a href="{{%s:prefix}}/about">{{ %s : about_link_str }}</a>
<span class="bullet-separate">&bull;</span>
<a href="{{%s:prefix}}/about/license">{{ %s : license_link_str }}</a>
<span class="bullet-separate">&bull;</span>
<a href="https://fossil.nekobit.net/treebird">{{ %s : source_link_str }}</a>
</div>
</td>
<!-- Display for posts -->
<td id="main">
{{ %s : main }}
</td>
<!-- Notifications and such -->
<td id="rightbar" class="sidebar">
{{ %s : sidebar_rightbar }}
</td>
</tr>
</table>
</div>
<!-- Source -->
<script src="/js/main.js"></script>
<script src="/js/emoji.js"></script>
</body>
</html>