Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
conduwuit
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Package registry
Container Registry
Model registry
Operate
Environments
Terraform modules
Monitor
Incidents
Service Desk
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
🥺
conduwuit
Commits
dba6c466
Unverified
Commit
dba6c466
authored
4 years ago
by
timokoesters
Browse files
Options
Downloads
Patches
Plain Diff
Use sled::Tree::prefix_search for deviceids
parent
b508b4d1
No related branches found
Branches containing commit
No related tags found
Tags containing commit
No related merge requests found
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
rustfmt.toml
+1
-0
1 addition, 0 deletions
rustfmt.toml
src/data.rs
+57
-76
57 additions, 76 deletions
src/data.rs
src/database.rs
+117
-0
117 additions, 0 deletions
src/database.rs
src/main.rs
+15
-11
15 additions, 11 deletions
src/main.rs
src/utils.rs
+16
-14
16 additions, 14 deletions
src/utils.rs
with
206 additions
and
101 deletions
rustfmt.toml
0 → 100644
+
1
−
0
View file @
dba6c466
merge_imports
=
true
This diff is collapsed.
Click to expand it.
src/data.rs
+
57
−
76
View file @
dba6c466
use
crate
::
utils
;
use
crate
::{
utils
,
Database
};
use
directories
::
ProjectDirs
;
use
log
::
debug
;
use
ruma_events
::
collections
::
all
::
Event
;
use
ruma_events
::
collections
::
all
::
Event
;
use
ruma_identifiers
::{
EventId
,
RoomId
,
UserId
};
use
ruma_identifiers
::{
EventId
,
RoomId
,
UserId
};
use
std
::
convert
::
TryInto
;
use
std
::
convert
::
TryInto
;
const
USERID_PASSWORD
:
&
str
=
"userid_password"
;
pub
struct
Data
{
const
USERID_DEVICEIDS
:
&
str
=
"userid_deviceids"
;
hostname
:
String
,
const
DEVICEID_TOKEN
:
&
str
=
"deviceid_token"
;
db
:
Database
,
const
TOKEN_USERID
:
&
str
=
"token_userid"
;
}
pub
struct
Data
(
sled
::
Db
);
impl
Data
{
impl
Data
{
/// Load an existing database or create a new one.
/// Load an existing database or create a new one.
pub
fn
load_or_create
()
->
Self
{
pub
fn
load_or_create
(
hostname
:
&
str
)
->
Self
{
Data
(
Self
{
sled
::
open
(
hostname
:
hostname
.to_owned
(),
ProjectDirs
::
from
(
"xyz"
,
"koesters"
,
"matrixserver"
)
db
:
Database
::
load_or_create
(
hostname
),
.unwrap
()
}
.data_dir
(),
)
.unwrap
(),
)
}
/// Set the hostname of the server. Warning: Hostname changes will likely break things.
pub
fn
set_hostname
(
&
self
,
hostname
:
&
str
)
{
self
.0
.insert
(
"hostname"
,
hostname
)
.unwrap
();
}
}
/// Get the hostname of the server.
/// Get the hostname of the server.
pub
fn
hostname
(
&
self
)
->
String
{
pub
fn
hostname
(
&
self
)
->
&
str
{
utils
::
bytes_to_string
(
&
self
.0
.get
(
"hostname"
)
.unwrap
()
.unwrap
())
&
self
.hostname
}
}
/// Check if a user has an account by looking for an assigned password.
/// Check if a user has an account by looking for an assigned password.
pub
fn
user_exists
(
&
self
,
user_id
:
&
UserId
)
->
bool
{
pub
fn
user_exists
(
&
self
,
user_id
:
&
UserId
)
->
bool
{
self
.0
self
.db
.open_tree
(
USERID_PASSWORD
)
.userid_password
.unwrap
()
.contains_key
(
user_id
.to_string
())
.contains_key
(
user_id
.to_string
())
.unwrap
()
.unwrap
()
}
}
/// Create a new user account by assigning them a password.
/// Create a new user account by assigning them a password.
pub
fn
user_add
(
&
self
,
user_id
:
&
UserId
,
password
:
Option
<
String
>
)
{
pub
fn
user_add
(
&
self
,
user_id
:
&
UserId
,
password
:
Option
<
String
>
)
{
self
.0
self
.db
.open_tree
(
USERID_PASSWORD
)
.userid_password
.unwrap
()
.insert
(
user_id
.to_string
(),
&*
password
.unwrap_or_default
())
.insert
(
user_id
.to_string
(),
&*
password
.unwrap_or_default
())
.unwrap
();
.unwrap
();
}
}
/// Find out which user an access token belongs to.
/// Find out which user an access token belongs to.
pub
fn
user_from_token
(
&
self
,
token
:
&
str
)
->
Option
<
UserId
>
{
pub
fn
user_from_token
(
&
self
,
token
:
&
str
)
->
Option
<
UserId
>
{
self
.0
self
.db
.open_tree
(
TOKEN_USERID
)
.token_userid
.unwrap
()
.get
(
token
)
.get
(
token
)
.unwrap
()
.unwrap
()
.and_then
(|
bytes
|
(
*
utils
::
bytes_to_string
(
&
bytes
))
.try_into
()
.ok
())
.and_then
(|
bytes
|
(
*
utils
::
string_from_bytes
(
&
bytes
))
.try_into
()
.ok
())
}
}
/// Checks if the given password is equal to the one in the database.
/// Checks if the given password is equal to the one in the database.
pub
fn
password_get
(
&
self
,
user_id
:
&
UserId
)
->
Option
<
String
>
{
pub
fn
password_get
(
&
self
,
user_id
:
&
UserId
)
->
Option
<
String
>
{
self
.0
self
.db
.open_tree
(
USERID_PASSWORD
)
.userid_password
.unwrap
()
.get
(
user_id
.to_string
())
.get
(
user_id
.to_string
())
.unwrap
()
.unwrap
()
.map
(|
bytes
|
utils
::
bytes_to_string
(
&
bytes
))
.map
(|
bytes
|
utils
::
string_from_bytes
(
&
bytes
))
}
}
/// Add a new device to a user.
/// Add a new device to a user.
pub
fn
device_add
(
&
self
,
user_id
:
&
UserId
,
device_id
:
&
str
)
{
pub
fn
device_add
(
&
self
,
user_id
:
&
UserId
,
device_id
:
&
str
)
{
self
.0
if
self
.open_tree
(
USERID_DEVICEIDS
)
.db
.unwrap
()
.userid_deviceids
.insert
(
user_id
.to_string
(),
device_id
)
.get_iter
(
&
user_id
.to_string
()
.as_bytes
())
.unwrap
();
.filter_map
(|
item
|
item
.ok
())
.map
(|(
_key
,
value
)|
value
)
.all
(|
device
|
device
!=
device_id
)
{
self
.db
.userid_deviceids
.add
(
user_id
.to_string
()
.as_bytes
(),
device_id
.into
());
}
}
}
/// Replace the access token of one device.
/// Replace the access token of one device.
pub
fn
token_replace
(
&
self
,
user_id
:
&
UserId
,
device_id
:
&
String
,
token
:
String
)
{
pub
fn
token_replace
(
&
self
,
user_id
:
&
UserId
,
device_id
:
&
String
,
token
:
String
)
{
// Make sure the device id belongs to the user
// Make sure the device id belongs to the user
debug_assert!
(
self
debug_assert!
(
self
.0
.db
.open_tree
(
USERID_DEVICEIDS
)
.userid_deviceids
.unwrap
()
.get_iter
(
&
user_id
.to_string
()
.as_bytes
())
.get
(
&
user_id
.to_string
())
// Does the user exist?
.filter_map
(|
item
|
item
.ok
())
.unwrap
()
.map
(|(
_key
,
value
)|
value
)
.map
(|
bytes
|
utils
::
bytes_to_vec
(
&
bytes
))
.any
(|
device
|
device
==
device_id
.as_bytes
()));
// Does the user have that device?
.filter
(|
devices
|
devices
.contains
(
device_id
))
// Does the user have that device?
.is_some
());
// Remove old token
// Remove old token
if
let
Some
(
old_token
)
=
self
if
let
Some
(
old_token
)
=
self
.db.deviceid_token
.get
(
device_id
)
.unwrap
()
{
.0
self
.db.token_userid
.remove
(
old_token
)
.unwrap
();
.open_tree
(
DEVICEID_TOKEN
)
// It will be removed from deviceid_token by the insert later
.unwrap
()
.get
(
device_id
)
.unwrap
()
{
self
.0
.open_tree
(
TOKEN_USERID
)
.unwrap
()
.remove
(
old_token
)
.unwrap
();
// It will be removed from DEVICEID_TOKEN by the insert later
}
}
// Assign token to device_id
// Assign token to device_id
self
.0
self
.db.deviceid_token
.insert
(
device_id
,
&*
token
)
.unwrap
();
.open_tree
(
DEVICEID_TOKEN
)
.unwrap
()
.insert
(
device_id
,
&*
token
)
.unwrap
();
// Assign token to user
// Assign token to user
self
.0
self
.db
.open_tree
(
TOKEN_USERID
)
.token_userid
.unwrap
()
.insert
(
token
,
&*
user_id
.to_string
())
.insert
(
token
,
&*
user_id
.to_string
())
.unwrap
();
.unwrap
();
}
}
/// Create a new room event.
/// Create a new room event.
pub
fn
event_add
(
&
self
,
event
:
&
Event
,
room_id
:
&
RoomId
,
event_id
:
&
EventId
)
{
pub
fn
event_add
(
&
self
,
room_id
:
&
RoomId
,
event_id
:
&
EventId
,
event
:
&
Event
)
{
debug!
(
"{}"
,
serde_json
::
to_string
(
event
)
.unwrap
());
let
mut
key
=
room_id
.to_string
()
.as_bytes
()
.to_vec
();
todo!
();
key
.extend_from_slice
(
event_id
.to_string
()
.as_bytes
());
self
.db
.roomid_eventid_event
.insert
(
&
key
,
&*
serde_json
::
to_string
(
event
)
.unwrap
())
.unwrap
();
}
pub
fn
debug
(
&
self
)
{
self
.db
.debug
();
}
}
}
}
This diff is collapsed.
Click to expand it.
src/database.rs
0 → 100644
+
117
−
0
View file @
dba6c466
use
crate
::
utils
;
use
directories
::
ProjectDirs
;
use
sled
::
IVec
;
pub
struct
MultiValue
(
sled
::
Tree
);
impl
MultiValue
{
/// Get an iterator over all values.
pub
fn
iter_all
(
&
self
)
->
sled
::
Iter
{
self
.0
.iter
()
}
/// Get an iterator over all values of this id.
pub
fn
get_iter
(
&
self
,
id
:
&
[
u8
])
->
sled
::
Iter
{
// Data keys start with d
let
mut
key
=
vec!
[
b'd'
];
key
.extend_from_slice
(
id
.as_ref
());
key
.push
(
0xff
);
// Add delimiter so we don't find usernames starting with the same id
self
.0
.scan_prefix
(
key
)
}
/// Add another value to the id.
pub
fn
add
(
&
self
,
id
:
&
[
u8
],
value
:
IVec
)
{
// The new value will need a new index. We store the last used index in 'n' + id
let
mut
count_key
:
Vec
<
u8
>
=
vec!
[
b'n'
];
count_key
.extend_from_slice
(
id
.as_ref
());
// Increment the last index and use that
let
index
=
self
.0
.update_and_fetch
(
&
count_key
,
utils
::
increment
)
.unwrap
()
.unwrap
();
// Data keys start with d
let
mut
key
=
vec!
[
b'd'
];
key
.extend_from_slice
(
id
.as_ref
());
key
.push
(
0xff
);
key
.extend_from_slice
(
&
index
);
self
.0
.insert
(
key
,
value
)
.unwrap
();
}
}
pub
struct
Database
{
pub
userid_password
:
sled
::
Tree
,
pub
userid_deviceids
:
MultiValue
,
pub
deviceid_token
:
sled
::
Tree
,
pub
token_userid
:
sled
::
Tree
,
pub
roomid_eventid_event
:
sled
::
Tree
,
_db
:
sled
::
Db
,
}
impl
Database
{
/// Load an existing database or create a new one.
pub
fn
load_or_create
(
hostname
:
&
str
)
->
Self
{
let
mut
path
=
ProjectDirs
::
from
(
"xyz"
,
"koesters"
,
"matrixserver"
)
.unwrap
()
.data_dir
()
.to_path_buf
();
path
.push
(
hostname
);
let
db
=
sled
::
open
(
&
path
)
.unwrap
();
Self
{
userid_password
:
db
.open_tree
(
"userid_password"
)
.unwrap
(),
userid_deviceids
:
MultiValue
(
db
.open_tree
(
"userid_deviceids"
)
.unwrap
()),
deviceid_token
:
db
.open_tree
(
"deviceid_token"
)
.unwrap
(),
token_userid
:
db
.open_tree
(
"token_userid"
)
.unwrap
(),
roomid_eventid_event
:
db
.open_tree
(
"roomid_eventid_event"
)
.unwrap
(),
_db
:
db
,
}
}
pub
fn
debug
(
&
self
)
{
println!
(
"# UserId -> Password:"
);
for
(
k
,
v
)
in
self
.userid_password
.iter
()
.map
(|
r
|
r
.unwrap
())
{
println!
(
"{} -> {}"
,
String
::
from_utf8_lossy
(
&
k
),
String
::
from_utf8_lossy
(
&
v
),
);
}
println!
(
"# UserId -> DeviceIds:"
);
for
(
k
,
v
)
in
self
.userid_deviceids
.iter_all
()
.map
(|
r
|
r
.unwrap
())
{
println!
(
"{} -> {}"
,
String
::
from_utf8_lossy
(
&
k
),
String
::
from_utf8_lossy
(
&
v
),
);
}
println!
(
"# DeviceId -> Token:"
);
for
(
k
,
v
)
in
self
.deviceid_token
.iter
()
.map
(|
r
|
r
.unwrap
())
{
println!
(
"{} -> {}"
,
String
::
from_utf8_lossy
(
&
k
),
String
::
from_utf8_lossy
(
&
v
),
);
}
println!
(
"# Token -> UserId:"
);
for
(
k
,
v
)
in
self
.token_userid
.iter
()
.map
(|
r
|
r
.unwrap
())
{
println!
(
"{} -> {}"
,
String
::
from_utf8_lossy
(
&
k
),
String
::
from_utf8_lossy
(
&
v
),
);
}
println!
(
"# RoomId + EventId -> Event:"
);
for
(
k
,
v
)
in
self
.roomid_eventid_event
.iter
()
.map
(|
r
|
r
.unwrap
())
{
println!
(
"{} -> {}"
,
String
::
from_utf8_lossy
(
&
k
),
String
::
from_utf8_lossy
(
&
v
),
);
}
}
}
This diff is collapsed.
Click to expand it.
src/main.rs
+
15
−
11
View file @
dba6c466
#![feature(proc_macro_hygiene,
decl_macro)]
#![feature(proc_macro_hygiene,
decl_macro)]
mod
data
;
mod
data
;
mod
database
;
mod
ruma_wrapper
;
mod
ruma_wrapper
;
mod
utils
;
mod
utils
;
pub
use
data
::
Data
;
pub
use
data
::
Data
;
pub
use
database
::
Database
;
use
log
::
debug
;
use
log
::
debug
;
use
rocket
::{
get
,
post
,
put
,
routes
,
State
};
use
rocket
::{
get
,
post
,
put
,
routes
,
State
};
use
ruma_client_api
::{
use
ruma_client_api
::{
...
@@ -14,13 +17,14 @@
...
@@ -14,13 +17,14 @@
},
},
unversioned
::
get_supported_versions
,
unversioned
::
get_supported_versions
,
};
};
use
ruma_events
::
collections
::
all
::
Event
;
use
ruma_events
::{
collections
::
all
::
Event
,
room
::
message
::
MessageEvent
};
use
ruma_events
::
room
::
message
::
MessageEvent
;
use
ruma_identifiers
::{
EventId
,
UserId
};
use
ruma_identifiers
::{
EventId
,
UserId
};
use
ruma_wrapper
::{
MatrixResult
,
Ruma
};
use
ruma_wrapper
::{
MatrixResult
,
Ruma
};
use
serde_json
::
map
::
Map
;
use
serde_json
::
map
::
Map
;
use
std
::
convert
::
TryFrom
;
use
std
::{
use
std
::{
collections
::
HashMap
,
convert
::
TryInto
};
collections
::
HashMap
,
convert
::{
TryFrom
,
TryInto
},
};
#[get(
"/_matrix/client/versions"
)]
#[get(
"/_matrix/client/versions"
)]
fn
get_supported_versions_route
()
->
MatrixResult
<
get_supported_versions
::
Response
>
{
fn
get_supported_versions_route
()
->
MatrixResult
<
get_supported_versions
::
Response
>
{
...
@@ -90,7 +94,7 @@ fn register_route(
...
@@ -90,7 +94,7 @@ fn register_route(
MatrixResult
(
Ok
(
register
::
Response
{
MatrixResult
(
Ok
(
register
::
Response
{
access_token
:
token
,
access_token
:
token
,
home_server
:
data
.hostname
(),
home_server
:
data
.hostname
()
.to_owned
()
,
user_id
,
user_id
,
device_id
,
device_id
,
}))
}))
...
@@ -153,7 +157,7 @@ fn login_route(data: State<Data>, body: Ruma<login::Request>) -> MatrixResult<lo
...
@@ -153,7 +157,7 @@ fn login_route(data: State<Data>, body: Ruma<login::Request>) -> MatrixResult<lo
.clone
()
.clone
()
.unwrap_or
(
"TODO:randomdeviceid"
.to_owned
());
.unwrap_or
(
"TODO:randomdeviceid"
.to_owned
());
// Add device
(TODO: We might not want to call it when using an existing device)
// Add device
data
.device_add
(
&
user_id
,
&
device_id
);
data
.device_add
(
&
user_id
,
&
device_id
);
// Generate a new token for the device
// Generate a new token for the device
...
@@ -163,7 +167,7 @@ fn login_route(data: State<Data>, body: Ruma<login::Request>) -> MatrixResult<lo
...
@@ -163,7 +167,7 @@ fn login_route(data: State<Data>, body: Ruma<login::Request>) -> MatrixResult<lo
return
MatrixResult
(
Ok
(
login
::
Response
{
return
MatrixResult
(
Ok
(
login
::
Response
{
user_id
,
user_id
,
access_token
:
token
,
access_token
:
token
,
home_server
:
Some
(
data
.hostname
()),
home_server
:
Some
(
data
.hostname
()
.to_owned
()
),
device_id
,
device_id
,
well_known
:
None
,
well_known
:
None
,
}));
}));
...
@@ -217,6 +221,8 @@ fn create_message_event_route(
...
@@ -217,6 +221,8 @@ fn create_message_event_route(
// Generate event id
// Generate event id
let
event_id
=
EventId
::
try_from
(
"$TODOrandomeventid:localhost"
)
.unwrap
();
let
event_id
=
EventId
::
try_from
(
"$TODOrandomeventid:localhost"
)
.unwrap
();
data
.event_add
(
data
.event_add
(
&
body
.room_id
,
&
event_id
,
&
Event
::
RoomMessage
(
MessageEvent
{
&
Event
::
RoomMessage
(
MessageEvent
{
content
:
body
.data
.clone
()
.into_result
()
.unwrap
(),
content
:
body
.data
.clone
()
.into_result
()
.unwrap
(),
event_id
:
event_id
.clone
(),
event_id
:
event_id
.clone
(),
...
@@ -225,8 +231,6 @@ fn create_message_event_route(
...
@@ -225,8 +231,6 @@ fn create_message_event_route(
sender
:
body
.user_id
.clone
()
.expect
(
"user is authenticated"
),
sender
:
body
.user_id
.clone
()
.expect
(
"user is authenticated"
),
unsigned
:
Map
::
default
(),
unsigned
:
Map
::
default
(),
}),
}),
&
body
.room_id
,
&
event_id
,
);
);
MatrixResult
(
Ok
(
create_message_event
::
Response
{
event_id
}))
MatrixResult
(
Ok
(
create_message_event
::
Response
{
event_id
}))
...
@@ -239,8 +243,8 @@ fn main() {
...
@@ -239,8 +243,8 @@ fn main() {
}
}
pretty_env_logger
::
init
();
pretty_env_logger
::
init
();
let
data
=
Data
::
load_or_create
();
let
data
=
Data
::
load_or_create
(
"localhost"
);
data
.
set_hostname
(
"localhost"
);
data
.
debug
(
);
rocket
::
ignite
()
rocket
::
ignite
()
.mount
(
.mount
(
...
...
This diff is collapsed.
Click to expand it.
src/utils.rs
+
16
−
14
View file @
dba6c466
use
std
::
time
::{
SystemTime
,
UNIX_EPOCH
};
use
std
::{
convert
::
TryInto
,
time
::{
SystemTime
,
UNIX_EPOCH
},
};
pub
fn
millis_since_unix_epoch
()
->
js_int
::
UInt
{
pub
fn
millis_since_unix_epoch
()
->
js_int
::
UInt
{
(
SystemTime
::
now
()
(
SystemTime
::
now
()
...
@@ -8,20 +11,19 @@ pub fn millis_since_unix_epoch() -> js_int::UInt {
...
@@ -8,20 +11,19 @@ pub fn millis_since_unix_epoch() -> js_int::UInt {
.into
()
.into
()
}
}
pub
fn
bytes_to_string
(
bytes
:
&
[
u8
])
->
String
{
pub
fn
increment
(
old
:
Option
<&
[
u8
]
>
)
->
Option
<
Vec
<
u8
>>
{
String
::
from_utf8
(
bytes
.to_vec
())
.expect
(
"convert bytes to string"
)
let
number
=
match
old
{
}
Some
(
bytes
)
=>
{
let
array
:
[
u8
;
8
]
=
bytes
.try_into
()
.unwrap
();
let
number
=
u64
::
from_be_bytes
(
array
);
number
+
1
}
None
=>
0
,
};
pub
fn
vec_to_bytes
(
vec
:
Vec
<
String
>
)
->
Vec
<
u8
>
{
Some
(
number
.to_be_bytes
()
.to_vec
())
vec
.into_iter
()
.map
(|
string
|
string
.into_bytes
())
.collect
::
<
Vec
<
Vec
<
u8
>>>
()
.join
(
&
0
)
}
}
pub
fn
bytes_to_vec
(
bytes
:
&
[
u8
])
->
Vec
<
String
>
{
pub
fn
string_from_bytes
(
bytes
:
&
[
u8
])
->
String
{
bytes
String
::
from_utf8
(
bytes
.to_vec
())
.expect
(
"bytes are valid utf8"
)
.split
(|
&
b
|
b
==
0
)
.map
(|
bytes_string
|
bytes_to_string
(
bytes_string
))
.collect
::
<
Vec
<
String
>>
()
}
}
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment