use std::{
io::{self, Read},
str::FromStr,
};
use anyhow::Context as _;
use clap::{Args, Parser};
mod args;
use mqi::{
MqStr, Object,
connection::{ThreadNone, Tls},
constants,
header::TextEnc,
open::ObjectString,
prelude::*,
string::CCSID,
types::{ApplName, CipherSpec, MQENC, MQOO, MQPMO, MessageFormat, QueueManagerName, QueueName},
};
use tracing::Level;
const APP_NAME: ApplName = ApplName(mqstr!("open_put"));
const DEFAULT_CIPHER: CipherSpec = CipherSpec(mqstr!("TLS_AES_128_GCM_SHA256"));
#[derive(Parser, Debug)]
struct Cli {
#[command(flatten)]
connection: args::ConnectionArgs,
#[arg(long)]
format: Option<String>,
#[arg(long)]
oo: Vec<String>,
#[arg(long)]
pmo: Vec<String>,
#[command(flatten)]
target: Target,
}
#[derive(Args, Debug)]
#[group(required = true, multiple = true)]
struct Target {
#[arg(short, long, conflicts_with("queue"), conflicts_with("queue_manager"))]
topic: Option<String>,
#[arg(short, long)]
queue: Option<String>,
#[arg(short = 'm', long, requires("queue"))]
queue_manager: Option<String>,
}
fn main() -> anyhow::Result<()> {
let subscriber = tracing_subscriber::fmt().compact().with_max_level(Level::TRACE).finish();
tracing::subscriber::set_global_default(subscriber)?;
let args = Cli::parse();
let client_method = args.connection.method.connect_option()?;
let qm_name = args
.connection
.queue_manager_name()
.context("Connection queue manager name is invalid")?;
let creds = args.connection.credentials();
let cno = args.connection.cno().context("MQCNO options are invalid")?;
let tls = args.connection.tls(&DEFAULT_CIPHER).context("TLS options are not valid")?;
let tls_connect = tls
.as_ref()
.map(|(repo, cipher, label)| Tls::new(repo, label.as_ref(), cipher));
let target_topic = args.target.topic.as_deref().map(ObjectString);
let target_queue = args
.target
.queue
.as_deref()
.map(QueueName::from_str)
.transpose()
.context("Target queue name is invalid")?;
let target_qm = args
.target
.queue_manager
.as_deref()
.map(QueueManagerName::from_str)
.transpose()
.context("Target queue manager name is invalid")?;
let mut oo = constants::MQOO_OUTPUT;
for o in &args.oo {
oo.insert(MQOO::from_str(o).context("MQOO options are invalid")?);
}
let mut pmo = constants::MQPMO_NONE;
for p in &args.pmo {
pmo.insert(MQPMO::from_str(p).context("MQPMO options are invalid")?);
}
let fmt: MqStr<8> = (*args.format.unwrap_or_default()).try_into()?;
let msg_fmt = MessageFormat {
ccsid: CCSID(1208),
encoding: MQENC::default(),
fmt: TextEnc::Ascii(*fmt.as_mqchar()),
};
let qm = mqi::connect::<ThreadNone>(&(APP_NAME, tls_connect, qm_name, creds, cno, client_method))
.warn_as_error()
.context("Unable to connect to the queue manager")?;
let object = Object::open(qm, &(target_queue, target_qm, target_topic, oo))
.warn_as_error()
.context("Unable to open the object")?;
let mut stdin = io::stdin();
let mut message = Vec::new();
stdin.read_to_end(&mut message)?;
object
.put_message(&pmo, &(message, msg_fmt))
.warn_as_error()
.context("Unable to put the message")?;
Ok(())
}