Move magpie_types and magpie_client into magpie
This commit is contained in:
parent
412a9bf480
commit
7e1ec1ed39
|
@ -1,13 +1,23 @@
|
|||
[package]
|
||||
name = "magpie"
|
||||
name = "canary-magpie"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[[bin]]
|
||||
name = "magpie"
|
||||
path = "src/main.rs"
|
||||
required-features = ["service"]
|
||||
|
||||
[dependencies]
|
||||
canary = { path = "../.." }
|
||||
glium = "0.32"
|
||||
magpie-types = { path = "../../crates/magpie-types" }
|
||||
mio = { version = "0.8", features = ["net", "os-poll"] }
|
||||
mio-signals = "0.2"
|
||||
parking_lot = "0.12"
|
||||
slab = "0.4"
|
||||
byteorder = "1.4"
|
||||
canary = { path = "../..", optional = true }
|
||||
glium = { version = "0.32", optional = true}
|
||||
mio = { version = "0.8", features = ["net", "os-poll"], optional = true }
|
||||
mio-signals = { version = "0.2", optional = true }
|
||||
parking_lot = { version = "0.12", optional = true}
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
serde_json = "1"
|
||||
slab = { version = "0.4", optional = true}
|
||||
|
||||
[features]
|
||||
service = ["dep:canary", "dep:glium", "dep:mio", "dep:mio-signals", "dep:parking_lot", "dep:slab"]
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
use serde::Serialize;
|
||||
|
||||
use std::os::unix::net::UnixStream;
|
||||
use std::path::Path;
|
||||
|
||||
use crate::protocol::{ClientMessenger, MagpieServerMsg, PanelId, SendMessage, MAGPIE_SOCK};
|
||||
|
||||
/// A client to a Magpie server.
|
||||
pub struct MagpieClient {
|
||||
pub messenger: ClientMessenger<UnixStream>,
|
||||
}
|
||||
|
||||
impl MagpieClient {
|
||||
pub fn new() -> std::io::Result<Self> {
|
||||
let sock_dir = std::env::var("XDG_RUNTIME_DIR").expect("XDG_RUNTIME_DIR not set");
|
||||
let sock_dir = Path::new(&sock_dir);
|
||||
let sock_path = sock_dir.join(MAGPIE_SOCK);
|
||||
let socket = UnixStream::connect(sock_path)?;
|
||||
Ok(Self {
|
||||
messenger: ClientMessenger::new(socket),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn send(&mut self, msg: &MagpieServerMsg) {
|
||||
if let Err(err) = self.messenger.send(msg) {
|
||||
eprintln!("Message send error: {:?}", err);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn send_json_message<T: Serialize>(&mut self, id: PanelId, msg: &T) {
|
||||
let msg = serde_json::to_string(msg).unwrap();
|
||||
eprintln!("Sending message: {}", msg);
|
||||
|
||||
let msg = SendMessage {
|
||||
id,
|
||||
msg: msg.into_bytes(),
|
||||
};
|
||||
|
||||
self.send(&MagpieServerMsg::SendMessage(msg));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
pub mod client;
|
||||
pub mod protocol;
|
||||
|
||||
#[cfg(feature = "service")]
|
||||
pub mod service;
|
|
@ -1,14 +1,14 @@
|
|||
use glium::glutin::event_loop::EventLoopBuilder;
|
||||
|
||||
pub mod gl;
|
||||
pub mod ipc;
|
||||
pub mod window;
|
||||
use canary_magpie::service::*;
|
||||
use ipc::Ipc;
|
||||
use window::{WindowMessage, WindowStore};
|
||||
|
||||
fn main() -> std::io::Result<()> {
|
||||
let event_loop = EventLoopBuilder::<window::WindowMessage>::with_user_event().build();
|
||||
let event_loop = EventLoopBuilder::<WindowMessage>::with_user_event().build();
|
||||
let window_sender = event_loop.create_proxy();
|
||||
let (ipc, ipc_sender) = ipc::Ipc::new(window_sender)?;
|
||||
let (ipc, ipc_sender) = Ipc::new(window_sender)?;
|
||||
let _ipc_thread = std::thread::spawn(|| ipc.run());
|
||||
let window_store = window::WindowStore::new(ipc_sender);
|
||||
let window_store = WindowStore::new(ipc_sender);
|
||||
window_store.run(event_loop)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,142 @@
|
|||
use std::collections::VecDeque;
|
||||
use std::io::{Read, Write};
|
||||
use std::marker::PhantomData;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use serde::{de::DeserializeOwned, Deserialize, Serialize};
|
||||
|
||||
/// The name of the Magpie server socket.
|
||||
pub const MAGPIE_SOCK: &str = "magpie.sock";
|
||||
|
||||
/// An identifier for a Magpie panel.
|
||||
///
|
||||
/// Only valid on a connection between a single client and its server. Clients
|
||||
/// are allowed to use arbitrary values for [PanelId].
|
||||
pub type PanelId = u32;
|
||||
|
||||
/// Creates a new Magpie panel with a given ID.
|
||||
///
|
||||
/// If the given [PanelId] is already being used on this connection, the server
|
||||
/// will delete the old panel using that [PanelId].
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
pub struct CreatePanel {
|
||||
pub id: PanelId,
|
||||
pub script: PathBuf,
|
||||
}
|
||||
|
||||
/// Sends a panel a message.
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
pub struct SendMessage {
|
||||
pub id: PanelId,
|
||||
pub msg: Vec<u8>,
|
||||
}
|
||||
|
||||
/// A message sent from a Magpie client to the server.
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
#[serde(tag = "kind")]
|
||||
pub enum MagpieServerMsg {
|
||||
CreatePanel(CreatePanel),
|
||||
SendMessage(SendMessage),
|
||||
}
|
||||
|
||||
/// A message sent from the Magpie server to a client.
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
#[serde(tag = "kind")]
|
||||
pub enum MagpieClientMsg {}
|
||||
|
||||
/// A [Messenger] specialized for Magpie clients.
|
||||
pub type ClientMessenger<T> = Messenger<T, MagpieClientMsg, MagpieServerMsg>;
|
||||
|
||||
/// A [Messenger] specialized for Magpie servers.
|
||||
pub type ServerMessenger<T> = Messenger<T, MagpieServerMsg, MagpieClientMsg>;
|
||||
|
||||
/// Bidirectional, transport-agnostic Magpie IO wrapper struct.
|
||||
pub struct Messenger<T, I, O> {
|
||||
pub transport: T,
|
||||
expected_len: Option<usize>,
|
||||
received_buf: VecDeque<u8>,
|
||||
received_queue: VecDeque<I>,
|
||||
closed: bool,
|
||||
_output: PhantomData<O>,
|
||||
}
|
||||
|
||||
impl<T: Read + Write, I: DeserializeOwned, O: Serialize> Messenger<T, I, O> {
|
||||
pub fn new(transport: T) -> Self {
|
||||
Self {
|
||||
transport,
|
||||
expected_len: None,
|
||||
received_buf: Default::default(),
|
||||
received_queue: Default::default(),
|
||||
closed: false,
|
||||
_output: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_closed(&self) -> bool {
|
||||
self.closed
|
||||
}
|
||||
|
||||
pub fn send(&mut self, msg: &O) -> std::io::Result<()> {
|
||||
use byteorder::{LittleEndian, WriteBytesExt};
|
||||
let payload = serde_json::to_vec(msg).unwrap();
|
||||
let len = payload.len() as u32;
|
||||
self.transport.write_u32::<LittleEndian>(len)?;
|
||||
self.transport.write_all(&payload)?;
|
||||
self.transport.flush()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Receives all pending messages and queues them for [recv].
|
||||
pub fn flush_recv(&mut self) -> std::io::Result<()> {
|
||||
let mut buf = [0u8; 1024];
|
||||
|
||||
loop {
|
||||
match self.transport.read(&mut buf) {
|
||||
Ok(0) => {
|
||||
self.closed = true;
|
||||
break;
|
||||
}
|
||||
Ok(n) => {
|
||||
self.received_buf.write(&buf[..n])?;
|
||||
}
|
||||
Err(ref err) if err.kind() == std::io::ErrorKind::WouldBlock => break,
|
||||
Err(ref err) if err.kind() == std::io::ErrorKind::Interrupted => continue,
|
||||
Err(err) => return Err(err),
|
||||
}
|
||||
}
|
||||
|
||||
loop {
|
||||
if let Some(expected_len) = self.expected_len {
|
||||
if self.received_buf.len() < expected_len {
|
||||
break;
|
||||
}
|
||||
|
||||
self.expected_len = None;
|
||||
let mut buf = vec![0u8; expected_len];
|
||||
self.received_buf.read_exact(&mut buf)?;
|
||||
match serde_json::from_slice::<I>(&buf) {
|
||||
Ok(received) => self.received_queue.push_front(received),
|
||||
Err(e) => {
|
||||
let kind = std::io::ErrorKind::InvalidData;
|
||||
let payload = Box::new(e);
|
||||
let error = std::io::Error::new(kind, payload);
|
||||
return Err(error);
|
||||
}
|
||||
}
|
||||
} else if self.received_buf.len() >= 4 {
|
||||
use byteorder::{LittleEndian, ReadBytesExt};
|
||||
let expected_len = self.received_buf.read_u32::<LittleEndian>()?;
|
||||
self.expected_len = Some(expected_len as usize);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Tries to receive a single input packet.
|
||||
pub fn recv(&mut self) -> Option<I> {
|
||||
self.received_queue.pop_back()
|
||||
}
|
||||
}
|
|
@ -5,14 +5,14 @@ use std::sync::mpsc::{channel, Receiver, Sender};
|
|||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
|
||||
use magpie_types::{CreatePanel, MagpieServerMsg, SendMessage, ServerMessenger};
|
||||
use mio::net::{UnixListener, UnixStream};
|
||||
use mio::{Events, Interest, Poll, Token, Waker};
|
||||
use mio_signals::{Signal, Signals};
|
||||
use parking_lot::RwLock;
|
||||
use slab::Slab;
|
||||
|
||||
use crate::window::{WindowMessage, WindowMessageSender};
|
||||
use crate::service::window::{WindowMessage, WindowMessageSender};
|
||||
use crate::protocol::{CreatePanel, MagpieServerMsg, SendMessage, ServerMessenger};
|
||||
|
||||
const SOCK_NAME: &str = "magpie.sock";
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
pub mod gl;
|
||||
pub mod ipc;
|
||||
pub mod window;
|
|
@ -9,8 +9,8 @@ use glutin::event::{Event, WindowEvent};
|
|||
use glutin::event_loop::{ControlFlow, EventLoop, EventLoopProxy, EventLoopWindowTarget};
|
||||
use glutin::window::WindowId;
|
||||
|
||||
use crate::gl::Graphics;
|
||||
use crate::ipc::{IpcMessage, IpcMessageSender};
|
||||
use crate::service::gl::Graphics;
|
||||
use crate::service::ipc::{IpcMessage, IpcMessageSender};
|
||||
|
||||
pub enum WindowMessage {
|
||||
OpenWindow { id: usize, script: PathBuf },
|
Loading…
Reference in New Issue