Это документация Trixnity. Запомни её.

---
sidebar_position: 0
---

# Introduction

Trixnity is a multiplatform [Matrix](https://matrix.org) SDK written in Kotlin.
You can write clients, bots, appservices and servers with
it. This SDK supports JVM (also Android), JS and Native as targets for most
modules.
[Ktor](https://github.com/ktorio/ktor) is used for the HTTP client/server and
[kotlinx.serialization](https://github.com/Kotlin/kotlinx.serialization) for the
serialization/deserialization.

Trixnity aims to be reactive, strongly typed, customizable and easy to use. You can
register custom events and Trixnity will take
care, that you can send and receive that type.

---

---
sidebar_position: 1
---

# Modules

![modules](./assets/modules.png)

This project contains among others the following modules, which can be used independently:

- [trixnity-core](https://gitlab.com/trixnity/trixnity/-/tree/main/trixnity-core)
  contains all basic data structures of the spec and it’s serialization algorithms. This includes events, identifiers
  and other things like CrossSigningKeys.
- [trixnity-olm](https://gitlab.com/trixnity/trixnity/-/tree/main/trixnity-olm)
  implements the wrappers of the
  E2E-olm-library [libolm](https://gitlab.matrix.org/matrix-org/olm) for Kotlin
  JVM/Android/JS/Native. It also ships the
  olm binaries for most Android, JVM and Native targets.
- [trixnity-crypto](https://gitlab.com/trixnity/trixnity/-/tree/main/trixnity-crypto)
  contains various cryptographic algorithms
  used in Matrix.
- [trixnity-api-client](https://gitlab.com/trixnity/trixnity/-/tree/main/trixnity-api-client)
  provides tools for api client
  modules.
- [trixnity-api-server](https://gitlab.com/trixnity/trixnity/-/tree/main/trixnity-api-server)
  provides tools for api server
  modules.
- [trixnity-clientserverapi-*](https://gitlab.com/trixnity/trixnity/-/tree/main/trixnity-clientserverapi)
  provides modules to
  use
  the [Client-Server API](https://spec.matrix.org/latest/client-server-api/).
    - [trixnity-clientserverapi-model](https://gitlab.com/trixnity/trixnity/-/tree/main/trixnity-clientserverapi/trixnity-clientserverapi-model)
      provides shared model
      classes.
    - [trixnity-clientserverapi-client](https://gitlab.com/trixnity/trixnity/-/tree/main/trixnity-clientserverapi/trixnity-clientserverapi-client)
      is the client
      implementation without logic.
    - [trixnity-clientserverapi-server](https://gitlab.com/trixnity/trixnity/-/tree/main/trixnity-clientserverapi/trixnity-clientserverapi-server)
      is the server
      implementation without logic.
- [trixnity-serverserverapi-*](https://gitlab.com/trixnity/trixnity/-/tree/main/trixnity-serverserverapi)
  provides modules to
  use
  the [Server-Server API](https://spec.matrix.org/latest/server-server-api/).
    - [trixnity-serverserverapi-model](https://gitlab.com/trixnity/trixnity/-/tree/main/trixnity-serverserverapi/trixnity-serverserverapi-model)
      provides shared model
      classes.
    - [trixnity-serverserverapi-client](https://gitlab.com/trixnity/trixnity/-/tree/main/trixnity-serverserverapi/trixnity-serverserverapi-client)
      is the client
      implementation without logic.
    - [trixnity-serverserverapi-server](https://gitlab.com/trixnity/trixnity/-/tree/main/trixnity-serverserverapi/trixnity-serverserverapi-server)
      is the server
      implementation without logic.
- [trixnity-applicationserviceapi-*](https://gitlab.com/trixnity/trixnity/-/tree/main/trixnity-applicationserviceapi)
  provides
  modules to use
  the [Application Service API](https://spec.matrix.org/latest/application-service-api/).
    - [trixnity-applicationserviceapi-model](https://gitlab.com/trixnity/trixnity/-/tree/main/trixnity-applicationserviceapi/trixnity-applicationserviceapi-model)
      provides shared model classes.
    - [trixnity-applicationserviceapi-server](https://gitlab.com/trixnity/trixnity/-/tree/main/trixnity-applicationserviceapi/trixnity-applicationserviceapi-server)
      is
      the server implementation without logic.
- [trixnity-client](https://gitlab.com/trixnity/trixnity/-/tree/main/trixnity-client)
  provides a high level client
  implementation. It allows you to easily implement
  clients by just rendering data from and passing user interactions to Trixnity.
- [trixnity-applicationservice](https://gitlab.com/trixnity/trixnity/-/tree/main/trixnity-applicationservice)
  provides a basic
  high level application service
  implementation. It does not support advanced features like E2E or persistence
  at the moment.

---

---
sidebar_position: 2
---

# Getting Started

## Add Trixnity to you project

Select from [modules](/docs/modules) the dependency you need and add it to you project:

```kotlin
// get version from https://gitlab.com/benkuly/trixnity/-/releases
val trixnityVersion = "x.x.x"

fun trixnity(module: String, version: String = trixnityVersion) =
    "net.folivo:trixnity-$module:$version"

// for example:
implementation(trixnity("client"))
```

Alternatively, add the Trixnity BOM as a `platform` dependency. This then allows for version resolution of Trixnity
modules:

```kotlin
val trixnityVersion = "x.x.x"

dependencies {
    implementation(platform("net.folivo:trixnity-bom:$trixnityVersion"))

    // Trixnity dependency versions are covered by the Trixnity BOM
    implementation("net.folivo:trixnity-client")
}
```

Modules containing `-client` in the name (for example `trixnity-client` or `trixnity-clientserverapi-client`) also need
a Ktor client engine, that can be found [here](https://ktor.io/docs/http-client-engines.html).

## Examples

If you want to see Trixnity in action, take a look into
the [trixnity-examples](https://gitlab.com/trixnity/trixnity-examples).
You may also take a look into
the [integration tests](https://gitlab.com/trixnity/trixnity/-/tree/main/trixnity-client/integration-tests).

For a messenger implementation you can take a look into the community
project [Smalk](https://gitlab.com/terrakok/smalk).

If you you just want to implement a messenger without having to dive too deep into trixnity-client and Matrix, consider
using [trixnity-messenger](https://gitlab.com/connect2x/trixnity-messenger).

## dev builds

Dev builds are published on each commit to main.
Add `https://gitlab.com/api/v4/projects/26519650/packages/maven` to your
maven repositories. You can find
the complete version names here (
containing `DEV`): https://gitlab.com/trixnity/trixnity/-/packages?search[]=trixnity-bom

---

---
sidebar_position: 12
---

# Features

- [x] exchangeable database
    - in memory (e. g. for tests)
    - [trixnity-client-repository-exposed](https://gitlab.com/trixnity/trixnity/-/tree/main/trixnity-client/trixnity-client-repository-exposed)
      implements a database for trixnity-client with [Exposed](https://github.com/JetBrains/Exposed).
      This supports JVM based platforms only.
    - [trixnity-client-repository-realm](https://gitlab.com/trixnity/trixnity/-/tree/main/trixnity-client/trixnity-client-repository-realm)
      implements a database for trixnity-client with [realm](https://github.com/realm/realm-kotlin).
      This supports JVM/Android/Native.
    - [trixnity-client-repository-indexeddb](https://gitlab.com/trixnity/trixnity/-/tree/main/trixnity-client/trixnity-client-repository-indexeddb)
      implements a database for trixnity-client with [indexeddb](https://github.com/JuulLabs/indexeddb).
      This supports JS (browser).
    - [trixnity-client-repository-room](https://gitlab.com/trixnity/trixnity/-/tree/main/trixnity-client/trixnity-client-repository-room)
      implements a database for trixnity-client
      with [room](https://developer.android.com/jetpack/androidx/releases/room).
      This supports JVM/Android (Native comes soon).
- [x] extremely fast reactive cache on top of the database
- [x] exchangeable media store
    - in memory (e. g. for tests)
    - [trixnity-client-media-okio](https://gitlab.com/trixnity/trixnity/-/tree/main/trixnity-client/trixnity-client-media-okio)
      implements a file system based media store with [okio](https://github.com/square/okio).
      This supports JVM/Android/Native/NodeJs.
    - [trixnity-client-media-opfs](https://gitlab.com/trixnity/trixnity/-/tree/main/trixnity-client/trixnity-client-media-indexeddb)
      implements a store
      with [Origin private file system](https://developer.mozilla.org/en-US/docs/Web/API/File_System_API/Origin_private_file_system).
      This supports JS (browser).
    - [trixnity-client-media-indexeddb](https://gitlab.com/trixnity/trixnity/-/tree/main/trixnity-client/trixnity-client-media-indexeddb)
      implements a store with [indexeddb](https://github.com/JuulLabs/indexeddb).
      This supports JS (browser). This does not support streaming data yet.
- [x] media support (thumbnail generation, offline "upload", huge files, etc.)
- [x] E2E (olm, megolm)
- [x] verification
- [x] cross signing
- [x] fallback keys
- [x] room key backup
- [x] room key requests (only between own verified devices and when key backup is disabled)
- [x] room list
- [x] timelines
- [x] room upgrades (invisible due to merged timelines and auto-join)
- [x] user and room display name calculation
- [x] asynchronous message sending without caring about E2E stuff or online status
- [x] redactions
- [x] relations:
    - [x] reply (without fallback)
    - [x] replace
    - [x] reaction via annotation
    - [ ] thread (basic support, no separate timelines or client aggregations yet)
- [x] notifications
- [x] server discovery

## Cache

Because reactive UIs are really common, Trixnity wants to give the UI access to data in a reactive way.
There are only a few databases, that support listeners and this would limit support for multiple supported
databases. That's why an intermediate layer based on Kotlin Flows has been introduced. This intermediate layer reads
values directly from
a generic database layer and also writes changes to it. The values are kept in this layer as long as they are
subscribed. This means, that if someone else subscribes a value, he will immediately get the value without an additional
database call. This goes so far, that even if there are no subscribers anymore, the value is kept a bit longer in
this layer. If someone ask for the value (for example) 10 seconds later, there is – again - no database call needed.

---

---
sidebar_position: 13
---

# Create MatrixClient

With `MatrixClient` you have access to the whole library. It can be instantiated
by various static functions,
e.g. `MatrixClient.login(...)`. You always need to pass a `repositoriesModule`
for a Database and `mediaStore` for media.

Secrets are also stored in the store. Therefore, you should encrypt the store!

```kotlin
val repositoriesModule = createRepositoriesModule() // e.g. createExposedRepositoriesModule(...)
val mediaStore = createMediaStore() // e.g. OkioMediaStore(...)

val matrixClient = MatrixClient.fromStore(
    repositoriesModule = repositoriesModule,
    mediaStore = mediaStore,
).getOrThrow() ?: MatrixClient.login(
    baseUrl = Url("https://example.org"),
    identifier = User("username"),
    password = "password",
    repositoriesModule = repositoriesModule,
    mediaStore = mediaStore,
).getOrThrow()

matrixClient.startSync() // important to fully start the client!
// do something
matrixClient.stop() // important to fully stop the client!
```

To get the `baseUrl` via server discovery you can use the `.serverDiscovery()`
extension on `UserId`s or `String`s.

---

---
sidebar_position: 14
---

# Usage

## Read data

Most data in Trixnity is wrapped into Kotlins `Flow`. This means, that you
get the current value, but also every
future values. This is useful when e.g. the display name or the avatar of a user
changes, because you only need to
rerender that change and not your complete application.

There are some important data, which are described below:

### Rooms

To get the room list, call `matrixClient.room.getAll()`. Use `.flatten()` or `flattenValues()` to flatten the Flow of
Flows.
With `matrixClient.room.getById(...)` you can get one room.

### Users

To get all members of a room, call `matrixClient.user.getAll(...)`. Use `.flatten()` or `flattenValues()` to flatten the
Flow of Flows.
Because room members are loaded lazily, you should
also call `matrixClient.user.loadMembers(...)` as soon as you open a room.
With `matrixClient.user.getById(...)` you can
get one user.

### Timeline and TimelineEvents

The easiest way to compose a timeline is to call `matrixClient.room.getTimeline(...)`.

Normally a sync sends a fragment of the timeline to the client. There also can be gaps. Other clients save this almost
the same into the database, so with fragments pointing to each other.
In Trixnity there are no fragments. One `TimelineEvent` represent one event in a room timeline. Each `TimelineEvent`
points to the previous and next known event id and also saves, if there is a gap.
This allows Trixnity to benefit from Kotlin Flows, because a timeline is just a stream of
`TimelineEvent`s. So everytime a subscriber wants a new timeline event, the producer loads or fetches the next.

This way, it is also possible to connect upgraded rooms. That happens invisible from the developer. The timelines are
merged and the flow just gives you the next timeline event.

![Timeline](../assets/timeline.png)

You can always get the last known `TimelineEvent` of a room with `matrixClient.room.getLastTimelineEvent(...)`.

The following example will always print the last 20 events of a room. Note, that
this doesn't have to be the best way to compose a timeline. It is just a nice
example.

```kotlin
matrixClient.room.getLastTimelineEvents(roomId)
    .toFlowList(MutableStateFlow(20)) // we always get max. 20 TimelineEvents
    .collectLatest { timelineEvents ->
        timelineEvents.forEach { timelineEvent ->
            val event = timelineEvent.first()?.event
            val content = timelineEvent.first()?.content?.getOrNull()
            val sender = event?.sender?.let {
                matrixClient.user.getById(it, roomId).first()?.name
            }
            when {
                content is RoomMessageEventContent -> println("${sender}: ${content.body}")
                content == null -> println("${sender}: not yet decrypted")
                event is MessageEvent -> println("${sender}: $event")
                event is StateEvent -> println("${sender}: $event")
                else -> {
                }
            }
        }
    }
```

### Outbox

Messages, that were sent with Trixnity can be accessed
with `matrixClient.room.getOutbox()` as long as they are not
received (also called "echo") from the matrix server.

## Other operations

Many operations can be done
with [trixnity-clientserverapi-client](https://gitlab.com/trixnity/trixnity/-/tree/main/trixnity-clientserverapi/trixnity-clientserverapi-client).
You have access to it
via `matrixClient.api`. There are also some high level operations, which are
managed by Trixnity. Some of them are
described below.

### Send messages

With `matrixClient.room.sendMessage(...)` you get access to an extensible DSL to
send messages. This messages will be
saved locally and sent as soon as you are online.

```kotlin
// send a text message
matrixClient.room.sendMessage(roomId) {
    text("Hi!")
}
// send an image
matrixClient.room.sendMessage(roomId) {
    image("dino.png", image, ContentType.Image.PNG)
}
```

### Media

To upload media there is `MediaService` (can be accessed
with `matrixClient.media`).

### Verification

To verify own and other devices there is `VerificationService` (can be accessed
with `matrixClient.verification`).

### Cross Signing

To bootstrap cross signing there is `KeyService` (can be accessed
with `matrixClient.key`).

---

---
sidebar_position: 15
---

# Customizing

The client can be customized via dependency injection:

```kotlin
matrixClient.login(...){
    modules = createDefaultTrixnityModules() + customModule
}
```

## Custom events

One goal on developing Trixnity was the ability to add custom events. This is achieved by a mapping event types to
Serializers. In this example we added a new message event `net.folivo.dino`. As a developer you than can receive events
of this Kotlin type like all other default events.

```kotlin
@Serializable
data class DinoEventContent(
    val dinoCount: Long,
) : MessageEventContent {
    // just ignore these properties when you don't need them
    override val relatesTo: RelatesTo? = null
    override val mentions: Mentions? = null
    override val externalUrl: String? = null
}

val customMappings = createEventContentSerializerMappings {
    messageOf<DinoEventContent>("net.folivo.dino")
    // or if you have a custom serializer
    // messageOf("net.folivo.dino", DingoEventContentSerializer)
}

// add the module to MatrixClient as shown above
val customMappingsModule = module {
    single<EventContentSerializerMappings> {
        DefaultEventContentSerializerMappings + customMappings
    }
}
```

---

---
sidebar_position: 16
---

# Bot mode

The bot mode disables many features of the client and speeds it up. You don't have access to usual services like
`RoomService` or `UserService`. Instead, you need to manually listen to the sync events via `SyncApiClient` and send
events via `RoomsApiClient` (both can be received via `MatrixClient.api`).
You can encrypt and decrypt events by using `MatrixClient.roomEventEncryptionServices`.

## Usage

Override the `modules` in `MatrixClientConfiguration`. For example:

```kotlin
matrixClient.login(...){
    modules = createTrixnityBotModules()
}
```

---

---
sidebar_position: 21
---

# Client

## Create MatrixClientServerApiClient

Here is a typical example, how to create a `MatrixClientServerApiClient`:

```kotlin
val matrixRestClient = MatrixClientServerApiClient(
    baseUrl = Url("http://host"),
).apply { accessToken.value = "token" }
```

## Use Matrix Client-Server API

Example 1: You can send messages.

```kotlin
matrixRestClient.room.sendRoomEvent(
    RoomId("awoun3w8fqo3bfq92a", "your.home.server"),
    RoomMessageEventContent.TextBased.Text("hello from platform $Platform")
)
```

Example 2: You can receive different type of events from sync.

```kotlin
matrixRestClient.sync.subscribeContent<RoomMessageEventContent.TextBased.Text> { println(it.content.body) }
matrixRestClient.sync.subscribeContent<MemberEventContent> { println("${it.content.displayName} did ${it.content.membership}") }
matrixRestClient.sync.subscribeEachEvent { println(it) }

matrixRestClient.sync.start() // you need to start the sync to receive messages
delay(30.seconds) // wait some time
matrixRestClient.sync.stop() // stop the sync
```

---

---
sidebar_position: 31
---

# Applicationservice

The appservice module of Trixnity contains a webserver, which hosts the Matrix
Application-Service API.

You also need to add a server engine to your project, that you can
find [here](https://ktor.io/docs/engines.html).

## Usage

### Register module in Ktor

The ktor Application extension `matrixApplicationServiceApiServer` is used to
register the appservice endpoints within a
Ktor server. [See here](https://ktor.io/docs/create-server.html) for more
information on how to create a Ktor server.

```kotlin
val engine: ApplicationEngine = embeddedServer(CIO, port = 443) {
    matrixApplicationServiceApiServer("asToken", handler)
}
engine.start(wait = true)
```

### Use `DefaultApplicationServiceApiServerHandler` as default handler

The `DefaultApplicationServiceApiServerHandler`
implements `ApplicationServiceApiServerHandler`. It makes the
implementation of a Matrix Appservice more abstract and easier. For that it
uses `ApplicationServiceEventTxnService`
, `ApplicationServiceUserService` and `ApplicationServiceRoomService`, which you
need to implement.

It also allows you to retrieve events with `subscribe` in the same way as
described [here](#use-matrix-client-server-api).

---

---
sidebar_position: 51
---

# Olm

We build [libolm](https://gitlab.matrix.org/matrix-org/olm) for various targets.
The currently supported targets can be found [here](https://gitlab.com/trixnity/olm-binaries/-/blob/main/build.sh). If
your platform is not supported, feel free to open a merge request or issue.

If you are using a module, which depends on `trixnity-olm` you may need to do some extra steps:

- JS: You need to provide the url path `/olm.wasm`. The file can be found in the
  official olm npm package. You can do this with webpack
  like [here](https://gitlab.com/trixnity/trixnity-examples/-/blob/main/webpack.config.d/webpack-olm.js).
- JVM: If your platform is not supported yet, you can
  [download or build libolm yourself](https://gitlab.matrix.org/matrix-org/olm)
  and make it available to your JVM (e.g.
  with `-Djna.library.path="build/olm"`).

---

---
sidebar_position: 100
---

# Logging

This project uses [kotlin-logging](https://github.com/MicroUtils/kotlin-logging). On JVM this needs a logging backend.
You can use for example `implementation("ch.qos.logback:logback-classic:<version>")`.

---

All modules:
client-repository-test
trixnity-api-client
trixnity-api-server
trixnity-applicationservice
trixnity-applicationserviceapi-model
trixnity-applicationserviceapi-server
trixnity-client
trixnity-client-media-indexeddb
trixnity-client-media-okio
trixnity-client-media-opfs
trixnity-client-repository-exposed
trixnity-client-repository-indexeddb
trixnity-client-repository-realm
trixnity-client-repository-room
trixnity-clientserverapi-client
trixnity-clientserverapi-model
trixnity-clientserverapi-server
trixnity-core
trixnity-crypto
trixnity-crypto-core
trixnity-olm
trixnity-serverserverapi-client
trixnity-serverserverapi-model
trixnity-serverserverapi-server
trixnity-utils