Move wayvr-ipc to our workspace (#324)
This commit is contained in:
496
wayvr-ipc/src/client.rs
Normal file
496
wayvr-ipc/src/client.rs
Normal file
@@ -0,0 +1,496 @@
|
||||
use bytes::BufMut;
|
||||
use interprocess::local_socket::{
|
||||
self,
|
||||
tokio::{prelude::*, Stream},
|
||||
GenericNamespaced,
|
||||
};
|
||||
use serde::Serialize;
|
||||
use smallvec::SmallVec;
|
||||
use std::sync::{Arc, Weak};
|
||||
use tokio::{
|
||||
io::{AsyncReadExt, AsyncWriteExt},
|
||||
sync::Mutex,
|
||||
};
|
||||
use tokio_util::sync::CancellationToken;
|
||||
|
||||
use crate::{
|
||||
gen_id,
|
||||
ipc::{self, Serial},
|
||||
packet_client::{self, PacketClient},
|
||||
packet_server::{self, PacketServer},
|
||||
util::notifier::Notifier,
|
||||
};
|
||||
|
||||
pub struct QueuedPacket {
|
||||
notifier: Notifier,
|
||||
serial: Serial,
|
||||
packet: Option<PacketServer>,
|
||||
}
|
||||
|
||||
gen_id!(
|
||||
QueuedPacketVec,
|
||||
QueuedPacket,
|
||||
QueuedPacketCell,
|
||||
QueuedPacketHandle
|
||||
);
|
||||
|
||||
#[derive(Debug, Serialize, Clone)]
|
||||
pub struct AuthInfo {
|
||||
pub runtime: String,
|
||||
}
|
||||
|
||||
type SignalFunc = Box<dyn FnMut(&packet_server::PacketServer) -> bool + Send>;
|
||||
|
||||
pub struct WayVRClient {
|
||||
receiver: ReceiverMutex,
|
||||
sender: SenderMutex,
|
||||
cancel_token: CancellationToken,
|
||||
exiting: bool,
|
||||
queued_packets: QueuedPacketVec,
|
||||
pub auth: Option<AuthInfo>, // Some if authenticated
|
||||
pub on_signal: Option<SignalFunc>,
|
||||
}
|
||||
|
||||
pub async fn send_packet(sender: &SenderMutex, data: &[u8]) -> anyhow::Result<()> {
|
||||
let mut bytes = bytes::BytesMut::new();
|
||||
|
||||
// packet size
|
||||
bytes.put_u32(data.len() as u32);
|
||||
|
||||
// packet data
|
||||
bytes.put_slice(data);
|
||||
|
||||
sender.lock().await.write_all(&bytes).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub type WayVRClientMutex = Arc<Mutex<WayVRClient>>;
|
||||
pub type WayVRClientWeak = Weak<Mutex<WayVRClient>>;
|
||||
|
||||
type ReceiverMutex = Arc<Mutex<local_socket::tokio::RecvHalf>>;
|
||||
type SenderMutex = Arc<Mutex<local_socket::tokio::SendHalf>>;
|
||||
|
||||
async fn client_runner(client: WayVRClientMutex) -> anyhow::Result<()> {
|
||||
loop {
|
||||
WayVRClient::tick(client.clone()).await?;
|
||||
}
|
||||
}
|
||||
|
||||
type Payload = SmallVec<[u8; 64]>;
|
||||
|
||||
async fn read_payload(
|
||||
conn: &mut local_socket::tokio::RecvHalf,
|
||||
size: u32,
|
||||
) -> anyhow::Result<Payload> {
|
||||
let mut payload = Payload::new();
|
||||
payload.resize(size as usize, 0);
|
||||
conn.read_exact(&mut payload).await?;
|
||||
Ok(payload)
|
||||
}
|
||||
|
||||
macro_rules! bail_unexpected_response {
|
||||
() => {
|
||||
anyhow::bail!("unexpected response");
|
||||
};
|
||||
}
|
||||
|
||||
// Send and wait for a response from the server
|
||||
macro_rules! send_and_wait {
|
||||
($client_mtx:expr, $serial:expr, $packet_to_send:expr, $expected_response_type:ident) => {{
|
||||
let result =
|
||||
WayVRClient::queue_wait_packet($client_mtx, $serial, &ipc::data_encode($packet_to_send))
|
||||
.await?;
|
||||
if let PacketServer::$expected_response_type(_, res) = result {
|
||||
res
|
||||
} else {
|
||||
bail_unexpected_response!();
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
||||
// Send without expecting any response
|
||||
macro_rules! send_only {
|
||||
($client_mtx:expr, $packet_to_send:expr) => {{
|
||||
WayVRClient::send_payload($client_mtx, &ipc::data_encode($packet_to_send)).await?;
|
||||
}};
|
||||
}
|
||||
|
||||
impl WayVRClient {
|
||||
pub fn set_signal_handler(&mut self, on_signal: SignalFunc) {
|
||||
self.on_signal = Some(on_signal);
|
||||
}
|
||||
|
||||
pub async fn new(client_name: &str) -> anyhow::Result<WayVRClientMutex> {
|
||||
let printname = "/tmp/wayvr_ipc.sock";
|
||||
let name = printname.to_ns_name::<GenericNamespaced>()?;
|
||||
|
||||
let stream = match Stream::connect(name).await {
|
||||
Ok(c) => c,
|
||||
Err(e) => {
|
||||
anyhow::bail!("Failed to connect to the WayVR IPC: {}", e)
|
||||
}
|
||||
};
|
||||
let (receiver, sender) = stream.split();
|
||||
|
||||
let receiver = Arc::new(Mutex::new(receiver));
|
||||
let sender = Arc::new(Mutex::new(sender));
|
||||
|
||||
let cancel_token = CancellationToken::new();
|
||||
|
||||
let client = Arc::new(Mutex::new(Self {
|
||||
receiver,
|
||||
sender: sender.clone(),
|
||||
exiting: false,
|
||||
cancel_token: cancel_token.clone(),
|
||||
queued_packets: QueuedPacketVec::new(),
|
||||
auth: None,
|
||||
on_signal: None,
|
||||
}));
|
||||
|
||||
WayVRClient::start_runner(client.clone(), cancel_token);
|
||||
|
||||
// Send handshake to the server
|
||||
send_packet(
|
||||
&sender,
|
||||
&ipc::data_encode(&PacketClient::Handshake(packet_client::Handshake {
|
||||
client_name: String::from(client_name),
|
||||
magic: String::from(ipc::CONNECTION_MAGIC),
|
||||
protocol_version: ipc::PROTOCOL_VERSION,
|
||||
})),
|
||||
)
|
||||
.await?;
|
||||
|
||||
Ok(client)
|
||||
}
|
||||
|
||||
fn start_runner(client: WayVRClientMutex, cancel_token: CancellationToken) {
|
||||
tokio::spawn(async move {
|
||||
tokio::select! {
|
||||
_ = cancel_token.cancelled() => {
|
||||
log::info!("Exiting IPC runner gracefully");
|
||||
}
|
||||
e = client_runner(client.clone()) => {
|
||||
log::info!("IPC Runner failed: {:?}", e);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async fn tick(client_mtx: WayVRClientMutex) -> anyhow::Result<()> {
|
||||
let receiver = {
|
||||
let client = client_mtx.lock().await;
|
||||
client.receiver.clone()
|
||||
};
|
||||
|
||||
// read packet
|
||||
let packet = {
|
||||
let mut receiver = receiver.lock().await;
|
||||
let packet_size = receiver.read_u32().await?;
|
||||
log::trace!("packet size {}", packet_size);
|
||||
if packet_size > 128 * 1024 {
|
||||
anyhow::bail!("packet size too large (> 128 KiB)");
|
||||
}
|
||||
let payload = read_payload(&mut receiver, packet_size).await?;
|
||||
let packet: PacketServer = ipc::data_decode(&payload)?;
|
||||
packet
|
||||
};
|
||||
|
||||
{
|
||||
let mut client = client_mtx.lock().await;
|
||||
|
||||
if let PacketServer::HandshakeSuccess(success) = &packet {
|
||||
if client.auth.is_some() {
|
||||
anyhow::bail!("Got handshake response twice");
|
||||
}
|
||||
|
||||
client.auth = Some(AuthInfo {
|
||||
runtime: success.runtime.clone(),
|
||||
});
|
||||
|
||||
log::info!(
|
||||
"Authenticated. Server runtime name: \"{}\"",
|
||||
success.runtime
|
||||
);
|
||||
}
|
||||
|
||||
if let PacketServer::Disconnect(disconnect) = &packet {
|
||||
anyhow::bail!("Server disconnected us. Reason: {}", disconnect.reason);
|
||||
}
|
||||
|
||||
if client.auth.is_none() {
|
||||
anyhow::bail!(
|
||||
"Server tried to send us a packet which is not a HandshakeSuccess or Disconnect"
|
||||
);
|
||||
}
|
||||
|
||||
if let PacketServer::WvrStateChanged(_) = &packet {
|
||||
if let Some(on_signal) = &mut client.on_signal {
|
||||
if (*on_signal)(&packet) {
|
||||
// Signal consumed
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// queue packet to read if it contains a serial response
|
||||
if let Some(serial) = packet.serial() {
|
||||
for qpacket in &mut client.queued_packets.vec {
|
||||
let Some(qpacket) = qpacket else {
|
||||
continue;
|
||||
};
|
||||
|
||||
let qpacket = &mut qpacket.obj;
|
||||
if qpacket.serial != *serial {
|
||||
continue; //skip
|
||||
}
|
||||
|
||||
// found response serial, fill it and notify the receiver
|
||||
qpacket.packet = Some(packet);
|
||||
let notifier = qpacket.notifier.clone();
|
||||
|
||||
drop(client);
|
||||
notifier.notify();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Send packet without feedback
|
||||
async fn send_payload(client_mtx: WayVRClientMutex, payload: &[u8]) -> anyhow::Result<()> {
|
||||
let client = client_mtx.lock().await;
|
||||
let sender = client.sender.clone();
|
||||
drop(client);
|
||||
send_packet(&sender, payload).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn queue_wait_packet(
|
||||
client_mtx: WayVRClientMutex,
|
||||
serial: Serial,
|
||||
payload: &[u8],
|
||||
) -> anyhow::Result<PacketServer> {
|
||||
let notifier = Notifier::new();
|
||||
|
||||
// Send packet to the server
|
||||
let queued_packet_handle = {
|
||||
let mut client = client_mtx.lock().await;
|
||||
let handle = client.queued_packets.add(QueuedPacket {
|
||||
notifier: notifier.clone(),
|
||||
packet: None, // will be filled after notify
|
||||
serial,
|
||||
});
|
||||
|
||||
let sender = client.sender.clone();
|
||||
|
||||
drop(client);
|
||||
|
||||
send_packet(&sender, payload).await?;
|
||||
handle
|
||||
};
|
||||
|
||||
// Wait for response message
|
||||
notifier.wait().await;
|
||||
|
||||
// Fetch response packet
|
||||
{
|
||||
let mut client = client_mtx.lock().await;
|
||||
|
||||
let cell = client
|
||||
.queued_packets
|
||||
.get_mut(&queued_packet_handle)
|
||||
.ok_or(anyhow::anyhow!(
|
||||
"missing packet cell, this shouldn't happen"
|
||||
))?;
|
||||
|
||||
let Some(packet) = cell.packet.take() else {
|
||||
anyhow::bail!("packet is None, this shouldn't happen");
|
||||
};
|
||||
|
||||
client.queued_packets.remove(&queued_packet_handle);
|
||||
|
||||
Ok(packet)
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn fn_wvr_display_list(
|
||||
client: WayVRClientMutex,
|
||||
serial: Serial,
|
||||
) -> anyhow::Result<Vec<packet_server::WvrDisplay>> {
|
||||
Ok(
|
||||
send_and_wait!(
|
||||
client,
|
||||
serial,
|
||||
&PacketClient::WvrDisplayList(serial),
|
||||
WvrDisplayListResponse
|
||||
)
|
||||
.list,
|
||||
)
|
||||
}
|
||||
|
||||
pub async fn fn_wvr_display_get(
|
||||
client: WayVRClientMutex,
|
||||
serial: Serial,
|
||||
handle: packet_server::WvrDisplayHandle,
|
||||
) -> anyhow::Result<Option<packet_server::WvrDisplay>> {
|
||||
Ok(send_and_wait!(
|
||||
client,
|
||||
serial,
|
||||
&PacketClient::WvrDisplayGet(serial, handle),
|
||||
WvrDisplayGetResponse
|
||||
))
|
||||
}
|
||||
|
||||
pub async fn fn_wvr_display_remove(
|
||||
client: WayVRClientMutex,
|
||||
serial: Serial,
|
||||
handle: packet_server::WvrDisplayHandle,
|
||||
) -> anyhow::Result<()> {
|
||||
send_and_wait!(
|
||||
client,
|
||||
serial,
|
||||
&PacketClient::WvrDisplayRemove(serial, handle),
|
||||
WvrDisplayRemoveResponse
|
||||
)
|
||||
.map_err(|e| anyhow::anyhow!("{}", e))
|
||||
}
|
||||
|
||||
pub async fn fn_wvr_display_create(
|
||||
client: WayVRClientMutex,
|
||||
serial: Serial,
|
||||
params: packet_client::WvrDisplayCreateParams,
|
||||
) -> anyhow::Result<packet_server::WvrDisplayHandle> {
|
||||
Ok(send_and_wait!(
|
||||
client,
|
||||
serial,
|
||||
&PacketClient::WvrDisplayCreate(serial, params),
|
||||
WvrDisplayCreateResponse
|
||||
))
|
||||
}
|
||||
|
||||
pub async fn fn_wvr_display_set_visible(
|
||||
client: WayVRClientMutex,
|
||||
handle: packet_server::WvrDisplayHandle,
|
||||
visible: bool,
|
||||
) -> anyhow::Result<()> {
|
||||
send_only!(client, &PacketClient::WvrDisplaySetVisible(handle, visible));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn fn_wvr_display_set_layout(
|
||||
client: WayVRClientMutex,
|
||||
handle: packet_server::WvrDisplayHandle,
|
||||
layout: packet_server::WvrDisplayWindowLayout,
|
||||
) -> anyhow::Result<()> {
|
||||
send_only!(
|
||||
client,
|
||||
&PacketClient::WvrDisplaySetWindowLayout(handle, layout)
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn fn_wvr_display_window_list(
|
||||
client: WayVRClientMutex,
|
||||
serial: Serial,
|
||||
handle: packet_server::WvrDisplayHandle,
|
||||
) -> anyhow::Result<Option<Vec<packet_server::WvrWindow>>> {
|
||||
Ok(
|
||||
send_and_wait!(
|
||||
client,
|
||||
serial,
|
||||
&PacketClient::WvrDisplayWindowList(serial, handle),
|
||||
WvrDisplayWindowListResponse
|
||||
)
|
||||
.map(|res| res.list),
|
||||
)
|
||||
}
|
||||
|
||||
pub async fn fn_wvr_window_set_visible(
|
||||
client: WayVRClientMutex,
|
||||
handle: packet_server::WvrWindowHandle,
|
||||
visible: bool,
|
||||
) -> anyhow::Result<()> {
|
||||
send_only!(client, &PacketClient::WvrWindowSetVisible(handle, visible));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn fn_wvr_process_list(
|
||||
client: WayVRClientMutex,
|
||||
serial: Serial,
|
||||
) -> anyhow::Result<Vec<packet_server::WvrProcess>> {
|
||||
Ok(
|
||||
send_and_wait!(
|
||||
client,
|
||||
serial,
|
||||
&PacketClient::WvrProcessList(serial),
|
||||
WvrProcessListResponse
|
||||
)
|
||||
.list,
|
||||
)
|
||||
}
|
||||
|
||||
pub async fn fn_wvr_process_get(
|
||||
client: WayVRClientMutex,
|
||||
serial: Serial,
|
||||
handle: packet_server::WvrProcessHandle,
|
||||
) -> anyhow::Result<Option<packet_server::WvrProcess>> {
|
||||
Ok(send_and_wait!(
|
||||
client,
|
||||
serial,
|
||||
&PacketClient::WvrProcessGet(serial, handle),
|
||||
WvrProcessGetResponse
|
||||
))
|
||||
}
|
||||
|
||||
pub async fn fn_wvr_process_terminate(
|
||||
client: WayVRClientMutex,
|
||||
handle: packet_server::WvrProcessHandle,
|
||||
) -> anyhow::Result<()> {
|
||||
send_only!(client, &PacketClient::WvrProcessTerminate(handle));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn fn_wvr_process_launch(
|
||||
client: WayVRClientMutex,
|
||||
serial: Serial,
|
||||
params: packet_client::WvrProcessLaunchParams,
|
||||
) -> anyhow::Result<packet_server::WvrProcessHandle> {
|
||||
send_and_wait!(
|
||||
client,
|
||||
serial,
|
||||
&PacketClient::WvrProcessLaunch(serial, params),
|
||||
WvrProcessLaunchResponse
|
||||
)
|
||||
.map_err(|e| anyhow::anyhow!("{}", e))
|
||||
}
|
||||
|
||||
pub async fn fn_wlx_input_state(
|
||||
client: WayVRClientMutex,
|
||||
serial: Serial,
|
||||
) -> anyhow::Result<packet_server::WlxInputState> {
|
||||
Ok(send_and_wait!(
|
||||
client,
|
||||
serial,
|
||||
&PacketClient::WlxInputState(serial),
|
||||
WlxInputStateResponse
|
||||
))
|
||||
}
|
||||
|
||||
pub async fn fn_wlx_haptics(
|
||||
client: WayVRClientMutex,
|
||||
params: packet_client::WlxHapticsParams,
|
||||
) -> anyhow::Result<()> {
|
||||
send_only!(client, &PacketClient::WlxHaptics(params));
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for WayVRClient {
|
||||
fn drop(&mut self) {
|
||||
self.exiting = true;
|
||||
self.cancel_token.cancel();
|
||||
}
|
||||
}
|
||||
42
wayvr-ipc/src/ipc.rs
Normal file
42
wayvr-ipc/src/ipc.rs
Normal file
@@ -0,0 +1,42 @@
|
||||
use std::sync::{Arc, Mutex as SyncMutex};
|
||||
|
||||
pub type Serial = u64;
|
||||
|
||||
#[derive(Clone, Default)]
|
||||
pub struct SerialGenerator {
|
||||
serial: Arc<SyncMutex<u64>>,
|
||||
}
|
||||
|
||||
impl SerialGenerator {
|
||||
pub fn new() -> SerialGenerator {
|
||||
Self {
|
||||
serial: Arc::new(SyncMutex::new(0)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn increment_get(&self) -> Serial {
|
||||
let mut serial = self.serial.lock().unwrap();
|
||||
let cur = *serial;
|
||||
*serial += 1;
|
||||
cur
|
||||
}
|
||||
}
|
||||
|
||||
pub const PROTOCOL_VERSION: u32 = 3;
|
||||
pub const CONNECTION_MAGIC: &str = "wayvr_ipc";
|
||||
|
||||
pub fn data_encode<T>(data: &T) -> Vec<u8>
|
||||
where
|
||||
T: serde::Serialize,
|
||||
{
|
||||
let str = serde_json::to_string(&data).unwrap();
|
||||
log::debug!("serialized data: {}", str);
|
||||
str.into_bytes()
|
||||
}
|
||||
|
||||
pub fn data_decode<T>(data: &[u8]) -> anyhow::Result<T>
|
||||
where
|
||||
T: for<'a> serde::Deserialize<'a>,
|
||||
{
|
||||
Ok(serde_json::from_str::<T>(std::str::from_utf8(data)?)?)
|
||||
}
|
||||
7
wayvr-ipc/src/lib.rs
Normal file
7
wayvr-ipc/src/lib.rs
Normal file
@@ -0,0 +1,7 @@
|
||||
pub mod ipc;
|
||||
pub mod packet_client;
|
||||
pub mod packet_server;
|
||||
mod util;
|
||||
|
||||
#[cfg(feature = "client")]
|
||||
pub mod client;
|
||||
71
wayvr-ipc/src/packet_client.rs
Normal file
71
wayvr-ipc/src/packet_client.rs
Normal file
@@ -0,0 +1,71 @@
|
||||
// Contents of this file should be the same as on wlx-overlay-s.
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use super::{ipc::Serial, packet_server};
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||
pub struct Handshake {
|
||||
pub protocol_version: u32, // always set to PROTOCOL_VERSION
|
||||
pub magic: String, // always set to CONNECTION_MAGIC
|
||||
pub client_name: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||
pub enum AttachTo {
|
||||
None,
|
||||
HandLeft,
|
||||
HandRight,
|
||||
Head,
|
||||
Stage,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct WvrProcessLaunchParams {
|
||||
pub name: String,
|
||||
pub exec: String,
|
||||
pub target_display: packet_server::WvrDisplayHandle,
|
||||
pub env: Vec<String>,
|
||||
pub args: String,
|
||||
pub userdata: HashMap<String, String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct WvrDisplayCreateParams {
|
||||
pub width: u16,
|
||||
pub height: u16,
|
||||
pub name: String,
|
||||
pub scale: Option<f32>,
|
||||
pub attach_to: AttachTo,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct WlxHapticsParams {
|
||||
pub intensity: f32,
|
||||
pub duration: f32,
|
||||
pub frequency: f32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub enum PacketClient {
|
||||
Handshake(Handshake),
|
||||
WvrDisplayCreate(Serial, WvrDisplayCreateParams),
|
||||
WvrDisplayGet(Serial, packet_server::WvrDisplayHandle),
|
||||
WvrDisplayList(Serial),
|
||||
WvrDisplayRemove(Serial, packet_server::WvrDisplayHandle),
|
||||
WvrDisplaySetVisible(packet_server::WvrDisplayHandle, bool),
|
||||
WvrDisplayWindowList(Serial, packet_server::WvrDisplayHandle),
|
||||
WvrDisplaySetWindowLayout(
|
||||
packet_server::WvrDisplayHandle,
|
||||
packet_server::WvrDisplayWindowLayout,
|
||||
),
|
||||
WvrWindowSetVisible(packet_server::WvrWindowHandle, bool),
|
||||
WvrProcessGet(Serial, packet_server::WvrProcessHandle),
|
||||
WvrProcessLaunch(Serial, WvrProcessLaunchParams),
|
||||
WvrProcessList(Serial),
|
||||
WvrProcessTerminate(packet_server::WvrProcessHandle),
|
||||
WlxHaptics(WlxHapticsParams),
|
||||
WlxInputState(Serial),
|
||||
}
|
||||
163
wayvr-ipc/src/packet_server.rs
Normal file
163
wayvr-ipc/src/packet_server.rs
Normal file
@@ -0,0 +1,163 @@
|
||||
// Contents of this file should be the same as on wlx-overlay-s.
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use super::ipc::Serial;
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct ServerInfo {}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct HandshakeSuccess {
|
||||
pub runtime: String, // Runtime name, for example "wlx-overlay-s"
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct Disconnect {
|
||||
pub reason: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
|
||||
pub struct WvrDisplayHandle {
|
||||
pub idx: u32,
|
||||
pub generation: u64,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
|
||||
pub struct WvrProcessHandle {
|
||||
pub idx: u32,
|
||||
pub generation: u64,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
|
||||
pub struct WvrWindowHandle {
|
||||
pub idx: u32,
|
||||
pub generation: u64,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct WvrDisplay {
|
||||
pub width: u16,
|
||||
pub height: u16,
|
||||
pub name: String,
|
||||
pub visible: bool,
|
||||
pub handle: WvrDisplayHandle,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct WvrWindow {
|
||||
pub pos_x: i32,
|
||||
pub pos_y: i32,
|
||||
pub size_x: u32,
|
||||
pub size_y: u32,
|
||||
pub visible: bool,
|
||||
pub handle: WvrWindowHandle,
|
||||
pub process_handle: WvrProcessHandle,
|
||||
pub display_handle: WvrDisplayHandle,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct WvrDisplayList {
|
||||
pub list: Vec<WvrDisplay>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct WvrWindowList {
|
||||
pub list: Vec<WvrWindow>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct WvrProcess {
|
||||
pub name: String,
|
||||
pub display_handle: WvrDisplayHandle,
|
||||
pub handle: WvrProcessHandle,
|
||||
pub userdata: HashMap<String, String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct WvrProcessList {
|
||||
pub list: Vec<WvrProcess>,
|
||||
}
|
||||
|
||||
#[derive(Default, Clone, PartialEq, Debug, Serialize, Deserialize)]
|
||||
pub struct Margins {
|
||||
pub left: u16,
|
||||
pub right: u16,
|
||||
pub top: u16,
|
||||
pub bottom: u16,
|
||||
}
|
||||
|
||||
#[derive(Default, Clone, PartialEq, Debug, Serialize, Deserialize)]
|
||||
pub struct StackingOptions {
|
||||
pub margins_first: Margins,
|
||||
pub margins_rest: Margins,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
|
||||
pub enum WvrDisplayWindowLayout {
|
||||
Tiling,
|
||||
Stacking(StackingOptions),
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
|
||||
pub enum WvrStateChanged {
|
||||
DisplayCreated,
|
||||
DisplayRemoved,
|
||||
ProcessCreated,
|
||||
ProcessRemoved,
|
||||
WindowCreated,
|
||||
WindowRemoved,
|
||||
DashboardShown,
|
||||
DashboardHidden,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
|
||||
pub struct WlxInputStatePointer {
|
||||
pub pos: [f32; 3],
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
|
||||
pub struct WlxInputState {
|
||||
pub hmd_pos: [f32; 3],
|
||||
pub left: WlxInputStatePointer,
|
||||
pub right: WlxInputStatePointer,
|
||||
}
|
||||
|
||||
// "Wvr" prefixes are WayVR-specific
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub enum PacketServer {
|
||||
Disconnect(Disconnect),
|
||||
HandshakeSuccess(HandshakeSuccess),
|
||||
WlxInputStateResponse(Serial, WlxInputState),
|
||||
WvrDisplayCreateResponse(Serial, WvrDisplayHandle),
|
||||
WvrDisplayGetResponse(Serial, Option<WvrDisplay>),
|
||||
WvrDisplayListResponse(Serial, WvrDisplayList),
|
||||
WvrDisplayRemoveResponse(Serial, Result<(), String>),
|
||||
WvrDisplayWindowListResponse(Serial, Option<WvrWindowList>),
|
||||
WvrProcessGetResponse(Serial, Option<WvrProcess>),
|
||||
WvrProcessLaunchResponse(Serial, Result<WvrProcessHandle, String>),
|
||||
WvrProcessListResponse(Serial, WvrProcessList),
|
||||
WvrStateChanged(WvrStateChanged),
|
||||
}
|
||||
|
||||
impl PacketServer {
|
||||
pub fn serial(&self) -> Option<&Serial> {
|
||||
match self {
|
||||
PacketServer::Disconnect(_) => None,
|
||||
PacketServer::HandshakeSuccess(_) => None,
|
||||
PacketServer::WlxInputStateResponse(serial, _) => Some(serial),
|
||||
PacketServer::WvrDisplayCreateResponse(serial, _) => Some(serial),
|
||||
PacketServer::WvrDisplayGetResponse(serial, _) => Some(serial),
|
||||
PacketServer::WvrDisplayListResponse(serial, _) => Some(serial),
|
||||
PacketServer::WvrDisplayRemoveResponse(serial, _) => Some(serial),
|
||||
PacketServer::WvrDisplayWindowListResponse(serial, _) => Some(serial),
|
||||
PacketServer::WvrProcessGetResponse(serial, _) => Some(serial),
|
||||
PacketServer::WvrProcessLaunchResponse(serial, _) => Some(serial),
|
||||
PacketServer::WvrProcessListResponse(serial, _) => Some(serial),
|
||||
PacketServer::WvrStateChanged(_) => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
173
wayvr-ipc/src/util/handle.rs
Normal file
173
wayvr-ipc/src/util/handle.rs
Normal file
@@ -0,0 +1,173 @@
|
||||
#[macro_export]
|
||||
macro_rules! gen_id {
|
||||
(
|
||||
$container_name:ident,
|
||||
$instance_name:ident,
|
||||
$cell_name:ident,
|
||||
$handle_name:ident) => {
|
||||
//ThingCell
|
||||
pub struct $cell_name {
|
||||
pub obj: $instance_name,
|
||||
pub generation: u64,
|
||||
}
|
||||
|
||||
//ThingVec
|
||||
pub struct $container_name {
|
||||
// Vec<Option<ThingCell>>
|
||||
pub vec: Vec<Option<$cell_name>>,
|
||||
|
||||
cur_generation: u64,
|
||||
}
|
||||
|
||||
//ThingHandle
|
||||
#[derive(Default, Clone, Copy, PartialEq, Hash, Eq)]
|
||||
pub struct $handle_name {
|
||||
idx: u32,
|
||||
generation: u64,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
impl $handle_name {
|
||||
pub fn reset(&mut self) {
|
||||
self.generation = 0;
|
||||
}
|
||||
|
||||
pub fn is_set(&self) -> bool {
|
||||
self.generation > 0
|
||||
}
|
||||
|
||||
pub fn id(&self) -> u32 {
|
||||
self.idx
|
||||
}
|
||||
|
||||
pub fn new(idx: u32, generation: u64) -> Self {
|
||||
Self { idx, generation }
|
||||
}
|
||||
}
|
||||
|
||||
//ThingVec
|
||||
#[allow(dead_code)]
|
||||
impl $container_name {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
vec: Vec::new(),
|
||||
cur_generation: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn iter(&self, callback: &dyn Fn($handle_name, &$instance_name)) {
|
||||
for (idx, opt_cell) in self.vec.iter().enumerate() {
|
||||
if let Some(cell) = opt_cell {
|
||||
let handle = $container_name::get_handle(&cell, idx);
|
||||
callback(handle, &cell.obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn iter_mut(
|
||||
&mut self,
|
||||
callback: &mut dyn FnMut($handle_name, &mut $instance_name),
|
||||
) {
|
||||
for (idx, opt_cell) in self.vec.iter_mut().enumerate() {
|
||||
if let Some(cell) = opt_cell {
|
||||
let handle = $container_name::get_handle(&cell, idx);
|
||||
callback(handle, &mut cell.obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_handle(cell: &$cell_name, idx: usize) -> $handle_name {
|
||||
$handle_name {
|
||||
idx: idx as u32,
|
||||
generation: cell.generation,
|
||||
}
|
||||
}
|
||||
|
||||
fn find_unused_idx(&mut self) -> Option<u32> {
|
||||
for (num, obj) in self.vec.iter().enumerate() {
|
||||
if obj.is_none() {
|
||||
return Some(num as u32);
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
pub fn add(&mut self, obj: $instance_name) -> $handle_name {
|
||||
self.cur_generation += 1;
|
||||
let generation = self.cur_generation;
|
||||
|
||||
let unused_idx = self.find_unused_idx();
|
||||
|
||||
let idx = if let Some(idx) = unused_idx {
|
||||
idx
|
||||
} else {
|
||||
self.vec.len() as u32
|
||||
};
|
||||
|
||||
let handle = $handle_name { idx, generation };
|
||||
|
||||
let cell = $cell_name { obj, generation };
|
||||
|
||||
if let Some(idx) = unused_idx {
|
||||
self.vec[idx as usize] = Some(cell);
|
||||
} else {
|
||||
self.vec.push(Some(cell))
|
||||
}
|
||||
|
||||
handle
|
||||
}
|
||||
|
||||
pub fn remove(&mut self, handle: &$handle_name) {
|
||||
// Out of bounds, ignore
|
||||
if handle.idx as usize >= self.vec.len() {
|
||||
return;
|
||||
}
|
||||
|
||||
// Remove only if the generation matches
|
||||
if let Some(cell) = &self.vec[handle.idx as usize] {
|
||||
if cell.generation == handle.generation {
|
||||
self.vec[handle.idx as usize] = None;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get(&self, handle: &$handle_name) -> Option<&$instance_name> {
|
||||
// Out of bounds, ignore
|
||||
if handle.idx as usize >= self.vec.len() {
|
||||
return None;
|
||||
}
|
||||
|
||||
if let Some(cell) = &self.vec[handle.idx as usize] {
|
||||
if cell.generation == handle.generation {
|
||||
return Some(&cell.obj);
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
pub fn get_mut(&mut self, handle: &$handle_name) -> Option<&mut $instance_name> {
|
||||
// Out of bounds, ignore
|
||||
if handle.idx as usize >= self.vec.len() {
|
||||
return None;
|
||||
}
|
||||
|
||||
if let Some(cell) = &mut self.vec[handle.idx as usize] {
|
||||
if cell.generation == handle.generation {
|
||||
return Some(&mut cell.obj);
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/* Example usage:
|
||||
gen_id!(ThingVec, ThingInstance, ThingCell, ThingHandle);
|
||||
|
||||
struct ThingInstance {}
|
||||
|
||||
impl ThingInstance {}
|
||||
*/
|
||||
4
wayvr-ipc/src/util/mod.rs
Normal file
4
wayvr-ipc/src/util/mod.rs
Normal file
@@ -0,0 +1,4 @@
|
||||
pub mod handle;
|
||||
|
||||
#[cfg(feature = "client")]
|
||||
pub mod notifier;
|
||||
25
wayvr-ipc/src/util/notifier.rs
Normal file
25
wayvr-ipc/src/util/notifier.rs
Normal file
@@ -0,0 +1,25 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use tokio::sync::Notify;
|
||||
|
||||
// Copyable wrapped Notify struct for easier usage
|
||||
#[derive(Default, Clone)]
|
||||
pub struct Notifier {
|
||||
notifier: Arc<Notify>,
|
||||
}
|
||||
|
||||
impl Notifier {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
notifier: Arc::new(Notify::new()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn notify(&self) {
|
||||
self.notifier.notify_waiters();
|
||||
}
|
||||
|
||||
pub async fn wait(&self) {
|
||||
self.notifier.notified().await;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user