summaryrefslogtreecommitdiffstats
path: root/README.adoc
blob: 645fe31414b00a372e57c53c065ccb38d0512a5d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
= mastodonpp
:toc: preamble
:project: mastodonpp
:uri-base: https://schlomp.space/tastytea/{project}
:uri-branch-main: {uri-base}/src/branch/main
:uri-mastodon-cpp: https://schlomp.space/tastytea/mastodon-cpp
:uri-reference: https://doc.schlomp.space/{project}/
:uri-gcc: https://gcc.gnu.org/
:uti-clang: https://clang.llvm.org/
:uri-cmake: https://cmake.org/
:uri-doxygen: http://www.doxygen.nl/
:uri-catch: https://github.com/catchorg/Catch2
:uri-dpkg: https://packages.qa.debian.org/dpkg
:uri-rpm-build: http://www.rpm.org
:uri-libcurl: https://curl.haxx.se/libcurl/

*{project}* is a C++ wrapper for the Mastodon and Pleroma APIs. It replaces
link:{uri-mastodon-cpp}[mastodon-cpp].

We aim to create a library that is comfortable, yet minimal. All API endpoints
from Mastodon and Pleroma are stored in ``enum class``es, to counteract typos and
make your life easier. The network-facing code is built on
link:{uri-libcurl}[libcurl], a mature and stable library that is available on
virtually every operating system. The library does not parse the responses
itself, but returns to you the raw data, because we know everyone has their
favorite JSON library and we don't want to impose our choice on you!

== Features

This is still a work in progress; here is a rough overview of the features:

* [x]  `GET`, Streaming `GET`, `POST`, `PATCH`, `PUT` and `DELETE` requests.
* [x] Report maximum allowed character per post.
* [ ] Comfortable access to pagination headers.
* [ ] Comfortable function to register a new “app” (get an access token).
* [ ] Report which mime types are allowed for posting statuses.

== Usage

Have a look at the link:{uri-reference}[reference].

=== Example

[source,cpp]
--------------------------------------------------------------------------------
#include "mastodonpp.hpp"
#include <iostream>

int main()
{
    mastodonpp::Instance instance{"example.com", "123AccessToken123"};
    instance.set_proxy("socks4a://[fd14::1:1]:9050");
    mastodonpp::Connection connection{instance};

    const mastodonpp::parametermap parameters
        {
            {"status", "How is the weather?"},
            {"poll[options]", vector<string_view>{"Nice", "not nice"}},
            {"poll[expires_in]", "86400"}
        };
    auto answer{connection.post(mastodonpp::API::v1::statuses, parameters)};

    if (answer)
    {
        std::cout << answer << std::endl;
    }
}
--------------------------------------------------------------------------------

link:{uri-reference}/examples.html[More examples] are included in the reference.

== Install

=== Gentoo

[source,shell]
--------------------------------------------------------------------------------
eselect repository enable tastytea
echo 'dev-cpp/mastodonpp' >> /etc/portage/package.accept_keywords/mastodonpp
emaint sync -r tastytea
emerge -a dev-cpp/mastodonpp
--------------------------------------------------------------------------------

=== Debian and Ubuntu

We automatically generate packages for Debian buster (10) and Ubuntu bionic
(18.04), but only for x86_64 (amd64). Download them at
link:{uri-base}/releases[schlomp.space].

[source,shell]
--------------------------------------------------------------------------------
apt install ./libmastodonpp*.deb
--------------------------------------------------------------------------------

=== CentOS

We automatically generate packages for CentOS 8, but only for x86_64
(amd64). Download them at link:{uri-base}/releases[schlomp.space].

[source,shell]
--------------------------------------------------------------------------------
yum install ./libmastodonpp*.rpm
--------------------------------------------------------------------------------

=== From source

==== Dependencies

* Tested OS: Linux
* C++ compiler (tested: link:{uri-gcc}[GCC] 7/8/9, link:{uri-lang}[clang] 6/7)
* link:{uri-cmake}[CMake] (at least: 3.9)
* link:{uri-libcurl}[libcurl] (at least: 7.56)
* Optional
  ** Documentation: link:{uri-doxygen}[Doxygen] (tested: 1.8)
  ** Tests: link:{uri-catch}[Catch] (tested: 2.5 / 1.2)
  ** DEB package: link:{uri-dpkg}[dpkg] (tested: 1.18)
  ** RPM package: link:{uri-rpm-build}[rpm-build] (tested: 4.11)

==== Get sourcecode

===== Release

Download the current release at link:{uri-base}/releases[schlomp.space].

===== Development version

[source,shell]
--------------------------------------------------------------------------------
git clone https://schlomp.space/tastytea/mastodonpp.git
--------------------------------------------------------------------------------

==== Compile

[source,shell]
--------------------------------------------------------------------------------
mkdir -p build && cd build
cmake ..
cmake --build . -- -j$(nproc --ignore=1)
--------------------------------------------------------------------------------

.CMake options:
* `-DCMAKE_BUILD_TYPE=Debug` for a debug build.
* `-DWITH_TESTS=YES` if you want to compile the tests.
* `-DWITH_EXAMPLES=YES` if you want to compile the examples.
* One of:
  ** `-DWITH_DEB=YES` if you want to be able to generate a deb-package.
  ** `-DWITH_RPM=YES` if you want to be able to generate an rpm-package.

