Message timestamps
This commit is contained in:
parent
3543ef2824
commit
03a9df81ec
@ -410,23 +410,42 @@ button:hover::after {
|
|||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
white-space: pre-wrap;
|
white-space: pre-wrap;
|
||||||
}
|
}
|
||||||
|
#msg_log li {
|
||||||
|
display: flex;
|
||||||
|
align-items: end;
|
||||||
|
gap: 10px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
padding-right: 10px;
|
||||||
|
}
|
||||||
|
#msg_log li>div {
|
||||||
|
flex-grow: 1;
|
||||||
|
}
|
||||||
|
#msg_log li .timestamp {
|
||||||
|
opacity: .5;
|
||||||
|
font-family: "Liberation Sans", Arial, sans-serif;
|
||||||
|
font-size: .8em;
|
||||||
|
}
|
||||||
#msg_log p {
|
#msg_log p {
|
||||||
font-size: 1.1em;
|
font-size: 1.1em;
|
||||||
word-break: break-word;
|
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
#msg_log .avatar {
|
||||||
|
font-size: .8em;
|
||||||
|
}
|
||||||
#msg_log li .header {
|
#msg_log li .header {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
margin-top: 15px;
|
|
||||||
}
|
}
|
||||||
#msg_log li .header p {
|
#msg_log li .header p {
|
||||||
color: var(--accent);
|
color: var(--accent);
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
|
margin-left: .5em;
|
||||||
}
|
}
|
||||||
#msg_log li .content {
|
#msg_log li .content {
|
||||||
margin-left: 3em;
|
margin-left: 3em;
|
||||||
margin-bottom: 10px;
|
}
|
||||||
|
#msg_log li .content p {
|
||||||
|
word-break: break-word;
|
||||||
}
|
}
|
||||||
#msg_log a {
|
#msg_log a {
|
||||||
color: #238cf5;
|
color: #238cf5;
|
||||||
|
@ -215,7 +215,7 @@ document.getElementById("attach_file").onchange = function(event) {
|
|||||||
formData.append("", files[i]);
|
formData.append("", files[i]);
|
||||||
fetch("/send_file", {method: "POST", body: formData}).then(response => {
|
fetch("/send_file", {method: "POST", body: formData}).then(response => {
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
response.text().then(uuid => onFileSent(currentSessionId, uuid, files[i].name));
|
response.text().then(uuid => onFileSent(currentSessionId, new Date.now(), uuid, files[i].name));
|
||||||
} else {
|
} else {
|
||||||
console.log(response);
|
console.log(response);
|
||||||
}
|
}
|
||||||
@ -436,6 +436,16 @@ function getCookie(cname) {
|
|||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
function parseTimestamp(timestamp) {
|
||||||
|
return new Date(Number(timestamp) * 1000);
|
||||||
|
}
|
||||||
|
function toTwoNumbers(n) {
|
||||||
|
if (n < 10) {
|
||||||
|
return '0'+n;
|
||||||
|
} else {
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
socket.onopen = function() {
|
socket.onopen = function() {
|
||||||
console.log("Connected");
|
console.log("Connected");
|
||||||
@ -467,10 +477,10 @@ socket.onmessage = function(msg) {
|
|||||||
onNewSession(args[1], args[2] === "true", args[3], args[4], msg.data.slice(args[0].length+args[1].length+args[2].length+args[3].length+args[4].length+5));
|
onNewSession(args[1], args[2] === "true", args[3], args[4], msg.data.slice(args[0].length+args[1].length+args[2].length+args[3].length+args[4].length+5));
|
||||||
break;
|
break;
|
||||||
case "new_message":
|
case "new_message":
|
||||||
onNewMessage(args[1], args[2] === "true", msg.data.slice(args[0].length+args[1].length+args[2].length+3));
|
onNewMessage(args[1], args[2] === "true", parseTimestamp(args[3]), msg.data.slice(args[0].length+args[1].length+args[2].length+args[3].length+4));
|
||||||
break;
|
break;
|
||||||
case "file":
|
case "file":
|
||||||
onFileReceived(args[1], args[2], msg.data.slice(args[0].length+args[1].length+args[2].length+3));
|
onFileReceived(args[1], parseTimestamp(args[2]), args[3], msg.data.slice(args[0].length+args[1].length+args[2].length+args[3].length+4));
|
||||||
break;
|
break;
|
||||||
case "files_transfer":
|
case "files_transfer":
|
||||||
onNewFilesTransfer(args[1], args[2], msg.data.slice(args[0].length+args[1].length+args[2].length+3));
|
onNewFilesTransfer(args[1], args[2], msg.data.slice(args[0].length+args[1].length+args[2].length+3));
|
||||||
@ -600,8 +610,8 @@ function onMsgOrFileReceived(sessionId, outgoing, body) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function onNewMessage(sessionId, outgoing, msg) {
|
function onNewMessage(sessionId, outgoing, timestamp, msg) {
|
||||||
msgHistory.get(sessionId).push([outgoing, false, msg]);
|
msgHistory.get(sessionId).push([outgoing, timestamp, false, msg]);
|
||||||
onMsgOrFileReceived(sessionId, outgoing, msg);
|
onMsgOrFileReceived(sessionId, outgoing, msg);
|
||||||
}
|
}
|
||||||
function onNewFilesTransfer(sessionId, index, filesInfo) {
|
function onNewFilesTransfer(sessionId, index, filesInfo) {
|
||||||
@ -731,29 +741,32 @@ function onIncFilesTransfer(sessionId, chunkSize) {
|
|||||||
}
|
}
|
||||||
function onMsgsLoad(sessionId, strMsgs) {
|
function onMsgsLoad(sessionId, strMsgs) {
|
||||||
let msgs = strMsgs.split(' ');
|
let msgs = strMsgs.split(' ');
|
||||||
let n = 0;
|
if (msgs.length > 3) {
|
||||||
while (n < msgs.length) {
|
let n = 0;
|
||||||
let outgoing = msgs[n+1] === "true";
|
while (n < msgs.length) {
|
||||||
switch (msgs[n]) {
|
let outgoing = msgs[n+1] === "true";
|
||||||
case 'm':
|
let timestamp = parseTimestamp(msgs[n+2]);
|
||||||
let msg = b64DecodeUnicode(msgs[n+2]);
|
switch (msgs[n]) {
|
||||||
msgHistory.get(sessionId).unshift([outgoing, false, msg]);
|
case 'm':
|
||||||
n += 3;
|
let msg = b64DecodeUnicode(msgs[n+3]);
|
||||||
break;
|
msgHistory.get(sessionId).unshift([outgoing, timestamp, false, msg]);
|
||||||
case 'f':
|
n += 4;
|
||||||
let uuid = msgs[n+2];
|
break;
|
||||||
let fileName = b64DecodeUnicode(msgs[n+3]);
|
case 'f':
|
||||||
msgHistory.get(sessionId).unshift([outgoing, true, [uuid, fileName]]);
|
let uuid = msgs[n+3];
|
||||||
n += 4;
|
let fileName = b64DecodeUnicode(msgs[n+4]);
|
||||||
|
msgHistory.get(sessionId).unshift([outgoing, timestamp, true, [uuid, fileName]]);
|
||||||
|
n += 5;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
if (currentSessionId == sessionId) {
|
||||||
if (currentSessionId == sessionId) {
|
if (msg_log.scrollHeight - msg_log.scrollTop === msg_log.clientHeight) {
|
||||||
if (msg_log.scrollHeight - msg_log.scrollTop === msg_log.clientHeight) {
|
displayHistory();
|
||||||
displayHistory();
|
} else {
|
||||||
} else {
|
let backupHeight = msg_log.scrollHeight;
|
||||||
let backupHeight = msg_log.scrollHeight;
|
displayHistory(false);
|
||||||
displayHistory(false);
|
msg_log.scrollTop = msg_log.scrollHeight-backupHeight;
|
||||||
msg_log.scrollTop = msg_log.scrollHeight-backupHeight;
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -774,12 +787,12 @@ function onDisconnected(sessionId) {
|
|||||||
}
|
}
|
||||||
displaySessions();
|
displaySessions();
|
||||||
}
|
}
|
||||||
function onFileReceived(sessionId, uuid, file_name) {
|
function onFileReceived(sessionId, timestamp, uuid, file_name) {
|
||||||
msgHistory.get(sessionId).push([false, true, [uuid, file_name]]);
|
msgHistory.get(sessionId).push([false, timestamp, true, [uuid, file_name]]);
|
||||||
onMsgOrFileReceived(sessionId, false, file_name);
|
onMsgOrFileReceived(sessionId, false, file_name);
|
||||||
}
|
}
|
||||||
function onFileSent(sessionId, uuid, file_name) {
|
function onFileSent(sessionId, timestamp, uuid, file_name) {
|
||||||
msgHistory.get(sessionId).push([true, true, [uuid, file_name]]);
|
msgHistory.get(sessionId).push([true, timestamp, true, [uuid, file_name]]);
|
||||||
if (currentSessionId == sessionId) {
|
if (currentSessionId == sessionId) {
|
||||||
displayHistory();
|
displayHistory();
|
||||||
}
|
}
|
||||||
@ -1030,18 +1043,25 @@ function generateMsgHeader(name, sessionId) {
|
|||||||
div.appendChild(p);
|
div.appendChild(p);
|
||||||
return div;
|
return div;
|
||||||
}
|
}
|
||||||
|
function generateMessageTimestamp(timestamp) {
|
||||||
|
let p = document.createElement("p");
|
||||||
|
p.classList.add("timestamp");
|
||||||
|
p.title = timestamp;
|
||||||
|
p.textContent = toTwoNumbers(timestamp.getHours())+":"+toTwoNumbers(timestamp.getMinutes());
|
||||||
|
return p;
|
||||||
|
}
|
||||||
function generateMessage(name, sessionId, msg) {
|
function generateMessage(name, sessionId, msg) {
|
||||||
let p = document.createElement("p");
|
let p = document.createElement("p");
|
||||||
p.appendChild(document.createTextNode(msg));
|
p.appendChild(document.createTextNode(msg));
|
||||||
let div = document.createElement("div");
|
let div = document.createElement("div");
|
||||||
div.classList.add("content");
|
div.classList.add("content");
|
||||||
div.appendChild(linkifyElement(p));
|
div.appendChild(linkifyElement(p));
|
||||||
let li = document.createElement("li");
|
let divContainer = document.createElement("div");
|
||||||
if (typeof name !== "undefined") {
|
if (typeof name !== "undefined") {
|
||||||
li.appendChild(generateMsgHeader(name, sessionId));
|
divContainer.appendChild(generateMsgHeader(name, sessionId));
|
||||||
}
|
}
|
||||||
li.appendChild(div);
|
divContainer.appendChild(div);
|
||||||
return li;
|
return divContainer;
|
||||||
}
|
}
|
||||||
function generateFile(name, sessionId, outgoing, file_info) {
|
function generateFile(name, sessionId, outgoing, file_info) {
|
||||||
let div1 = document.createElement("div");
|
let div1 = document.createElement("div");
|
||||||
@ -1063,12 +1083,12 @@ function generateFile(name, sessionId, outgoing, file_info) {
|
|||||||
a.href = "/load_file?uuid="+file_info[0]+"&file_name="+encodeURIComponent(file_info[1]);
|
a.href = "/load_file?uuid="+file_info[0]+"&file_name="+encodeURIComponent(file_info[1]);
|
||||||
a.target = "_blank";
|
a.target = "_blank";
|
||||||
div1.appendChild(a);
|
div1.appendChild(a);
|
||||||
let li = document.createElement("li");
|
let divContainer = document.createElement("div");
|
||||||
if (typeof name !== "undefined") {
|
if (typeof name !== "undefined") {
|
||||||
li.appendChild(generateMsgHeader(name, sessionId));
|
divContainer.appendChild(generateMsgHeader(name, sessionId));
|
||||||
}
|
}
|
||||||
li.appendChild(div1);
|
divContainer.appendChild(div1);
|
||||||
return li;
|
return divContainer;
|
||||||
}
|
}
|
||||||
function generateFileInfo(fileName, fileSize, p) {
|
function generateFileInfo(fileName, fileSize, p) {
|
||||||
let span = document.createElement("span");
|
let span = document.createElement("span");
|
||||||
@ -1152,11 +1172,16 @@ function displayHistory(scrollToBottom = true) {
|
|||||||
sessionId = currentSessionId;
|
sessionId = currentSessionId;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (entry[1]) { //is file
|
let div;
|
||||||
msg_log.appendChild(generateFile(name, sessionId, entry[0], entry[2]));
|
if (entry[2]) { //is file
|
||||||
|
div = generateFile(name, sessionId, entry[0], entry[3]);
|
||||||
} else {
|
} else {
|
||||||
msg_log.appendChild(generateMessage(name, sessionId, entry[2]));
|
div = generateMessage(name, sessionId, entry[3]);
|
||||||
}
|
}
|
||||||
|
let li = document.createElement("li");
|
||||||
|
li.appendChild(div);
|
||||||
|
li.appendChild(generateMessageTimestamp(entry[1]));
|
||||||
|
msg_log.appendChild(li);
|
||||||
});
|
});
|
||||||
if (scrollToBottom) {
|
if (scrollToBottom) {
|
||||||
msg_log.scrollTop = msg_log.scrollHeight;
|
msg_log.scrollTop = msg_log.scrollHeight;
|
||||||
|
@ -43,12 +43,11 @@ fn get_database_path() -> String {
|
|||||||
AppDirs::new(Some(constants::APPLICATION_FOLDER), false).unwrap().data_dir.join(constants::DB_NAME).to_str().unwrap().to_owned()
|
AppDirs::new(Some(constants::APPLICATION_FOLDER), false).unwrap().data_dir.join(constants::DB_NAME).to_str().unwrap().to_owned()
|
||||||
}
|
}
|
||||||
|
|
||||||
struct EncryptedIdentity {
|
#[derive(Debug, Clone)]
|
||||||
name: String,
|
pub struct Message {
|
||||||
encrypted_keypair: Vec<u8>,
|
pub outgoing: bool,
|
||||||
salt: Vec<u8>,
|
pub timestamp: u64,
|
||||||
encrypted_master_key: Vec<u8>,
|
pub data: Vec<u8>,
|
||||||
encrypted_use_padding: Vec<u8>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Contact {
|
pub struct Contact {
|
||||||
@ -60,6 +59,14 @@ pub struct Contact {
|
|||||||
pub seen: bool,
|
pub seen: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct EncryptedIdentity {
|
||||||
|
name: String,
|
||||||
|
encrypted_keypair: Vec<u8>,
|
||||||
|
salt: Vec<u8>,
|
||||||
|
encrypted_master_key: Vec<u8>,
|
||||||
|
encrypted_use_padding: Vec<u8>,
|
||||||
|
}
|
||||||
|
|
||||||
pub struct Identity {
|
pub struct Identity {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub keypair: Keypair,
|
pub keypair: Keypair,
|
||||||
@ -242,16 +249,17 @@ impl Identity {
|
|||||||
Ok(file_uuid)
|
Ok(file_uuid)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn store_msg(&self, contact_uuid: &Uuid, outgoing: bool, data: &[u8]) -> Result<usize, rusqlite::Error> {
|
pub fn store_msg(&self, contact_uuid: &Uuid, message: Message) -> Result<usize, rusqlite::Error> {
|
||||||
let db = Connection::open(get_database_path())?;
|
let db = Connection::open(get_database_path())?;
|
||||||
db.execute(&format!("CREATE TABLE IF NOT EXISTS \"{}\" (outgoing BLOB, data BLOB)", contact_uuid), [])?;
|
db.execute(&format!("CREATE TABLE IF NOT EXISTS \"{}\" (outgoing BLOB, timestamp BLOB, data BLOB)", contact_uuid), [])?;
|
||||||
let outgoing_byte: u8 = bool_to_byte(outgoing);
|
let outgoing_byte: u8 = bool_to_byte(message.outgoing);
|
||||||
let encrypted_outgoing = crypto::encrypt_data(&[outgoing_byte], &self.master_key).unwrap();
|
let encrypted_outgoing = crypto::encrypt_data(&[outgoing_byte], &self.master_key).unwrap();
|
||||||
let encrypted_data = crypto::encrypt_data(data, &self.master_key).unwrap();
|
let encrypted_timestamp = crypto::encrypt_data(&message.timestamp.to_be_bytes(), &self.master_key).unwrap();
|
||||||
db.execute(&format!("INSERT INTO \"{}\" (outgoing, data) VALUES (?1, ?2)", contact_uuid), params![encrypted_outgoing, encrypted_data])
|
let encrypted_data = crypto::encrypt_data(&message.data, &self.master_key).unwrap();
|
||||||
|
db.execute(&format!("INSERT INTO \"{}\" (outgoing, timestamp, data) VALUES (?1, ?2, ?3)", contact_uuid), params![encrypted_outgoing, encrypted_timestamp, encrypted_data])
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn load_msgs(&self, contact_uuid: &Uuid, offset: usize, mut count: usize) -> Option<Vec<(bool, Vec<u8>)>> {
|
pub fn load_msgs(&self, contact_uuid: &Uuid, offset: usize, mut count: usize) -> Option<Vec<Message>> {
|
||||||
match Connection::open(get_database_path()) {
|
match Connection::open(get_database_path()) {
|
||||||
Ok(db) => {
|
Ok(db) => {
|
||||||
if let Ok(mut stmt) = db.prepare(&format!("SELECT count(*) FROM \"{}\"", contact_uuid)) {
|
if let Ok(mut stmt) = db.prepare(&format!("SELECT count(*) FROM \"{}\"", contact_uuid)) {
|
||||||
@ -262,7 +270,7 @@ impl Identity {
|
|||||||
if offset+count >= total {
|
if offset+count >= total {
|
||||||
count = total-offset;
|
count = total-offset;
|
||||||
}
|
}
|
||||||
let mut stmt = db.prepare(&format!("SELECT outgoing, data FROM \"{}\" LIMIT {} OFFSET {}", contact_uuid, count, total-offset-count)).unwrap();
|
let mut stmt = db.prepare(&format!("SELECT outgoing, timestamp, data FROM \"{}\" LIMIT {} OFFSET {}", contact_uuid, count, total-offset-count)).unwrap();
|
||||||
let mut rows = stmt.query([]).unwrap();
|
let mut rows = stmt.query([]).unwrap();
|
||||||
let mut msgs = Vec::new();
|
let mut msgs = Vec::new();
|
||||||
while let Ok(Some(row)) = rows.next() {
|
while let Ok(Some(row)) = rows.next() {
|
||||||
@ -271,9 +279,19 @@ impl Identity {
|
|||||||
Ok(outgoing) => {
|
Ok(outgoing) => {
|
||||||
match byte_to_bool(outgoing[0]) {
|
match byte_to_bool(outgoing[0]) {
|
||||||
Ok(outgoing) => {
|
Ok(outgoing) => {
|
||||||
let encrypted_data: Vec<u8> = row.get(1).unwrap();
|
let encrypted_timestamp: Vec<u8> = row.get(1).unwrap();
|
||||||
match crypto::decrypt_data(encrypted_data.as_slice(), &self.master_key) {
|
match crypto::decrypt_data(&encrypted_timestamp, &self.master_key) {
|
||||||
Ok(data) => msgs.push((outgoing, data)),
|
Ok(timestamp) => {
|
||||||
|
let encrypted_data: Vec<u8> = row.get(2).unwrap();
|
||||||
|
match crypto::decrypt_data(encrypted_data.as_slice(), &self.master_key) {
|
||||||
|
Ok(data) => msgs.push(Message {
|
||||||
|
outgoing,
|
||||||
|
timestamp: u64::from_be_bytes(timestamp.try_into().unwrap()),
|
||||||
|
data,
|
||||||
|
}),
|
||||||
|
Err(e) => print_error!(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
Err(e) => print_error!(e)
|
Err(e) => print_error!(e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
18
src/main.rs
18
src/main.rs
@ -13,7 +13,6 @@ use image::GenericImageView;
|
|||||||
use tokio::{net::TcpListener, runtime::Handle, sync::mpsc};
|
use tokio::{net::TcpListener, runtime::Handle, sync::mpsc};
|
||||||
use actix_web::{App, HttpMessage, HttpRequest, HttpResponse, HttpServer, http::{header, CookieBuilder}, web, web::Data};
|
use actix_web::{App, HttpMessage, HttpRequest, HttpResponse, HttpServer, http::{header, CookieBuilder}, web, web::Data};
|
||||||
use actix_multipart::Multipart;
|
use actix_multipart::Multipart;
|
||||||
use tungstenite::Message;
|
|
||||||
use futures::{StreamExt, TryStreamExt};
|
use futures::{StreamExt, TryStreamExt};
|
||||||
use rand::{RngCore, rngs::OsRng};
|
use rand::{RngCore, rngs::OsRng};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
@ -24,6 +23,7 @@ use utils::escape_double_quote;
|
|||||||
use identity::Identity;
|
use identity::Identity;
|
||||||
use session_manager::{SessionManager, SessionCommand};
|
use session_manager::{SessionManager, SessionCommand};
|
||||||
use ui_interface::UiConnection;
|
use ui_interface::UiConnection;
|
||||||
|
use crate::{identity::Message, utils::get_unix_timestamp_sec};
|
||||||
|
|
||||||
async fn start_websocket_server(global_vars: Arc<RwLock<GlobalVars>>) -> u16 {
|
async fn start_websocket_server(global_vars: Arc<RwLock<GlobalVars>>) -> u16 {
|
||||||
let websocket_bind_addr = env::var("AIRA_WEBSOCKET_ADDR").unwrap_or("127.0.0.1".to_owned());
|
let websocket_bind_addr = env::var("AIRA_WEBSOCKET_ADDR").unwrap_or("127.0.0.1".to_owned());
|
||||||
@ -137,7 +137,7 @@ async fn websocket_worker(mut ui_connection: UiConnection, global_vars: Arc<RwLo
|
|||||||
match ui_connection.websocket.read_message() {
|
match ui_connection.websocket.read_message() {
|
||||||
Ok(msg) => {
|
Ok(msg) => {
|
||||||
if msg.is_ping() {
|
if msg.is_ping() {
|
||||||
ui_connection.write_message(Message::Pong(Vec::new())); //not sure if I'm doing this right
|
ui_connection.write_message(tungstenite::Message::Pong(Vec::new())); //not sure if I'm doing this right
|
||||||
} else if msg.is_text() {
|
} else if msg.is_text() {
|
||||||
let msg = msg.into_text().unwrap();
|
let msg = msg.into_text().unwrap();
|
||||||
let mut ui_connection = ui_connection.clone();
|
let mut ui_connection = ui_connection.clone();
|
||||||
@ -161,10 +161,15 @@ async fn websocket_worker(mut ui_connection: UiConnection, global_vars: Arc<RwLo
|
|||||||
"send" => {
|
"send" => {
|
||||||
let session_id: usize = args[1].parse().unwrap();
|
let session_id: usize = args[1].parse().unwrap();
|
||||||
let buffer = protocol::new_message(msg[args[0].len()+args[1].len()+2..].to_string());
|
let buffer = protocol::new_message(msg[args[0].len()+args[1].len()+2..].to_string());
|
||||||
|
let timestamp = get_unix_timestamp_sec();
|
||||||
if session_manager.send_command(&session_id, SessionCommand::Send {
|
if session_manager.send_command(&session_id, SessionCommand::Send {
|
||||||
buff: buffer.clone()
|
buff: buffer.clone()
|
||||||
}).await {
|
}).await {
|
||||||
session_manager.store_msg(&session_id, true, buffer);
|
session_manager.store_msg(&session_id, Message {
|
||||||
|
outgoing: true,
|
||||||
|
timestamp,
|
||||||
|
data: buffer,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"large_files" => {
|
"large_files" => {
|
||||||
@ -435,13 +440,18 @@ async fn handle_send_file(req: HttpRequest, mut payload: Multipart) -> HttpRespo
|
|||||||
while let Some(Ok(chunk)) = field.next().await {
|
while let Some(Ok(chunk)) = field.next().await {
|
||||||
buffer.extend(chunk);
|
buffer.extend(chunk);
|
||||||
}
|
}
|
||||||
|
let timestamp = get_unix_timestamp_sec();
|
||||||
if global_vars_read.session_manager.send_command(&session_id, SessionCommand::Send {
|
if global_vars_read.session_manager.send_command(&session_id, SessionCommand::Send {
|
||||||
buff: protocol::file(filename, &buffer)
|
buff: protocol::file(filename, &buffer)
|
||||||
}).await {
|
}).await {
|
||||||
match global_vars_read.session_manager.store_file(&session_id, &buffer) {
|
match global_vars_read.session_manager.store_file(&session_id, &buffer) {
|
||||||
Ok(file_uuid) => {
|
Ok(file_uuid) => {
|
||||||
let msg = [&[protocol::Headers::FILE][..], file_uuid.as_bytes(), filename.as_bytes()].concat();
|
let msg = [&[protocol::Headers::FILE][..], file_uuid.as_bytes(), filename.as_bytes()].concat();
|
||||||
global_vars_read.session_manager.store_msg(&session_id, true, msg);
|
global_vars_read.session_manager.store_msg(&session_id, Message {
|
||||||
|
outgoing: true,
|
||||||
|
timestamp,
|
||||||
|
data: msg,
|
||||||
|
});
|
||||||
return HttpResponse::Ok().body(file_uuid.to_string());
|
return HttpResponse::Ok().body(file_uuid.to_string());
|
||||||
}
|
}
|
||||||
Err(e) => print_error!(e)
|
Err(e) => print_error!(e)
|
||||||
|
@ -4,8 +4,7 @@ use libmdns::Service;
|
|||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
use platform_dirs::UserDirs;
|
use platform_dirs::UserDirs;
|
||||||
use async_psec::{PUBLIC_KEY_LENGTH, Session, SessionWriteHalf, PsecWriter, PsecReader, PsecError};
|
use async_psec::{PUBLIC_KEY_LENGTH, Session, SessionWriteHalf, PsecWriter, PsecReader, PsecError};
|
||||||
use crate::{constants, protocol, crypto, discovery, identity::{Contact, Identity}, print_error, utils::{get_unix_timestamp, get_not_used_path}};
|
use crate::{constants, crypto, discovery, identity::{Contact, Identity, Message}, ui_interface::UiConnection, print_error, protocol, utils::{get_not_used_path, get_unix_timestamp_ms, get_unix_timestamp_sec}};
|
||||||
use crate::ui_interface::UiConnection;
|
|
||||||
|
|
||||||
pub enum SessionCommand {
|
pub enum SessionCommand {
|
||||||
Send {
|
Send {
|
||||||
@ -55,7 +54,7 @@ pub struct SessionManager {
|
|||||||
ui_connection: Mutex<Option<UiConnection>>,
|
ui_connection: Mutex<Option<UiConnection>>,
|
||||||
loaded_contacts: RwLock<HashMap<usize, Contact>>,
|
loaded_contacts: RwLock<HashMap<usize, Contact>>,
|
||||||
pub last_loaded_msg_offsets: RwLock<HashMap<usize, usize>>,
|
pub last_loaded_msg_offsets: RwLock<HashMap<usize, usize>>,
|
||||||
pub saved_msgs: RwLock<HashMap<usize, Vec<(bool, Vec<u8>)>>>,
|
pub saved_msgs: RwLock<HashMap<usize, Vec<Message>>>,
|
||||||
pub not_seen: RwLock<Vec<usize>>,
|
pub not_seen: RwLock<Vec<usize>>,
|
||||||
mdns_service: Mutex<Option<Service>>,
|
mdns_service: Mutex<Option<Service>>,
|
||||||
listener_stop_signal: Mutex<Option<Sender<()>>>,
|
listener_stop_signal: Mutex<Option<Sender<()>>>,
|
||||||
@ -88,11 +87,11 @@ impl SessionManager {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn store_msg(&self, session_id: &usize, outgoing: bool, buffer: Vec<u8>) {
|
pub fn store_msg(&self, session_id: &usize, message: Message) {
|
||||||
let mut msg_saved = false;
|
let mut msg_saved = false;
|
||||||
if let Some(contact) = self.loaded_contacts.read().unwrap().get(session_id) {
|
if let Some(contact) = self.loaded_contacts.read().unwrap().get(session_id) {
|
||||||
let mut offsets = self.last_loaded_msg_offsets.write().unwrap(); //locking mutex before modifying the DB to prevent race conditions with load_msgs()
|
let mut offsets = self.last_loaded_msg_offsets.write().unwrap(); //locking mutex before modifying the DB to prevent race conditions with load_msgs()
|
||||||
match self.identity.read().unwrap().as_ref().unwrap().store_msg(&contact.uuid, outgoing, &buffer) {
|
match self.identity.read().unwrap().as_ref().unwrap().store_msg(&contact.uuid, message.clone()) {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
*offsets.get_mut(session_id).unwrap() += 1;
|
*offsets.get_mut(session_id).unwrap() += 1;
|
||||||
msg_saved = true;
|
msg_saved = true;
|
||||||
@ -101,7 +100,7 @@ impl SessionManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !msg_saved {
|
if !msg_saved {
|
||||||
self.saved_msgs.write().unwrap().get_mut(&session_id).unwrap().push((outgoing, buffer));
|
self.saved_msgs.write().unwrap().get_mut(&session_id).unwrap().push(message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -151,7 +150,7 @@ impl SessionManager {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn send_msg(&self, session_id: usize, session_write: &mut SessionWriteHalf, buff: &[u8], is_sending: &mut bool, file_ack_sender: &mut Option<Sender<bool>>) -> Result<(), PsecError> {
|
async fn send_msg(&self, session_id: usize, session_write: &mut SessionWriteHalf, buff: Vec<u8>, is_sending: &mut bool, file_ack_sender: &mut Option<Sender<bool>>) -> Result<(), PsecError> {
|
||||||
self.encrypt_and_send(session_write, &buff).await?;
|
self.encrypt_and_send(session_write, &buff).await?;
|
||||||
if buff[0] == protocol::Headers::ACCEPT_LARGE_FILES {
|
if buff[0] == protocol::Headers::ACCEPT_LARGE_FILES {
|
||||||
self.sessions.write().unwrap().get_mut(&session_id).unwrap().files_download.as_mut().unwrap().accepted = true;
|
self.sessions.write().unwrap().get_mut(&session_id).unwrap().files_download.as_mut().unwrap().accepted = true;
|
||||||
@ -166,7 +165,7 @@ impl SessionManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.with_ui_connection(|ui_connection| {
|
self.with_ui_connection(|ui_connection| {
|
||||||
ui_connection.on_msg_sent(session_id, &buff);
|
ui_connection.on_msg_sent(session_id, get_unix_timestamp_sec(), buff);
|
||||||
});
|
});
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -223,7 +222,7 @@ impl SessionManager {
|
|||||||
let mut sessions = self.sessions.write().unwrap();
|
let mut sessions = self.sessions.write().unwrap();
|
||||||
let files_transfer = sessions.get_mut(&session_id).unwrap().files_download.as_mut().unwrap();
|
let files_transfer = sessions.get_mut(&session_id).unwrap().files_download.as_mut().unwrap();
|
||||||
let file_transfer = &mut files_transfer.files[files_transfer.index];
|
let file_transfer = &mut files_transfer.files[files_transfer.index];
|
||||||
file_transfer.last_chunk = get_unix_timestamp();
|
file_transfer.last_chunk = get_unix_timestamp_ms();
|
||||||
file_transfer.transferred += chunk_size;
|
file_transfer.transferred += chunk_size;
|
||||||
if file_transfer.transferred >= file_transfer.file_size { //we downloaded all the file
|
if file_transfer.transferred >= file_transfer.file_size { //we downloaded all the file
|
||||||
if files_transfer.index+1 == files_transfer.files.len() {
|
if files_transfer.index+1 == files_transfer.files.len() {
|
||||||
@ -281,7 +280,7 @@ impl SessionManager {
|
|||||||
self.sessions.write().unwrap().get_mut(&session_id).unwrap().files_download = None;
|
self.sessions.write().unwrap().get_mut(&session_id).unwrap().files_download = None;
|
||||||
local_file_handle = None;
|
local_file_handle = None;
|
||||||
self.with_ui_connection(|ui_connection| {
|
self.with_ui_connection(|ui_connection| {
|
||||||
ui_connection.on_received(&session_id, &buffer);
|
ui_connection.on_received(&session_id, get_unix_timestamp_sec(), buffer);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
protocol::Headers::ASK_LARGE_FILES => {
|
protocol::Headers::ASK_LARGE_FILES => {
|
||||||
@ -293,7 +292,7 @@ impl SessionManager {
|
|||||||
file_name: info.1,
|
file_name: info.1,
|
||||||
file_size: info.0,
|
file_size: info.0,
|
||||||
transferred: 0,
|
transferred: 0,
|
||||||
last_chunk: get_unix_timestamp(),
|
last_chunk: get_unix_timestamp_ms(),
|
||||||
}
|
}
|
||||||
}).collect();
|
}).collect();
|
||||||
self.sessions.write().unwrap().get_mut(&session_id).unwrap().files_download = Some(LargeFilesDownload {
|
self.sessions.write().unwrap().get_mut(&session_id).unwrap().files_download = Some(LargeFilesDownload {
|
||||||
@ -389,8 +388,9 @@ impl SessionManager {
|
|||||||
Some(buffer)
|
Some(buffer)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
if buffer.is_some() {
|
if let Some(buffer) = buffer {
|
||||||
let is_classical_message = header == protocol::Headers::MESSAGE || header == protocol::Headers::FILE;
|
let is_classical_message = header == protocol::Headers::MESSAGE || header == protocol::Headers::FILE;
|
||||||
|
let timestamp = get_unix_timestamp_sec();
|
||||||
if is_classical_message {
|
if is_classical_message {
|
||||||
self.set_seen(session_id, false);
|
self.set_seen(session_id, false);
|
||||||
} else if header == protocol::Headers::ACCEPT_LARGE_FILES {
|
} else if header == protocol::Headers::ACCEPT_LARGE_FILES {
|
||||||
@ -398,10 +398,14 @@ impl SessionManager {
|
|||||||
last_chunks_sizes = Some(Vec::new());
|
last_chunks_sizes = Some(Vec::new());
|
||||||
}
|
}
|
||||||
self.with_ui_connection(|ui_connection| {
|
self.with_ui_connection(|ui_connection| {
|
||||||
ui_connection.on_received(&session_id, buffer.as_ref().unwrap());
|
ui_connection.on_received(&session_id, timestamp, buffer.clone());
|
||||||
});
|
});
|
||||||
if is_classical_message {
|
if is_classical_message {
|
||||||
self.store_msg(&session_id, false, buffer.unwrap());
|
self.store_msg(&session_id, Message {
|
||||||
|
outgoing: false,
|
||||||
|
timestamp,
|
||||||
|
data: buffer,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -422,7 +426,7 @@ impl SessionManager {
|
|||||||
if is_sending {
|
if is_sending {
|
||||||
msg_queue.push(buff);
|
msg_queue.push(buff);
|
||||||
} else {
|
} else {
|
||||||
if let Err(e) = self.send_msg(session_id, &mut session_write, &buff, &mut is_sending, &mut file_ack_sender).await {
|
if let Err(e) = self.send_msg(session_id, &mut session_write, buff, &mut is_sending, &mut file_ack_sender).await {
|
||||||
print_error!(e);
|
print_error!(e);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -440,7 +444,7 @@ impl SessionManager {
|
|||||||
//once the pre-encrypted chunk is sent, we can send the pending messages
|
//once the pre-encrypted chunk is sent, we can send the pending messages
|
||||||
while msg_queue.len() > 0 {
|
while msg_queue.len() > 0 {
|
||||||
let msg = msg_queue.remove(0);
|
let msg = msg_queue.remove(0);
|
||||||
if let Err(e) = self.send_msg(session_id, &mut session_write, &msg, &mut is_sending, &mut file_ack_sender).await {
|
if let Err(e) = self.send_msg(session_id, &mut session_write, msg, &mut is_sending, &mut file_ack_sender).await {
|
||||||
print_error!(e);
|
print_error!(e);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -583,7 +587,7 @@ impl SessionManager {
|
|||||||
self.loaded_contacts.read().unwrap().iter().map(|c| (*c.0, c.1.name.clone(), c.1.verified, c.1.public_key)).collect()
|
self.loaded_contacts.read().unwrap().iter().map(|c| (*c.0, c.1.name.clone(), c.1.verified, c.1.public_key)).collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_saved_msgs(&self) -> HashMap<usize, Vec<(bool, Vec<u8>)>> {
|
pub fn get_saved_msgs(&self) -> HashMap<usize, Vec<Message>> {
|
||||||
self.saved_msgs.read().unwrap().clone()
|
self.saved_msgs.read().unwrap().clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -659,7 +663,7 @@ impl SessionManager {
|
|||||||
}, data)
|
}, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn load_msgs(&self, session_id: &usize, count: usize) -> Option<Vec<(bool, Vec<u8>)>> {
|
pub fn load_msgs(&self, session_id: &usize, count: usize) -> Option<Vec<Message>> {
|
||||||
let mut offsets = self.last_loaded_msg_offsets.write().unwrap();
|
let mut offsets = self.last_loaded_msg_offsets.write().unwrap();
|
||||||
let msgs = self.identity.read().unwrap().as_ref().unwrap().load_msgs(
|
let msgs = self.identity.read().unwrap().as_ref().unwrap().load_msgs(
|
||||||
&self.loaded_contacts.read().unwrap().get(session_id)?.uuid,
|
&self.loaded_contacts.read().unwrap().get(session_id)?.uuid,
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
use std::net::{IpAddr, TcpStream};
|
use std::{net::{IpAddr, TcpStream}};
|
||||||
use tungstenite::{WebSocket, protocol::Role, Message};
|
use tungstenite::{WebSocket, protocol::Role, Message};
|
||||||
use crate::{protocol, session_manager::{LargeFileDownload, LargeFilesDownload}};
|
use crate::{identity, protocol, session_manager::{LargeFileDownload, LargeFilesDownload}};
|
||||||
|
|
||||||
mod ui_messages {
|
mod ui_messages {
|
||||||
use std::{fmt::Display, iter::FromIterator, net::IpAddr, str::from_utf8};
|
use std::{fmt::Display, iter::FromIterator, net::IpAddr, str::from_utf8};
|
||||||
use tungstenite::Message;
|
use tungstenite::Message;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
use crate::{print_error, session_manager::{LargeFileDownload, LargeFilesDownload}, protocol, utils::to_uuid_bytes};
|
use crate::{identity, print_error, protocol, session_manager::{LargeFileDownload, LargeFilesDownload}, utils::to_uuid_bytes};
|
||||||
|
|
||||||
fn simple_event(command: &str, session_id: &usize) -> Message {
|
fn simple_event(command: &str, session_id: &usize) -> Message {
|
||||||
Message::from(format!("{} {}", command, session_id))
|
Message::from(format!("{} {}", command, session_id))
|
||||||
@ -23,10 +23,10 @@ mod ui_messages {
|
|||||||
pub fn on_new_session(session_id: &usize, name: &str, outgoing: bool, fingerprint: &str, ip: IpAddr) -> Message {
|
pub fn on_new_session(session_id: &usize, name: &str, outgoing: bool, fingerprint: &str, ip: IpAddr) -> Message {
|
||||||
Message::from(format!("new_session {} {} {} {} {}", session_id, outgoing, fingerprint, ip, name))
|
Message::from(format!("new_session {} {} {} {} {}", session_id, outgoing, fingerprint, ip, name))
|
||||||
}
|
}
|
||||||
pub fn on_file_received(session_id: &usize, buffer: &[u8]) -> Option<Message> {
|
pub fn on_file_received(session_id: &usize, timestamp: u64, buffer: &[u8]) -> Option<Message> {
|
||||||
let uuid = Uuid::from_bytes(to_uuid_bytes(&buffer[1..17])?);
|
let uuid = Uuid::from_bytes(to_uuid_bytes(&buffer[1..17])?);
|
||||||
match from_utf8(&buffer[17..]) {
|
match from_utf8(&buffer[17..]) {
|
||||||
Ok(file_name) => Some(Message::from(format!("file {} {} {}", session_id, uuid.to_string(), file_name))),
|
Ok(file_name) => Some(Message::from(format!("file {} {} {} {}", session_id, timestamp, uuid.to_string(), file_name))),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
print_error!(e);
|
print_error!(e);
|
||||||
None
|
None
|
||||||
@ -71,9 +71,9 @@ mod ui_messages {
|
|||||||
pub fn on_file_transfer_aborted(session_id: &usize) -> Message {
|
pub fn on_file_transfer_aborted(session_id: &usize) -> Message {
|
||||||
simple_event("aborted", session_id)
|
simple_event("aborted", session_id)
|
||||||
}
|
}
|
||||||
pub fn on_new_message(session_id: &usize, outgoing: bool, buffer: &[u8]) -> Option<Message> {
|
pub fn on_new_message(session_id: &usize, message: identity::Message) -> Option<Message> {
|
||||||
match from_utf8(&buffer[1..]) {
|
match from_utf8(&message.data[1..]) {
|
||||||
Ok(msg) => Some(Message::from(format!("{} {} {} {}", "new_message", session_id, outgoing, msg))),
|
Ok(msg) => Some(Message::from(format!("new_message {} {} {} {}", session_id, message.outgoing, message.timestamp, msg))),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
print_error!(e);
|
print_error!(e);
|
||||||
None
|
None
|
||||||
@ -83,18 +83,18 @@ mod ui_messages {
|
|||||||
pub fn inc_files_transfer(session_id: &usize, chunk_size: u64) -> Message {
|
pub fn inc_files_transfer(session_id: &usize, chunk_size: u64) -> Message {
|
||||||
Message::from(format!("inc_file_transfer {} {}", session_id, chunk_size))
|
Message::from(format!("inc_file_transfer {} {}", session_id, chunk_size))
|
||||||
}
|
}
|
||||||
pub fn load_msgs(session_id: &usize, msgs: &Vec<(bool, Vec<u8>)>) -> Message {
|
pub fn load_msgs(session_id: &usize, msgs: &Vec<identity::Message>) -> Message {
|
||||||
let mut s = format!("load_msgs {}", session_id);
|
let mut s = format!("load_msgs {}", session_id);
|
||||||
msgs.into_iter().rev().for_each(|entry| {
|
msgs.into_iter().rev().for_each(|message| {
|
||||||
match entry.1[0] {
|
match message.data[0] {
|
||||||
protocol::Headers::MESSAGE => match from_utf8(&entry.1[1..]) {
|
protocol::Headers::MESSAGE => match from_utf8(&message.data[1..]) {
|
||||||
Ok(msg) => s.push_str(&format!(" m {} {}", entry.0, base64::encode(msg))),
|
Ok(msg) => s.push_str(&format!(" m {} {} {}", message.outgoing, message.timestamp, base64::encode(msg))),
|
||||||
Err(e) => print_error!(e)
|
Err(e) => print_error!(e)
|
||||||
}
|
}
|
||||||
protocol::Headers::FILE => {
|
protocol::Headers::FILE => {
|
||||||
let uuid = Uuid::from_bytes(to_uuid_bytes(&entry.1[1..17]).unwrap());
|
let uuid = Uuid::from_bytes(to_uuid_bytes(&message.data[1..17]).unwrap());
|
||||||
match from_utf8(&entry.1[17..]) {
|
match from_utf8(&message.data[17..]) {
|
||||||
Ok(file_name) => s.push_str(&format!(" f {} {} {}", entry.0, uuid.to_string(), base64::encode(file_name))),
|
Ok(file_name) => s.push_str(&format!(" f {} {} {} {}", message.outgoing, message.timestamp, uuid.to_string(), base64::encode(file_name))),
|
||||||
Err(e) => print_error!(e)
|
Err(e) => print_error!(e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -148,10 +148,14 @@ impl UiConnection {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn on_received(&mut self, session_id: &usize, buffer: &[u8]) {
|
pub fn on_received(&mut self, session_id: &usize, timestamp: u64, buffer: Vec<u8>) {
|
||||||
let ui_message = match buffer[0] {
|
let ui_message = match buffer[0] {
|
||||||
protocol::Headers::MESSAGE => ui_messages::on_new_message(session_id, false, buffer),
|
protocol::Headers::MESSAGE => ui_messages::on_new_message(session_id, identity::Message {
|
||||||
protocol::Headers::FILE => ui_messages::on_file_received(session_id, buffer),
|
outgoing: false,
|
||||||
|
timestamp,
|
||||||
|
data: buffer
|
||||||
|
}),
|
||||||
|
protocol::Headers::FILE => ui_messages::on_file_received(session_id, timestamp, &buffer),
|
||||||
protocol::Headers::ACCEPT_LARGE_FILES => Some(ui_messages::on_large_files_accepted(session_id)),
|
protocol::Headers::ACCEPT_LARGE_FILES => Some(ui_messages::on_large_files_accepted(session_id)),
|
||||||
protocol::Headers::ABORT_FILES_TRANSFER => Some(ui_messages::on_file_transfer_aborted(session_id)),
|
protocol::Headers::ABORT_FILES_TRANSFER => Some(ui_messages::on_file_transfer_aborted(session_id)),
|
||||||
_ => None
|
_ => None
|
||||||
@ -163,9 +167,13 @@ impl UiConnection {
|
|||||||
pub fn on_ask_large_files(&mut self, session_id: &usize, files: &Vec<LargeFileDownload>, download_location: &str) {
|
pub fn on_ask_large_files(&mut self, session_id: &usize, files: &Vec<LargeFileDownload>, download_location: &str) {
|
||||||
self.write_message(ui_messages::on_ask_large_files(session_id, files, download_location))
|
self.write_message(ui_messages::on_ask_large_files(session_id, files, download_location))
|
||||||
}
|
}
|
||||||
pub fn on_msg_sent(&mut self, session_id: usize, buffer: &[u8]) {
|
pub fn on_msg_sent(&mut self, session_id: usize, timestamp: u64, buffer: Vec<u8>) {
|
||||||
match buffer[0] {
|
match buffer[0] {
|
||||||
protocol::Headers::MESSAGE => match ui_messages::on_new_message(&session_id, true, buffer) {
|
protocol::Headers::MESSAGE => match ui_messages::on_new_message(&session_id, identity::Message {
|
||||||
|
outgoing: true,
|
||||||
|
timestamp,
|
||||||
|
data: buffer
|
||||||
|
}) {
|
||||||
Some(msg) => self.write_message(msg),
|
Some(msg) => self.write_message(msg),
|
||||||
None => {}
|
None => {}
|
||||||
}
|
}
|
||||||
@ -195,7 +203,7 @@ impl UiConnection {
|
|||||||
pub fn set_as_contact(&mut self, session_id: usize, name: &str, verified: bool, fingerprint: &str) {
|
pub fn set_as_contact(&mut self, session_id: usize, name: &str, verified: bool, fingerprint: &str) {
|
||||||
self.write_message(ui_messages::set_as_contact(session_id, name, verified, fingerprint));
|
self.write_message(ui_messages::set_as_contact(session_id, name, verified, fingerprint));
|
||||||
}
|
}
|
||||||
pub fn load_msgs(&mut self, session_id: &usize, msgs: &Vec<(bool, Vec<u8>)>) {
|
pub fn load_msgs(&mut self, session_id: &usize, msgs: &Vec<identity::Message>) {
|
||||||
self.write_message(ui_messages::load_msgs(session_id, msgs));
|
self.write_message(ui_messages::load_msgs(session_id, msgs));
|
||||||
}
|
}
|
||||||
pub fn set_not_seen(&mut self, session_ids: Vec<usize>) {
|
pub fn set_not_seen(&mut self, session_ids: Vec<usize>) {
|
||||||
|
@ -16,10 +16,14 @@ pub fn escape_double_quote(origin: String) -> String {
|
|||||||
origin.replace("\"", "\\\"")
|
origin.replace("\"", "\\\"")
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_unix_timestamp() -> u128 {
|
pub fn get_unix_timestamp_ms() -> u128 {
|
||||||
SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_millis()
|
SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_millis()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_unix_timestamp_sec() -> u64 {
|
||||||
|
SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_not_used_path(file_name: &str, parent_directory: &PathBuf) -> String {
|
pub fn get_not_used_path(file_name: &str, parent_directory: &PathBuf) -> String {
|
||||||
let has_extension = file_name.matches('.').count() > 0;
|
let has_extension = file_name.matches('.').count() > 0;
|
||||||
let mut path = parent_directory.join(&file_name);
|
let mut path = parent_directory.join(&file_name);
|
||||||
|
Loading…
Reference in New Issue
Block a user