Ran rustfmt
This commit is contained in:
@@ -1,9 +1,13 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use indication::{CodePage, ConnectAttempt, Connection, Erase, FileTransfer, Hello, Model, Oia, Passthru, Popup, Proxy, RunResult, Screen, ScreenMode, Scroll, Setting, Stats, TerminalName, Thumb, Tls, TlsHello, TraceFile, UiError};
|
||||
use indication::{
|
||||
CodePage, ConnectAttempt, Connection, Erase, FileTransfer, Hello, Model, Oia, Passthru, Popup,
|
||||
Proxy, RunResult, Screen, ScreenMode, Scroll, Setting, Stats, TerminalName, Thumb, Tls,
|
||||
TlsHello, TraceFile, UiError,
|
||||
};
|
||||
use operation::{Fail, Register, Run, Succeed};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
pub mod operation;
|
||||
pub mod indication;
|
||||
pub mod operation;
|
||||
pub mod types;
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
|
||||
@@ -70,7 +74,7 @@ pub enum Indication {
|
||||
/// Xterm escape sequence requested a change to the window title
|
||||
WindowTitle {
|
||||
text: String,
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
|
||||
@@ -88,7 +92,9 @@ pub enum InitializeIndication {
|
||||
/// Change in the state of the Operator Information Area
|
||||
Oia(Oia),
|
||||
/// Set of supported prefixes
|
||||
Prefixes{value: String},
|
||||
Prefixes {
|
||||
value: String,
|
||||
},
|
||||
/// List of supported proxies
|
||||
Proxies(Vec<Proxy>),
|
||||
/// Screen dimensions/characteristics changed
|
||||
@@ -117,4 +123,3 @@ pub enum Operation {
|
||||
/// Tell b3270 that a passthru action succeeded
|
||||
Succeed(Succeed),
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use crate::b3270::types::{Color, GraphicRendition};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, PartialEq, Copy, Clone)]
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
@@ -118,11 +118,13 @@ pub enum OiaField {
|
||||
type_: Option<ComposeType>,
|
||||
},
|
||||
/// Insert mode
|
||||
Insert{value: bool},
|
||||
Insert {
|
||||
value: bool,
|
||||
},
|
||||
/// Keyboard is locked
|
||||
Lock {
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
value: Option<String>
|
||||
value: Option<String>,
|
||||
},
|
||||
Lu {
|
||||
/// Host session logical unit name
|
||||
@@ -270,7 +272,7 @@ pub enum FileTransferState {
|
||||
Awaiting,
|
||||
Running {
|
||||
/// Number of bytes transferred
|
||||
bytes: usize
|
||||
bytes: usize,
|
||||
},
|
||||
Aborting,
|
||||
Complete {
|
||||
@@ -325,7 +327,6 @@ pub struct Row {
|
||||
pub changes: Vec<Change>,
|
||||
}
|
||||
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
|
||||
#[serde(rename = "kebab-case")]
|
||||
pub enum CountOrText {
|
||||
@@ -433,7 +434,13 @@ mod test {
|
||||
use super::*;
|
||||
#[test]
|
||||
pub fn connection_state_serializes_as_expected() {
|
||||
assert_eq!(serde_json::to_string(&ConnectionState::ConnectedETn3270e).unwrap(),r#""connected-e-tn3270e""#);
|
||||
assert_eq!(serde_json::to_string(&ConnectionState::ConnectedESscp).unwrap(),r#""connected-e-sscp""#);
|
||||
assert_eq!(
|
||||
serde_json::to_string(&ConnectionState::ConnectedETn3270e).unwrap(),
|
||||
r#""connected-e-tn3270e""#
|
||||
);
|
||||
assert_eq!(
|
||||
serde_json::to_string(&ConnectionState::ConnectedESscp).unwrap(),
|
||||
r#""connected-e-sscp""#
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
use bitflags::bitflags;
|
||||
use serde::de::{Error, Visitor};
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
use std::fmt::{Display, Formatter, Write};
|
||||
use std::str::FromStr;
|
||||
use bitflags::bitflags;
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
use serde::de::{Error, Visitor};
|
||||
|
||||
bitflags! {
|
||||
#[derive(Clone,Copy,Debug,PartialEq, Eq, Hash)]
|
||||
@@ -36,7 +36,8 @@ static FLAG_NAMES: &'static [(GraphicRendition, &'static str)] = &[
|
||||
|
||||
impl Display for GraphicRendition {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
let flag_names = FLAG_NAMES.iter()
|
||||
let flag_names = FLAG_NAMES
|
||||
.iter()
|
||||
.filter_map(|(val, name)| self.contains(*val).then_some(*name));
|
||||
for (n, name) in flag_names.enumerate() {
|
||||
if n != 0 {
|
||||
@@ -49,7 +50,10 @@ impl Display for GraphicRendition {
|
||||
}
|
||||
|
||||
impl Serialize for GraphicRendition {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
if serializer.is_human_readable() {
|
||||
serializer.serialize_str(&self.to_string())
|
||||
} else {
|
||||
@@ -60,7 +64,6 @@ impl Serialize for GraphicRendition {
|
||||
|
||||
struct GrVisitor;
|
||||
|
||||
|
||||
impl Visitor<'_> for GrVisitor {
|
||||
type Value = GraphicRendition;
|
||||
|
||||
@@ -68,15 +71,24 @@ impl Visitor<'_> for GrVisitor {
|
||||
write!(formatter, "graphic rendition string or binary value")
|
||||
}
|
||||
|
||||
fn visit_i64<E>(self, v: i64) -> Result<Self::Value, E> where E: Error {
|
||||
fn visit_i64<E>(self, v: i64) -> Result<Self::Value, E>
|
||||
where
|
||||
E: Error,
|
||||
{
|
||||
self.visit_u64((v & 0xFFFF) as u64)
|
||||
}
|
||||
|
||||
fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E> where E: Error {
|
||||
fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E>
|
||||
where
|
||||
E: Error,
|
||||
{
|
||||
Ok(GraphicRendition::from_bits_truncate((v & 0xFFFF) as u16))
|
||||
}
|
||||
|
||||
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E> where E: Error {
|
||||
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
|
||||
where
|
||||
E: Error,
|
||||
{
|
||||
GraphicRendition::from_str(v).map_err(E::custom)
|
||||
}
|
||||
}
|
||||
@@ -87,7 +99,8 @@ impl FromStr for GraphicRendition {
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
s.split(",")
|
||||
.map(|attr| {
|
||||
FLAG_NAMES.iter()
|
||||
FLAG_NAMES
|
||||
.iter()
|
||||
.find(|(_, name)| *name == attr)
|
||||
.map(|x| x.0)
|
||||
.ok_or_else(|| format!("Invalid attr name {attr}"))
|
||||
@@ -97,7 +110,10 @@ impl FromStr for GraphicRendition {
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for GraphicRendition {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: Deserializer<'de> {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
if deserializer.is_human_readable() {
|
||||
deserializer.deserialize_str(GrVisitor)
|
||||
} else {
|
||||
@@ -108,11 +124,14 @@ impl<'de> Deserialize<'de> for GraphicRendition {
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use std::str::FromStr;
|
||||
use super::GraphicRendition;
|
||||
use std::str::FromStr;
|
||||
#[test]
|
||||
fn from_str_1() {
|
||||
assert_eq!(GraphicRendition::from_str("underline,blink"), Ok(GraphicRendition::BLINK | GraphicRendition::UNDERLINE))
|
||||
assert_eq!(
|
||||
GraphicRendition::from_str("underline,blink"),
|
||||
Ok(GraphicRendition::BLINK | GraphicRendition::UNDERLINE)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
use std::collections::HashMap;
|
||||
use crate::b3270::indication::{Change, Connection, ConnectionState, CountOrText, Cursor, Erase, Oia, OiaFieldName, Row, RunResult, Screen, ScreenMode, Scroll, Setting, TerminalName, Thumb, Tls, TraceFile};
|
||||
use crate::b3270::{Indication, InitializeIndication};
|
||||
use crate::b3270::indication::{
|
||||
Change, Connection, ConnectionState, CountOrText, Cursor, Erase, Oia, OiaFieldName, Row,
|
||||
RunResult, Screen, ScreenMode, Scroll, Setting, TerminalName, Thumb, Tls, TraceFile,
|
||||
};
|
||||
use crate::b3270::types::{Color, GraphicRendition, PackedAttr};
|
||||
use crate::b3270::{Indication, InitializeIndication};
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
struct CharCell {
|
||||
@@ -48,9 +51,7 @@ impl Tracker {
|
||||
| Indication::Icon { .. }
|
||||
| Indication::Popup(_)
|
||||
| Indication::Stats(_)
|
||||
| Indication::WindowTitle { .. }
|
||||
|
||||
=> (),
|
||||
| Indication::WindowTitle { .. } => (),
|
||||
Indication::Connection(conn) => {
|
||||
self.connection = conn.clone();
|
||||
}
|
||||
@@ -64,43 +65,47 @@ impl Tracker {
|
||||
let cols = self.erase.logical_cols.unwrap_or(self.screen_mode.cols) as usize;
|
||||
|
||||
self.screen = vec![
|
||||
vec![CharCell{
|
||||
vec![
|
||||
CharCell {
|
||||
attr: u32::c_pack(
|
||||
erase.fg.unwrap_or(Color::NeutralBlack),
|
||||
erase.bg.unwrap_or(Color::Blue),
|
||||
GraphicRendition::empty(),
|
||||
),
|
||||
ch: ' ',
|
||||
};cols]
|
||||
; rows
|
||||
};
|
||||
cols
|
||||
];
|
||||
rows
|
||||
]
|
||||
}
|
||||
Indication::Formatted { state } => {self.formatted = *state; }
|
||||
Indication::Formatted { state } => {
|
||||
self.formatted = *state;
|
||||
}
|
||||
|
||||
Indication::Initialize(init) => {
|
||||
let mut static_init = Vec::with_capacity(init.len());
|
||||
for indicator in init.clone() {
|
||||
match indicator {
|
||||
InitializeIndication::CodePages(_) |
|
||||
InitializeIndication::Hello(_) |
|
||||
InitializeIndication::Models(_) |
|
||||
InitializeIndication::Prefixes { .. } |
|
||||
InitializeIndication::Proxies(_) |
|
||||
InitializeIndication::TlsHello(_) |
|
||||
InitializeIndication::Tls(_) |
|
||||
InitializeIndication::TraceFile(_) =>
|
||||
static_init.push(indicator),
|
||||
InitializeIndication::CodePages(_)
|
||||
| InitializeIndication::Hello(_)
|
||||
| InitializeIndication::Models(_)
|
||||
| InitializeIndication::Prefixes { .. }
|
||||
| InitializeIndication::Proxies(_)
|
||||
| InitializeIndication::TlsHello(_)
|
||||
| InitializeIndication::Tls(_)
|
||||
| InitializeIndication::TraceFile(_) => static_init.push(indicator),
|
||||
|
||||
// The rest are passed through to normal processing.
|
||||
InitializeIndication::Thumb(thumb) => {
|
||||
self.handle_indication(&mut Indication::Thumb(thumb));
|
||||
},
|
||||
}
|
||||
InitializeIndication::Setting(setting) => {
|
||||
self.handle_indication(&mut Indication::Setting(setting));
|
||||
}
|
||||
InitializeIndication::ScreenMode(mode) => {
|
||||
self.handle_indication(&mut Indication::ScreenMode(mode));
|
||||
},
|
||||
}
|
||||
InitializeIndication::Oia(oia) => {
|
||||
self.handle_indication(&mut Indication::Oia(oia));
|
||||
}
|
||||
@@ -127,8 +132,7 @@ impl Tracker {
|
||||
// update screen contents
|
||||
let cols = self.screen[row_idx].iter_mut().skip(col_idx);
|
||||
match change.change {
|
||||
CountOrText::Count(n) => {
|
||||
cols.take(n).for_each(|cell| {
|
||||
CountOrText::Count(n) => cols.take(n).for_each(|cell| {
|
||||
let mut attr = cell.attr;
|
||||
if let Some(fg) = change.fg {
|
||||
attr = attr.c_setfg(fg);
|
||||
@@ -140,8 +144,7 @@ impl Tracker {
|
||||
attr = attr.c_setgr(gr);
|
||||
}
|
||||
cell.attr = attr;
|
||||
})
|
||||
}
|
||||
}),
|
||||
CountOrText::Text(ref text) => {
|
||||
cols.zip(text.chars()).for_each(|(cell, ch)| {
|
||||
let mut attr = cell.attr;
|
||||
@@ -208,9 +211,8 @@ impl Tracker {
|
||||
return Disposition::Drop;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return Disposition::Broadcast
|
||||
return Disposition::Broadcast;
|
||||
}
|
||||
|
||||
pub fn get_init_indication(&self) -> Vec<Indication> {
|
||||
@@ -219,12 +221,13 @@ impl Tracker {
|
||||
contents.push(InitializeIndication::Erase(self.erase));
|
||||
contents.push(InitializeIndication::Thumb(self.thumb));
|
||||
|
||||
contents.extend(self.oia.values()
|
||||
contents.extend(self.oia.values().cloned().map(InitializeIndication::Oia));
|
||||
contents.extend(
|
||||
self.settings
|
||||
.values()
|
||||
.cloned()
|
||||
.map(InitializeIndication::Oia));
|
||||
contents.extend(self.settings.values()
|
||||
.cloned()
|
||||
.map(InitializeIndication::Setting));
|
||||
.map(InitializeIndication::Setting),
|
||||
);
|
||||
contents.extend(self.tls.clone().map(InitializeIndication::Tls));
|
||||
|
||||
// Construct a screen snapshot
|
||||
@@ -232,7 +235,9 @@ impl Tracker {
|
||||
Indication::Initialize(contents),
|
||||
Indication::Connection(self.connection.clone()),
|
||||
Indication::Screen(self.screen_snapshot()),
|
||||
Indication::Formatted {state: self.formatted},
|
||||
Indication::Formatted {
|
||||
state: self.formatted,
|
||||
},
|
||||
];
|
||||
if let Some(terminal_name) = self.terminal_name.clone() {
|
||||
result.push(Indication::TerminalName(terminal_name));
|
||||
@@ -271,14 +276,17 @@ impl Tracker {
|
||||
fn screen_snapshot(&self) -> Screen {
|
||||
Screen {
|
||||
cursor: Some(self.cursor),
|
||||
rows: self.screen.iter()
|
||||
.map(Vec::as_slice).map(Self::format_row)
|
||||
rows: self
|
||||
.screen
|
||||
.iter()
|
||||
.map(Vec::as_slice)
|
||||
.map(Self::format_row)
|
||||
.enumerate()
|
||||
.map(|(row_id, changes)| Row {
|
||||
row: row_id as u8 - 1,
|
||||
changes,
|
||||
})
|
||||
.collect()
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -313,7 +321,7 @@ impl Default for Tracker {
|
||||
cursor: Cursor {
|
||||
enabled: false,
|
||||
row: None,
|
||||
column: None
|
||||
column: None,
|
||||
},
|
||||
connection: Connection {
|
||||
state: ConnectionState::NotConnected,
|
||||
|
||||
@@ -1,23 +1,23 @@
|
||||
use anyhow::anyhow;
|
||||
use base64::engine::general_purpose::STANDARD as B64_STANDARD;
|
||||
use base64::Engine;
|
||||
use bytes::Buf;
|
||||
use d3270_common::b3270::indication::RunResult;
|
||||
use d3270_common::b3270::operation::Action;
|
||||
use d3270_common::b3270::{operation, Indication, Operation};
|
||||
use d3270_common::tracker::{Disposition, Tracker};
|
||||
use futures::future::BoxFuture;
|
||||
use futures::{FutureExt, Stream, StreamExt, TryFutureExt};
|
||||
use rand::RngCore;
|
||||
use std::collections::{HashMap, VecDeque};
|
||||
use std::future::Future;
|
||||
use std::pin::Pin;
|
||||
use std::task::{Context, Poll};
|
||||
use anyhow::anyhow;
|
||||
use base64::Engine;
|
||||
use base64::engine::general_purpose::STANDARD as B64_STANDARD;
|
||||
use bytes::Buf;
|
||||
use futures::{FutureExt, Stream, StreamExt, TryFutureExt};
|
||||
use futures::future::BoxFuture;
|
||||
use rand::RngCore;
|
||||
use tokio::io::{BufReader, AsyncBufReadExt, Lines, AsyncWrite};
|
||||
use tokio::io::{AsyncBufReadExt, AsyncWrite, BufReader, Lines};
|
||||
use tokio::process::{Child, ChildStdout};
|
||||
use tokio::sync::{mpsc, oneshot, broadcast};
|
||||
use tokio_stream::wrappers::{BroadcastStream, errors::BroadcastStreamRecvError};
|
||||
use tokio::sync::{broadcast, mpsc, oneshot};
|
||||
use tokio_stream::wrappers::{errors::BroadcastStreamRecvError, BroadcastStream};
|
||||
use tracing::{error, info, warn};
|
||||
use d3270_common::b3270::{Indication, Operation, operation};
|
||||
use d3270_common::b3270::indication::RunResult;
|
||||
use d3270_common::b3270::operation::Action;
|
||||
use d3270_common::tracker::{Disposition, Tracker};
|
||||
|
||||
pub struct B3270 {
|
||||
tracker: Tracker, //
|
||||
@@ -38,8 +38,14 @@ pub enum B3270Request {
|
||||
enum HandleReceiveState {
|
||||
Steady(BroadcastStream<Indication>),
|
||||
Wait(oneshot::Receiver<(Vec<Indication>, broadcast::Receiver<Indication>)>),
|
||||
Resume(std::vec::IntoIter<Indication>, broadcast::Receiver<Indication>),
|
||||
TryRestart(BoxFuture<'static, Result<(), ()>>, oneshot::Receiver<(Vec<Indication>, broadcast::Receiver<Indication>)>),
|
||||
Resume(
|
||||
std::vec::IntoIter<Indication>,
|
||||
broadcast::Receiver<Indication>,
|
||||
),
|
||||
TryRestart(
|
||||
BoxFuture<'static, Result<(), ()>>,
|
||||
oneshot::Receiver<(Vec<Indication>, broadcast::Receiver<Indication>)>,
|
||||
),
|
||||
}
|
||||
pub struct Handle {
|
||||
sender: mpsc::Sender<B3270Request>,
|
||||
@@ -66,11 +72,12 @@ impl Stream for Handle {
|
||||
match rcvr.poll_unpin(cx) {
|
||||
Poll::Ready(Ok((inds, rcvr))) => {
|
||||
// reverse the indicators so that they can be popped.
|
||||
self.receiver = Some(HandleReceiveState::Resume(inds.into_iter(), rcvr));
|
||||
self.receiver =
|
||||
Some(HandleReceiveState::Resume(inds.into_iter(), rcvr));
|
||||
}
|
||||
Poll::Ready(Err(error)) => {
|
||||
warn!(%error, "unable to reconnect to b3270 server");
|
||||
return Poll::Ready(None)
|
||||
return Poll::Ready(None);
|
||||
}
|
||||
Poll::Pending => {
|
||||
self.receiver = Some(HandleReceiveState::Wait(rcvr));
|
||||
@@ -78,27 +85,28 @@ impl Stream for Handle {
|
||||
}
|
||||
}
|
||||
}
|
||||
Some(HandleReceiveState::Resume(mut inds, rcvr)) => {
|
||||
match inds.next() {
|
||||
Some(HandleReceiveState::Resume(mut inds, rcvr)) => match inds.next() {
|
||||
Some(next) => {
|
||||
self.receiver = Some(HandleReceiveState::Resume(inds, rcvr));
|
||||
return Poll::Ready(Some(next));
|
||||
}
|
||||
None => {
|
||||
self.receiver = Some(HandleReceiveState::Steady(BroadcastStream::new(rcvr)));
|
||||
self.receiver =
|
||||
Some(HandleReceiveState::Steady(BroadcastStream::new(rcvr)));
|
||||
}
|
||||
}
|
||||
}
|
||||
Some(HandleReceiveState::Steady(mut rcvr)) => {
|
||||
match rcvr.poll_next_unpin(cx) {
|
||||
},
|
||||
Some(HandleReceiveState::Steady(mut rcvr)) => match rcvr.poll_next_unpin(cx) {
|
||||
Poll::Ready(Some(Ok(msg))) => {
|
||||
self.receiver = Some(HandleReceiveState::Steady(rcvr));
|
||||
return Poll::Ready(Some(msg))
|
||||
return Poll::Ready(Some(msg));
|
||||
}
|
||||
Poll::Ready(Some(Err(BroadcastStreamRecvError::Lagged(_)))) => {
|
||||
warn!("Dropped messages from b3270 server; starting resync");
|
||||
let (os_snd, os_rcv) = oneshot::channel();
|
||||
let fut = self.sender.clone().reserve_owned()
|
||||
let fut = self
|
||||
.sender
|
||||
.clone()
|
||||
.reserve_owned()
|
||||
.map_ok(move |permit| {
|
||||
permit.send(B3270Request::Resync(os_snd));
|
||||
})
|
||||
@@ -108,11 +116,10 @@ impl Stream for Handle {
|
||||
}
|
||||
Poll::Ready(None) => {
|
||||
warn!("Failed to receive from b3270 server");
|
||||
return Poll::Ready(None)
|
||||
return Poll::Ready(None);
|
||||
}
|
||||
Poll::Pending => return Poll::Pending,
|
||||
},
|
||||
Poll::Pending => return Poll::Pending
|
||||
}
|
||||
}
|
||||
|
||||
None => {
|
||||
return Poll::Ready(None);
|
||||
@@ -122,11 +129,18 @@ impl Stream for Handle {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl B3270 {
|
||||
pub fn spawn(mut child: Child) -> (tokio::task::JoinHandle<anyhow::Error>, mpsc::Sender<B3270Request>) {
|
||||
pub fn spawn(
|
||||
mut child: Child,
|
||||
) -> (
|
||||
tokio::task::JoinHandle<anyhow::Error>,
|
||||
mpsc::Sender<B3270Request>,
|
||||
) {
|
||||
let (subproc_snd, subproc_rcv) = mpsc::channel(10);
|
||||
let child_reader = child.stdout.take().expect("Should always be given a child that has stdout captured");
|
||||
let child_reader = child
|
||||
.stdout
|
||||
.take()
|
||||
.expect("Should always be given a child that has stdout captured");
|
||||
let child_reader = BufReader::new(child_reader).lines();
|
||||
// A single connect can result in a flurry of messages, so we need a big buffer
|
||||
let (ind_chan, _) = broadcast::channel(100);
|
||||
@@ -153,9 +167,7 @@ impl Future for B3270 {
|
||||
while let Poll::Ready(buf) = Pin::new(&mut self.child_reader).poll_next_line(cx) {
|
||||
match buf {
|
||||
Ok(Some(line)) => match serde_json::from_str(&line) {
|
||||
Ok(ind) => {
|
||||
indications.push(ind)
|
||||
},
|
||||
Ok(ind) => indications.push(ind),
|
||||
Err(error) => {
|
||||
warn!(%error, msg=line, "Failed to parse indication");
|
||||
}
|
||||
@@ -204,13 +216,15 @@ impl Future for B3270 {
|
||||
let mut sync_state = None;
|
||||
while let Poll::Ready(cmd) = self.comm.poll_recv(cx) {
|
||||
match cmd {
|
||||
None => {},
|
||||
None => {}
|
||||
Some(B3270Request::Resync(sender)) => {
|
||||
if sync_state.is_none() {
|
||||
sync_state = Some(self.tracker.get_init_indication());
|
||||
}
|
||||
// it's OK for this to fail; we just don't get a new client
|
||||
sender.send((sync_state.clone().unwrap(), self.ind_chan.subscribe())).ok();
|
||||
sender
|
||||
.send((sync_state.clone().unwrap(), self.ind_chan.subscribe()))
|
||||
.ok();
|
||||
}
|
||||
Some(B3270Request::Action(actions, response_chan)) => {
|
||||
let tag = 'find_tag: loop {
|
||||
@@ -225,15 +239,12 @@ impl Future for B3270 {
|
||||
type_: Some("keymap".to_owned()),
|
||||
actions,
|
||||
});
|
||||
let result = serde_json::to_writer(
|
||||
&mut self.write_buf,
|
||||
&op
|
||||
);
|
||||
let result = serde_json::to_writer(&mut self.write_buf, &op);
|
||||
match result {
|
||||
Ok(()) => {
|
||||
self.write_buf.push_back(b'\n');
|
||||
self.action_response_map.insert(tag, response_chan);
|
||||
},
|
||||
}
|
||||
Err(error) => error!(?op, %error, "Failed to serialize op"),
|
||||
}
|
||||
}
|
||||
@@ -244,7 +255,13 @@ impl Future for B3270 {
|
||||
'write: while !self.write_buf.is_empty() {
|
||||
let myself = &mut *self;
|
||||
let chunk = myself.write_buf.chunk();
|
||||
let stdin = Pin::new(myself.child.stdin.as_mut().expect("Should always have child stdin"));
|
||||
let stdin = Pin::new(
|
||||
myself
|
||||
.child
|
||||
.stdin
|
||||
.as_mut()
|
||||
.expect("Should always have child stdin"),
|
||||
);
|
||||
match stdin.poll_write(cx, chunk) {
|
||||
Poll::Pending | Poll::Ready(Ok(0)) => {
|
||||
break 'write;
|
||||
|
||||
@@ -1,28 +1,29 @@
|
||||
use anyhow::anyhow;
|
||||
use std::ffi::OsString;
|
||||
use std::process::Stdio;
|
||||
use std::str::FromStr;
|
||||
use anyhow::anyhow;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> anyhow::Result<()> {
|
||||
let mut subprocess_args = vec![
|
||||
OsString::from_str("-json").unwrap(),
|
||||
];
|
||||
let mut subprocess_args = vec![OsString::from_str("-json").unwrap()];
|
||||
let mut args_iter = std::env::args_os().peekable();
|
||||
let mut connect_str = None;
|
||||
while let Some(arg) = args_iter.next() {
|
||||
// we default to one of the ignored args
|
||||
match arg.to_str().unwrap_or("-json") {
|
||||
"-json" | "-xml" | "-indent" | "--" |
|
||||
"-scriptportonce" | "-nowrapperdoc" |
|
||||
"-socket" | "-v" | "--version" => {}
|
||||
"-json" | "-xml" | "-indent" | "--" | "-scriptportonce" | "-nowrapperdoc"
|
||||
| "-socket" | "-v" | "--version" => {}
|
||||
"-scriptport" | "-httpd" => {
|
||||
args_iter.next();
|
||||
}
|
||||
"-connect" => {
|
||||
connect_str = args_iter.next()
|
||||
connect_str = args_iter
|
||||
.next()
|
||||
.ok_or_else(|| anyhow!("Arg required for -connect"))
|
||||
.and_then(|arg| arg.into_string().map_err(|_| anyhow!("Invalid connect string")))
|
||||
.and_then(|arg| {
|
||||
arg.into_string()
|
||||
.map_err(|_| anyhow!("Invalid connect string"))
|
||||
})
|
||||
.map(Some)?;
|
||||
}
|
||||
"-e" => {
|
||||
@@ -51,5 +52,4 @@ async fn main() -> anyhow::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
pub mod connection;
|
||||
Reference in New Issue
Block a user