Giter VIP home page Giter VIP logo

tootik's Introduction

          ..    .        ..                                        ..
 ...            .       ....                     ...
 ...   .     .   .   .   ... ..      .  .     .  . ...                 ...
 ..    .  .    ..   .         .    .. .       .. ..     .                   .
 .,     .               . . . ..             .  ..                  .        .
 .                .     . .. .. .... .       .  .  .               ..  ..
            .              ..   ...  .       .    .   .   .        ..  .   .
 .   .        .   ..        .    ..             ...' .. .          .   .    . .
 . .              . .    .  __     .     .__  _ __ ,; .'. .  .     ....
    . .          .         / /____  ___  /./_(_) /__  .'  ..         . .  . .
  ..      ... .    .  .   /.__/ _ \/ _ \/ __/./  '_/.   .       .. .   .    .
  .'   ...  .             \__/\___/\___/\__/_/_/\_\              .  .  . .
      .         .    .    . .    .    ...     ... .           .      ..
 ..  .. .   . .... ..  .  .         ..   .  .     .          .  .  ... ....' .
   ...  .      .   .  .. .  ... ...      . ..   ..         .,..    .....
 .   ..   ......             . .''.  .  ..          .         . .  ...
 ' .      .. ..  ..     . . ... ......::.   ..       .,.       .  .. ....    ..
 . ....  . .....     .  .. .  . ... . .,'.   .        ..          ,..  ..
 . .    .  .  . ..   .  .   .. .  .     ..     ..  .  . .       . . .        .'
   .  ....   '...                ...    . .  ..  .     ...     . '.   '     ...

# localhost.localdomain:8443

Welcome, fedinaut! localhost.localdomain:8443 is an instance of tootik, a federated nanoblogging service.

────

📻 My radio
📞 Mentions
⚡️ Followed users
😈 My profile
📡 This planet
🔥 Hashtags
🔭 Find user
🔎 Search posts
📣 New post
⚙️ Settings
📊 Statistics
🛟 Help

Latest release Build status Go Reference

Overview

tootik is a federated nanoblogging service for the small internet. With tootik, you can interact with your friends, including those on Mastodon, Lemmy and other ActivityPub-compatible servers, from the comfort of a minimalistic, text-based interface in the small internet:

                         Gemini           ActivityPub (HTTPS)
                           →                     ⇄
 ┌───────────────────────┐   ┌─────────────────┐   ┌─────────────────────────┐
 │  Bob's Gemini client  ├─┬─┤ tootik instance ├─┬─┤ Another tootik instance │
 ├───────────────────────┤ │ ├─────────────────┤ │ └─────────────────────────┘
 │2024-01-01 alice       │ │ │$ ./tootik ...   │ │ ┌────────────────┐
 │> Hi @bob and @carol!  │ │ └─────────────────┘ ├─┤ Something else │
 │...                    │ │                     │ └────────────────┘
 └───────────────────────┘ │                     │ ┌───────────────────┐
               ┌───────────┴───────────┐         └─┤ Mastodon instance ├─┐
               │ Alice's Gemini client │           └───────────────────┘ │
               ├───────────────────────┤              ┌──────────────────┴────┐
               │2024-01-01 bob         │              │  Carol's web browser  │
               │> Hi @alice!           │              ├───────────────────────┤
               │...                    │              │╔═╗ alice              │
               └───────────────────────┘              │╚═╝             17h ago│
                                                      │Hi @bob and @carol!    │
                                                      │                       │
                                                      │  ╔═╗ bob              │
                                                      │  ╚═╝           16h ago│
                                                      │  Hi @alice!           │
                                                      ├───────────────────────┤
                                                      │┌────────────┐┏━━━━━━━┓│
                                                      ││ Hola       │┃Publish┃│
                                                      │└────────────┘┗━━━━━━━┛│
                                                      └───────────────────────┘

tootik is lightweight, private and accessible social network:

  • Its UI is served over Gemini, Gopher, Finger and Guppy: there's a wide variety of clients to choose from and some work great on old devices.
  • Rich content is reduced to plain text and links: it's a fast, low-bandwidth UI suitable for screen readers.
  • Anonymity: you authenticate using a TLS client certificate and don't have to share your email address or real name.
  • No promoted content, tracking or analytics: social networking, with the slow and non-commercial vibe of the small internet.
  • It's a single static executable, making it easy to set up your own instance instead of joining an existing one.
  • All instance data is stored in a single file, a sqlite database that is easy to backup and restore.
  • It's lightweight: a <=$5/mo VPS or a SBC is more than enough for a small instance.
  • It implements the subset of ActivityPub required for its feature set but not more, to stay small, reliable and maintainable.
  • It's written in two languages (Go and SQL), making the codebase suitable for educational purposes and easy to hack on.
  • It's permissively-licensed.

Features

Using tootik

You can join an existing instance or set up your own.

Building

go generate ./migrations

Then:

go build ./cmd/tootik -tags fts5

or, to build a static executable:

go build -tags netgo,sqlite_omit_load_extension,fts5 -ldflags "-linkmode external -extldflags -static" ./cmd/tootik