include::{uri-base}/raw/branch/main/CONTRIBUTING.adoc[]
ass="nc">refinfo *r1 = *(struct refinfo **)a; struct refinfo *r2 = *(struct refinfo **)b; return strcmp(r1->refname, r2->refname); } static int cmp_branch_age(const void *a, const void *b) { struct refinfo *r1 = *(struct refinfo **)a; struct refinfo *r2 = *(struct refinfo **)b; return cmp_age(r1->commit->committer_date, r2->commit->committer_date); } static int get_ref_age(struct refinfo *ref) { if (!ref->object) return 0; switch (ref->object->type) { case OBJ_TAG: return ref->tag ? ref->tag->tagger_date : 0; case OBJ_COMMIT: return ref->commit ? ref->commit->committer_date : 0; } return 0; } static int cmp_tag_age(const void *a, const void *b) { struct refinfo *r1 = *(struct refinfo **)a; struct refinfo *r2 = *(struct refinfo **)b; return cmp_age(get_ref_age(r1), get_ref_age(r2)); } static int print_branch(struct refinfo *ref) { struct commitinfo *info = ref->commit; char *name = (char *)ref->refname; if (!info) return 1; html("<tr><td>"); cgit_log_link(name, NULL, NULL, name, NULL, NULL, 0, NULL, NULL, ctx.qry.showmsg, 0); html("</td><td>"); if (ref->object->type == OBJ_COMMIT) { cgit_commit_link(info->subject, NULL, NULL, name, NULL, NULL); html("</td><td>"); cgit_open_filter(ctx.repo->email_filter, info->author_email, "refs"); html_txt(info->author); cgit_close_filter(ctx.repo->email_filter); html("</td><td colspan='2'>"); cgit_print_age(info->commit->date, -1, NULL); } else { html("</td><td></td><td>"); cgit_object_link(ref->object); } html("</td></tr>\n"); return 0; } static void print_tag_header(void) { html("<tr class='nohover'><th class='left'>Tag</th>" "<th class='left'>Download</th>" "<th class='left'>Author</th>" "<th class='left' colspan='2'>Age</th></tr>\n"); } static void print_tag_downloads(const struct cgit_repo *repo, const char *ref) { const struct cgit_snapshot_format* f; struct strbuf filename = STRBUF_INIT; const char *basename; int free_ref = 0; if (!ref || strlen(ref) < 1) return; basename = cgit_repobasename(repo->url); if (!starts_with(ref, basename)) { if ((ref[0] == 'v' || ref[0] == 'V') && isdigit(ref[1])) ref++; if (isdigit(ref[0])) { ref = fmtalloc("%s-%s", basename, ref); free_ref = 1; } } for (f = cgit_snapshot_formats; f->suffix; f++) { if (!(repo->snapshots & f->bit)) continue; strbuf_reset(&filename); strbuf_addf(&filename, "%s%s", ref, f->suffix); cgit_snapshot_link(filename.buf, NULL, NULL, NULL, NULL, filename.buf); html("&nbsp;&nbsp;"); } if (free_ref) free((char *)ref); strbuf_release(&filename); } static int print_tag(struct refinfo *ref) { struct tag *tag = NULL; struct taginfo *info = NULL; char *name = (char *)ref->refname; struct object *obj = ref->object; if (obj->type == OBJ_TAG) { tag = (struct tag *)obj; obj = tag->tagged; info = ref->tag; if (!tag || !info) return 1; } html("<tr><td>"); cgit_tag_link(name, NULL, NULL, name); html("</td><td>"); if (ctx.repo->snapshots && (obj->type == OBJ_COMMIT)) print_tag_downloads(ctx.repo, name); else cgit_object_link(obj); html("</td><td>"); if (info) { if (info->tagger) { cgit_open_filter(ctx.repo->email_filter, info->tagger_email, "refs"); html_txt(info->tagger); cgit_close_filter(ctx.repo->email_filter); } } else if (ref->object->type == OBJ_COMMIT) { cgit_open_filter(ctx.repo->email_filter, ref->commit->author_email, "refs"); html_txt(ref->commit->author); cgit_close_filter(ctx.repo->email_filter); } html("</td><td colspan='2'>"); if (info) { if (info->tagger_date > 0) cgit_print_age(info->tagger_date, -1, NULL); } else if (ref->object->type == OBJ_COMMIT) { cgit_print_age(ref->commit->commit->date, -1, NULL); } html("</td></tr>\n"); return 0; } static void print_refs_link(char *path) { html("<tr class='nohover'><td colspan='5'>"); cgit_refs_link("[...]", NULL, NULL, ctx.qry.head, NULL, path); html("</td></tr>"); } void cgit_print_branches(int maxcount) { struct reflist list; int i; html("<tr class='nohover'><th class='left'>Branch</th>" "<th class='left'>Commit message</th>" "<th class='left'>Author</th>" "<th class='left' colspan='2'>Age</th></tr>\n"); list.refs = NULL; list.alloc = list.count = 0; for_each_branch_ref(cgit_refs_cb, &list); if (ctx.repo->enable_remote_branches) for_each_remote_ref(cgit_refs_cb, &list); if (maxcount == 0 || maxcount > list.count) maxcount = list.count; qsort(list.refs, list.count, sizeof(*list.refs), cmp_branch_age); if (ctx.repo->branch_sort == 0) qsort(list.refs, maxcount, sizeof(*list.refs), cmp_ref_name); for (i = 0; i < maxcount; i++) print_branch(list.refs[i]); if (maxcount < list.count) print_refs_link("heads"); cgit_free_reflist_inner(&list); } void cgit_print_tags(int maxcount) { struct reflist list; int i; list.refs = NULL; list.alloc = list.count = 0; for_each_tag_ref(cgit_refs_cb, &list); if (list.count == 0) return; qsort(list.refs, list.count, sizeof(*list.refs), cmp_tag_age); if (!maxcount) maxcount = list.count; else if (maxcount > list.count) maxcount = list.count; print_tag_header(); for (i = 0; i < maxcount; i++) print_tag(list.refs[i]); if (maxcount < list.count) print_refs_link("tags"); cgit_free_reflist_inner(&list); } void cgit_print_refs(void) { cgit_print_layout_start(); html("<table class='list nowrap'>"); if (ctx.qry.path && starts_with(ctx.qry.path, "heads")) cgit_print_branches(0); else if (ctx.qry.path && starts_with(ctx.qry.path, "tags")) cgit_print_tags(0); else { cgit_print_branches(0); html("<tr class='nohover'><td colspan='5'>&nbsp;</td></tr>"); cgit_print_tags(0); } html("</table>"); cgit_print_layout_end(); }