1#![allow(dead_code)]
67
68extern crate chrono;
69#[macro_use]
70extern crate lazy_static;
71extern crate ts3plugin_sys;
72
73pub use ts3plugin_sys::plugin_definitions::*;
74pub use ts3plugin_sys::public_definitions::*;
75pub use ts3plugin_sys::public_errors::Error;
76pub use ts3plugin_sys::ts3functions::Ts3Functions;
77
78pub use plugin::*;
79
80use chrono::*;
81use std::collections::HashMap as Map;
82use std::ffi::{CStr, CString};
83use std::fmt;
84use std::mem::transmute;
85use std::ops::{Deref, DerefMut};
86use std::os::raw::{c_char, c_int};
87use std::sync::MutexGuard;
88
89macro_rules! to_cstring {
91 ($string: expr) => {
92 CString::new($string).unwrap_or(CString::new("String contains null character").unwrap())
93 };
94}
95
96macro_rules! to_string {
98 ($string: expr) => {{
99 String::from_utf8_lossy(CStr::from_ptr($string).to_bytes()).into_owned()
100 }};
101}
102
103pub mod plugin;
105pub mod ts3interface;
106
107include!(concat!(env!("OUT_DIR"), "/channel.rs"));
109include!(concat!(env!("OUT_DIR"), "/connection.rs"));
110include!(concat!(env!("OUT_DIR"), "/server.rs"));
111
112#[doc(hidden)]
117pub static mut TS3_FUNCTIONS: Option<Ts3Functions> = None;
118
119#[derive(Clone)]
123pub enum MessageReceiver {
124 Connection(ConnectionId),
125 Channel,
126 Server,
127}
128
129#[derive(Debug, PartialEq, Eq, Clone)]
131pub struct Permissions;
132
133#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash)]
135pub struct ServerId(u64);
136
137#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash)]
139pub struct ChannelId(u64);
140
141#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash)]
143pub struct ConnectionId(u16);
144
145#[derive(Debug, Clone)]
146pub struct Permission {}
147
148#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash)]
149pub struct PermissionId(u32);
150
151#[derive(Debug, Clone)]
152pub struct ServerGroup {}
153
154#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash)]
155pub struct ServerGroupId(u64);
156
157#[derive(Debug, Clone)]
158pub struct ChannelGroup {}
159
160#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash)]
161pub struct ChannelGroupId(u64);
162
163#[derive(Debug, Eq)]
167pub struct InvokerData {
168 id: ConnectionId,
169 uid: String,
170 name: String,
171}
172
173impl PartialEq<InvokerData> for InvokerData {
174 fn eq(&self, other: &InvokerData) -> bool { self.id == other.id }
175}
176
177impl InvokerData {
178 fn new(id: ConnectionId, uid: String, name: String) -> InvokerData {
179 InvokerData { id, uid, name }
180 }
181
182 pub fn get_id(&self) -> ConnectionId { self.id }
184
185 pub fn get_uid(&self) -> &String { &self.uid }
187
188 pub fn get_name(&self) -> &String { &self.name }
190}
191
192#[derive(Debug, Eq)]
195pub struct Invoker<'a> {
196 server: Server<'a>,
197 data: InvokerData,
198}
199
200impl<'a, 'b> PartialEq<Invoker<'b>> for Invoker<'a> {
201 fn eq(&self, other: &Invoker) -> bool { self.server == other.server && self.data == other.data }
202}
203impl<'a> Deref for Invoker<'a> {
204 type Target = InvokerData;
205 fn deref(&self) -> &Self::Target { &self.data }
206}
207
208impl<'a> Invoker<'a> {
209 fn new(server: Server<'a>, data: InvokerData) -> Invoker<'a> { Invoker { server, data } }
210
211 pub fn get_connection(&self) -> Option<Connection> { self.server.get_connection(self.id) }
212}
213
214#[derive(Clone)]
216pub struct Server<'a> {
217 api: &'a TsApi,
218 data: Result<&'a ServerData, ServerId>,
219}
220
221impl<'a, 'b> PartialEq<Server<'b>> for Server<'a> {
222 fn eq(&self, other: &Server<'b>) -> bool { self.get_id() == other.get_id() }
223}
224impl<'a> Eq for Server<'a> {}
225impl<'a> fmt::Debug for Server<'a> {
226 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
227 write!(f, "Server({})", self.get_id().0)
228 }
229}
230
231impl PartialEq<ServerData> for ServerData {
232 fn eq(&self, other: &ServerData) -> bool { self.id == other.id }
233}
234impl Eq for ServerData {}
235
236impl ServerData {
237 fn get_property_as_string(
239 id: ServerId, property: VirtualServerProperties,
240 ) -> Result<String, Error> {
241 unsafe {
242 let mut name: *mut c_char = std::ptr::null_mut();
243 let res: Error =
244 transmute((TS3_FUNCTIONS
245 .as_ref()
246 .expect("Functions should be loaded")
247 .get_server_variable_as_string)(id.0, property as usize, &mut name));
248 match res {
249 Error::Ok => Ok(to_string!(name)),
250 _ => Err(res),
251 }
252 }
253 }
254
255 fn get_property_as_int(id: ServerId, property: VirtualServerProperties) -> Result<i32, Error> {
257 unsafe {
258 let mut number: c_int = 0;
259 let res: Error =
260 transmute((TS3_FUNCTIONS
261 .as_ref()
262 .expect("Functions should be loaded")
263 .get_server_variable_as_int)(id.0, property as usize, &mut number));
264 match res {
265 Error::Ok => Ok(number as i32),
266 _ => Err(res),
267 }
268 }
269 }
270
271 fn get_property_as_uint64(
273 id: ServerId, property: VirtualServerProperties,
274 ) -> Result<u64, Error> {
275 unsafe {
276 let mut number: u64 = 0;
277 let res: Error = transmute((TS3_FUNCTIONS
278 .as_ref()
279 .expect("Functions should be loaded")
280 .get_server_variable_as_uint64)(
281 id.0, property as usize, &mut number
282 ));
283 match res {
284 Error::Ok => Ok(number),
285 _ => Err(res),
286 }
287 }
288 }
289
290 fn query_own_connection_id(id: ServerId) -> Result<ConnectionId, Error> {
293 unsafe {
294 let mut number: u16 = 0;
295 let res: Error = transmute((TS3_FUNCTIONS
296 .as_ref()
297 .expect("Functions should be loaded")
298 .get_client_id)(id.0, &mut number));
299 match res {
300 Error::Ok => Ok(ConnectionId(number)),
301 _ => Err(res),
302 }
303 }
304 }
305
306 fn query_connections(id: ServerId) -> Map<ConnectionId, ConnectionData> {
310 let mut map = Map::new();
311 let mut result: *mut u16 = std::ptr::null_mut();
313 let res: Error =
314 unsafe {
315 transmute((TS3_FUNCTIONS
316 .as_ref()
317 .expect("Functions should be loaded")
318 .get_client_list)(id.0, &mut result))
319 };
320 if res == Error::Ok {
321 unsafe {
322 let mut counter = 0;
323 while *result.offset(counter) != 0 {
324 let connection_id = ConnectionId(*result.offset(counter));
325 let mut connection = ConnectionData::new(id, connection_id);
326 connection.update();
327 map.insert(connection_id, connection);
328 counter += 1;
329 }
330 }
331 }
332 map
333 }
334
335 fn query_channels(id: ServerId) -> Result<Map<ChannelId, ChannelData>, Error> {
339 let mut map = Map::new();
340 let mut result: *mut u64 = std::ptr::null_mut();
342 let res: Error = unsafe {
343 transmute((TS3_FUNCTIONS
344 .as_ref()
345 .expect("Functions should be loaded")
346 .get_channel_list)(id.0, &mut result))
347 };
348 if res == Error::Ok {
349 unsafe {
350 let mut counter = 0;
351 while *result.offset(counter) != 0 {
352 let channel_id = ChannelId(*result.offset(counter));
353 let mut channel = ChannelData::new(id, channel_id);
354 channel.update();
355 map.insert(channel_id, channel);
356 counter += 1;
357 }
358 }
359 Ok(map)
360 } else {
361 Err(res)
362 }
363 }
364
365 fn add_connection(&mut self, connection_id: ConnectionId) -> &mut ConnectionData {
368 let mut connection = ConnectionData::new(self.id, connection_id);
369 connection.update();
370 self.visible_connections.insert(connection_id, connection);
371 self.visible_connections.get_mut(&connection_id).unwrap()
372 }
373
374 fn remove_connection(&mut self, connection_id: ConnectionId) -> Option<ConnectionData> {
375 self.visible_connections.remove(&connection_id)
376 }
377
378 fn add_channel(&mut self, channel_id: ChannelId) -> Result<&mut ChannelData, Error> {
379 match self.channels {
380 Ok(ref mut cs) => {
381 let mut channel = ChannelData::new(self.id, channel_id);
382 channel.update();
383 cs.insert(channel_id, channel);
384 Ok(cs.get_mut(&channel_id).unwrap())
385 }
386 Err(error) => Err(error),
387 }
388 }
389
390 fn remove_channel(&mut self, channel_id: ChannelId) -> Option<ChannelData> {
391 self.channels.as_mut().ok().and_then(|cs| cs.remove(&channel_id))
392 }
393
394 fn get_mut_connection(&mut self, connection_id: ConnectionId) -> Option<&mut ConnectionData> {
397 self.visible_connections.get_mut(&connection_id)
398 }
399
400 fn get_mut_channel(&mut self, channel_id: ChannelId) -> Option<&mut ChannelData> {
403 self.channels.as_mut().ok().and_then(|cs| cs.get_mut(&channel_id))
404 }
405}
406
407impl<'a> Server<'a> {
408 fn new(api: &'a TsApi, data: &'a ServerData) -> Server<'a> { Server { api, data: Ok(data) } }
409
410 fn new_err(api: &'a TsApi, server_id: ServerId) -> Server<'a> {
411 Server { api, data: Err(server_id) }
412 }
413
414 pub fn get_id(&self) -> ServerId {
415 match self.data {
416 Ok(data) => data.get_id(),
417 Err(id) => id,
418 }
419 }
420
421 fn get_connection_unwrap(&self, connection_id: ConnectionId) -> Connection<'a> {
424 self.get_connection(connection_id).unwrap_or_else(|| {
425 self.api.log_or_print(
426 format!("Can't find connection {:?}", connection_id),
427 "rust-ts3plugin",
428 ::LogLevel::Warning,
429 );
430 Connection::new_err(&self.api, self.get_id(), connection_id)
431 })
432 }
433
434 fn get_channel_unwrap(&self, channel_id: ChannelId) -> Channel<'a> {
437 self.get_channel(channel_id).unwrap_or_else(|| {
438 self.api.log_or_print(
439 format!("Can't find channel {:?}", channel_id),
440 "rust-ts3plugin",
441 ::LogLevel::Warning,
442 );
443 Channel::new_owned(&self.api, self.get_id(), channel_id)
444 })
445 }
446
447 fn get_server_group_unwrap(&self, server_group_id: ServerGroupId) -> ServerGroup {
448 self.get_server_group(server_group_id).unwrap_or_else(|| {
449 ServerGroup {}
453 })
454 }
455
456 fn get_channel_group_unwrap(&self, channel_group_id: ChannelGroupId) -> ChannelGroup {
457 self.get_channel_group(channel_group_id).unwrap_or_else(|| {
458 ChannelGroup {}
461 })
462 }
463
464 pub fn get_own_connection(&self) -> Result<Connection<'a>, Error> {
473 match self.data {
474 Ok(data) => data.get_own_connection_id().map(|id| self.get_connection_unwrap(id)),
475 Err(_) => Err(Error::Ok),
476 }
477 }
478
479 pub fn get_connections(&self) -> Vec<Connection<'a>> {
481 match self.data {
482 Ok(data) => {
483 data.visible_connections.values().map(|c| Connection::new(self.api, &c)).collect()
484 }
485 Err(_) => Vec::new(),
486 }
487 }
488
489 pub fn get_channels(&self) -> Vec<Channel<'a>> {
491 match self.data {
492 Ok(data) => match data.channels {
493 Ok(ref cs) => cs.values().map(|c| Channel::new(self.api, &c)).collect(),
494 Err(_) => Vec::new(),
495 },
496 Err(_) => Vec::new(),
497 }
498 }
499
500 pub fn get_connection(&self, connection_id: ConnectionId) -> Option<Connection<'a>> {
503 self.data.ok().and_then(|data| {
504 data.visible_connections.get(&connection_id).map(|c| Connection::new(&self.api, c))
505 })
506 }
507
508 pub fn get_channel(&self, channel_id: ChannelId) -> Option<Channel<'a>> {
511 self.data.ok().and_then(|data| {
512 data.channels
513 .as_ref()
514 .ok()
515 .and_then(|cs| cs.get(&channel_id))
516 .map(|c| Channel::new(&self.api, c))
517 })
518 }
519
520 pub fn get_server_group(&self, _server_group_id: ServerGroupId) -> Option<ServerGroup> {
521 todo!()
522 }
523
524 pub fn get_channel_group(&self, _channel_group_id: ChannelGroupId) -> Option<ChannelGroup> {
525 todo!()
526 }
527
528 pub fn send_message<S: AsRef<str>>(&self, message: S) -> Result<(), Error> {
530 unsafe {
531 let text = to_cstring!(message.as_ref());
532 let res: Error = transmute((TS3_FUNCTIONS
533 .as_ref()
534 .expect("Functions should be loaded")
535 .request_send_server_text_msg)(
536 self.get_id().0, text.as_ptr(), std::ptr::null()
537 ));
538 match res {
539 Error::Ok => Ok(()),
540 _ => Err(res),
541 }
542 }
543 }
544
545 pub fn send_plugin_message<S: AsRef<str>>(&self, message: S) {
552 unsafe {
553 let text = to_cstring!(message.as_ref());
554 (TS3_FUNCTIONS.as_ref().expect("Functions should be loaded").send_plugin_command)(
555 self.get_id().0,
556 to_cstring!(self.api.get_plugin_id()).as_ptr(),
557 text.as_ptr(),
558 PluginTargetMode::Server as i32,
559 std::ptr::null(),
560 std::ptr::null(),
561 );
562 }
563 }
564
565 pub fn print_message<S: AsRef<str>>(&self, message: S, target: MessageTarget) {
568 unsafe {
569 let text = to_cstring!(message.as_ref());
570 (TS3_FUNCTIONS.as_ref().expect("Functions should be loaded").print_message)(
571 self.get_id().0,
572 text.as_ptr(),
573 target,
574 );
575 }
576 }
577}
578
579#[derive(Clone)]
581pub struct Channel<'a> {
582 api: &'a TsApi,
583 data: Result<&'a ChannelData, (ServerId, ChannelId)>,
584}
585
586impl<'a, 'b> PartialEq<Channel<'b>> for Channel<'a> {
587 fn eq(&self, other: &Channel<'b>) -> bool {
588 self.get_server_id() == other.get_server_id() && self.get_id() == other.get_id()
589 }
590}
591impl<'a> Eq for Channel<'a> {}
592impl<'a> fmt::Debug for Channel<'a> {
593 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
594 write!(f, "Channel({})", self.get_id().0)
595 }
596}
597
598impl PartialEq<ChannelData> for ChannelData {
599 fn eq(&self, other: &ChannelData) -> bool {
600 self.server_id == other.server_id && self.id == other.id
601 }
602}
603impl Eq for ChannelData {}
604
605impl ChannelData {
606 fn get_property_as_string(
608 server_id: ServerId, id: ChannelId, property: ChannelProperties,
609 ) -> Result<String, Error> {
610 unsafe {
611 let mut name: *mut c_char = std::ptr::null_mut();
612 let res: Error = transmute((TS3_FUNCTIONS
613 .as_ref()
614 .expect("Functions should be loaded")
615 .get_channel_variable_as_string)(
616 server_id.0, id.0, property as usize, &mut name
617 ));
618 match res {
619 Error::Ok => Ok(to_string!(name)),
620 _ => Err(res),
621 }
622 }
623 }
624
625 fn get_property_as_int(
627 server_id: ServerId, id: ChannelId, property: ChannelProperties,
628 ) -> Result<i32, Error> {
629 unsafe {
630 let mut number: c_int = 0;
631 let res: Error = transmute((TS3_FUNCTIONS
632 .as_ref()
633 .expect("Functions should be loaded")
634 .get_channel_variable_as_int)(
635 server_id.0, id.0, property as usize, &mut number
636 ));
637 match res {
638 Error::Ok => Ok(number as i32),
639 _ => Err(res),
640 }
641 }
642 }
643
644 fn get_property_as_uint64(
646 server_id: ServerId, id: ChannelId, property: ChannelProperties,
647 ) -> Result<i32, Error> {
648 unsafe {
649 let mut number: u64 = 0;
650 let res: Error = transmute((TS3_FUNCTIONS
651 .as_ref()
652 .expect("Functions should be loaded")
653 .get_channel_variable_as_uint64)(
654 server_id.0, id.0, property as usize, &mut number
655 ));
656 match res {
657 Error::Ok => Ok(number as i32),
658 _ => Err(res),
659 }
660 }
661 }
662
663 fn query_parent_channel_id(server_id: ServerId, id: ChannelId) -> Result<ChannelId, Error> {
665 unsafe {
666 let mut number: u64 = 0;
667 let res: Error =
668 transmute((TS3_FUNCTIONS
669 .as_ref()
670 .expect("Functions should be loaded")
671 .get_parent_channel_of_channel)(server_id.0, id.0, &mut number));
672 match res {
673 Error::Ok => Ok(ChannelId(number)),
674 _ => Err(res),
675 }
676 }
677 }
678}
679
680impl<'a> Channel<'a> {
681 fn new(api: &'a TsApi, data: &'a ChannelData) -> Channel<'a> { Channel { api, data: Ok(data) } }
682
683 fn new_owned(api: &'a TsApi, server_id: ServerId, channel_id: ChannelId) -> Channel<'a> {
684 Channel { api, data: Err((server_id, channel_id)) }
685 }
686
687 fn get_server_id(&self) -> ServerId {
688 match self.data {
689 Ok(data) => data.get_server_id(),
690 Err((server_id, _)) => server_id,
691 }
692 }
693
694 pub fn get_id(&self) -> ChannelId {
695 match self.data {
696 Ok(data) => data.get_id(),
697 Err((_, channel_id)) => channel_id,
698 }
699 }
700
701 pub fn get_server(&self) -> Server<'a> { self.api.get_server_unwrap(self.get_server_id()) }
703
704 pub fn get_parent_channel(&self) -> Result<Option<Channel<'a>>, Error> {
705 match self.data {
706 Ok(data) => data.get_parent_channel_id().map(|parent_channel_id| {
707 if parent_channel_id.0 == 0 {
708 None
709 } else {
710 Some(self.get_server().get_channel_unwrap(parent_channel_id))
711 }
712 }),
713 Err(_) => Err(Error::Ok),
714 }
715 }
716
717 pub fn send_message<S: AsRef<str>>(&self, message: S) -> Result<(), Error> {
719 unsafe {
720 let text = to_cstring!(message.as_ref());
721 let res: Error = transmute((TS3_FUNCTIONS
722 .as_ref()
723 .expect("Functions should be loaded")
724 .request_send_channel_text_msg)(
725 self.data.unwrap().server_id.0,
726 text.as_ptr(),
727 self.data.unwrap().id.0,
728 std::ptr::null(),
729 ));
730 match res {
731 Error::Ok => Ok(()),
732 _ => Err(res),
733 }
734 }
735 }
736}
737
738#[derive(Clone)]
740pub struct Connection<'a> {
741 api: &'a TsApi,
742 data: Result<&'a ConnectionData, (ServerId, ConnectionId)>,
743}
744
745impl<'a, 'b> PartialEq<Connection<'b>> for Connection<'a> {
746 fn eq(&self, other: &Connection<'b>) -> bool {
747 self.get_server_id() == other.get_server_id() && self.get_id() == other.get_id()
748 }
749}
750impl<'a> Eq for Connection<'a> {}
751impl<'a> fmt::Debug for Connection<'a> {
752 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
753 write!(f, "Connection({})", self.get_id().0)
754 }
755}
756
757impl PartialEq<ConnectionData> for ConnectionData {
758 fn eq(&self, other: &ConnectionData) -> bool {
759 self.server_id == other.server_id && self.id == other.id
760 }
761}
762impl Eq for ConnectionData {}
763
764impl ConnectionData {
765 fn get_connection_property_as_string(
767 server_id: ServerId, id: ConnectionId, property: ConnectionProperties,
768 ) -> Result<String, Error> {
769 unsafe {
770 let mut name: *mut c_char = std::ptr::null_mut();
771 let res: Error = transmute((TS3_FUNCTIONS
772 .as_ref()
773 .expect("Functions should be loaded")
774 .get_connection_variable_as_string)(
775 server_id.0, id.0, property as usize, &mut name
776 ));
777 match res {
778 Error::Ok => Ok(to_string!(name)),
779 _ => Err(res),
780 }
781 }
782 }
783
784 fn get_connection_property_as_uint64(
786 server_id: ServerId, id: ConnectionId, property: ConnectionProperties,
787 ) -> Result<u64, Error> {
788 unsafe {
789 let mut number: u64 = 0;
790 let res: Error = transmute((TS3_FUNCTIONS
791 .as_ref()
792 .expect("Functions should be loaded")
793 .get_connection_variable_as_uint64)(
794 server_id.0, id.0, property as usize, &mut number
795 ));
796 match res {
797 Error::Ok => Ok(number),
798 _ => Err(res),
799 }
800 }
801 }
802
803 fn get_connection_property_as_double(
805 server_id: ServerId, id: ConnectionId, property: ConnectionProperties,
806 ) -> Result<f64, Error> {
807 unsafe {
808 let mut number: f64 = 0.0;
809 let res: Error = transmute((TS3_FUNCTIONS
810 .as_ref()
811 .expect("Functions should be loaded")
812 .get_connection_variable_as_double)(
813 server_id.0, id.0, property as usize, &mut number
814 ));
815 match res {
816 Error::Ok => Ok(number),
817 _ => Err(res),
818 }
819 }
820 }
821
822 fn get_client_property_as_string(
824 server_id: ServerId, id: ConnectionId, property: ClientProperties,
825 ) -> Result<String, Error> {
826 unsafe {
827 let mut name: *mut c_char = std::ptr::null_mut();
828 let res: Error = transmute((TS3_FUNCTIONS
829 .as_ref()
830 .expect("Functions should be loaded")
831 .get_client_variable_as_string)(
832 server_id.0, id.0, property as usize, &mut name
833 ));
834 match res {
835 Error::Ok => Ok(to_string!(name)),
836 _ => Err(res),
837 }
838 }
839 }
840
841 fn get_client_property_as_int(
843 server_id: ServerId, id: ConnectionId, property: ClientProperties,
844 ) -> Result<c_int, Error> {
845 unsafe {
846 let mut number: c_int = 0;
847 let res: Error = transmute((TS3_FUNCTIONS
848 .as_ref()
849 .expect("Functions should be loaded")
850 .get_client_variable_as_int)(
851 server_id.0, id.0, property as usize, &mut number
852 ));
853 match res {
854 Error::Ok => Ok(number),
855 _ => Err(res),
856 }
857 }
858 }
859
860 fn query_channel_id(server_id: ServerId, id: ConnectionId) -> Result<ChannelId, Error> {
862 unsafe {
863 let mut number: u64 = 0;
864 let res: Error = transmute((TS3_FUNCTIONS
865 .as_ref()
866 .expect("Functions should be loaded")
867 .get_channel_of_client)(server_id.0, id.0, &mut number));
868 match res {
869 Error::Ok => Ok(ChannelId(number)),
870 _ => Err(res),
871 }
872 }
873 }
874
875 fn query_whispering(server_id: ServerId, id: ConnectionId) -> Result<bool, Error> {
878 unsafe {
879 let mut number: c_int = 0;
880 let res: Error = transmute((TS3_FUNCTIONS
881 .as_ref()
882 .expect("Functions should be loaded")
883 .is_whispering)(server_id.0, id.0, &mut number));
884 match res {
885 Error::Ok => Ok(number != 0),
886 _ => Err(res),
887 }
888 }
889 }
890}
891
892impl<'a> Connection<'a> {
893 fn new(api: &'a TsApi, data: &'a ConnectionData) -> Connection<'a> {
894 Connection { api, data: Ok(data) }
895 }
896
897 fn new_err(api: &'a TsApi, server_id: ServerId, connection_id: ConnectionId) -> Connection<'a> {
898 Connection { api, data: Err((server_id, connection_id)) }
899 }
900
901 fn get_server_id(&self) -> ServerId {
902 match self.data {
903 Ok(data) => data.get_server_id(),
904 Err((server_id, _)) => server_id,
905 }
906 }
907
908 pub fn get_id(&self) -> ConnectionId {
909 match self.data {
910 Ok(data) => data.get_id(),
911 Err((_, connection_id)) => connection_id,
912 }
913 }
914
915 pub fn get_server(&self) -> Server<'a> { self.api.get_server_unwrap(self.get_server_id()) }
917
918 pub fn get_channel(&self) -> Result<Channel<'a>, Error> {
920 match self.data {
921 Ok(data) => data.get_channel_id().map(|c| self.get_server().get_channel_unwrap(c)),
922 Err(_) => Err(Error::Ok),
923 }
924 }
925
926 pub fn get_channel_group_inherited_channel(&self) -> Result<Channel<'a>, Error> {
927 match self.data {
928 Ok(data) => data
929 .get_channel_group_inherited_channel_id()
930 .map(|c| self.get_server().get_channel_unwrap(c)),
931 Err(_) => Err(Error::Ok),
932 }
933 }
934
935 pub fn send_message<S: AsRef<str>>(&self, message: S) -> Result<(), Error> {
952 unsafe {
953 let text = to_cstring!(message.as_ref());
954 let res: Error = transmute((TS3_FUNCTIONS
955 .as_ref()
956 .expect("Functions should be loaded")
957 .request_send_private_text_msg)(
958 self.data.unwrap().server_id.0,
959 text.as_ptr(),
960 self.data.unwrap().id.0,
961 std::ptr::null(),
962 ));
963 match res {
964 Error::Ok => Ok(()),
965 _ => Err(res),
966 }
967 }
968 }
969}
970
971pub struct TsApiLock {
972 guard: MutexGuard<'static, (Option<(TsApi, Box<dyn Plugin>)>, Option<String>)>,
973}
974impl Deref for TsApiLock {
975 type Target = TsApi;
976 fn deref(&self) -> &Self::Target { &self.guard.0.as_ref().unwrap().0 }
977}
978impl DerefMut for TsApiLock {
979 fn deref_mut(&mut self) -> &mut Self::Target { &mut self.guard.0.as_mut().unwrap().0 }
980}
981
982pub struct PluginLock {
983 guard: MutexGuard<'static, (Option<(TsApi, Box<dyn Plugin>)>, Option<String>)>,
984}
985impl Deref for PluginLock {
986 type Target = dyn Plugin;
987 fn deref(&self) -> &Self::Target { &*self.guard.0.as_ref().unwrap().1 }
988}
989impl DerefMut for PluginLock {
990 fn deref_mut(&mut self) -> &mut Self::Target { &mut *self.guard.0.as_mut().unwrap().1 }
991}
992
993pub struct TsApi {
996 servers: Map<ServerId, ServerData>,
998 plugin_id: String,
1000}
1001
1002impl TsApi {
1005 fn new(plugin_id: String) -> TsApi { TsApi { servers: Map::new(), plugin_id: plugin_id } }
1007
1008 fn load(&mut self) -> Result<(), Error> {
1011 let mut result: *mut u64 = std::ptr::null_mut();
1013 let res: Error = unsafe {
1014 transmute((TS3_FUNCTIONS
1015 .as_ref()
1016 .expect("Functions should be loaded")
1017 .get_server_connection_handler_list)(&mut result))
1018 };
1019 match res {
1020 Error::Ok => unsafe {
1021 let mut counter = 0;
1022 while *result.offset(counter) != 0 {
1023 let mut status: c_int = 0;
1026 let res: Error = transmute((TS3_FUNCTIONS
1027 .as_ref()
1028 .expect("Functions should be loaded")
1029 .get_connection_status)(
1030 *result.offset(counter), &mut status
1031 ));
1032 if res == Error::Ok
1033 && transmute::<c_int, ConnectStatus>(status) != ConnectStatus::Disconnected
1034 {
1035 self.add_server(ServerId(*result.offset(counter)));
1036 }
1037 counter += 1;
1038 }
1039 },
1040 _ => return Err(res),
1041 }
1042 Ok(())
1043 }
1044
1045 pub fn lock_api() -> Option<TsApiLock> {
1048 let guard = ts3interface::DATA.lock().unwrap();
1049 if guard.0.is_none() { None } else { Some(TsApiLock { guard }) }
1050 }
1051
1052 pub fn lock_plugin() -> Option<PluginLock> {
1054 let guard = ts3interface::DATA.lock().unwrap();
1055 if guard.0.is_none() { None } else { Some(PluginLock { guard }) }
1056 }
1057
1058 pub fn static_log_message<S1: AsRef<str>, S2: AsRef<str>>(
1060 message: S1, channel: S2, severity: LogLevel,
1061 ) -> Result<(), Error> {
1062 unsafe {
1063 let res: Error = transmute((TS3_FUNCTIONS
1064 .as_ref()
1065 .expect("Functions should be loaded")
1066 .log_message)(
1067 to_cstring!(message.as_ref()).as_ptr(),
1068 severity,
1069 to_cstring!(channel.as_ref()).as_ptr(),
1070 0,
1071 ));
1072 match res {
1073 Error::Ok => Ok(()),
1074 _ => Err(res),
1075 }
1076 }
1077 }
1078
1079 pub fn static_log_or_print<S1: AsRef<str>, S2: AsRef<str>>(
1081 message: S1, channel: S2, severity: LogLevel,
1082 ) {
1083 if let Err(error) = TsApi::static_log_message(message.as_ref(), channel.as_ref(), severity)
1084 {
1085 println!(
1086 "Error {:?} while printing '{}' to '{}' ({:?})",
1087 error,
1088 message.as_ref(),
1089 channel.as_ref(),
1090 severity
1091 );
1092 }
1093 }
1094
1095 pub fn static_get_error_message(error: Error) -> Result<String, Error> {
1097 unsafe {
1098 let mut message: *mut c_char = std::ptr::null_mut();
1099 let res: Error = transmute((TS3_FUNCTIONS
1100 .as_ref()
1101 .expect("Functions should be loaded")
1102 .get_error_message)(error as u32, &mut message));
1103 match res {
1104 Error::Ok => Ok(to_string!(message)),
1105 _ => Err(res),
1106 }
1107 }
1108 }
1109
1110 fn add_server(&mut self, server_id: ServerId) -> &mut ServerData {
1115 self.servers.insert(server_id, ServerData::new(server_id));
1116 let server = self.servers.get_mut(&server_id).unwrap();
1117 server.update();
1118 server
1119 }
1120
1121 fn remove_server(&mut self, server_id: ServerId) -> Option<ServerData> {
1123 self.servers.remove(&server_id)
1124 }
1125
1126 fn try_update_invoker(&mut self, server_id: ServerId, invoker: &InvokerData) {
1129 if let Some(server) = self.get_mut_server(server_id) {
1130 if let Some(connection) = server.get_mut_connection(invoker.get_id()) {
1131 if connection.get_uid() != Ok(invoker.get_uid()) {
1132 connection.uid = Ok(invoker.get_uid().clone());
1133 }
1134 if connection.get_name() != Ok(invoker.get_name()) {
1135 connection.name = Ok(invoker.get_name().clone())
1136 }
1137 }
1138 }
1139 }
1140
1141 fn get_path<F: Fn(*mut c_char, usize)>(fun: F) -> String {
1148 const START_SIZE: usize = 512;
1149 const MAX_SIZE: usize = 100_000;
1150 let mut size = START_SIZE;
1151 loop {
1152 let mut buf = vec![0 as u8; size];
1153 fun(buf.as_mut_ptr() as *mut c_char, size - 1);
1154 if buf[size - 3] != 0 {
1156 size *= 2;
1157 if size > MAX_SIZE {
1158 return String::new();
1159 }
1160 } else {
1161 buf[size - 1] = 0;
1163 let s = unsafe { CStr::from_ptr(buf.as_ptr() as *const c_char) };
1164 let result = s.to_string_lossy();
1165 return result.into_owned();
1166 }
1167 }
1168 }
1169
1170 fn get_mut_server(&mut self, server_id: ServerId) -> Option<&mut ServerData> {
1173 self.servers.get_mut(&server_id)
1174 }
1175
1176 fn get_server_unwrap<'a>(&'a self, server_id: ServerId) -> Server<'a> {
1177 self.servers.get(&server_id).map(|s| Server::<'a>::new(&self, s)).unwrap_or_else(|| {
1178 Server::new_err(&self, server_id)
1183 })
1184 }
1185
1186 pub unsafe fn get_raw_api() -> &'static Ts3Functions { TS3_FUNCTIONS.as_ref().unwrap() }
1193
1194 pub fn get_plugin_id(&self) -> &str { &self.plugin_id }
1196
1197 pub fn get_servers<'a>(&'a self) -> Vec<Server<'a>> {
1199 self.servers.values().map(|s| Server::new(&self, &s)).collect()
1200 }
1201
1202 pub fn log_message<S1: AsRef<str>, S2: AsRef<str>>(
1204 &self, message: S1, channel: S2, severity: LogLevel,
1205 ) -> Result<(), Error> {
1206 TsApi::static_log_message(message, channel, severity)
1207 }
1208
1209 pub fn log_or_print<S1: AsRef<str>, S2: AsRef<str>>(
1212 &self, message: S1, channel: S2, severity: LogLevel,
1213 ) {
1214 TsApi::static_log_or_print(message, channel, severity)
1215 }
1216
1217 pub fn get_server(&self, server_id: ServerId) -> Option<Server> {
1220 self.servers.get(&server_id).map(|s| Server::new(&self, s))
1221 }
1222
1223 pub fn get_permission(&self, _permission_id: PermissionId) -> Option<&Permission> { todo!() }
1224
1225 pub fn print_message<S: AsRef<str>>(&self, message: S) {
1228 unsafe {
1229 let text = to_cstring!(message.as_ref());
1230 (TS3_FUNCTIONS
1231 .as_ref()
1232 .expect("Functions should be loaded")
1233 .print_message_to_current_tab)(text.as_ptr());
1234 }
1235 }
1236
1237 pub fn get_app_path(&self) -> String {
1239 unsafe {
1240 TsApi::get_path(|p, l| {
1241 (TS3_FUNCTIONS.as_ref().expect("Functions should be loaded").get_app_path)(p, l)
1242 })
1243 }
1244 }
1245
1246 pub fn get_resources_path(&self) -> String {
1248 unsafe {
1249 TsApi::get_path(|p, l| {
1250 (TS3_FUNCTIONS.as_ref().expect("Functions should be loaded").get_resources_path)(
1251 p, l,
1252 )
1253 })
1254 }
1255 }
1256
1257 pub fn get_config_path(&self) -> String {
1260 unsafe {
1261 TsApi::get_path(|p, l| {
1262 (TS3_FUNCTIONS.as_ref().expect("Functions should be loaded").get_config_path)(p, l)
1263 })
1264 }
1265 }
1266
1267 pub fn get_plugin_path(&self) -> String {
1269 unsafe {
1270 TsApi::get_path(|p, l| {
1271 (TS3_FUNCTIONS.as_ref().expect("Functions should be loaded").get_plugin_path)(
1272 p,
1273 l,
1274 to_cstring!(self.plugin_id.as_str()).as_ptr(),
1275 )
1276 })
1277 }
1278 }
1279}