Architecture

┌───────┐ ┌────────┐ ┌─────────┐ ┌─────────┐
│ notes │ │ shares │ │ persons │ │ follows │
├───────┤ ├────────┤ ├─────────┤ ├─────────┤
│object │ │note    │ │actor    │ │follower │
│author │ │by      │ │...      │ │followed │
│...    │ │...     │ │         │ │...      │
└───────┘ └────────┘ └─────────┘ └─────────┘

Most user-visible data is stored in 4 tables in tootik's database:

  1. notes, which contains Object objects that represent posts
  2. shares, which records "user A shared post B" relationships
  3. persons, which contains Actor objects that represent users
  4. follows, which records "user A follows user B" relationships

notes.author, shares.by, follows.follower and follows.followed point to a row in persons.

shares.note points to a row in notes.

┌───────┐ ┌────────┐ ┌─────────┐ ┌─────────┐ ┏━━━━━━━━━┓ ┏━━━━━━━━━┓
│ notes │ │ shares │ │ persons │ │ follows │ ┃ outbox  ┃ ┃  inbox  ┃
├───────┤ ├────────┤ ├─────────┤ ├─────────┤ ┣━━━━━━━━━┫ ┣━━━━━━━━━┫
│object │ │note    │ │actor    │ │follower │ ┃activity ┃ ┃activity ┃
│author │ │by      │ │...      │ │followed │ ┃sender   ┃ ┃sender   ┃
│...    │ │...     │ │         │ │...      │ ┃...      ┃ ┃...      ┃
└───────┘ └────────┘ └─────────┘ └─────────┘ ┗━━━━━━━━━┛ ┗━━━━━━━━━┛

Federation happens through two tables, inbox and outbox. Both contain Activity objects that represent actions performed by the users in persons.

inbox contains activities by users on other servers, while outbox contains activities of local users.

                    ┏━━━━━━━━━━━━━━━━━┓
                    ┃ gemini.Listener ┃
                    ┗━━━━━━━━┳━━━━━━━━┛
                    ┏━━━━━━━━┻━━━━━━━━┓
                    ┃  front.Handler  ┃
                    ┗━━━━━┳━━━━━━━━━━━┛
┌───────┐ ┌────────┐ ┌────┸────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐
│ notes │ │ shares │ │ persons │ │ follows │ │ outbox  │ │  inbox  │
├───────┤ ├────────┤ ├─────────┤ ├─────────┤ ├─────────┤ ├─────────┤
│object │ │note    │ │actor    │ │follower │ │activity │ │activity │
│author │ │by      │ │...      │ │followed │ │sender   │ │sender   │
│...    │ │...     │ │         │ │...      │ │...      │ │...      │
└───────┘ └────────┘ └────┰────┘ └─────────┘ └─────────┘ └─────────┘
                  ┏━━━━━━━┻━━━━━━┓
                  ┃ fed.Resolver ┃
                  ┗━━━━━━━━━━━━━━┛

gemini.Listener is a Gemini server that handles requests through Handler. It adds rows to persons during new user registration and changes rows when users change properties like their display name.

Resolver is responsible for fetching Actors that represents users of other servers. The fetched objects are cached in persons.

                ┌─────────────────┐
                │ gemini.Listener │
                └────────┬────────┘
                ┌────────┴─────────┐
    ┏━━━━━━━━━━━┥  front.Handler   │
    ┃           └┰────────┬───────┰┘
┌───┸───┐ ┌──────┸─┐ ┌────┴────┐ ┌┸────────┐ ┌─────────┐ ┌─────────┐
│ notes │ │ shares │ │ persons │ │ follows │ │ outbox  │ │  inbox  │
├───────┤ ├────────┤ ├─────────┤ ├─────────┤ ├─────────┤ ├─────────┤
│object │ │note    │ │actor    │ │follower │ │activity │ │activity │
│author │ │by      │ │...      │ │followed │ │sender   │ │sender   │
│...    │ │...     │ │         │ │...      │ │...      │ │...      │
└───────┘ └────────┘ └────┬────┘ └─────────┘ └─────────┘ └─────────┘
                  ┌───────┴──────┐
                  │ fed.Resolver │
                  └──────────────┘

In addition, Gemini requests can:

  • Add rows to notes (new post)
  • Change rows in notes (post editing)
  • Add rows to shares (user shares a post)
  • Remove rows from shares (user no longer shares a post)
  • Add rows to follows (user A followed user B)
  • Remove rows from follows (user A unfollowed user B)
  • ...
                ┌─────────────────┐
                │ gemini.Listener │
                └────────┬────────┘
                ┌────────┴─────────┐
    ┌───────────┤  front.Handler   ┝━━━━━━━━━━━┓
    │           └┬────────┬───────┬┘           ┃
┌───┴───┐ ┌──────┴─┐ ┌────┴────┐ ┌┴────────┐ ┌─┸───────┐ ┌─────────┐
│ notes │ │ shares │ │ persons │ │ follows │ │ outbox  │ │  inbox  │
├───────┤ ├────────┤ ├─────────┤ ├─────────┤ ├─────────┤ ├─────────┤
│object │ │note    │ │actor    │ │follower │ │activity │ │activity │
│author │ │by      │ │...      │ │followed │ │sender   │ │sender   │
│...    │ │...     │ │         │ │...      │ │...      │ │...      │
└───────┘ └────────┘ └────┬────┘ └───────┰─┘ └┰────────┘ └─────────┘
                  ┌───────┴──────┐      ┏┻━━━━┻━━━━━┓
                  │ fed.Resolver │      ┃ fed.Queue ┃
                  └──────────────┘      ┗━━━━━━━━━━━┛

Each user action (post creation, post deletion, ...) is recorded as an Activity object written to outbox.

fed.Queue is responsible for sending activities to followers from other servers, if needed.

                                      ┏━━━━━━━━━━━━━━━┓
                ┌─────────────────┐   ┃ outbox.Mover  ┃
                │ gemini.Listener │   ┃ outbox.Poller ┃
                └────────┬────────┘   ┃ fed.Syncer    ┃
                ┌────────┴─────────┐  ┗━━━┳━━━━━┳━━━━━┛
    ┌───────────┤  front.Handler   ├──────╂────┐┃
    │           └┬────────┬───────┬┘      ┃    │┃
┌───┴───┐ ┌──────┴─┐ ┌────┴────┐ ┌┴───────┸┐ ┌─┴┸──────┐ ┌─────────┐
│ notes │ │ shares │ │ persons │ │ follows │ │ outbox  │ │  inbox  │
├───────┤ ├────────┤ ├─────────┤ ├─────────┤ ├─────────┤ ├─────────┤
│object │ │note    │ │actor    │ │follower │ │activity │ │activity │
│author │ │by      │ │...      │ │followed │ │sender   │ │sender   │
│...    │ │...     │ │         │ │...      │ │...      │ │...      │
└───────┘ └────────┘ └────┬────┘ └───────┬─┘ └┬────────┘ └─────────┘
                  ┌───────┴──────┐      ┌┴────┴─────┐
                  │ fed.Resolver │      │ fed.Queue │
                  └──────────────┘      └───────────┘

tootik may perform automatic actions in the name of the user:

  1. Follow the new account and unfollow the old one, if a followed user moved their account
  2. Update poll results for polls published by the user, and send the new results to followers
  3. Handle disagreement between follows rows for this user and what other servers know
                                      ┌───────────────┐
                ┌─────────────────┐   │ outbox.Mover  │
                │ gemini.Listener │   │ outbox.Poller │
                └────────┬────────┘   │ fed.Syncer    │
                ┌────────┴─────────┐  └───┬─────┬─────┘ ┏━━━━━━━━━━━━━━┓
    ┌───────────┤  front.Handler   ├──────┼────┐│    ┏━━┫ fed.Listener ┣━━┓
    │           └┬────────┬───────┬┘      │    ││    ┃  ┗━━━━━┳━━━━━━━━┛  ┃
┌───┴───┐ ┌──────┴─┐ ┌────┴────┐ ┌┴───────┴┐ ┌─┴┴────┸─┐ ┌────┸────┐      ┃
│ notes │ │ shares │ │ persons │ │ follows │ │ outbox  │ │  inbox  │      ┃
├───────┤ ├────────┤ ├─────────┤ ├─────────┤ ├─────────┤ ├─────────┤      ┃
│object │ │note    │ │actor    │ │follower │ │activity │ │activity │      ┃
│author │ │by      │ │...      │ │followed │ │sender   │ │sender   │      ┃
│...    │ │...     │ │         │ │...      │ │...      │ │...      │      ┃
└───────┘ └────────┘ └────┬────┘ └───────┬─┘ └┬────────┘ └─────────┘      ┃
                  ┌───────┴──────┐      ┌┴────┴─────┐                     ┃
                  │ fed.Resolver │      │ fed.Queue │                     ┃
                  └───────┰──────┘      └───────────┘                     ┃
                          ┃                                               ┃
                          ┃                                               ┃
                          ┃                                               ┃
                          ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛

Requests from other servers are handled by fed.Listener, a HTTP server.

It extracts the signature and key ID from a request using httpsig.Extract, uses Resolver to fetch the public key if needed, validates the request using Verify and inserts the received Activity object into inbox.

In addition, fed.Listener allows other servers to fetch public activity (like public posts) from outbox, so they can fetch some past activity by a newly-followed user.

                                      ┌───────────────┐
                ┌─────────────────┐   │ outbox.Mover  │
                │ gemini.Listener │   │ outbox.Poller │
                └────────┬────────┘   │ fed.Syncer    │
                ┌────────┴─────────┐  └───┬─────┬─────┘ ┌──────────────┐
    ┌───────────┤  front.Handler   ├──────┼────┐│    ┌──┤ fed.Listener ├──┐
    │           └┬────────┬───────┬┘      │    ││    │  └─────┬────────┘  │
┌───┴───┐ ┌──────┴─┐ ┌────┴────┐ ┌┴───────┴┐ ┌─┴┴────┴─┐ ┌────┴────┐      │
│ notes │ │ shares │ │ persons │ │ follows │ │ outbox  │ │  inbox  │      │
├───────┤ ├────────┤ ├─────────┤ ├─────────┤ ├─────────┤ ├─────────┤      │
│object │ │note    │ │actor    │ │follower │ │activity │ │activity │      │
│author │ │by      │ │...      │ │followed │ │sender   │ │sender   │      │
│...    │ │...     │ │         │ │...      │ │...      │ │...      │      │
└───┰───┘ └───┰────┘ └────┬────┘ └────┰──┬─┘ └┬────────┘ └──────┰──┘      │
    ┃         ┃   ┌───────┴──────┐    ┃ ┌┴────┴─────┐     ┏━━━━━┻━━━━━━━┓ │
    ┃         ┃   │ fed.Resolver │    ┃ │ fed.Queue │     ┃ inbox.Queue ┃ │
    ┃         ┃   └───────┬──────┘    ┃ └───────────┘     ┗━┳━┳━┳━━━━━━━┛ │
    ┃         ┃           │           ┗━━━━━━━━━━━━━━━━━━━━━┛ ┃ ┃         │
    ┃         ┗━━━━━━━━━━━┿━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃         │
    ┗━━━━━━━━━━━━━━━━━━━━━┿━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛         │
                          └───────────────────────────────────────────────┘

Once inserted into inbox, inbox.Queue processes the received activities:

  • Adds new posts received in Create activities to notes
  • Edits post in notes according to Update activities
  • Records Announce activities in shares
  • Marks a follower-followed relationship in follows as accepted, when the followed user sends an Accept activity
  • Adds a new row to follows when a remote user sends a Follow activity to a local user
  • ...
                                      ┌───────────────┐
                ┌─────────────────┐   │ outbox.Mover  │
                │ gemini.Listener │   │ outbox.Poller │
                └────────┬────────┘   │ fed.Syncer    │
                ┌────────┴─────────┐  └───┬─────┬─────┘ ┌──────────────┐
    ┌───────────┤  front.Handler   ├──────┼────┐│    ┌──┤ fed.Listener ├──┐
    │           └┬────────┬───────┬┘      │    ││    │  └─────┬────────┘  │
┌───┴───┐ ┌──────┴─┐ ┌────┴────┐ ┌┴───────┴┐ ┌─┴┴────┴─┐ ┌────┴────┐      │
│ notes │ │ shares │ │ persons │ │ follows │ │ outbox  │ │  inbox  │      │
├───────┤ ├────────┤ ├─────────┤ ├─────────┤ ├─────────┤ ├─────────┤      │
│object │ │note    │ │actor    │ │follower │ │activity │ │activity │      │
│author │ │by      │ │...      │ │followed │ │sender   │ │sender   │      │
│...    │ │...     │ │         │ │...      │ │...      │ │...      │      │
└───┬───┘ └───┬────┘ └────┬────┘ └────┬──┬─┘ └┬───────┰┘ └──────┬──┘      │
    │         │   ┌───────┴──────┐    │ ┌┴────┴─────┐ ┃   ┌─────┴───────┐ │
    │         │   │ fed.Resolver │    │ │ fed.Queue │ ┗━━━┥ inbox.Queue │ │
    │         │   └───────┬──────┘    │ └───────────┘     └─┬─┬─┬───────┘ │
    │         │           │           └─────────────────────┘ │ │         │
    │         └───────────┼───────────────────────────────────┘ │         │
    └─────────────────────┼─────────────────────────────────────┘         │
                          └───────────────────────────────────────────────┘

When a remote user replies in a thread started by a local user, the received Activity is inserted into outbox and forwarded to all followers of the local user.

                                      ┌───────────────┐
                ┌─────────────────┐   │ outbox.Mover  │
                │ gemini.Listener │   │ outbox.Poller │
                └────────┬────────┘   │ fed.Syncer    │
                ┌────────┴─────────┐  └───┬─────┬─────┘ ┌──────────────┐
    ┌───────────┤  front.Handler   ├──────┼────┐│    ┌──┤ fed.Listener ├──┐
    │           └┬────────┬───────┬┘      │    ││    │  └─────┬────────┘  │
┌───┴───┐ ┌──────┴─┐ ┌────┴────┐ ┌┴───────┴┐ ┌─┴┴────┴─┐ ┌────┴────┐      │
│ notes │ │ shares │ │ persons │ │ follows │ │ outbox  │ │  inbox  │      │
├───────┤ ├────────┤ ├─────────┤ ├─────────┤ ├─────────┤ ├─────────┤      │
│object │ │note    │ │actor    │ │follower │ │activity │ │activity │      │
│author │ │by      │ │...      │ │followed │ │sender   │ │sender   │      │
│...    │ │...     │ │         │ │...      │ │...      │ │...      │      │
└───┬───┘ └───┬────┘ └────┬────┘ └────┬──┬─┘ └┬───────┬┘ └──────┬──┘      │
    │         │   ┌───────┴──────┐    │ ┌┴────┴─────┐ │   ┌─────┴───────┐ │
    │         │   │ fed.Resolver │    │ │ fed.Queue │ └───┤ inbox.Queue │ │
    │         │   └───────┬─┰────┘    │ └───────────┘     └─┬─┬─┬─┰─────┘ │
    │         │           │ ┃         └─────────────────────┘ │ │ ┃       │
    │         └───────────┼─╂─────────────────────────────────┘ │ ┃       │
    └─────────────────────┼─╂───────────────────────────────────┘ ┃       │
                          └─╂─────────────────────────────────────╂───────┘
                            ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛

To display details like the user's name and speed up the verification of future incoming replies, inbox.Queue uses Resolver to fetch the Actor objects of mentioned users (if needed).

More Documentation

Credits and Legal Information

tootik is free and unencumbered software released under the terms of the Apache License Version 2.0; see LICENSE for the license text.

The ASCII art logo at the top was made using FIGlet.

tootik's People

Contributors

dependabot[bot] avatar dimkr avatar snan avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

Forkers

renowncoder snan

tootik's Issues

Fetched posts displaying out of order

I would expect posts to display in reverse chronological order (newest at the top) and for the most part this is what happens, but not always. Quite often posts get shuffled around, and replies can even appear underneath the posts they're replying to. I don't think this is even a matter of server timezones, because I've seen this happen to my own replies to my own posts.

See my local page for examples -- gemini://toot.locrian.zone/users/local.

I'm happy to provide stuff from my sqlite database or logs if you need it, but please let me know what specifically to look for.

And I don't know if I said this before, but thank you for writing this wonderful piece of software. It fills a hole in my life I didn't know was there.

Run alongside another HTTPS server?

Hi, I have set up tootik on my home server. However, there already is an NGINX running on port 443. I have tried to set up tootik with -addr 8443.

curl -v https://schettler.net:8443 returns plausible communication with a "location: gemini://schettler.net" in the end. However, Firefox complains that the connection is not encrypted. Maybe I have messed up the Letsencrypt certificates?

I can access the Gemini interface and follow some people. However, I never receive any posts by them. I am not sure if the two problems are related.

What would be a recommended setup to run tootik alongside an existing HTTPS server?

idn usernames

do you think you'd like to support unicode usernames?

mastodon and socialhome do not allow to register unicode usernames. but i looked in the activity pub spec and didn't find there a limitation. i think unicode usernames are permitted by the spec.

the other question would be - if mastodon would receive updates from such a user.

Listener has failed, address already in use

Following the quick setup guide, I got as far as running tootik, but I ran into this snag:

{"time":"2023-12-18T02:16:45.351946743Z","level":"INFO","msg":"Collecting garbage"}
{"time":"2023-12-18T02:16:45.352876769Z","level":"INFO","msg":"Starting HTTPS server"}
{"time":"2023-12-18T02:16:45.353559439Z","level":"ERROR","msg":"Gemini listener has failed","error":"listen tcp :1965: bind: address already in use"}
{"time":"2023-12-18T02:16:45.353788972Z","level":"INFO","msg":"Updating poll results"}
{"time":"2023-12-18T02:16:45.355657219Z","level":"ERROR","msg":"Failed to update poll results","error":"context canceled"}
{"time":"2023-12-18T02:16:45.355193575Z","level":"ERROR","msg":"HTTPS listener has failed","error":"listen tcp :443: bind: address already in use"}
{"time":"2023-12-18T02:16:45.355990915Z","level":"WARN","msg":"Failed to accept a connection","error":"accept tcp [::]:79: use of closed network connection"}
{"time":"2023-12-18T02:16:45.356152332Z","level":"WARN","msg":"Failed to accept a connection","error":"accept tcp [::]:70: use of closed network connection"}
{"time":"2023-12-18T02:16:45.356332647Z","level":"ERROR","msg":"Failed to receive a packet","error":"read udp [::]:6775: use of closed network connection"}
{"time":"2023-12-18T02:16:45.356433595Z","level":"INFO","msg":"Shutting down"}
{"time":"2023-12-18T02:16:45.356627584Z","level":"ERROR","msg":"Failed to collect garbage","error":"failed to remove posts by authors without followers: context canceled"}

I do already have ports 443 and 1965 in use by Apache and Agate respectively. I tried using different ports to see what would happen and tootik seemed to run just fine, but when visiting the domain in Gemini I get a TLS/SSL handshake error, and when running curl to test the HTTPS server (or just visiting the address) it directs me to my already-existing website???

Help, what do.

Can about-mes be added?

Just a little spot to write a blurb about yourself that can show up above your posts (and in the Profile section when viewed on Mastodon et al). Doesn't have to be fancy.

Cannot start Tootik as systemctl service

All right, I'm coming back to report this problem like a good user.

I've filled out /etc/systemd/system/tootik.service as described in the quick setup guide:

[Unit]
Description=tootik
After=network.target

[Service]
ExecStart=tootik -domain toot.locrian.zone -addr :443 -gemaddr :1965 -gopherad>
User=tootik
Group=tootik
AmbientCapabilities=CAP_NET_BIND_SERVICE
NoNewPrivileges=true
Restart=always

[Install]
WantedBy=multi-user.target

Then ran systemctl daemon-reload and systemctl enable tootik.

At this point, running systemctl status tootik gives this output:

○ tootik.service - tootik
     Loaded: loaded (/etc/systemd/system/tootik.service; enabled; vendor preset: enabled)
     Active: inactive (dead)

I run systemctl start tootik, but toot.locrian.zone is not accessible over Gemini or HTTPS. Now when I run systemctl status tootik I get this:

× tootik.service - tootik
     Loaded: loaded (/etc/systemd/system/tootik.service; enabled; vendor preset: enabled)
     Active: failed (Result: exit-code) since Tue 2023-12-19 14:03:10 UTC; 2min 8s ago
   Main PID: 9985 (code=exited, status=2)
        CPU: 9ms

Dec 19 14:03:10 ubuntu-s-1vcpu-512mb-10gb-fra1-01 systemd[1]: tootik.service: Main process exited, code=exited, status=2/INVALIDARGUMENT
Dec 19 14:03:10 ubuntu-s-1vcpu-512mb-10gb-fra1-01 systemd[1]: tootik.service: Failed with result 'exit-code'.
Dec 19 14:03:10 ubuntu-s-1vcpu-512mb-10gb-fra1-01 systemd[1]: tootik.service: Scheduled restart job, restart counter is at 5.
Dec 19 14:03:10 ubuntu-s-1vcpu-512mb-10gb-fra1-01 systemd[1]: Stopped tootik.
Dec 19 14:03:10 ubuntu-s-1vcpu-512mb-10gb-fra1-01 systemd[1]: tootik.service: Start request repeated too quickly.
Dec 19 14:03:10 ubuntu-s-1vcpu-512mb-10gb-fra1-01 systemd[1]: tootik.service: Failed with result 'exit-code'.
Dec 19 14:03:10 ubuntu-s-1vcpu-512mb-10gb-fra1-01 systemd[1]: Failed to start tootik.

journalctl -u tootik -S 'today' gives me this:

