Builds again, and now uses thread-safe mutexes and interior mutability to handle the pipelines
This commit is contained in:
parent
25a7458b51
commit
f6e422accb
7 changed files with 119 additions and 97 deletions
|
@ -1,5 +1,5 @@
|
||||||
unstable_features = true
|
unstable_features = true
|
||||||
blank_lines_lower_bound = 1
|
blank_lines_lower_bound = 0
|
||||||
blank_lines_upper_bound = 3
|
blank_lines_upper_bound = 3
|
||||||
#chain_width = 120
|
#chain_width = 120
|
||||||
wrap_comments = true
|
wrap_comments = true
|
||||||
|
|
|
@ -42,7 +42,6 @@ impl CallManager {
|
||||||
matrix_receiver: Receiver<MatrixToCallManager>,
|
matrix_receiver: Receiver<MatrixToCallManager>,
|
||||||
) -> Self
|
) -> Self
|
||||||
{
|
{
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
botname: botname.to_string(),
|
botname: botname.to_string(),
|
||||||
client,
|
client,
|
||||||
|
@ -62,7 +61,6 @@ impl CallManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_turn_server(&self) -> Result<(), anyhow::Error> {
|
pub async fn get_turn_server(&self) -> Result<(), anyhow::Error> {
|
||||||
|
|
||||||
let client = &self.client;
|
let client = &self.client;
|
||||||
|
|
||||||
let request = voip::get_turn_server_info::Request {};
|
let request = voip::get_turn_server_info::Request {};
|
||||||
|
@ -75,9 +73,7 @@ impl CallManager {
|
||||||
pub fn can_start_call(&self) -> bool { !&self.call_in_progress }
|
pub fn can_start_call(&self) -> bool { !&self.call_in_progress }
|
||||||
|
|
||||||
pub async fn start_incoming_call(&self, offer: String, room_id: RoomId) -> Result<(), anyhow::Error> {
|
pub async fn start_incoming_call(&self, offer: String, room_id: RoomId) -> Result<(), anyhow::Error> {
|
||||||
|
|
||||||
if self.call_in_progress {
|
if self.call_in_progress {
|
||||||
|
|
||||||
error!("Existing call in progress already");
|
error!("Existing call in progress already");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,9 +81,7 @@ impl CallManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn start_outgoing_call(&self, room_id: RoomId) -> Result<(), anyhow::Error> {
|
pub async fn start_outgoing_call(&self, room_id: RoomId) -> Result<(), anyhow::Error> {
|
||||||
|
|
||||||
if self.call_in_progress {
|
if self.call_in_progress {
|
||||||
|
|
||||||
error!("Existing call in progress already");
|
error!("Existing call in progress already");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,14 +11,12 @@ pub struct Channels<L: Send + Clone, R: Send + Clone> {
|
||||||
|
|
||||||
impl<L: Send + Clone, R: Send + Clone> Channels<L, R> {
|
impl<L: Send + Clone, R: Send + Clone> Channels<L, R> {
|
||||||
pub fn get_pair_left(&self) -> (Sender<L>, Receiver<L>) {
|
pub fn get_pair_left(&self) -> (Sender<L>, Receiver<L>) {
|
||||||
|
|
||||||
let (sender, receiver) = &self.left;
|
let (sender, receiver) = &self.left;
|
||||||
|
|
||||||
(sender.clone(), receiver.clone())
|
(sender.clone(), receiver.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_pair_right(&self) -> (Sender<R>, Receiver<R>) {
|
pub fn get_pair_right(&self) -> (Sender<R>, Receiver<R>) {
|
||||||
|
|
||||||
let (sender, receiver) = &self.right;
|
let (sender, receiver) = &self.right;
|
||||||
|
|
||||||
(sender.clone(), receiver.clone())
|
(sender.clone(), receiver.clone())
|
||||||
|
@ -26,7 +24,6 @@ impl<L: Send + Clone, R: Send + Clone> Channels<L, R> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_pair<L: Send + Clone, R: Send + Clone>() -> Channels<L, R> {
|
pub fn create_pair<L: Send + Clone, R: Send + Clone>() -> Channels<L, R> {
|
||||||
|
|
||||||
let (left_sender, left_receiver) = unbounded::<L>();
|
let (left_sender, left_receiver) = unbounded::<L>();
|
||||||
|
|
||||||
let (right_sender, right_receiver) = unbounded::<R>();
|
let (right_sender, right_receiver) = unbounded::<R>();
|
||||||
|
|
|
@ -56,7 +56,6 @@ pub struct ConfigError {
|
||||||
|
|
||||||
impl ConfigError {
|
impl ConfigError {
|
||||||
fn new(msg: &str) -> ConfigError {
|
fn new(msg: &str) -> ConfigError {
|
||||||
|
|
||||||
ConfigError {
|
ConfigError {
|
||||||
details: msg.to_string(),
|
details: msg.to_string(),
|
||||||
}
|
}
|
||||||
|
@ -72,26 +71,22 @@ impl Error for ConfigError {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_config_directory(botname: &str) -> Result<std::path::PathBuf, ConfigError> {
|
pub fn get_config_directory(botname: &str) -> Result<std::path::PathBuf, ConfigError> {
|
||||||
|
|
||||||
let home_maybe = dirs::home_dir();
|
let home_maybe = dirs::home_dir();
|
||||||
|
|
||||||
match home_maybe {
|
match home_maybe {
|
||||||
Some(mut home) => {
|
Some(mut home) => {
|
||||||
|
|
||||||
// TODO make this fit LFS setup
|
// TODO make this fit LFS setup
|
||||||
home.push(botname);
|
home.push(botname);
|
||||||
|
|
||||||
return Ok(home);
|
return Ok(home);
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
|
|
||||||
return Err(ConfigError::new("Unable to find home directory"));
|
return Err(ConfigError::new("Unable to find home directory"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn load_config(botname: &str) -> Result<Config, anyhow::Error> {
|
pub fn load_config(botname: &str) -> Result<Config, anyhow::Error> {
|
||||||
|
|
||||||
let mut config_path = get_config_directory(botname)?;
|
let mut config_path = get_config_directory(botname)?;
|
||||||
|
|
||||||
config_path.push("config.toml");
|
config_path.push("config.toml");
|
||||||
|
@ -102,7 +97,6 @@ pub fn load_config(botname: &str) -> Result<Config, anyhow::Error> {
|
||||||
|
|
||||||
match config_filemaybe {
|
match config_filemaybe {
|
||||||
Ok(mut config_file) => {
|
Ok(mut config_file) => {
|
||||||
|
|
||||||
let mut config_raw = String::new();
|
let mut config_raw = String::new();
|
||||||
|
|
||||||
config_file.read_to_string(&mut config_raw)?;
|
config_file.read_to_string(&mut config_raw)?;
|
||||||
|
@ -112,7 +106,6 @@ pub fn load_config(botname: &str) -> Result<Config, anyhow::Error> {
|
||||||
match config_maybe {
|
match config_maybe {
|
||||||
Ok(config) => return Ok(config),
|
Ok(config) => return Ok(config),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
|
|
||||||
let error_string = format!("Failed parsing config file {}", config_filename);
|
let error_string = format!("Failed parsing config file {}", config_filename);
|
||||||
|
|
||||||
return Err(anyhow::Error::new(e).context(error_string));
|
return Err(anyhow::Error::new(e).context(error_string));
|
||||||
|
@ -120,7 +113,6 @@ pub fn load_config(botname: &str) -> Result<Config, anyhow::Error> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
|
|
||||||
// I'm sure there's a more idiomatic way to do this
|
// I'm sure there's a more idiomatic way to do this
|
||||||
let error_string = format!("Couldn't load config file {}", config_filename);
|
let error_string = format!("Couldn't load config file {}", config_filename);
|
||||||
|
|
||||||
|
|
158
src/gstream.rs
158
src/gstream.rs
|
@ -10,10 +10,32 @@ use anyhow;
|
||||||
use crossbeam_channel::{self, Receiver, Sender};
|
use crossbeam_channel::{self, Receiver, Sender};
|
||||||
|
|
||||||
use std::sync::{Arc, Mutex, Weak};
|
use std::sync::{Arc, Mutex, Weak};
|
||||||
|
use gst::gst_element_error;
|
||||||
|
use std::ops::{Deref, DerefMut};
|
||||||
|
use std::cell::{RefCell, Ref};
|
||||||
|
|
||||||
|
// This whole module borrows heavily from https://github.com/centricular/gstwebrtc-demos/blob/master/sendrecv/gst-rust/src/main.rs
|
||||||
|
// I've changed it quite a bit still but it's got a lot in common still. TBD licensing
|
||||||
|
|
||||||
|
// upgrade weak reference or return
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! upgrade_weak {
|
||||||
|
($x:ident, $r:expr) => {{
|
||||||
|
match $x.upgrade() {
|
||||||
|
Some(o) => o,
|
||||||
|
None => return $r,
|
||||||
|
}
|
||||||
|
}};
|
||||||
|
($x:ident) => {
|
||||||
|
upgrade_weak!($x, ())
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct GstreamerPipeline {
|
struct GstreamerPipeline {
|
||||||
pub description: String,
|
pub description: String,
|
||||||
|
pipeline: gst::Pipeline,
|
||||||
|
bin: gst::Element,
|
||||||
// TBD what other stuff goes in here?
|
// TBD what other stuff goes in here?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,51 +46,61 @@ struct GstreamerPipeline {
|
||||||
|
|
||||||
// Weak reference to our application state
|
// Weak reference to our application state
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct GstreamerWeak(Weak<GstreamerModel>);
|
struct GstreamerWeak(Weak<GstreamerInner>);
|
||||||
|
|
||||||
// Better name TBD
|
// Better name TBD
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct GstreamerModel {
|
pub struct GstreamerInner {
|
||||||
current_pipeline: Option<GstreamerPipeline>,
|
current_pipeline: Mutex<RefCell<Option<GstreamerPipeline>>>,
|
||||||
incoming_pipeline: Option<GstreamerPipeline>,
|
incoming_pipeline: Mutex<RefCell<Option<GstreamerPipeline>>>,
|
||||||
gstream_receiver: Receiver<CallManagerToGst>,
|
gstream_receiver: Receiver<CallManagerToGst>,
|
||||||
gstream_sender: Sender<GstToCallManager>,
|
gstream_sender: Sender<GstToCallManager>,
|
||||||
config: config::GstreamerConfig,
|
config: config::GstreamerConfig,
|
||||||
call_active: bool,
|
call_active: bool,
|
||||||
|
|
||||||
running_pipeline: Option<gst::Element>,
|
|
||||||
webrtcbin: Option<gst::Element>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GstreamerModel {
|
#[derive(Debug)]
|
||||||
|
pub struct Gstreamer(Arc<GstreamerInner>);
|
||||||
|
|
||||||
|
impl GstreamerWeak {
|
||||||
|
// Try upgrading a weak reference to a strong one
|
||||||
|
fn upgrade(&self) -> Option<Gstreamer> {
|
||||||
|
self.0.upgrade().map(Gstreamer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// To be able to access the App's fields directly
|
||||||
|
impl std::ops::Deref for Gstreamer {
|
||||||
|
type Target = GstreamerInner;
|
||||||
|
|
||||||
|
fn deref(&self) -> &GstreamerInner { &self.0 }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Gstreamer {
|
||||||
|
fn downgrade(&self) -> GstreamerWeak { GstreamerWeak(Arc::downgrade(&self.0)) }
|
||||||
|
|
||||||
pub fn new(
|
pub fn new(
|
||||||
config: config::Config,
|
config: config::Config,
|
||||||
gstream_receiver: Receiver<CallManagerToGst>,
|
gstream_receiver: Receiver<CallManagerToGst>,
|
||||||
gstream_sender: Sender<GstToCallManager>,
|
gstream_sender: Sender<GstToCallManager>,
|
||||||
) -> Self
|
) -> Self
|
||||||
{
|
{
|
||||||
|
|
||||||
let gst_config = config.gstreamer;
|
let gst_config = config.gstreamer;
|
||||||
|
|
||||||
// TODO initialize the passive pipeline if it exists
|
|
||||||
|
|
||||||
// TODO make this only ever happen once somehow, not a big deal at the moment
|
// TODO make this only ever happen once somehow, not a big deal at the moment
|
||||||
gst::init().unwrap();
|
gst::init().unwrap();
|
||||||
|
|
||||||
GstreamerModel {
|
Gstreamer(Arc::new(GstreamerInner {
|
||||||
call_active: false,
|
call_active: false,
|
||||||
current_pipeline: None,
|
current_pipeline: Mutex::new(RefCell::new(None)),
|
||||||
incoming_pipeline: None,
|
incoming_pipeline: Mutex::new(RefCell::new(None)),
|
||||||
gstream_receiver,
|
gstream_receiver,
|
||||||
gstream_sender,
|
gstream_sender,
|
||||||
config: gst_config,
|
config: gst_config,
|
||||||
running_pipeline: None,
|
}))
|
||||||
webrtcbin: None,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn _foo() -> Result<i32, anyhow::Error> {
|
pub fn _foo() -> Result<i32, anyhow::Error> {
|
||||||
|
|
||||||
// Dummy webrtc pipeline, it sends test sources to the webrtc type
|
// Dummy webrtc pipeline, it sends test sources to the webrtc type
|
||||||
// The video is encoded with vp8 with deadline encoding, and opus for audio
|
// The video is encoded with vp8 with deadline encoding, and opus for audio
|
||||||
// This is then put into an rtp payload for vp8 and opus (no idea what pt=96/97 are)
|
// This is then put into an rtp payload for vp8 and opus (no idea what pt=96/97 are)
|
||||||
|
@ -87,29 +119,24 @@ impl GstreamerModel {
|
||||||
|
|
||||||
fn setup_pipeline(&self, pipeline_desc: String) -> Result<(), anyhow::Error> { Ok(()) }
|
fn setup_pipeline(&self, pipeline_desc: String) -> Result<(), anyhow::Error> { Ok(()) }
|
||||||
|
|
||||||
/// get the incoming pipeline from the config, should this do the full setup?
|
|
||||||
/// return a null pipeline if not found
|
|
||||||
|
|
||||||
fn get_incoming_pipeline(&self) -> Result<String, anyhow::Error> { Ok("foo".to_string()) }
|
|
||||||
|
|
||||||
/// get the passive pipeline from the config, if it exists
|
|
||||||
/// if it doesn't exist we don't return anything
|
|
||||||
|
|
||||||
fn get_passive_pipeline(&self) -> Result<Option<String>, anyhow::Error> { Ok(None) }
|
|
||||||
|
|
||||||
fn create_incoming_pipeline(&self, sdp: String) -> Result<(), anyhow::Error> {
|
fn create_incoming_pipeline(&self, sdp: String) -> Result<(), anyhow::Error> {
|
||||||
|
|
||||||
// We have an existing incoming pipeline, kill it
|
// We have an existing incoming pipeline, kill it
|
||||||
if let Some(_) = &self.incoming_pipeline {
|
// if let Some(_) = &self.incoming_pipeline {
|
||||||
|
// &self.delete_incoming_pipeline()?;
|
||||||
&self.delete_incoming_pipeline()?;
|
// }
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn delete_incoming_pipeline(&self) -> Result<(), anyhow::Error> { Ok(()) }
|
fn delete_incoming_pipeline(&self) -> Result<(), anyhow::Error> { Ok(()) }
|
||||||
|
|
||||||
|
/// we got a new ICE candidate, send it along
|
||||||
|
|
||||||
|
pub fn on_ice_candidate(&self, index: u32, sdp: String) -> Result<(), anyhow::Error> {
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
/// open_active_pipeline turns off the passive pipeline, and then sets up the active
|
/// open_active_pipeline turns off the passive pipeline, and then sets up the active
|
||||||
/// pipeline. It also then connects the incoming sdp to the incoming pipeline
|
/// pipeline. It also then connects the incoming sdp to the incoming pipeline
|
||||||
|
|
||||||
|
@ -119,7 +146,6 @@ impl GstreamerModel {
|
||||||
turn_server: Option<TurnAuth>,
|
turn_server: Option<TurnAuth>,
|
||||||
) -> Result<(), anyhow::Error>
|
) -> Result<(), anyhow::Error>
|
||||||
{
|
{
|
||||||
|
|
||||||
/* if let Some(sdp) = incoming_sdp {
|
/* if let Some(sdp) = incoming_sdp {
|
||||||
&self.create_incoming_pipeline(sdp)?;
|
&self.create_incoming_pipeline(sdp)?;
|
||||||
}*/
|
}*/
|
||||||
|
@ -130,14 +156,23 @@ impl GstreamerModel {
|
||||||
let pipeline_maybe = gst_parsed.downcast::<gst::Pipeline>();
|
let pipeline_maybe = gst_parsed.downcast::<gst::Pipeline>();
|
||||||
|
|
||||||
if let Ok(pipeline) = pipeline_maybe {
|
if let Ok(pipeline) = pipeline_maybe {
|
||||||
|
let bin = pipeline.get_by_name("webrtcbin").unwrap();
|
||||||
|
let pipeline_desc = Some(GstreamerPipeline {description: self.config.active_pipeline.clone(), pipeline, bin});
|
||||||
|
|
||||||
|
self.current_pipeline.lock().unwrap().replace(pipeline_desc);
|
||||||
|
|
||||||
self.webrtcbin = pipeline.get_by_name("webrtcbin");
|
// We have to reborrow this because of the move from above
|
||||||
|
// TODO rewrite this bit once I figure out what's going on
|
||||||
let webrtcbin = self.webrtcbin.as_ref().unwrap();
|
// I'm 100% positive that there's a better way to do this
|
||||||
|
let tempval = &self.current_pipeline;
|
||||||
|
let tempval2 = tempval.lock();
|
||||||
|
let tempval3 = tempval2.unwrap();
|
||||||
|
let tempval5 = tempval3.borrow();
|
||||||
|
let tempval4 = tempval5.as_ref().unwrap();
|
||||||
|
let webrtcbin = &tempval4.bin;
|
||||||
|
|
||||||
// calculate each turn server url, with the username and password
|
// calculate each turn server url, with the username and password
|
||||||
if let Some(turn_server) = turn_server {
|
if let Some(turn_server) = turn_server {
|
||||||
|
|
||||||
// I can only use the first turn-server from matrix, this is because I don't know how to call the
|
// I can only use the first turn-server from matrix, this is because I don't know how to call the
|
||||||
// proper gstreamer api for this
|
// proper gstreamer api for this
|
||||||
|
|
||||||
|
@ -147,9 +182,7 @@ impl GstreamerModel {
|
||||||
let mut turn_server_url = Url::parse(&base_url)?;
|
let mut turn_server_url = Url::parse(&base_url)?;
|
||||||
|
|
||||||
turn_server_url.set_username(&turn_server.username).unwrap();
|
turn_server_url.set_username(&turn_server.username).unwrap();
|
||||||
|
|
||||||
turn_server_url.set_password(Some(&turn_server.password)).unwrap();
|
turn_server_url.set_password(Some(&turn_server.password)).unwrap();
|
||||||
|
|
||||||
webrtcbin.set_property_from_str("turn-server", &turn_server_url.to_string());
|
webrtcbin.set_property_from_str("turn-server", &turn_server_url.to_string());
|
||||||
|
|
||||||
// }
|
// }
|
||||||
|
@ -159,9 +192,32 @@ impl GstreamerModel {
|
||||||
|
|
||||||
webrtcbin.set_property_from_str("bundle-policy", "max-bundle");
|
webrtcbin.set_property_from_str("bundle-policy", "max-bundle");
|
||||||
|
|
||||||
|
|
||||||
|
// Whenever there is a new ICE candidate, send it to the peer
|
||||||
|
let app_clone = self.downgrade();
|
||||||
|
webrtcbin
|
||||||
|
.connect("on-ice-candidate", false, move |values| {
|
||||||
|
let _webrtc = values[0].get::<gst::Element>().expect("Invalid argument");
|
||||||
|
let mlineindex = values[1].get_some::<u32>().expect("Invalid argument");
|
||||||
|
let candidate = values[2].get::<String>().expect("Invalid argument").unwrap();
|
||||||
|
|
||||||
|
let app = upgrade_weak!(app_clone, None);
|
||||||
|
|
||||||
|
if let Err(err) = app.on_ice_candidate(mlineindex, candidate) {
|
||||||
|
gst_element_error!(
|
||||||
|
app.current_pipeline.lock().unwrap().borrow().as_ref().unwrap().bin,
|
||||||
|
gst::LibraryError::Failed,
|
||||||
|
("Failed to send ICE candidate: {:?}", err)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
|
||||||
webrtcbin.connect_pad_added(move |_webrtc, pad| {});
|
webrtcbin.connect_pad_added(move |_webrtc, pad| {});
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
// TBD better handling
|
// TBD better handling
|
||||||
panic!("Failed to parse pipeline")
|
panic!("Failed to parse pipeline")
|
||||||
}
|
}
|
||||||
|
@ -175,3 +231,23 @@ impl GstreamerModel {
|
||||||
|
|
||||||
pub async fn loop_once(&self) {}
|
pub async fn loop_once(&self) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Make sure to shut down the pipeline when it goes out of scope
|
||||||
|
// to release any system resources
|
||||||
|
impl Drop for GstreamerInner {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
let current_cell = &self.current_pipeline.lock().unwrap();
|
||||||
|
let incoming_cell = &self.incoming_pipeline.lock().unwrap();
|
||||||
|
|
||||||
|
let old_current = current_cell.replace(None);
|
||||||
|
let old_incoming = incoming_cell.replace(None);
|
||||||
|
|
||||||
|
if let Some(pipe_desc) = old_current {
|
||||||
|
let _ = pipe_desc.bin.set_state(gst::State::Null);
|
||||||
|
}
|
||||||
|
if let Some(pipe_desc) = old_incoming {
|
||||||
|
let _ = pipe_desc.bin.set_state(gst::State::Null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -21,7 +21,6 @@ use tracing_subscriber;
|
||||||
#[tokio::main(core_threads = 4)]
|
#[tokio::main(core_threads = 4)]
|
||||||
|
|
||||||
async fn main() -> Result<(), anyhow::Error> {
|
async fn main() -> Result<(), anyhow::Error> {
|
||||||
|
|
||||||
tracing_subscriber::fmt::init();
|
tracing_subscriber::fmt::init();
|
||||||
|
|
||||||
//let (event_tx, event_rx) = channel::<ClientEventThingy>(100);// setup a channel with 100
|
//let (event_tx, event_rx) = channel::<ClientEventThingy>(100);// setup a channel with 100
|
||||||
|
@ -34,7 +33,6 @@ async fn main() -> Result<(), anyhow::Error> {
|
||||||
let botname = match env::args().nth(1) {
|
let botname = match env::args().nth(1) {
|
||||||
Some(a) => a,
|
Some(a) => a,
|
||||||
_ => {
|
_ => {
|
||||||
|
|
||||||
println!(
|
println!(
|
||||||
"Usage: {} <botname>
|
"Usage: {} <botname>
|
||||||
|
|
||||||
|
@ -70,14 +68,12 @@ async fn main() -> Result<(), anyhow::Error> {
|
||||||
let cm_client = matrix_client.clone();
|
let cm_client = matrix_client.clone();
|
||||||
|
|
||||||
let matrix_fut = tokio::spawn(async move {
|
let matrix_fut = tokio::spawn(async move {
|
||||||
|
|
||||||
matrixbot::sync_and_loop(looping_client, matrix_cm_sender, cm_matrix_receiver)
|
matrixbot::sync_and_loop(looping_client, matrix_cm_sender, cm_matrix_receiver)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
});
|
});
|
||||||
|
|
||||||
let cm_future = tokio::spawn(async move {
|
let cm_future = tokio::spawn(async move {
|
||||||
|
|
||||||
let botname = &botname_ref;
|
let botname = &botname_ref;
|
||||||
|
|
||||||
//let config = config::load_config(&botname).unwrap();
|
//let config = config::load_config(&botname).unwrap();
|
||||||
|
@ -95,13 +91,11 @@ async fn main() -> Result<(), anyhow::Error> {
|
||||||
});
|
});
|
||||||
|
|
||||||
let gst_fut = tokio::spawn(async move {
|
let gst_fut = tokio::spawn(async move {
|
||||||
|
|
||||||
let config = config::load_config(&botname).unwrap();
|
let config = config::load_config(&botname).unwrap();
|
||||||
|
|
||||||
let gstmodel = gstream::GstreamerModel::new(config, cm_gst_receiver, gst_cm_sender);
|
let gstmodel = gstream::Gstreamer::new(config, cm_gst_receiver, gst_cm_sender);
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
|
|
||||||
gstmodel.loop_once().await;
|
gstmodel.loop_once().await;
|
||||||
|
|
||||||
// this should really be doing stuff for gstreamer
|
// this should really be doing stuff for gstreamer
|
||||||
|
|
|
@ -46,17 +46,14 @@ impl CommandBot {
|
||||||
pub fn new(client: Client) -> Self { Self { client } }
|
pub fn new(client: Client) -> Self { Self { client } }
|
||||||
|
|
||||||
pub fn say_hello(&self) {
|
pub fn say_hello(&self) {
|
||||||
|
|
||||||
println!("Testing");
|
println!("Testing");
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO figure out a better way to refer to this type
|
// TODO figure out a better way to refer to this type
|
||||||
async fn handle_command(&self, room: Arc<RwLock<Room>>, sender: String, message: String) {
|
async fn handle_command(&self, room: Arc<RwLock<Room>>, sender: String, message: String) {
|
||||||
|
|
||||||
println!("<{}> {} ", sender, message);
|
println!("<{}> {} ", sender, message);
|
||||||
|
|
||||||
if message.contains("!party") {
|
if message.contains("!party") {
|
||||||
|
|
||||||
let content = MessageEventContent::Text(TextMessageEventContent {
|
let content = MessageEventContent::Text(TextMessageEventContent {
|
||||||
body: "🎉🎊🥳 let's PARTY!! 🥳🎊🎉".to_string(),
|
body: "🎉🎊🥳 let's PARTY!! 🥳🎊🎉".to_string(),
|
||||||
formatted: None,
|
formatted: None,
|
||||||
|
@ -82,7 +79,6 @@ impl CommandBot {
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn wait_for_confirmation(sas: Sas) {
|
async fn wait_for_confirmation(sas: Sas) {
|
||||||
|
|
||||||
println!("Emoji: {:?}", sas.emoji());
|
println!("Emoji: {:?}", sas.emoji());
|
||||||
|
|
||||||
// TODO make this verify things somehow, I can't do it interactively so I think send them in a
|
// TODO make this verify things somehow, I can't do it interactively so I think send them in a
|
||||||
|
@ -91,7 +87,6 @@ async fn wait_for_confirmation(sas: Sas) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print_result(sas: Sas) {
|
fn print_result(sas: Sas) {
|
||||||
|
|
||||||
let device = sas.other_device();
|
let device = sas.other_device();
|
||||||
|
|
||||||
println!(
|
println!(
|
||||||
|
@ -111,7 +106,6 @@ async fn handle_call_invite(
|
||||||
_offer: SessionDescription,
|
_offer: SessionDescription,
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
|
||||||
let myself = client.user_id().await.unwrap();
|
let myself = client.user_id().await.unwrap();
|
||||||
|
|
||||||
println!("Incoming call from {}", sender);
|
println!("Incoming call from {}", sender);
|
||||||
|
@ -125,7 +119,6 @@ async fn handle_call_invite(
|
||||||
|
|
||||||
//client.share_group_session(room_id);
|
//client.share_group_session(room_id);
|
||||||
let encrypted = {
|
let encrypted = {
|
||||||
|
|
||||||
let room = client.get_joined_room(room_id).await;
|
let room = client.get_joined_room(room_id).await;
|
||||||
|
|
||||||
match room {
|
match room {
|
||||||
|
@ -147,9 +140,7 @@ async fn create_call_invite(client: &Client, room_id: &RoomId) {
|
||||||
|
|
||||||
impl EventEmitter for CommandBot {
|
impl EventEmitter for CommandBot {
|
||||||
async fn on_room_message(&self, room: SyncRoom, event: &SyncMessageEvent<MessageEventContent>) {
|
async fn on_room_message(&self, room: SyncRoom, event: &SyncMessageEvent<MessageEventContent>) {
|
||||||
|
|
||||||
if let SyncRoom::Joined(room) = room {
|
if let SyncRoom::Joined(room) = room {
|
||||||
|
|
||||||
println!("Syncroom joined: {:?}", room);
|
println!("Syncroom joined: {:?}", room);
|
||||||
|
|
||||||
if let SyncMessageEvent {
|
if let SyncMessageEvent {
|
||||||
|
@ -158,7 +149,6 @@ impl EventEmitter for CommandBot {
|
||||||
..
|
..
|
||||||
} = event
|
} = event
|
||||||
{
|
{
|
||||||
|
|
||||||
let user_id = sender.localpart();
|
let user_id = sender.localpart();
|
||||||
|
|
||||||
let user_server = sender.server_name();
|
let user_server = sender.server_name();
|
||||||
|
@ -166,12 +156,9 @@ impl EventEmitter for CommandBot {
|
||||||
let myself = self.client.user_id().await.unwrap();
|
let myself = self.client.user_id().await.unwrap();
|
||||||
|
|
||||||
if (myself.localpart() == user_id && myself.server_name() == user_server) {
|
if (myself.localpart() == user_id && myself.server_name() == user_server) {
|
||||||
|
|
||||||
println!("Saw my own message, ignoring it");
|
println!("Saw my own message, ignoring it");
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
if (user_server == "matrix.voots.org") {
|
if (user_server == "matrix.voots.org") {
|
||||||
|
|
||||||
// TODO make this configurable on which servers
|
// TODO make this configurable on which servers
|
||||||
&self
|
&self
|
||||||
.handle_command(room, user_id.to_string(), msg_body.to_string())
|
.handle_command(room, user_id.to_string(), msg_body.to_string())
|
||||||
|
@ -189,16 +176,13 @@ impl EventEmitter for CommandBot {
|
||||||
event: Option<MemberEventContent>,
|
event: Option<MemberEventContent>,
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
|
||||||
println!("STRIPPED: {:?}", event);
|
println!("STRIPPED: {:?}", event);
|
||||||
|
|
||||||
if room_member.state_key != self.client.user_id().await.unwrap() {
|
if room_member.state_key != self.client.user_id().await.unwrap() {
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let SyncRoom::Invited(room) = room {
|
if let SyncRoom::Invited(room) = room {
|
||||||
|
|
||||||
let room = room.read().await;
|
let room = room.read().await;
|
||||||
|
|
||||||
println!("Autojoining room {}", room.display_name());
|
println!("Autojoining room {}", room.display_name());
|
||||||
|
@ -213,7 +197,6 @@ impl EventEmitter for CommandBot {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn login(botname: &String) -> Result<Client, anyhow::Error> {
|
pub async fn login(botname: &String) -> Result<Client, anyhow::Error> {
|
||||||
|
|
||||||
// the location for `JsonStore` to save files to
|
// the location for `JsonStore` to save files to
|
||||||
// homeserver_url: String, username: String, password: String
|
// homeserver_url: String, username: String, password: String
|
||||||
//let {homeserver_url: String, username: String, password: String} = config.matrix;
|
//let {homeserver_url: String, username: String, password: String} = config.matrix;
|
||||||
|
@ -265,7 +248,6 @@ pub async fn sync_and_loop(
|
||||||
receiver: Receiver<CallManagerToMatrix>,
|
receiver: Receiver<CallManagerToMatrix>,
|
||||||
) -> Result<(), anyhow::Error>
|
) -> Result<(), anyhow::Error>
|
||||||
{
|
{
|
||||||
|
|
||||||
// since we called sync before we `sync_forever` we must pass that sync token to
|
// since we called sync before we `sync_forever` we must pass that sync token to
|
||||||
// `sync_forever`
|
// `sync_forever`
|
||||||
let settings = SyncSettings::default().token(client.sync_token().await.unwrap());
|
let settings = SyncSettings::default().token(client.sync_token().await.unwrap());
|
||||||
|
@ -274,16 +256,13 @@ pub async fn sync_and_loop(
|
||||||
|
|
||||||
client
|
client
|
||||||
.sync_forever(settings, async move |response| {
|
.sync_forever(settings, async move |response| {
|
||||||
|
|
||||||
let client = &client_ref;
|
let client = &client_ref;
|
||||||
|
|
||||||
for event in &response.to_device.events {
|
for event in &response.to_device.events {
|
||||||
|
|
||||||
let e_maybe = event.deserialize();
|
let e_maybe = event.deserialize();
|
||||||
|
|
||||||
match e_maybe {
|
match e_maybe {
|
||||||
Ok(AnyToDeviceEvent::KeyVerificationStart(e)) => {
|
Ok(AnyToDeviceEvent::KeyVerificationStart(e)) => {
|
||||||
|
|
||||||
let sas = client
|
let sas = client
|
||||||
.get_verification(&e.content.transaction_id)
|
.get_verification(&e.content.transaction_id)
|
||||||
.await
|
.await
|
||||||
|
@ -293,7 +272,6 @@ pub async fn sync_and_loop(
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(AnyToDeviceEvent::KeyVerificationKey(e)) => {
|
Ok(AnyToDeviceEvent::KeyVerificationKey(e)) => {
|
||||||
|
|
||||||
let sas = client
|
let sas = client
|
||||||
.get_verification(&e.content.transaction_id)
|
.get_verification(&e.content.transaction_id)
|
||||||
.await
|
.await
|
||||||
|
@ -303,38 +281,31 @@ pub async fn sync_and_loop(
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(AnyToDeviceEvent::KeyVerificationMac(e)) => {
|
Ok(AnyToDeviceEvent::KeyVerificationMac(e)) => {
|
||||||
|
|
||||||
let sas = client
|
let sas = client
|
||||||
.get_verification(&e.content.transaction_id)
|
.get_verification(&e.content.transaction_id)
|
||||||
.await
|
.await
|
||||||
.expect("Sas object wasn't created");
|
.expect("Sas object wasn't created");
|
||||||
|
|
||||||
if sas.is_done() {
|
if sas.is_done() {
|
||||||
|
|
||||||
print_result(sas);
|
print_result(sas);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(_) => (), // Unknown or unhandled event
|
Ok(_) => (), // Unknown or unhandled event
|
||||||
Err(error) => {
|
Err(error) => {
|
||||||
|
|
||||||
eprintln!("Couldn't deserialize to to-device event: {:?} from {:?}", error, event);
|
eprintln!("Couldn't deserialize to to-device event: {:?} from {:?}", error, event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (room_id, room) in response.rooms.join {
|
for (room_id, room) in response.rooms.join {
|
||||||
|
|
||||||
for rawevent in &room.timeline.events {
|
for rawevent in &room.timeline.events {
|
||||||
|
|
||||||
let event = rawevent.deserialize().unwrap();
|
let event = rawevent.deserialize().unwrap();
|
||||||
|
|
||||||
// Check if it's a message type
|
// Check if it's a message type
|
||||||
if let Message(msg) = event {
|
if let Message(msg) = event {
|
||||||
|
|
||||||
match msg {
|
match msg {
|
||||||
CallCandidates(_e) => {}
|
CallCandidates(_e) => {}
|
||||||
CallInvite(e) => {
|
CallInvite(e) => {
|
||||||
|
|
||||||
println!("incoming debug: {:?}", e);
|
println!("incoming debug: {:?}", e);
|
||||||
|
|
||||||
let SyncMessageEvent {
|
let SyncMessageEvent {
|
||||||
|
@ -362,12 +333,10 @@ pub async fn sync_and_loop(
|
||||||
CallHangup(_e) => {}
|
CallHangup(_e) => {}
|
||||||
CallAnswer(_e) => {}
|
CallAnswer(_e) => {}
|
||||||
e => {
|
e => {
|
||||||
|
|
||||||
println!("unhandled debug: {:?}", e);
|
println!("unhandled debug: {:?}", e);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
println!("Got unknown event type here: {:?}", event);
|
println!("Got unknown event type here: {:?}", event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue