Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/picohz/metropolis
🏙️ Async/await-based Matrix client library in Swift
https://github.com/picohz/metropolis
async-await ios macos matrix matrix-org rest-api swift
Last synced: 6 days ago
JSON representation
🏙️ Async/await-based Matrix client library in Swift
- Host: GitHub
- URL: https://github.com/picohz/metropolis
- Owner: picoHz
- License: mit
- Created: 2021-12-29T14:10:39.000Z (about 3 years ago)
- Default Branch: main
- Last Pushed: 2022-01-15T01:57:43.000Z (about 3 years ago)
- Last Synced: 2024-11-19T10:53:58.777Z (2 months ago)
- Topics: async-await, ios, macos, matrix, matrix-org, rest-api, swift
- Language: Swift
- Homepage:
- Size: 89.8 KB
- Stars: 4
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
🚧 This package is not production-ready 🚧
- [About](#about)
- [Supported Features](#supported-features)
- [Installation](#installation)
- [Usage](#usage)
- [Anonymous Access](#anonymous-access)
- [Authorization](#authorization)
- [User-Interactive Authentication](#user-interactive-authentication)
- [Custom Authorization Method](#custom-authorization-method)
- [Pagination](#pagination)
- [Media Downloading and Uploading](#media-downloading-and-uploading)
- [Handling Schema-free JSON Objects](handling-schema-free-json-objects)
- [Testing](#testing)
- [License](#license)## About
Metropolis is an asynchronous client library for [Matrix Messaging Protocol](https://matrix.org/)
written in pure Swift.
It provides a low-level wrapper for client-server API integrated with the Swift type system.### What is Matrix?
> Matrix is an open standard for interoperable, decentralised, real-time communication over IP. It can be used to power Instant Messaging, VoIP/WebRTC signalling, Internet of Things communication - or anywhere you need a standard HTTP API for publishing and subscribing to data whilst tracking the conversation history.
https://matrix.org/faq## Supported Features
- [x] Account Management
- [x] Session Management
- [x] Device Management
- [x] Room Directory
- [x] Room Participation
- [x] Presence
- [x] Media
- [x] User Data
- [x] User Directory
- [x] Full Text Search
- [ ] Push Notifications
- [ ] End-To-End Encryption## Installation
### Swift Package Manager
Metropolis supports installation via Swift Package Manager.
To add the package as your project's dependency, put the repository url into the dependencies section in `Package.swift` like this:```swift
// swift-tools-version:5.5
import PackageDescriptionlet package = Package(
name: "PackageName",
dependencies: [
.package(url: "https://github.com/picoHz/Metropolis.git", .branch("main"))
]
)
```
You can also add dependencies from Xcode.
https://developer.apple.com/documentation/swift_packages/adding_package_dependencies_to_your_app## Usage
Note that this library is basically just a thin wrapper of Matrix client-server API and does not provide high-level functionalities, so you need to read the [Matrix Specification](https://spec.matrix.org/v1.1/client-server-api) to understand how these endpoints work.
### Anonymous Access
Public endpoints are accessible without login.
```swift
let client = try MPClient(url: URL(string: "https://matrix.org")!)
try await client.checkUsernameAvailability(username: "metro")
```### Authorization
```swift
let client = try MPClient(url: URL(string: "https://matrix.org")!)let method = MPPasswordAuth(
identifier: .user(user: "metro"),
password: "pass")let authClient = try await client.login(method: method)
```#### Custom Authorization Method
`client.login()` method accepts any objects that conform to `MPAuthMethod` protocol.
```swift
public protocol MPAuthMethod: Encodable {
var type: String { get }
}
``````swift
public struct CustomAuth: MPAuthMethod {
let type: String = "com.example.custom"
var customName: String
var customList: [String]
}let authClient = try await client.login(method: CustomAuth(customName: "aaa", customList: ["bbb"]))
```
The property names will be converted to snakecase.
For example, `CustomAuth` will be encoded into the following JSON.```json
{
"type": "com.example.custom",
"custom_name": "aaa",
"custom_list": ["bbb"]
}
```### User-Interactive Authentication
```swift
var interactiveAuth = try await authClient.changePassword(newPassword: "new_password")guard case .failure(var state) = try await interactiveAuth.authenticate(method: method) {
return
}while true {
if !state.flows[0].stages.contains("m.login.password") {
// Password authentication is not supported.
break
}// Ask user to authenticate.
let method = MPPasswordAuth(
identifier: .user(user: "metro"),
password: "old_password")switch try await interactiveAuth.authenticate(method: method, state: state) {
case .success(_):
break
case .failure(let newState):
// Authentication failed or needs additional authentication.
state = newState
continue
}
}
```### Pagination
Paginated endpoints return a stream object that implements [`AsyncSequence`](https://developer.apple.com/documentation/swift/asyncsequence).
```swift
let stream = try await client.getPublicRooms(limit: 100)for try await chunk in stream {
// Fetch results.
}// Iterate manually.
var iter = stream.makeAsyncIterator()
let chunk = try await iter.next()// Get an estimated room count from the iterator.
iter.totalRoomCountEstimate// Resume the iteration using a pagination token.
let newStream = try await client.getPublicRooms(limit: 100, since: iter.nextBatch)
```#### Backward Pagination
Public Room Directory supports bidirectional pagination.
You can make a backward iterator using `prevBatch` token.```swift
let stream = try await client.getPublicRooms(limit: 100)var iter = stream.makeAsyncIterator()
while try await iter.next() != nil {}let backwardStream = try await client.getPublicRooms(limit: 100, since: iter.prevBatch)
for try await chunk in backwardStream {
// Fetch backward results.
}
```### Media Downloading and Uploading
Metropolis does not directly provide methods to download/upload media.
Instead, it provides the following methods returning URLs for downloading or uploading so you can use your favorite HTTP client library to handle them.```swift
public protocol MPMediaAPI {
func getMediaDownloadUrl(serverName: String, mediaId: String) -> URL
func getMediaThumbnailUrl(serverName: String, mediaId: String) -> URL
func getMediaUploadUrl() -> URL
}
```### Handling Schema-free JSON Objects
Some endpoints use unstructured (a.k.a schema-free) JSON objects.
Metropolis handles them with [SwiftyJSON](https://github.com/SwiftyJSON/SwiftyJSON).```swift
let profile: JSON = try await client.getProfile(userId: "@[email protected]")// Access as a JSON object
if let displayName = profile.dictionaryValue["displayname"].string {
print(displayName)
}// Decode as a struct
struct Profile: Decodable { var displayname: String }
let data = try JSONDecoder().decode(Profile.self, from: profile.rawData())
print(data.displayname)
```## Testing
To run tests, you need running a matrix instance on `localhost:8080`.
The following commands run up-to-date demo server instances.
Please check [Synapse Documantation](https://github.com/matrix-org/synapse#quick-start)
for more information about Matrix servers.```bash
git clone https://github.com/matrix-org/synapse.git
cd synapsepython3 -m venv ./env
source ./env/bin/activate
pip install -e ".[all,dev]"./demo/start.sh
```If there is already a running matrix instance on `localhost:8080`,
you can simply run `swift test`.## License
Metropolis is released under the MIT license.
Headline Photo by [Leonhard Niederwimmer](https://unsplash.com/@lnlnln) on [Unsplash](https://unsplash.com/photos/ZETyWNCn5bw)