Dec 19 14:03:09 ubuntu-s-1vcpu-512mb-10gb-fra1-01 systemd[1]: Started tootik.
Dec 19 14:03:09 ubuntu-s-1vcpu-512mb-10gb-fra1-01 tootik[9957]: panic: failed to remove invisible posts: attempt to write a readonly database
Dec 19 14:03:09 ubuntu-s-1vcpu-512mb-10gb-fra1-01 tootik[9957]: goroutine 1 [running]:
Dec 19 14:03:09 ubuntu-s-1vcpu-512mb-10gb-fra1-01 tootik[9957]: main.main()
Dec 19 14:03:09 ubuntu-s-1vcpu-512mb-10gb-fra1-01 tootik[9957]:         /home/runner/work/tootik/tootik/cmd/tootik/main.go:126 +0xf8e
Dec 19 14:03:09 ubuntu-s-1vcpu-512mb-10gb-fra1-01 systemd[1]: tootik.service: Main process exited, code=exited, status=2/INVALIDARGUMENT
Dec 19 14:03:09 ubuntu-s-1vcpu-512mb-10gb-fra1-01 systemd[1]: tootik.service: Failed with result 'exit-code'.
Dec 19 14:03:09 ubuntu-s-1vcpu-512mb-10gb-fra1-01 systemd[1]: tootik.service: Scheduled restart job, restart counter is at 1.
Dec 19 14:03:09 ubuntu-s-1vcpu-512mb-10gb-fra1-01 systemd[1]: Stopped tootik.
Dec 19 14:03:09 ubuntu-s-1vcpu-512mb-10gb-fra1-01 systemd[1]: Started tootik.
Dec 19 14:03:09 ubuntu-s-1vcpu-512mb-10gb-fra1-01 tootik[9964]: panic: failed to remove invisible posts: attempt to write a readonly database
Dec 19 14:03:09 ubuntu-s-1vcpu-512mb-10gb-fra1-01 tootik[9964]: goroutine 1 [running]:
Dec 19 14:03:09 ubuntu-s-1vcpu-512mb-10gb-fra1-01 tootik[9964]: main.main()
Dec 19 14:03:09 ubuntu-s-1vcpu-512mb-10gb-fra1-01 tootik[9964]:         /home/runner/work/tootik/tootik/cmd/tootik/main.go:126 +0xf8e
Dec 19 14:03:09 ubuntu-s-1vcpu-512mb-10gb-fra1-01 systemd[1]: tootik.service: Main process exited, code=exited, status=2/INVALIDARGUMENT
Dec 19 14:03:09 ubuntu-s-1vcpu-512mb-10gb-fra1-01 systemd[1]: tootik.service: Failed with result 'exit-code'.
Dec 19 14:03:09 ubuntu-s-1vcpu-512mb-10gb-fra1-01 systemd[1]: tootik.service: Scheduled restart job, restart counter is at 2.
Dec 19 14:03:09 ubuntu-s-1vcpu-512mb-10gb-fra1-01 systemd[1]: Stopped tootik.
Dec 19 14:03:09 ubuntu-s-1vcpu-512mb-10gb-fra1-01 systemd[1]: Started tootik.
Dec 19 14:03:09 ubuntu-s-1vcpu-512mb-10gb-fra1-01 tootik[9971]: panic: failed to remove invisible posts: attempt to write a readonly database
Dec 19 14:03:09 ubuntu-s-1vcpu-512mb-10gb-fra1-01 tootik[9971]: goroutine 1 [running]:
Dec 19 14:03:09 ubuntu-s-1vcpu-512mb-10gb-fra1-01 tootik[9971]: main.main()
Dec 19 14:03:09 ubuntu-s-1vcpu-512mb-10gb-fra1-01 tootik[9971]:         /home/runner/work/tootik/tootik/cmd/tootik/main.go:126 +0xf8e
Dec 19 14:03:09 ubuntu-s-1vcpu-512mb-10gb-fra1-01 systemd[1]: tootik.service: Main process exited, code=exited, status=2/INVALIDARGUMENT
Dec 19 14:03:09 ubuntu-s-1vcpu-512mb-10gb-fra1-01 systemd[1]: tootik.service: Failed with result 'exit-code'.
Dec 19 14:03:10 ubuntu-s-1vcpu-512mb-10gb-fra1-01 systemd[1]: tootik.service: Scheduled restart job, restart counter is at 3.
Dec 19 14:03:10 ubuntu-s-1vcpu-512mb-10gb-fra1-01 systemd[1]: Stopped tootik.
Dec 19 14:03:10 ubuntu-s-1vcpu-512mb-10gb-fra1-01 systemd[1]: Started tootik.
Dec 19 14:03:10 ubuntu-s-1vcpu-512mb-10gb-fra1-01 tootik[9978]: panic: failed to remove invisible posts: attempt to write a readonly database
Dec 19 14:03:10 ubuntu-s-1vcpu-512mb-10gb-fra1-01 tootik[9978]: goroutine 1 [running]:
Dec 19 14:03:10 ubuntu-s-1vcpu-512mb-10gb-fra1-01 tootik[9978]: main.main()
Dec 19 14:03:10 ubuntu-s-1vcpu-512mb-10gb-fra1-01 tootik[9978]:         /home/runner/work/tootik/tootik/cmd/tootik/main.go:126 +0xf8e
Dec 19 14:03:10 ubuntu-s-1vcpu-512mb-10gb-fra1-01 systemd[1]: tootik.service: Main process exited, code=exited, status=2/INVALIDARGUMENT
Dec 19 14:03:10 ubuntu-s-1vcpu-512mb-10gb-fra1-01 systemd[1]: tootik.service: Failed with result 'exit-code'.
Dec 19 14:03:10 ubuntu-s-1vcpu-512mb-10gb-fra1-01 systemd[1]: tootik.service: Scheduled restart job, restart counter is at 4.
Dec 19 14:03:10 ubuntu-s-1vcpu-512mb-10gb-fra1-01 systemd[1]: Stopped tootik.
Dec 19 14:03:10 ubuntu-s-1vcpu-512mb-10gb-fra1-01 systemd[1]: Started tootik.
Dec 19 14:03:10 ubuntu-s-1vcpu-512mb-10gb-fra1-01 tootik[9985]: panic: failed to remove invisible posts: attempt to write a readonly database
Dec 19 14:03:10 ubuntu-s-1vcpu-512mb-10gb-fra1-01 tootik[9985]: goroutine 1 [running]:

Panic when running without a blocklist

Hi, on Tootik 0.9.2, i am seeing a panic on incoming activities when running without -blocklist:

panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x5620b3f2a8b4]

goroutine 75 [running]:
github.com/dimkr/tootik/fed.(*BlockList).Contains(0x0, {0xc000198998?, 0xc0001e33a8?})
	github.com/dimkr/tootik/fed/blocklist.go:140 +0x54
github.com/dimkr/tootik/inbox.(*Queue).processCreateActivity(0xc000078fc0, {0x5620b42607e0, 0xc0001da150}, 0xc000184dd0, 0xc00019c680, 0xc0001f22d0, {0xc0001fe000, 0x427, 0x427}, 0xc0002ae000)
	github.com/dimkr/tootik/inbox/queue.go:116 +0x2fa
github.com/dimkr/tootik/inbox.(*Queue).processActivity(0xc000078fc0, {0x5620b42607e0, 0xc0001da150}, 0xc000184dd0, 0xc00019c680, 0xc0001f22d0, {0xc0001fe000, 0x427, 0x427})
	github.com/dimkr/tootik/inbox/queue.go:322 +0x1025
github.com/dimkr/tootik/inbox.(*Queue).processActivityWithTimeout(0xc000078fc0, {0x5620b4260770?, 0xc00007acd0?}, 0xc00019c680, 0xc0001f22d0, {0xc0001fe000, 0x427, 0x427})
	github.com/dimkr/tootik/inbox/queue.go:469 +0x1ae
github.com/dimkr/tootik/inbox.(*Queue).ProcessBatch.func1({0xc0001fe000, 0x427}, 0xc00019c680)
	github.com/dimkr/tootik/inbox/queue.go:521 +0x1df
github.com/dimkr/tootik/data.OrderedMap[...].Range(0x5620b42634e0, 0xc0001e3d20)
	github.com/dimkr/tootik/data/map.go:57 +0x17f
github.com/dimkr/tootik/inbox.(*Queue).ProcessBatch(0xc000078fc0, {0x5620b4260770, 0xc00007acd0})
	github.com/dimkr/tootik/inbox/queue.go:514 +0x605
github.com/dimkr/tootik/inbox.(*Queue).process(0xc000078fc0, {0x5620b4260770, 0xc00007acd0})
	github.com/dimkr/tootik/inbox/queue.go:537 +0xa8
github.com/dimkr/tootik/inbox.(*Queue).Process(0xc000078fc0, {0x5620b4260770, 0xc00007acd0})
	github.com/dimkr/tootik/inbox/queue.go:566 +0x105
main.main.func4()
	github.com/dimkr/tootik/cmd/tootik/main.go:297 +0x63
created by main.main in goroutine 1
	github.com/dimkr/tootik/cmd/tootik/main.go:296 +0x1a3a

I think maybe a nil check is needed in queue.go:116.

finding tootik posts

Hi!

I wanted to reply to this post gemini://hd.206267.xyz/view/77572017c3e3303677a7a1430179c23a452d25c91dc5b11b5ce602f531a0e229 from my Akkoma instance but I didn't know what to search for in there.

wget --header 'Accept: application/ld+json; profile="https://www.w3.org/ns/activitystreams"' -qO- "htt ps://hd.206267.xyz/user/dimkr"|jq|less

That worked fine, but the outbox address doesn't seem to work:

wget --header 'Accept: application/ld+json; profile="https://www.w3.org/ns/activitystreams"' -qO- https://hd.206267.xyz/outbox/dimkr|less

Nor can I do this:

wget --header 'Accept: application/ld+json; profile="https://www.w3.org/ns/activitystreams"' -qO- https://hd.206267.xyz/view/77572017c3e3303677a7a1430179c23a452d25c91dc5b11b5ce602f531a0e229
I tried grepping through Tootik's golang source code for hints, too.
Tootik is such a good idea. Thank you for starting this project.

Aggressive rate-limiting

So with everything else going on, I didn't think to mention this, but it is a bit annoying.

If I post from Tootik, even just one time, I can't post again for at least a minute; there's an error page that says "Please wait before posting again". This makes posting threads a bit annoying, especially since the character limit on Tootik seems to be fairly small. Is this intended behavior?

(On that note, account creation was disabled for an hour when I first launched the service, but I was willing to accept that as a one-time hurdle. Was that intended?)

MaxUint32 overflows int on 32-bit platforms

Hi, while building Tootik 0.9.5 for 32-bit platforms (x86 and ARM), i am seeing this error:
cfg/cfg.go:265:51: math.MaxUint32 (untyped int constant 4294967295) overflows int.

unicode domains are not handled

hello,

i was trying to follow user inky from xn--y9azesw6bu.xn--y9a3aq and i get 'failed to resolve, the request has failed, but may succeed if you try again in the future'

same happens if i use unicode representation, not punicode one.

render punycode domain names as unicode

can you render punycode domain names as unicode?

let's say here gemini://hd.206267.xyz/outbox/688041bb1d1eeccf2fd4705b5859a1a6557a6f313713240dfda5630f70a6fde3

or maybe even mentioned users gemini://hd.206267.xyz/view/78ebe1c4622578a946d753b46279b2f4dd1e8eb2eda5ae435a06e3236d2bd640

translations

i would be glad to contribute, when you add a translation infrastructure.

Request: is it possible to add a 4th level, local accounts?

Hi. Thank you very much for sharing this beautiful and simple tool. :)

I'd like to know how much effort (or concept breaking) would it be to add another level of privacy, inspired in a great feature of Hometown?

As you clearly state, today we have 3 privacy levels:

  • Public
  • To followers
  • To mentioned users

In Hometown, there is "community" between Public and followers, which means all accounts in the same instance. This allows the instance to become a campfire, a cozy web to gather and talk.

Be it possible or not, thank you very much for linking these worlds. :)

Best...

does tootik contain a gemini server, and other questions regarding running it and configuration.

hello, it's me again.

i don't really understand how to setup tootik.

do i need to not have an existing gemini server on 1965?

does tootik includes a gemini server or i can use it together with gemini server?

i decided to build and run it to answer the questions myself by let's say using netstat or strace.

i built it by

cd cmd/tootik
go build

tootik binary is generated. if i run it from the same directory, it creates

db.sqlite3  db.sqlite3-shm  db.sqlite3-wal

files, and then it doesn't run with message:Failed to remove invisible posts: no such table: notes.

maybe i missed if there is documentation. or maybe i just cannot figure out how to use it.

so i'll appreciate hints on how the layout should be, where the binary should be put, how to configure it, and if the gemini server is needed for tootik to run.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.