Implemented internal request function for client
added skeleton for other files added todo
This commit is contained in:
parent
dd15b606b8
commit
0e1b69f526
13 changed files with 986 additions and 25 deletions
6
.vscode/settings.json
vendored
Normal file
6
.vscode/settings.json
vendored
Normal file
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"cSpell.words": [
|
||||
"errcode",
|
||||
"reqwest"
|
||||
]
|
||||
}
|
|
@ -7,3 +7,8 @@ edition = "2018"
|
|||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
url = "2.1"
|
||||
reqwest = "0.9"
|
||||
serde_json = "1.0"
|
||||
serde = "1.0"
|
||||
olm-rs = "0.2"
|
||||
|
|
442
docs/todo.md
Normal file
442
docs/todo.md
Normal file
|
@ -0,0 +1,442 @@
|
|||
# r0.5
|
||||
|
||||
- [ ] 2 API Standards
|
||||
- [ ] 2.1 GET /_matrix/client/versions
|
||||
- [x] ~~3 Web Browser Clients~~ *Not applicable*
|
||||
- [ ] 4 Server Discovery
|
||||
- [ ] 4.1 Well-known URI
|
||||
- [ ] 4.1.1 GET /.well-known/matrix/client
|
||||
- [ ] 5 Client Authentication
|
||||
- [ ] 5.1 Using access tokens
|
||||
- [ ] 5.2 Relationship between access tokens and devices
|
||||
- [ ] 5.3 User-Interactive Authentication API
|
||||
- [ ] 5.3.1 Overview
|
||||
- [ ] 5.3.2 User-interactive API in the REST API
|
||||
- [ ] 5.3.3 Example
|
||||
- [ ] 5.3.4 Authentication types
|
||||
- [ ] 5.3.4.1 Password-based
|
||||
- [ ] 5.3.4.2 Google ReCaptcha
|
||||
- [ ] 5.3.4.3 Token-based
|
||||
- [ ] 5.3.4.4 OAuth2-based
|
||||
- [ ] 5.3.4.5 Email-based (identity / homeserver)
|
||||
- [ ] 5.3.4.6 Phone number/MSISDN-based (identity / homeserver)
|
||||
- [ ] 5.3.4.7 Dummy Auth
|
||||
- [ ] 5.3.5 Fallback
|
||||
- [ ] 5.3.5.1 Example
|
||||
- [ ] 5.3.6 Identifier types
|
||||
- [ ] 5.3.6.1 Matrix User ID
|
||||
- [ ] 5.3.6.2 Third-party ID
|
||||
- [ ] 5.3.6.3 Phone number
|
||||
- [ ] 5.4 Login
|
||||
- [ ] 5.4.1 GET /_matrix/client/r0/login
|
||||
- [ ] 5.4.2 POST /_matrix/client/r0/login
|
||||
- [ ] 5.4.3 POST /_matrix/client/r0/logout
|
||||
- [ ] 5.4.4 POST /_matrix/client/r0/logout/all
|
||||
- [ ] 5.4.5 Login Fallback
|
||||
- [ ] 5.5 Account registration and management
|
||||
- [ ] 5.5.1 POST /_matrix/client/r0/register
|
||||
- [ ] 5.5.2 POST /_matrix/client/r0/register/email/requestToken
|
||||
- [ ] 5.5.3 POST /_matrix/client/r0/register/msisdn/requestToken
|
||||
- [ ] 5.5.4 POST /_matrix/client/r0/account/password
|
||||
- [ ] 5.5.5 POST /_matrix/client/r0/account/password/email/requestToken
|
||||
- [ ] 5.5.6 POST /_matrix/client/r0/account/password/msisdn/requestToken
|
||||
- [ ] 5.5.7 POST /_matrix/client/r0/account/deactivate
|
||||
- [ ] 5.5.8 GET /_matrix/client/r0/register/available
|
||||
- [ ] 5.5.9 Notes on password management
|
||||
- [ ] 5.6 Adding Account Administrative Contact Information
|
||||
- [ ] 5.6.1 GET /_matrix/client/r0/account/3pid
|
||||
- [ ] 5.6.2 POST /_matrix/client/r0/account/3pid
|
||||
- [ ] 5.6.3 POST /_matrix/client/r0/account/3pid/delete
|
||||
- [ ] 5.6.4 POST /_matrix/client/r0/account/3pid/email/requestToken
|
||||
- [ ] 5.6.5 POST /_matrix/client/r0/account/3pid/msisdn/requestToken
|
||||
- [ ] 5.7 Current account information
|
||||
- [ ] 5.7.1 GET /_matrix/client/r0/account/whoami
|
||||
- [ ] 6 Capabilities negotiation
|
||||
- [ ] 6.1 GET /_matrix/client/r0/capabilities
|
||||
- [ ] 6.2 m.change_password capability
|
||||
- [ ] 6.3 m.room_versions capability
|
||||
- [ ] 7 Pagination
|
||||
- [ ] 8 Filtering
|
||||
- [ ] 8.1 Lazy-loading room members
|
||||
- [ ] 8.2 API endpoints
|
||||
- [ ] 8.2.1 POST /_matrix/client/r0/user/{userId}/filter
|
||||
- [ ] 8.2.2 GET /_matrix/client/r0/user/{userId}/filter/{filterId}
|
||||
- [ ] 9 Events
|
||||
- [ ] 9.1 Types of room events
|
||||
- [ ] 9.1.1 Event Fields
|
||||
- [ ] 9.1.2 Room Event Fields
|
||||
- [ ] 9.1.3 State Event Fields
|
||||
- [ ] 9.2 Size limits
|
||||
- [ ] 9.3 Room Events
|
||||
- [ ] 9.3.1 m.room.aliases
|
||||
- [ ] 9.3.2 m.room.canonical_alias
|
||||
- [ ] 9.3.3 m.room.create
|
||||
- [ ] 9.3.4 m.room.join_rules
|
||||
- [ ] 9.3.5 m.room.member
|
||||
- [ ] 9.3.6 m.room.power_levels
|
||||
- [ ] 9.3.7 m.room.redaction
|
||||
- [x] 9.4 Syncing
|
||||
- [x] 9.4.1 GET /_matrix/client/r0/sync
|
||||
- [x] ~~9.4.2 GET /_matrix/client/r0/events~~ *Deprecated*
|
||||
- [x] ~~9.4.3 GET /_matrix/client/r0/initialSync~~ *Deprecated*
|
||||
- [x] ~~9.4.4 GET /_matrix/client/r0/events/{eventId}~~ *Deprecated*
|
||||
- [ ] 9.5 Getting events for a room
|
||||
- [ ] 9.5.1 GET /_matrix/client/r0/rooms/{roomId}/event/{eventId}
|
||||
- [ ] 9.5.2 GET /_matrix/client/r0/rooms/{roomId}/state/{eventType}/{stateKey}
|
||||
- [ ] 9.5.3 GET /_matrix/client/r0/rooms/{roomId}/state
|
||||
- [ ] 9.5.4 GET /_matrix/client/r0/rooms/{roomId}/members
|
||||
- [ ] 9.5.5 GET /_matrix/client/r0/rooms/{roomId}/joined_members
|
||||
- [ ] 9.5.6 GET /_matrix/client/r0/rooms/{roomId}/messages
|
||||
- [ ] 9.5.7 GET /_matrix/client/r0/rooms/{roomId}/initialSync
|
||||
- [ ] 9.6 Sending events to a room
|
||||
- [ ] 9.6.1 PUT /_matrix/client/r0/rooms/{roomId}/state/{eventType}/{stateKey}
|
||||
- [ ] 9.6.2 PUT /_matrix/client/r0/rooms/{roomId}/send/{eventType}/{txnId}
|
||||
- [ ] 9.7 Redactions
|
||||
- [ ] 9.7.1 Events
|
||||
- [ ] 9.7.1.1 m.room.redaction
|
||||
- [ ] 9.7.2 Client behaviour
|
||||
- [ ] 9.7.2.1 PUT /_matrix/client/r0/rooms/{roomId}/redact/{eventId}/{txnId}
|
||||
- [ ] 10 Rooms
|
||||
- [ ] 10.1 Creation
|
||||
- [ ] 10.1.1 POST /_matrix/client/r0/createRoom
|
||||
- [ ] 10.2 Room aliases
|
||||
- [ ] 10.2.1 PUT /_matrix/client/r0/directory/room/{roomAlias}
|
||||
- [ ] 10.2.2 GET /_matrix/client/r0/directory/room/{roomAlias}
|
||||
- [ ] 10.2.3 DELETE /_matrix/client/r0/directory/room/{roomAlias}
|
||||
- [ ] 10.3 Permissions
|
||||
- [ ] 10.4 Room membership
|
||||
- [ ] 10.4.1 GET /_matrix/client/r0/joined_rooms
|
||||
- [ ] 10.4.2 Joining rooms
|
||||
- [ ] 10.4.2.1 POST /_matrix/client/r0/rooms/{roomId}/invite
|
||||
- [ ] 10.4.2.2 POST /_matrix/client/r0/rooms/{roomId}/join
|
||||
- [ ] 10.4.2.3 POST /_matrix/client/r0/join/{roomIdOrAlias}
|
||||
- [ ] 10.4.3 Leaving rooms
|
||||
- [ ] 10.4.3.1 POST /_matrix/client/r0/rooms/{roomId}/leave
|
||||
- [ ] 10.4.3.2 POST /_matrix/client/r0/rooms/{roomId}/forget
|
||||
- [ ] 10.4.3.3 POST /_matrix/client/r0/rooms/{roomId}/kick
|
||||
- [ ] 10.4.4 Banning users in a room
|
||||
- [ ] 10.4.4.1 POST /_matrix/client/r0/rooms/{roomId}/ban
|
||||
- [ ] 10.4.4.2 POST /_matrix/client/r0/rooms/{roomId}/unban
|
||||
- [ ] 10.5 Listing rooms
|
||||
- [ ] 10.5.1 GET /_matrix/client/r0/directory/list/room/{roomId}
|
||||
- [ ] 10.5.2 PUT /_matrix/client/r0/directory/list/room/{roomId}
|
||||
- [ ] 10.5.3 GET /_matrix/client/r0/publicRooms
|
||||
- [ ] 10.5.4 POST /_matrix/client/r0/publicRooms
|
||||
- [ ] 11 User Data
|
||||
- [ ] 11.1 User Directory
|
||||
- [ ] 11.1.1 POST /_matrix/client/r0/user_directory/search
|
||||
- [ ] 11.2 Profiles
|
||||
- [ ] 11.2.1 PUT /_matrix/client/r0/profile/{userId}/displayname
|
||||
- [ ] 11.2.2 GET /_matrix/client/r0/profile/{userId}/displayname
|
||||
- [ ] 11.2.3 PUT /_matrix/client/r0/profile/{userId}/avatar_url
|
||||
- [ ] 11.2.4 GET /_matrix/client/r0/profile/{userId}/avatar_url
|
||||
- [ ] 11.2.5 GET /_matrix/client/r0/profile/{userId}
|
||||
- [ ] 11.2.6 Events on Change of Profile Information
|
||||
- [ ] 12 Security
|
||||
- [ ] 12.1 Rate limiting
|
||||
- [ ] 13 Modules
|
||||
- [ ] 13.1 Feature Profiles
|
||||
- [ ] 13.1.1 Summary
|
||||
- [ ] 13.1.2 Clients
|
||||
- [ ] 13.1.2.1 Stand-alone web (Web)
|
||||
- [ ] 13.1.2.2 Mobile (Mobile)
|
||||
- [ ] 13.1.2.3 Desktop (Desktop)
|
||||
- [ ] 13.1.2.4 Command Line Interface (CLI)
|
||||
- [ ] 13.1.2.5 Embedded (Embedded)
|
||||
- [ ] 13.1.2.5.1 Application
|
||||
- [ ] 13.1.2.5.2 Device
|
||||
- [ ] 13.2 Instant Messaging
|
||||
- [ ] 13.2.1 Events
|
||||
- [ ] 13.2.1.1 m.room.message
|
||||
- [ ] 13.2.1.2 m.room.message.feedback
|
||||
- [ ] 13.2.1.3 m.room.name
|
||||
- [ ] 13.2.1.4 m.room.topic
|
||||
- [ ] 13.2.1.5 m.room.avatar
|
||||
- [ ] 13.2.1.6 m.room.pinned_events
|
||||
- [ ] 13.2.1.7 m.room.message msgtypes
|
||||
- [ ] 13.2.1.7.1 m.text
|
||||
- [ ] 13.2.1.7.2 m.emote
|
||||
- [ ] 13.2.1.7.3 m.notice
|
||||
- [ ] 13.2.1.7.4 m.image
|
||||
- [ ] 13.2.1.7.5 m.file
|
||||
- [ ] 13.2.1.7.6 m.audio
|
||||
- [ ] 13.2.1.7.7 m.location
|
||||
- [ ] 13.2.1.7.8 m.video
|
||||
- [ ] 13.2.2 Client behaviour
|
||||
- [ ] 13.2.2.1 Recommendations when sending messages
|
||||
- [ ] 13.2.2.2 Local echo
|
||||
- [ ] 13.2.2.3 Calculating the display name for a user
|
||||
- [ ] 13.2.2.4 Displaying membership information with messages
|
||||
- [ ] 13.2.2.5 Calculating the display name for a room
|
||||
- [ ] 13.2.2.6 Forming relationships between events
|
||||
- [ ] 13.2.2.6.1 Rich replies
|
||||
- [ ] 13.2.2.6.1.1 Fallbacks and event representation
|
||||
- [ ] 13.2.2.6.1.1.1 Stripping the fallback
|
||||
- [ ] 13.2.2.6.1.1.2 Fallback for m.text, m.notice, and unrecognised message types
|
||||
- [ ] 13.2.2.6.1.1.3 Fallback for m.emote
|
||||
- [ ] 13.2.2.6.1.1.4 Fallback for m.image, m.video, m.audio, and m.file
|
||||
- [ ] 13.2.3 Server behaviour
|
||||
- [ ] 13.2.4 Security considerations
|
||||
- [ ] 13.3 Voice over IP
|
||||
- [ ] 13.3.1 Events
|
||||
- [ ] 13.3.1.1 m.call.invite
|
||||
- [ ] 13.3.1.2 m.call.candidates
|
||||
- [ ] 13.3.1.3 m.call.answer
|
||||
- [ ] 13.3.1.4 m.call.hangup
|
||||
- [ ] 13.3.2 Client behaviour
|
||||
- [ ] 13.3.2.1 Glare
|
||||
- [ ] 13.3.3 Server behaviour
|
||||
- [ ] 13.3.3.1 GET /_matrix/client/r0/voip/turnServer
|
||||
- [ ] 13.3.4 Security considerations
|
||||
- [ ] 13.4 Typing Notifications
|
||||
- [ ] 13.4.1 Events
|
||||
- [ ] 13.4.1.1 m.typing
|
||||
- [ ] 13.4.2 Client behaviour
|
||||
- [ ] 13.4.2.1 PUT /_matrix/client/r0/rooms/{roomId}/typing/{userId}
|
||||
- [ ] 13.4.3 Security considerations
|
||||
- [ ] 13.5 Receipts
|
||||
- [ ] 13.5.1 Events
|
||||
- [ ] 13.5.1.1 m.receipt
|
||||
- [ ] 13.5.2 Client behaviour
|
||||
- [ ] 13.5.2.1 POST /_matrix/client/r0/rooms/{roomId}/receipt/{receiptType}/{eventId}
|
||||
- [ ] 13.5.3 Server behaviour
|
||||
- [ ] 13.5.4 Security considerations
|
||||
- [ ] 13.6 Fully read markers
|
||||
- [ ] 13.6.1 Events
|
||||
- [ ] 13.6.1.1 m.fully_read
|
||||
- [ ] 13.6.2 Client behaviour
|
||||
- [ ] 13.6.2.1 POST /_matrix/client/r0/rooms/{roomId}/read_markers
|
||||
- [ ] 13.6.3 Server behaviour
|
||||
- [ ] 13.7 Presence
|
||||
- [ ] 13.7.1 Events
|
||||
- [ ] 13.7.1.1 m.presence
|
||||
- [ ] 13.7.2 Client behaviour
|
||||
- [ ] 13.7.2.1 PUT /_matrix/client/r0/presence/{userId}/status
|
||||
- [ ] 13.7.2.2 GET /_matrix/client/r0/presence/{userId}/status
|
||||
- [ ] 13.7.2.3 Last active ago
|
||||
- [ ] 13.7.2.4 Idle timeout
|
||||
- [ ] 13.7.3 Security considerations
|
||||
- [ ] 13.8 Content repository
|
||||
- [ ] 13.8.1 Matrix Content (MXC) URIs
|
||||
- [ ] 13.8.2 Client behaviour
|
||||
- [ ] 13.8.2.1 POST /_matrix/media/r0/upload
|
||||
- [ ] 13.8.2.2 GET /_matrix/media/r0/download/{serverName}/{mediaId}
|
||||
- [ ] 13.8.2.3 GET /_matrix/media/r0/download/{serverName}/{mediaId}/{fileName}
|
||||
- [ ] 13.8.2.4 GET /_matrix/media/r0/thumbnail/{serverName}/{mediaId}
|
||||
- [ ] 13.8.2.5 GET /_matrix/media/r0/preview_url
|
||||
- [ ] 13.8.2.6 GET /_matrix/media/r0/config
|
||||
- [ ] 13.8.2.7 Thumbnails
|
||||
- [ ] 13.8.3 Security considerations
|
||||
- [ ] 13.9 Send-to-Device messaging
|
||||
- [ ] 13.9.1 Client behaviour
|
||||
- [ ] 13.9.2 Server behaviour
|
||||
- [ ] 13.9.3 Protocol definitions
|
||||
- [ ] 13.9.3.1 PUT /_matrix/client/r0/sendToDevice/{eventType}/{txnId}
|
||||
- [ ] 13.9.3.2 Extensions to /sync
|
||||
- [ ] 13.10 Device Management
|
||||
- [ ] 13.10.1 Client behaviour
|
||||
- [ ] 13.10.1.1 GET /_matrix/client/r0/devices
|
||||
- [ ] 13.10.1.2 GET /_matrix/client/r0/devices/{deviceId}
|
||||
- [ ] 13.10.1.3 PUT /_matrix/client/r0/devices/{deviceId}
|
||||
- [ ] 13.10.1.4 DELETE /_matrix/client/r0/devices/{deviceId}
|
||||
- [ ] 13.10.1.5 POST /_matrix/client/r0/delete_devices
|
||||
- [ ] 13.10.2 Security considerations
|
||||
- [ ] 13.11 End-to-End Encryption
|
||||
- [ ] 13.11.1 Key Distribution
|
||||
- [ ] 13.11.1.1 Overview
|
||||
- [ ] 13.11.1.2 Key algorithms
|
||||
- [ ] 13.11.1.3 Device keys
|
||||
- [ ] 13.11.1.4 Uploading keys
|
||||
- [ ] 13.11.1.5 Tracking the device list for a user
|
||||
- [ ] 13.11.1.6 Sending encrypted attachments
|
||||
- [ ] 13.11.1.6.1 Extensions to m.message msgtypes
|
||||
- [ ] 13.11.1.7 Claiming one-time keys
|
||||
- [ ] 13.11.2 Device verification
|
||||
- [ ] 13.11.2.1 Key verification framework
|
||||
- [ ] 13.11.2.1.1 m.key.verification.request
|
||||
- [ ] 13.11.2.1.2 m.key.verification.start
|
||||
- [ ] 13.11.2.1.3 m.key.verification.cancel
|
||||
- [ ] 13.11.2.2 Short Authentication String (SAS) verification
|
||||
- [ ] 13.11.2.2.1 Error and exception handling
|
||||
- [ ] 13.11.2.2.2 Verification messages specific to SAS
|
||||
- [ ] 13.11.2.2.3 m.key.verification.start
|
||||
- [ ] 13.11.2.2.4 m.key.verification.accept
|
||||
- [ ] 13.11.2.2.5 m.key.verification.key
|
||||
- [ ] 13.11.2.2.6 m.key.verification.mac
|
||||
- [ ] 13.11.2.2.7 HKDF calculation
|
||||
- [ ] 13.11.2.2.8 SAS method: decimal
|
||||
- [ ] 13.11.2.2.9 SAS method: emoji
|
||||
- [ ] 13.11.3 Sharing keys between devices
|
||||
- [ ] 13.11.3.1 Key requests
|
||||
- [ ] 13.11.3.2 Key exports
|
||||
- [ ] 13.11.3.2.1 Key export format
|
||||
- [ ] 13.11.4 Messaging Algorithms
|
||||
- [ ] 13.11.4.1 Messaging Algorithm Names
|
||||
- [ ] 13.11.4.2 m.olm.v1.curve25519-aes-sha2
|
||||
- [ ] 13.11.4.2.1 Recovering from undecryptable messages
|
||||
- [ ] 13.11.4.3 m.megolm.v1.aes-sha2
|
||||
- [ ] 13.11.5 Protocol definitions
|
||||
- [ ] 13.11.5.1 Events
|
||||
- [ ] 13.11.5.1.1 m.room.encryption
|
||||
- [ ] 13.11.5.1.2 m.room.encrypted
|
||||
- [ ] 13.11.5.1.3 m.room_key
|
||||
- [ ] 13.11.5.1.4 m.room_key_request
|
||||
- [ ] 13.11.5.1.5 m.forwarded_room_key
|
||||
- [ ] 13.11.5.1.6 m.dummy
|
||||
- [ ] 13.11.5.2 Key management API
|
||||
- [ ] 13.11.5.2.1 POST /_matrix/client/r0/keys/upload
|
||||
- [ ] 13.11.5.2.2 POST /_matrix/client/r0/keys/query
|
||||
- [ ] 13.11.5.2.3 POST /_matrix/client/r0/keys/claim
|
||||
- [ ] 13.11.5.2.4 GET /_matrix/client/r0/keys/changes
|
||||
- [ ] 13.11.5.3 Extensions to /sync
|
||||
- [ ] 13.12 Room History Visibility
|
||||
- [ ] 13.12.1 Events
|
||||
- [ ] 13.12.1.1 m.room.history_visibility
|
||||
- [ ] 13.12.2 Client behaviour
|
||||
- [ ] 13.12.3 Server behaviour
|
||||
- [ ] 13.12.4 Security considerations
|
||||
- [ ] 13.13 Push Notifications
|
||||
- [ ] 13.13.1 Client behaviour
|
||||
- [ ] 13.13.1.1 GET /_matrix/client/r0/pushers
|
||||
- [ ] 13.13.1.2 POST /_matrix/client/r0/pushers/set
|
||||
- [ ] 13.13.1.3 Listing Notifications
|
||||
- [ ] 13.13.1.3.1 GET /_matrix/client/r0/notifications
|
||||
- [ ] 13.13.1.4 Receiving notifications
|
||||
- [ ] 13.13.1.5 Push Rules
|
||||
- [ ] 13.13.1.5.1 Actions
|
||||
- [ ] 13.13.1.5.1.1 Tweaks
|
||||
- [ ] 13.13.1.5.2 Predefined Rules
|
||||
- [ ] 13.13.1.5.2.1 Default Override Rules
|
||||
- [ ] 13.13.1.5.2.1.1 .m.rule.master
|
||||
- [ ] 13.13.1.5.2.1.2 .m.rule.suppress_notices
|
||||
- [ ] 13.13.1.5.2.1.3 .m.rule.invite_for_me
|
||||
- [ ] 13.13.1.5.2.1.4 .m.rule.member_event
|
||||
- [ ] 13.13.1.5.2.1.5 .m.rule.contains_display_name
|
||||
- [ ] 13.13.1.5.2.1.6 .m.rule.tombstone
|
||||
- [ ] 13.13.1.5.2.1.7 .m.rule.roomnotif
|
||||
- [ ] 13.13.1.5.2.2 Default Content Rules
|
||||
- [ ] 13.13.1.5.2.2.1 .m.rule.contains_user_name
|
||||
- [ ] 13.13.1.5.2.3 Default Underride Rules
|
||||
- [ ] 13.13.1.5.2.3.1 .m.rule.call
|
||||
- [ ] 13.13.1.5.2.3.2 .m.rule.encrypted_room_one_to_one
|
||||
- [ ] 13.13.1.5.2.3.3 .m.rule.room_one_to_one
|
||||
- [ ] 13.13.1.5.2.3.4 .m.rule.message
|
||||
- [ ] 13.13.1.5.2.3.5 .m.rule.encrypted
|
||||
- [ ] 13.13.1.5.3 Conditions
|
||||
- [ ] 13.13.1.6 Push Rules: API
|
||||
- [ ] 13.13.1.6.1 GET /_matrix/client/r0/pushrules/
|
||||
- [ ] 13.13.1.6.2 GET /_matrix/client/r0/pushrules/{scope}/{kind}/{ruleId}
|
||||
- [ ] 13.13.1.6.3 DELETE /_matrix/client/r0/pushrules/{scope}/{kind}/{ruleId}
|
||||
- [ ] 13.13.1.6.4 PUT /_matrix/client/r0/pushrules/{scope}/{kind}/{ruleId}
|
||||
- [ ] 13.13.1.6.5 GET /_matrix/client/r0/pushrules/{scope}/{kind}/{ruleId}/enabled
|
||||
- [ ] 13.13.1.6.6 PUT /_matrix/client/r0/pushrules/{scope}/{kind}/{ruleId}/enabled
|
||||
- [ ] 13.13.1.6.7 GET /_matrix/client/r0/pushrules/{scope}/{kind}/{ruleId}/actions
|
||||
- [ ] 13.13.1.6.8 PUT /_matrix/client/r0/pushrules/{scope}/{kind}/{ruleId}/actions
|
||||
- [ ] 13.13.1.7 Push Rules: Events
|
||||
- [ ] 13.13.1.7.1 m.push_rules
|
||||
- [ ] 13.13.1.7.2 Examples
|
||||
- [ ] 13.13.2 Server behaviour
|
||||
- [ ] 13.13.3 Push Gateway behaviour
|
||||
- [ ] 13.13.3.1 Recommendations for APNS
|
||||
- [ ] 13.13.4 Security considerations
|
||||
- [ ] 13.14 Third party invites
|
||||
- [ ] 13.14.1 Events
|
||||
- [ ] 13.14.1.1 m.room.third_party_invite
|
||||
- [ ] 13.14.2 Client behaviour
|
||||
- [ ] 13.14.2.1 POST /_matrix/client/r0/rooms/{roomId}/invite
|
||||
- [ ] 13.14.3 Server behaviour
|
||||
- [ ] 13.14.4 Security considerations
|
||||
- [ ] 13.15 Server Side Search
|
||||
- [ ] 13.15.1 Client behaviour
|
||||
- [ ] 13.15.1.1 POST /_matrix/client/r0/search
|
||||
- [ ] 13.15.2 Search Categories
|
||||
- [ ] 13.15.2.1 room_events
|
||||
- [ ] 13.15.3 Ordering
|
||||
- [ ] 13.15.4 Groups
|
||||
- [ ] 13.15.5 Pagination
|
||||
- [ ] 13.15.6 Security considerations
|
||||
- [ ] 13.16 Guest Access
|
||||
- [ ] 13.16.1 Events
|
||||
- [ ] 13.16.1.1 m.room.guest_access
|
||||
- [ ] 13.16.2 Client behaviour
|
||||
- [ ] 13.16.3 Server behaviour
|
||||
- [ ] 13.16.4 Security considerations
|
||||
- [ ] 13.17 Room Previews
|
||||
- [ ] 13.17.1 Client behaviour
|
||||
- [ ] 13.17.1.1 GET /_matrix/client/r0/events
|
||||
- [ ] 13.17.2 Server behaviour
|
||||
- [ ] 13.17.3 Security considerations
|
||||
- [ ] 13.18 Room Tagging
|
||||
- [ ] 13.18.1 Events
|
||||
- [ ] 13.18.1.1 m.tag
|
||||
- [ ] 13.18.2 Client Behaviour
|
||||
- [ ] 13.18.2.1 GET /_matrix/client/r0/user/{userId}/rooms/{roomId}/tags
|
||||
- [ ] 13.18.2.2 PUT /_matrix/client/r0/user/{userId}/rooms/{roomId}/tags/{tag}
|
||||
- [ ] 13.18.2.3 DELETE /_matrix/client/r0/user/{userId}/rooms/{roomId}/tags/{tag}
|
||||
- [ ] 13.19 Client Config
|
||||
- [ ] 13.19.1 Events
|
||||
- [ ] 13.19.2 Client Behaviour
|
||||
- [ ] 13.19.2.1 PUT /_matrix/client/r0/user/{userId}/account_data/{type}
|
||||
- [ ] 13.19.2.2 GET /_matrix/client/r0/user/{userId}/account_data/{type}
|
||||
- [ ] 13.19.2.3 PUT /_matrix/client/r0/user/{userId}/rooms/{roomId}/account_data/{type}
|
||||
- [ ] 13.19.2.4 GET /_matrix/client/r0/user/{userId}/rooms/{roomId}/account_data/{type}
|
||||
- [ ] 13.19.3 Server Behaviour
|
||||
- [ ] 13.20 Server Administration
|
||||
- [ ] 13.20.1 Client Behaviour
|
||||
- [ ] 13.20.1.1 GET /_matrix/client/r0/admin/whois/{userId}
|
||||
- [ ] 13.21 Event Context
|
||||
- [ ] 13.21.1 Client behaviour
|
||||
- [ ] 13.21.1.1 GET /_matrix/client/r0/rooms/{roomId}/context/{eventId}
|
||||
- [ ] 13.21.2 Security considerations
|
||||
- [ ] 13.22 SSO client login
|
||||
- [ ] 13.22.1 Client behaviour
|
||||
- [ ] 13.22.1.1 GET /_matrix/client/r0/login/sso/redirect
|
||||
- [ ] 13.22.2 Server behaviour
|
||||
- [ ] 13.22.2.1 Handling the redirect endpoint
|
||||
- [ ] 13.22.2.2 Handling the authentication endpoint
|
||||
- [ ] 13.23 Direct Messaging
|
||||
- [ ] 13.23.1 Events
|
||||
- [ ] 13.23.1.1 m.direct
|
||||
- [ ] 13.23.2 Client behaviour
|
||||
- [ ] 13.23.3 Server behaviour
|
||||
- [ ] 13.24 Ignoring Users
|
||||
- [ ] 13.24.1 Events
|
||||
- [ ] 13.24.1.1 m.ignored_user_list
|
||||
- [ ] 13.24.2 Client behaviour
|
||||
- [ ] 13.24.3 Server behaviour
|
||||
- [ ] 13.25 Sticker Messages
|
||||
- [ ] 13.25.1 Events
|
||||
- [ ] 13.25.1.1 m.sticker
|
||||
- [ ] 13.25.2 Client behaviour
|
||||
- [ ] 13.26 Reporting Content
|
||||
- [ ] 13.26.1 Client behaviour
|
||||
- [ ] 13.26.1.1 POST /_matrix/client/r0/rooms/{roomId}/report/{eventId}
|
||||
- [ ] 13.26.2 Server behaviour
|
||||
- [ ] 13.27 Third Party Networks
|
||||
- [ ] 13.27.1 Third Party Lookups
|
||||
- [ ] 13.27.1.1 GET /_matrix/client/r0/thirdparty/protocols
|
||||
- [ ] 13.27.1.2 GET /_matrix/client/r0/thirdparty/protocol/{protocol}
|
||||
- [ ] 13.27.1.3 GET /_matrix/client/r0/thirdparty/location/{protocol}
|
||||
- [ ] 13.27.1.4 GET /_matrix/client/r0/thirdparty/user/{protocol}
|
||||
- [ ] 13.27.1.5 GET /_matrix/client/r0/thirdparty/location
|
||||
- [ ] 13.27.1.6 GET /_matrix/client/r0/thirdparty/user
|
||||
- [ ] 13.28 OpenID
|
||||
- [ ] 13.28.1 POST /_matrix/client/r0/user/{userId}/openid/request_token
|
||||
- [ ] 13.29 Server Access Control Lists (ACLs) for rooms
|
||||
- [ ] 13.29.1 m.room.server_acl
|
||||
- [ ] 13.29.2 Client behaviour
|
||||
- [ ] 13.29.3 Server behaviour
|
||||
- [ ] 13.29.4 Security considerations
|
||||
- [ ] 13.30 User, room, and group mentions
|
||||
- [ ] 13.30.1 Client behaviour
|
||||
- [ ] 13.31 Room Upgrades
|
||||
- [ ] 13.31.1 Events
|
||||
- [ ] 13.31.1.1 m.room.tombstone
|
||||
- [ ] 13.31.2 Client behaviour
|
||||
- [ ] 13.31.2.1 POST /_matrix/client/r0/rooms/{roomId}/upgrade
|
||||
- [ ] 13.31.3 Server behaviour
|
||||
- [ ] 13.32 Server Notices
|
||||
- [ ] 13.32.1 Events
|
||||
- [ ] 13.32.1.1 m.room.message (m.server_notice)
|
||||
- [ ] 13.32.2 Client behaviour
|
||||
- [ ] 13.32.3 Server behaviour
|
231
src/api/client.rs
Normal file
231
src/api/client.rs
Normal file
|
@ -0,0 +1,231 @@
|
|||
use crate::api::methods::sync::SyncResponse;
|
||||
use reqwest::Client as reqwest_client;
|
||||
use reqwest::{
|
||||
header::{HeaderMap, HeaderValue, CONTENT_TYPE, USER_AGENT},
|
||||
StatusCode,
|
||||
};
|
||||
use std::{collections::HashMap, error::Error, fmt, time};
|
||||
use url::{ParseError, Url};
|
||||
|
||||
const V2_API_PATH: &str = "/_matrix/client/r0";
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum MatrixParseError {
|
||||
ParseError(ParseError),
|
||||
EmptyScheme,
|
||||
}
|
||||
|
||||
pub enum PresenceState {
|
||||
Offline,
|
||||
Online,
|
||||
Unavailable,
|
||||
}
|
||||
|
||||
impl From<ParseError> for MatrixParseError {
|
||||
fn from(parse_error: ParseError) -> Self {
|
||||
MatrixParseError::ParseError(parse_error)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ResponseError {
|
||||
code: StatusCode,
|
||||
content: String,
|
||||
}
|
||||
|
||||
impl fmt::Display for ResponseError {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(formatter, "{}: {}", self.code, self.content)
|
||||
}
|
||||
}
|
||||
|
||||
impl Error for ResponseError {}
|
||||
|
||||
pub enum MatrixHTTPMethod {
|
||||
Get,
|
||||
Put,
|
||||
Delete,
|
||||
Post,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Client {
|
||||
homeserver_url: String,
|
||||
access_token: Option<String>,
|
||||
mxid: Option<String>,
|
||||
default_492_wait_ms: u64,
|
||||
use_auth_header: bool,
|
||||
reqwest_client: reqwest_client,
|
||||
}
|
||||
|
||||
impl Client {
|
||||
pub fn new(
|
||||
homeserver_url: &str,
|
||||
access_token: Option<String>,
|
||||
mxid: Option<String>,
|
||||
default_492_wait_ms: Option<u64>,
|
||||
use_auth_header: Option<bool>,
|
||||
) -> Result<Self, MatrixParseError> {
|
||||
let url = Url::parse(homeserver_url)?;
|
||||
if url.scheme().is_empty() {
|
||||
return Err(MatrixParseError::EmptyScheme);
|
||||
}
|
||||
|
||||
Ok(Client {
|
||||
homeserver_url: homeserver_url.to_string(),
|
||||
access_token,
|
||||
mxid,
|
||||
default_492_wait_ms: default_492_wait_ms.unwrap_or_else(|| 5000),
|
||||
use_auth_header: use_auth_header.unwrap_or_else(|| true),
|
||||
reqwest_client: reqwest_client::new(),
|
||||
})
|
||||
}
|
||||
|
||||
/// Sends an API request to the homeserver using the specified method and
|
||||
/// path, returning either an error or the response text.
|
||||
///
|
||||
/// The header will automatically be populated with a user agent and have
|
||||
/// the content type set to `application/json`. If a token was provided, it
|
||||
/// will be used as a bearer auth header or as a query.
|
||||
///
|
||||
/// This is a blocking, synchronous send. If the response from the
|
||||
/// homeserver indicates that too many requests were sent, it will attempt
|
||||
/// to wait the specified duration (or a provided default) before retrying.
|
||||
fn send(
|
||||
&self,
|
||||
method: MatrixHTTPMethod,
|
||||
path: Option<&str>,
|
||||
content: Option<String>,
|
||||
query_params: Option<HashMap<String, String>>,
|
||||
headers: Option<HeaderMap>,
|
||||
) -> Result<String, Box<dyn std::error::Error>> {
|
||||
let mut query_params = query_params.unwrap_or_default();
|
||||
let mut headers = headers.unwrap_or_default();
|
||||
let endpoint = &format!(
|
||||
"{}{}",
|
||||
self.homeserver_url,
|
||||
path.unwrap_or_else(|| V2_API_PATH),
|
||||
);
|
||||
let mut request = match method {
|
||||
MatrixHTTPMethod::Get => self.reqwest_client.get(endpoint),
|
||||
MatrixHTTPMethod::Put => self.reqwest_client.put(endpoint),
|
||||
MatrixHTTPMethod::Delete => self.reqwest_client.delete(endpoint),
|
||||
MatrixHTTPMethod::Post => self.reqwest_client.post(endpoint),
|
||||
};
|
||||
|
||||
if !headers.contains_key(&USER_AGENT) {
|
||||
let user_agent = &format!("libmatrix-client/{}", env!("CARGO_PKG_VERSION"));
|
||||
headers.insert(USER_AGENT, HeaderValue::from_str(user_agent)?);
|
||||
}
|
||||
|
||||
if !headers.contains_key(&CONTENT_TYPE) {
|
||||
headers.insert(CONTENT_TYPE, HeaderValue::from_str("application/json")?);
|
||||
}
|
||||
|
||||
if let Some(token) = &self.access_token {
|
||||
if self.use_auth_header {
|
||||
request = request.bearer_auth(token);
|
||||
} else {
|
||||
query_params.insert("access_token".to_string(), token.to_string());
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(id) = &self.mxid {
|
||||
query_params.insert("user_id".to_string(), id.to_string());
|
||||
}
|
||||
|
||||
request = request.headers(headers).query(&query_params);
|
||||
|
||||
if let Some(content) = content {
|
||||
request = request.body(content);
|
||||
}
|
||||
|
||||
loop {
|
||||
let mut res = request
|
||||
.try_clone()
|
||||
.expect("Unable to clone request")
|
||||
.send()?;
|
||||
|
||||
if res.status().is_success() {
|
||||
return Ok(res.text()?);
|
||||
} else if res.status() == StatusCode::TOO_MANY_REQUESTS {
|
||||
let mut body: HashMap<String, String> = res.json()?;
|
||||
if let Some(value) = body.get("error") {
|
||||
body = serde_json::from_str(value)?;
|
||||
}
|
||||
|
||||
if let Some(value) = body.get("retry_after_ms") {
|
||||
std::thread::sleep(time::Duration::from_millis(value.parse::<u64>()?));
|
||||
} else {
|
||||
std::thread::sleep(time::Duration::from_millis(self.default_492_wait_ms));
|
||||
}
|
||||
} else {
|
||||
return Err(Box::from(ResponseError {
|
||||
code: res.status(),
|
||||
content: res.text()?,
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn send_query(
|
||||
&self,
|
||||
method: MatrixHTTPMethod,
|
||||
path: &str,
|
||||
query_params: HashMap<String, String>,
|
||||
) -> Result<String, Box<dyn Error>> {
|
||||
self.send(method, Some(path), None, Some(query_params), None)
|
||||
}
|
||||
|
||||
pub fn sync(
|
||||
&self,
|
||||
bookmark_token: Option<&str>,
|
||||
timeout_ms: Option<u64>,
|
||||
filter: Option<&str>,
|
||||
get_full_state: Option<bool>,
|
||||
set_presence: Option<PresenceState>,
|
||||
) -> Result<SyncResponse, Box<dyn Error>> {
|
||||
let mut params: HashMap<String, String> = HashMap::with_capacity(5);
|
||||
params.insert(
|
||||
"timeout".to_string(),
|
||||
timeout_ms.unwrap_or_else(|| 30000).to_string(),
|
||||
);
|
||||
|
||||
if let Some(token) = bookmark_token {
|
||||
params.insert("since".to_string(), token.to_string());
|
||||
}
|
||||
|
||||
if let Some(filter) = filter {
|
||||
params.insert("filter".to_string(), filter.to_string());
|
||||
}
|
||||
|
||||
if let Some(true) = get_full_state {
|
||||
params.insert("full_state".to_string(), "true".to_string());
|
||||
}
|
||||
|
||||
params.insert(
|
||||
"full_state".to_string(),
|
||||
match set_presence {
|
||||
Some(PresenceState::Online) => "online",
|
||||
Some(PresenceState::Unavailable) => "unavailable",
|
||||
None | Some(PresenceState::Offline) => "offline",
|
||||
}
|
||||
.to_string(),
|
||||
);
|
||||
|
||||
Ok(serde_json::from_str(&self.send_query(
|
||||
MatrixHTTPMethod::Get,
|
||||
"/sync",
|
||||
params,
|
||||
)?)?)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct ApiError {}
|
||||
|
||||
impl fmt::Display for ApiError {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(formatter, "an error occurred!")
|
||||
}
|
||||
}
|
86
src/api/error.rs
Normal file
86
src/api/error.rs
Normal file
|
@ -0,0 +1,86 @@
|
|||
use serde::Deserialize;
|
||||
use std::collections::HashMap;
|
||||
|
||||
// Various helper constants for common error codes.
|
||||
pub const FORBIDDEN: &str = "M_FORBIDDEN";
|
||||
pub const UNKNOWN_TOKEN: &str = "M_UNKNOWN_TOKEN";
|
||||
pub const MISSING_TOKEN: &str = "M_MISSING_TOKEN";
|
||||
pub const BAD_JSON: &str = "M_BAD_JSON";
|
||||
pub const NOT_JSON: &str = "M_NOT_JSON";
|
||||
pub const NOT_FOUND: &str = "M_NOT_FOUND";
|
||||
pub const LIMIT_EXCEEDED: &str = "M_LIMIT_EXCEEDED";
|
||||
pub const UNKNOWN: &str = "M_UNKNOWN";
|
||||
pub const UNRECOGNIZED: &str = "M_UNRECOGNIZED";
|
||||
pub const UNAUTHORIZED: &str = "M_UNAUTHORIZED";
|
||||
pub const USER_IN_USE: &str = "M_USER_IN_USE";
|
||||
pub const INVALID_USERNAME: &str = "M_INVALID_USERNAME";
|
||||
pub const IN_USE: &str = "M_ROOM_IN_USE";
|
||||
pub const STATE: &str = "M_INVALID_ROOM_STATE";
|
||||
pub const THREEPID_IN_USE: &str = "M_THREEPID_IN_USE";
|
||||
pub const THREEPID_NOT_FOUND: &str = "M_THREEPID_NOT_FOUND";
|
||||
pub const THREEPID_AUTH_FAILED: &str = "M_THREEPID_AUTH_FAILED";
|
||||
pub const THREEPID_DENIED: &str = "M_THREEPID_DENIED";
|
||||
pub const SERVER_NOT_TRUSTED: &str = "M_SERVER_NOT_TRUSTED";
|
||||
pub const UNSUPPORTED_ROOM_VERSION: &str = "M_UNSUPPORTED_ROOM_VERSION";
|
||||
pub const INCOMPATIBLE_ROOM_VERSION: &str = "M_INCOMPATIBLE_ROOM_VERSION";
|
||||
pub const BAD_STATE: &str = "M_BAD_STATE";
|
||||
pub const GUEST_ACCESS_FORBIDDEN: &str = "M_GUEST_ACCESS_FORBIDDEN";
|
||||
pub const CAPTCHA_NEEDED: &str = "M_CAPTCHA_NEEDED";
|
||||
pub const CAPTCHA_INVALID: &str = "M_CAPTCHA_INVALID";
|
||||
pub const MISSING_PARAM: &str = "M_MISSING_PARAM";
|
||||
pub const INVALID_PARAM: &str = "M_INVALID_PARAM";
|
||||
pub const TOO_LARGE: &str = "M_TOO_LARGE";
|
||||
pub const EXCLUSIVE: &str = "M_EXCLUSIVE";
|
||||
pub const RESOURCE_LIMIT_EXCEEDED: &str = "M_RESOURCE_LIMIT_EXCEEDED";
|
||||
pub const CANNOT_LEAVE_SERVER_NOTICE_ROOM: &str = "M_CANNOT_LEAVE_SERVER_NOTICE_ROOM";
|
||||
|
||||
/// Implements the standard error response as defined by [Section 2](https://matrix.org/docs/spec/client_server/r0.5.0#api-standards)
|
||||
/// of the Client-Server API standard as a HashMap. We don't have a better way
|
||||
/// of representing this class, since we need to conform to having different
|
||||
/// fields for different errors.
|
||||
#[derive(Deserialize)]
|
||||
pub struct ApiError {
|
||||
#[serde(flatten)]
|
||||
pub data: HashMap<String, String>,
|
||||
}
|
||||
|
||||
impl ApiError {
|
||||
/// Helper function for obtaining the error code. Access the `errcode`
|
||||
/// field, which must be present on all valid error messages.
|
||||
pub fn error_code(&self) -> &str {
|
||||
self.data
|
||||
.get("errcode")
|
||||
.expect("Error did not contain required errcode field")
|
||||
}
|
||||
|
||||
/// Helper function for obtaining the error message, which is a
|
||||
/// human-readable field that explains the issue. This accesses the `error`
|
||||
/// field, which must be present on all valid error messages.
|
||||
pub fn error_message(&self) -> &str {
|
||||
self.data
|
||||
.get("error")
|
||||
.expect("Error did not contain required error field")
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn deserialize_basic_error_msg() {
|
||||
let test_msg = r#"{"errcode": "M_FORBIDDEN", "error": "hello"}"#;
|
||||
let deserialized: ApiError = serde_json::from_str(test_msg).unwrap();
|
||||
assert_eq!(deserialized.error_code(), FORBIDDEN);
|
||||
assert_eq!(deserialized.error_message(), "hello");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn deserialize_error_with_custom_field() {
|
||||
let test_msg = r#"{"errcode": "M_UNKNOWN", "error": "foo", "a": "b"}"#;
|
||||
let deserialized: ApiError = serde_json::from_str(test_msg).unwrap();
|
||||
assert_eq!(deserialized.error_code(), UNKNOWN);
|
||||
assert_eq!(deserialized.error_message(), "foo");
|
||||
assert_eq!(deserialized.data.get("a").unwrap(), "b");
|
||||
}
|
||||
}
|
1
src/api/methods/mod.rs
Normal file
1
src/api/methods/mod.rs
Normal file
|
@ -0,0 +1 @@
|
|||
pub mod sync;
|
169
src/api/methods/sync.rs
Normal file
169
src/api/methods/sync.rs
Normal file
|
@ -0,0 +1,169 @@
|
|||
use serde::Deserialize;
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct SyncResponse {
|
||||
pub next_batch: String,
|
||||
pub rooms: Option<Rooms>,
|
||||
pub presence: Option<Presence>,
|
||||
pub account_data: Option<AccountData>,
|
||||
pub to_device: Option<ToDevice>,
|
||||
pub device_lists: Option<DeviceLists>,
|
||||
pub device_one_time_keys_count: Option<HashMap<String, u64>>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct Rooms {
|
||||
pub join: Option<HashMap<String, JoinedRoom>>,
|
||||
pub invite: Option<HashMap<String, InvitedRoom>>,
|
||||
pub leave: Option<HashMap<String, LeftRoom>>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct JoinedRoom {
|
||||
pub summary: Option<RoomSummary>,
|
||||
pub state: Option<State>,
|
||||
pub timeline: Option<Timeline>,
|
||||
pub ephemeral: Option<Ephemeral>,
|
||||
pub account_date: Option<AccountData>,
|
||||
pub unread_notifications: Option<UnreadNotificationCounts>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct RoomSummary {
|
||||
#[serde(rename = "m.heroes")]
|
||||
pub heros: Option<Vec<String>>,
|
||||
#[serde(rename = "m.joined_member_count")]
|
||||
pub joined_member_count: Option<u64>,
|
||||
#[serde(rename = "m.invited_member_count")]
|
||||
pub invited_member_count: Option<u64>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct State {
|
||||
pub events: Option<StateEvents>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct StateEvents {
|
||||
pub content: serde_json::value::Value, // This is an json object
|
||||
pub r#type: String,
|
||||
pub event_id: String,
|
||||
pub sender: String,
|
||||
pub origin_server_ts: u64,
|
||||
pub unsigned: Option<UnsignedData>,
|
||||
pub prev_content: Option<EventContent>,
|
||||
pub state_key: String,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct UnsignedData {
|
||||
pub age: Option<u64>,
|
||||
pub redacted_because: Option<Event>,
|
||||
pub transaction_id: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct Event {
|
||||
pub content: serde_json::value::Value, // Json object
|
||||
pub r#type: String,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct EventContent {
|
||||
pub avatar_url: Option<String>,
|
||||
pub displayname: Option<String>, //type is string or null????
|
||||
pub membership: Membership,
|
||||
pub state_key: String,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
pub enum Membership {
|
||||
Invite,
|
||||
Join,
|
||||
Knock,
|
||||
Leave,
|
||||
Ban,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct Timeline {
|
||||
pub events: Option<Vec<RoomEvent>>,
|
||||
pub limited: Option<bool>,
|
||||
pub prev_batch: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct RoomEvent {
|
||||
pub content: String,
|
||||
pub r#type: String,
|
||||
pub event_id: String,
|
||||
pub sender: String,
|
||||
pub origin_server_ts: u64,
|
||||
pub unsigned: Option<UnsignedData>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct Ephemeral {
|
||||
pub events: Option<Vec<Event>>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct AccountData {
|
||||
pub events: Option<Vec<Event>>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct UnreadNotificationCounts {
|
||||
pub highlight_count: Option<u64>,
|
||||
pub notification_count: Option<u64>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct InvitedRoom {
|
||||
pub invite_state: Option<InviteState>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct InviteState {
|
||||
pub events: Option<Vec<StrippedState>>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct StrippedState {
|
||||
pub content: EventContent,
|
||||
pub state_key: String,
|
||||
pub r#type: String,
|
||||
pub sender: String,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct LeftRoom {
|
||||
pub state: Option<State>,
|
||||
pub timeline: Option<Timeline>,
|
||||
pub account_data: Option<AccountData>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct Presence {
|
||||
pub events: Option<Vec<Event>>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct ToDevice {
|
||||
pub events: Option<Vec<ToDeviceEvent>>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct ToDeviceEvent {
|
||||
pub content: Option<EventContent>,
|
||||
pub sender: Option<String>,
|
||||
pub r#type: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct DeviceLists {
|
||||
pub changed: Option<Vec<String>>,
|
||||
pub left: Option<Vec<String>>,
|
||||
}
|
|
@ -1,19 +1,14 @@
|
|||
use std::fmt;
|
||||
use serde::Deserialize;
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub struct Client {}
|
||||
pub mod client;
|
||||
pub mod error;
|
||||
pub mod methods;
|
||||
|
||||
impl Client{
|
||||
pub fn new() -> Self {
|
||||
Client {}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct ApiError {}
|
||||
|
||||
impl fmt::Display for ApiError {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(formatter, "an error occurred!")
|
||||
}
|
||||
pub type Result<T> = std::result::Result<T, error::ApiError>;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct VersionApiResp {
|
||||
pub versions: Vec<String>,
|
||||
pub unstable_features: HashMap<String, bool>,
|
||||
}
|
||||
|
|
3
src/api/rooms.rs
Normal file
3
src/api/rooms.rs
Normal file
|
@ -0,0 +1,3 @@
|
|||
trait RoomApi {
|
||||
fn send_state_event(room_id: &str, )
|
||||
}
|
0
src/api/util.rs
Normal file
0
src/api/util.rs
Normal file
|
@ -1,6 +1,7 @@
|
|||
#![forbid(unsafe_code)]
|
||||
// #![warn(missing_docs)]
|
||||
|
||||
mod api;
|
||||
pub mod api;
|
||||
mod client;
|
||||
mod room;
|
||||
mod user;
|
||||
|
|
0
src/room/events.rs
Normal file
0
src/room/events.rs
Normal file
38
src/user.rs
38
src/user.rs
|
@ -1,4 +1,4 @@
|
|||
use crate::api::{ApiError, Client};
|
||||
use crate::api::client::{ApiError, Client};
|
||||
use crate::room::Room;
|
||||
use std::fmt;
|
||||
|
||||
|
@ -29,13 +29,19 @@ impl fmt::Display for UserInitError {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
#[derive(Debug)]
|
||||
struct User {
|
||||
id: String,
|
||||
display_name: Option<String>,
|
||||
client: Client,
|
||||
}
|
||||
|
||||
impl PartialEq for User {
|
||||
fn eq(&self, rhs: &Self) -> bool {
|
||||
self.id == rhs.id && self.display_name == rhs.display_name
|
||||
}
|
||||
}
|
||||
|
||||
impl User {
|
||||
/// Constructs a new User. This represents a user in a room.
|
||||
///
|
||||
|
@ -46,7 +52,11 @@ impl User {
|
|||
///
|
||||
/// Returns either a new User struct or an error containing the reason why it failed to create a
|
||||
/// new User.
|
||||
pub fn new(id: String, display_name: Option<String>) -> Result<Self, UserInitError> {
|
||||
pub fn new(
|
||||
client: Client,
|
||||
id: String,
|
||||
display_name: Option<String>,
|
||||
) -> Result<Self, UserInitError> {
|
||||
if !id.starts_with("@") {
|
||||
Err(UserInitError::new(
|
||||
"User ID must start with a @",
|
||||
|
@ -61,7 +71,7 @@ impl User {
|
|||
Ok(User {
|
||||
id,
|
||||
display_name,
|
||||
client: Client::new(),
|
||||
client,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -90,7 +100,11 @@ mod tests {
|
|||
#[test]
|
||||
fn new_returns_err_on_invalid_id() {
|
||||
assert_eq!(
|
||||
User::new(String::from("abc:edf"), None),
|
||||
User::new(
|
||||
Client::new("https://google.com", None, None, None, None).unwrap(),
|
||||
String::from("abc:edf"),
|
||||
None
|
||||
),
|
||||
Err(UserInitError {
|
||||
message: "User ID must start with a @".to_string(),
|
||||
reason: UserInitErrorReason::InvalidUsername
|
||||
|
@ -98,7 +112,11 @@ mod tests {
|
|||
);
|
||||
|
||||
assert_eq!(
|
||||
User::new(String::from("@abcedf"), None),
|
||||
User::new(
|
||||
Client::new("https://google.com", None, None, None, None).unwrap(),
|
||||
String::from("@abcedf"),
|
||||
None
|
||||
),
|
||||
Err(UserInitError {
|
||||
message: "User ID must contain a :".to_string(),
|
||||
reason: UserInitErrorReason::NoDomainProvided
|
||||
|
@ -109,11 +127,15 @@ mod tests {
|
|||
#[test]
|
||||
fn new_returns_struct_on_valid_input() {
|
||||
assert_eq!(
|
||||
User::new("@eddie:eddie.sh".to_string(), None),
|
||||
User::new(
|
||||
Client::new("https://google.com", None, None, None, None).unwrap(),
|
||||
"@eddie:eddie.sh".to_string(),
|
||||
None
|
||||
),
|
||||
Ok(User {
|
||||
id: "@eddie:eddie.sh".to_string(),
|
||||
display_name: None,
|
||||
client: Client::new()
|
||||
client: Client::new("https://google.com", None, None, None, None).unwrap()
|
||||
})
|
||||
)
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue