Skip to content
This repository has been archived by the owner on Sep 2, 2021. It is now read-only.

Commit

Permalink
Fixing some timing issues and resolve some typos
Browse files Browse the repository at this point in the history
  • Loading branch information
farodin91 committed Jan 17, 2017
1 parent b7c200f commit ae282b1
Show file tree
Hide file tree
Showing 9 changed files with 89 additions and 44 deletions.
1 change: 0 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ serde = "0.8.21"
serde_derive = "0.8.21"
serde_json = "0.8.4"
serde_yaml = "0.5.0"
time = "0.1"
toml = "0.2.1"
unicase = "1.4.0"
url = "1.2.4"
Expand Down
66 changes: 56 additions & 10 deletions src/api/r0/presence.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ use iron::status::Status;
use iron::{Chain, Handler, IronResult, IronError, Plugin, Request, Response};
use ruma_identifiers::UserId;
use ruma_events::presence::PresenceState;
use time;

use config::Config;
use db::DB;
Expand All @@ -14,7 +13,7 @@ use middleware::{AccessTokenAuth, JsonRequest, MiddlewareChain, UserIdParam};
use modifier::SerializableResponse;
use models::room_membership::RoomMembership;
use models::presence_list::PresenceList;
use models::presence_status::PresenceStatus;
use models::presence_status::{PresenceStatus, get_now};
use models::user::User;

/// The PUT `/presence/:user_id/status` endpoint.
Expand Down Expand Up @@ -78,7 +77,7 @@ struct GetPresenceStatusResponse {
/// Whether the user is currently active.
currently_active: bool,
/// The length of time in milliseconds since an action was performed by this user.
last_active_ago: u64,
last_active_ago: i64,
/// This user's presence. One of: ["online", "offline", "unavailable"]
presence: PresenceState,
}
Expand All @@ -94,15 +93,15 @@ impl Handler for GetPresenceStatus {
let connection = DB::from_request(request)?;

if user.id != user_id {
let rooms = RoomMembership::find_common_joined_rooms(
let rooms = RoomMembership::find_common_rooms(
&connection,
&user.id,
&user_id,
"join"
)?;
if rooms.is_empty() {
Err(ApiError::unauthorized(
format!("You are not authorized to get the presence status for th given user_id: {}.", user_id)
format!("You are not authorized to get the presence status for the given user_id: {}.", user_id)
))?;
}
}
Expand All @@ -117,14 +116,13 @@ impl Handler for GetPresenceStatus {
let presence_state: PresenceState = status.presence.parse()
.expect("Database insert should ensure a PresenceState");

let now = time::get_time();
let last_update = time::Timespec::new(status.updated_at.0, 0);
let last_active_ago: time::Duration = last_update - now;
let now = get_now();
let last_active_ago = now - status.updated_at.0;

let response = GetPresenceStatusResponse {
status_msg: status.status_msg,
currently_active: PresenceState::Online == presence_state,
last_active_ago: last_active_ago.num_milliseconds() as u64,
last_active_ago: last_active_ago,
presence: presence_state,
};

Expand Down Expand Up @@ -202,9 +200,13 @@ impl Handler for GetPresenceList {

#[cfg(test)]
mod tests {
use test::Test;
use std::thread;
use std::time::Duration;

use iron::status::Status;

use test::Test;

#[test]
fn basic_presence_status() {
let test = Test::new();
Expand Down Expand Up @@ -435,4 +437,48 @@ mod tests {
let array = response.json().as_array().unwrap();
assert_eq!(array.len(), 0);
}

#[test]
fn last_active_ago() {
let test = Test::new();
let alice = test.create_user();
let bob = test.create_user();
let carl = test.create_user();

let room_options = format!(r#"{{"invite": ["{}", "{}"]}}"#, bob.id, carl.id);
let room_id = test.create_room_with_params(&alice.token, &room_options);

assert_eq!(test.join_room(&bob.token, &room_id).status, Status::Ok);
assert_eq!(test.join_room(&carl.token, &room_id).status, Status::Ok);

test.update_presence(&alice.token, &alice.id, r#"{"presence":"online"}"#);
thread::sleep(Duration::from_secs(2));

test.update_presence(&bob.token, &bob.id, r#"{"presence":"online"}"#);
thread::sleep(Duration::from_secs(2));

let alice_presence_path = format!(
"/_matrix/client/r0/presence/{}/status?access_token={}",
alice.id,
carl.token
);

let bob_presence_path = format!(
"/_matrix/client/r0/presence/{}/status?access_token={}",
bob.id,
carl.token
);

let bob_response = test.get(&bob_presence_path);
assert_eq!(bob_response.status, Status::Ok);
let last_active_ago = bob_response.json().find("last_active_ago").unwrap().as_u64().unwrap();
assert!(last_active_ago > 2_000);
assert!(last_active_ago < 2_500);

let alice_response = test.get(&alice_presence_path);
assert_eq!(alice_response.status, Status::Ok);
let last_active_ago = alice_response.json().find("last_active_ago").unwrap().as_u64().unwrap();
assert!(last_active_ago > 4_000);
assert!(last_active_ago < 4_500);
}
}
11 changes: 0 additions & 11 deletions src/api/r0/profile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -239,8 +239,6 @@ mod tests {
use test::Test;
use iron::status::Status;
use query::SyncOptions;
use std::time::Duration;
use std::thread;

#[test]
fn get_displayname_non_existent_user() {
Expand Down Expand Up @@ -510,9 +508,6 @@ mod tests {
timeout: 0
};

// The precision is in seconds.
thread::sleep(Duration::from_secs(2));

let response = test.sync(&carl.token, options);
let array = response
.json()
Expand Down Expand Up @@ -560,9 +555,6 @@ mod tests {
timeout: 0
};

// The precision is in seconds.
thread::sleep(Duration::from_secs(2));

let response = test.sync(&carl.token, options);
let array = response
.json()
Expand Down Expand Up @@ -596,9 +588,6 @@ mod tests {
timeout: 0
};

// The precision is in seconds.
thread::sleep(Duration::from_secs(2));

let response = test.sync(&carl.token, options);
let array = response
.json()
Expand Down
1 change: 0 additions & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ extern crate serde;
#[macro_use] extern crate serde_derive;
extern crate serde_json;
extern crate serde_yaml;
extern crate time;
extern crate toml;
extern crate unicase;
extern crate url;
Expand Down
15 changes: 7 additions & 8 deletions src/models/presence_list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,9 @@ use diesel::pg::PgConnection;
use ruma_events::EventType;
use ruma_events::presence::{PresenceEvent, PresenceEventContent, PresenceState};
use ruma_identifiers::UserId;
use time;

use error::ApiError;
use models::presence_status::PresenceStatus;
use models::presence_status::{PresenceStatus, get_now};
use models::profile::Profile;
use models::room_membership::RoomMembership;
use models::user::User;
Expand Down Expand Up @@ -88,7 +87,7 @@ impl PresenceList {
let mut invites: Vec<PresenceList> = Vec::new();
for ref observed_user in invite.clone() {
if observed_user != user_id {
let rooms = RoomMembership::get_common_rooms(
let rooms = RoomMembership::filter_rooms_by_state(
connection,
&room_ids,
observed_user,
Expand Down Expand Up @@ -136,7 +135,7 @@ impl PresenceList {
pub fn find_events_by_uid(
connection: &PgConnection,
user_id: &UserId,
since: Option<time::Timespec>
since: Option<i64>
) -> Result<(i64, Vec<PresenceEvent>), ApiError> {
let mut max_ordering = -1;

Expand All @@ -149,11 +148,11 @@ impl PresenceList {
let mut events = Vec::new();

for status in users_status {
let last_update = time::Timespec::new(status.updated_at.0, 0);
max_ordering = cmp::max(last_update.sec, max_ordering);
let last_update = status.updated_at.0;
max_ordering = cmp::max(last_update, max_ordering);

let presence_state: PresenceState = status.presence.parse().unwrap();
let last_active_ago: time::Duration = last_update - time::get_time();
let last_active_ago = get_now() - last_update;

let profile: Option<&Profile> = profiles.iter()
.filter(|profile| profile.id == status.user_id)
Expand All @@ -172,7 +171,7 @@ impl PresenceList {
avatar_url: avatar_url,
currently_active: PresenceState::Online == presence_state,
displayname: displayname,
last_active_ago: Some(last_active_ago.num_milliseconds() as u64),
last_active_ago: Some(last_active_ago as u64),
presence: presence_state,
user_id: status.user_id,
},
Expand Down
29 changes: 22 additions & 7 deletions src/models/presence_status.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
//! Storage and querying of presence status.
use chrono::{Duration, NaiveDateTime, NaiveDate, UTC};
use diesel::{
insert,
Connection,
Expand All @@ -16,7 +17,6 @@ use diesel::pg::data_types::PgTimestamp;
use diesel::result::Error as DieselError;
use ruma_events::presence::PresenceState;
use ruma_identifiers::{UserId, EventId};
use time;

use error::ApiError;
use schema::presence_status;
Expand All @@ -32,7 +32,9 @@ pub struct NewPresenceStatus {
/// The current presence state.
pub presence: String,
/// A possible status message from the user.
pub status_msg: Option<String>
pub status_msg: Option<String>,
/// Timestamp of the last update.
pub updated_at: PgTimestamp,
}

/// A Matrix presence status.
Expand All @@ -52,6 +54,20 @@ pub struct PresenceStatus {
pub updated_at: PgTimestamp,
}

/// Return now
pub fn get_now() -> i64 {
// Use seconds instead of microseconds (default for PgTimestamp)
let now = UTC::now().naive_utc();
get_milliseconds(now)
}

/// Return `time` in milliseconds with a same epoch as PostgreSQL.
pub fn get_milliseconds(time: NaiveDateTime) -> i64 {
let epoch = NaiveDate::from_ymd(2000, 1, 1).and_hms(0, 0, 0);
let duration: Duration = time - epoch;
duration.num_milliseconds()
}

impl PresenceStatus {
/// Update or insert a presence status entry.
pub fn upsert(
Expand Down Expand Up @@ -91,9 +107,7 @@ impl PresenceStatus {
self.presence = presence;
self.status_msg = status_msg;
self.event_id = event_id.clone();

// Use seconds instead of microseconds (default for PgTimestamp)
self.updated_at = PgTimestamp(time::get_time().sec);
self.updated_at = PgTimestamp(get_now());

match self.save_changes::<PresenceStatus>(connection) {
Ok(_) => Ok(()),
Expand All @@ -114,6 +128,7 @@ impl PresenceStatus {
event_id: event_id.clone(),
presence: presence,
status_msg: status_msg,
updated_at: PgTimestamp(get_now()),
};
insert(&new_status)
.into(presence_status::table)
Expand Down Expand Up @@ -141,11 +156,11 @@ impl PresenceStatus {
pub fn get_users(
connection: &PgConnection,
users: &Vec<UserId>,
since: Option<time::Timespec>,
since: Option<i64>,
) -> Result<Vec<PresenceStatus>, ApiError> {
match since {
Some(since) => {
let time = PgTimestamp(since.sec);
let time = PgTimestamp(since);

presence_status::table
.filter(presence_status::user_id.eq(any(users)))
Expand Down
6 changes: 3 additions & 3 deletions src/models/room_membership.rs
Original file line number Diff line number Diff line change
Expand Up @@ -405,7 +405,7 @@ impl RoomMembership {
}

/// Return `RoomId`'s for given `UserId`'s.
pub fn find_common_joined_rooms(
pub fn find_common_rooms(
connection: &PgConnection,
user_id: &UserId,
observed_user_id: &UserId,
Expand All @@ -425,8 +425,8 @@ impl RoomMembership {
.map_err(ApiError::from)
}

/// Return `RoomId`'s for given `RoomId`'s and `UserId`.
pub fn get_common_rooms(
/// Filter `RoomId`'s for `UserId` and membership state.
pub fn filter_rooms_by_state(
connection: &PgConnection,
room_ids: &Vec<RoomId>,
user_id: &UserId,
Expand Down
3 changes: 1 addition & 2 deletions src/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ use ruma_events::presence::PresenceState;
use ruma_events::collections::all::{RoomEvent, StateEvent};
use ruma_identifiers::RoomId;
use serde_json::Value;
use time;

use error::ApiError;
use models::event::Event;
Expand Down Expand Up @@ -208,7 +207,7 @@ impl Sync {

let since = match *context {
Context::Incremental(batch) | Context::FullState(batch) => {
Some(time::Timespec::new(batch.presence_key, 0))
Some(batch.presence_key)
}
Context::Initial => None,
};
Expand Down

0 comments on commit ae282b1

Please sign in to comment.