use std::{self, fmt};
use tracing::error;
use crate::{
argument::Argument,
attribute::AttributeId,
byte_string::ByteString,
constants,
localized_text::LocalizedText,
node_id::NodeId,
profiles,
qualified_name::QualifiedName,
response_header::{AsRequestHandle, ResponseHeader},
status_code::StatusCode,
string::UAString,
variant::Variant,
AnonymousIdentityToken, ApplicationDescription, CallMethodRequest, DataTypeId, DataValue,
EndpointDescription, Error, ExpandedNodeId, HistoryUpdateType, IdentityCriteriaType,
MessageSecurityMode, MonitoredItemCreateRequest, MonitoringMode, MonitoringParameters,
NumericRange, ObjectId, ReadValueId, ServiceCounterDataType, ServiceFault, SignatureData,
UserNameIdentityToken, UserTokenPolicy, UserTokenType, WriteValue,
};
use super::PerformUpdateType;
pub trait MessageInfo {
fn type_id(&self) -> ObjectId;
fn json_type_id(&self) -> ObjectId;
fn xml_type_id(&self) -> ObjectId;
fn data_type_id(&self) -> DataTypeId;
}
pub trait ExpandedMessageInfo {
fn full_type_id(&self) -> ExpandedNodeId;
fn full_json_type_id(&self) -> ExpandedNodeId;
fn full_xml_type_id(&self) -> ExpandedNodeId;
fn full_data_type_id(&self) -> ExpandedNodeId;
}
impl<T> ExpandedMessageInfo for T
where
T: MessageInfo,
{
fn full_type_id(&self) -> ExpandedNodeId {
self.type_id().into()
}
fn full_json_type_id(&self) -> ExpandedNodeId {
self.json_type_id().into()
}
fn full_xml_type_id(&self) -> ExpandedNodeId {
self.xml_type_id().into()
}
fn full_data_type_id(&self) -> ExpandedNodeId {
self.data_type_id().into()
}
}
impl ServiceFault {
pub fn new(request_header: impl AsRequestHandle, service_result: StatusCode) -> ServiceFault {
ServiceFault {
response_header: ResponseHeader::new_service_result(request_header, service_result),
}
}
}
impl UserTokenPolicy {
pub fn anonymous() -> UserTokenPolicy {
UserTokenPolicy {
policy_id: UAString::from("anonymous"),
token_type: UserTokenType::Anonymous,
issued_token_type: UAString::null(),
issuer_endpoint_url: UAString::null(),
security_policy_uri: UAString::null(),
}
}
}
impl EndpointDescription {
pub fn find_policy(&self, token_type: UserTokenType) -> Option<&UserTokenPolicy> {
if let Some(ref policies) = self.user_identity_tokens {
policies.iter().find(|t| t.token_type == token_type)
} else {
None
}
}
pub fn find_policy_by_id(&self, policy_id: &str) -> Option<&UserTokenPolicy> {
if let Some(ref policies) = self.user_identity_tokens {
policies.iter().find(|t| t.policy_id.as_ref() == policy_id)
} else {
None
}
}
}
impl UserNameIdentityToken {
pub fn is_valid(&self) -> bool {
!self.user_name.is_null() && !self.password.is_null()
}
pub fn plaintext_password(&self) -> Result<String, Error> {
if !self.encryption_algorithm.is_empty() {
return Err(Error::new(
StatusCode::BadSecurityChecksFailed,
"Password is encrypted",
));
}
String::from_utf8(self.password.as_ref().to_vec())
.map_err(|e| Error::new(StatusCode::BadSecurityChecksFailed, e))
}
}
impl<'a> From<&'a NodeId> for ReadValueId {
fn from(node_id: &'a NodeId) -> Self {
Self::from(node_id.clone())
}
}
impl From<NodeId> for ReadValueId {
fn from(node_id: NodeId) -> Self {
ReadValueId {
node_id,
attribute_id: AttributeId::Value as u32,
index_range: NumericRange::None,
data_encoding: QualifiedName::null(),
}
}
}
impl<'a> From<(u16, &'a str)> for ReadValueId {
fn from(v: (u16, &'a str)) -> Self {
Self::from(NodeId::from(v))
}
}
impl ReadValueId {
pub fn new(node_id: NodeId, attribute_id: AttributeId) -> Self {
Self {
node_id,
attribute_id: attribute_id as u32,
..Default::default()
}
}
pub fn new_value(node_id: NodeId) -> Self {
Self {
node_id,
attribute_id: AttributeId::Value as u32,
..Default::default()
}
}
}
impl Default for AnonymousIdentityToken {
fn default() -> Self {
AnonymousIdentityToken {
policy_id: UAString::from(profiles::SECURITY_USER_TOKEN_POLICY_ANONYMOUS),
}
}
}
impl SignatureData {
pub fn null() -> SignatureData {
SignatureData {
algorithm: UAString::null(),
signature: ByteString::null(),
}
}
}
impl From<NodeId> for MonitoredItemCreateRequest {
fn from(value: NodeId) -> Self {
Self::new(
value.into(),
MonitoringMode::Reporting,
MonitoringParameters::default(),
)
}
}
impl MonitoredItemCreateRequest {
pub fn new(
item_to_monitor: ReadValueId,
monitoring_mode: MonitoringMode,
requested_parameters: MonitoringParameters,
) -> MonitoredItemCreateRequest {
MonitoredItemCreateRequest {
item_to_monitor,
monitoring_mode,
requested_parameters,
}
}
}
impl From<(NodeId, NodeId, Option<Vec<Variant>>)> for CallMethodRequest {
fn from(value: (NodeId, NodeId, Option<Vec<Variant>>)) -> Self {
Self {
object_id: value.0,
method_id: value.1,
input_arguments: value.2,
}
}
}
impl<'a> From<&'a str> for EndpointDescription {
fn from(v: &'a str) -> Self {
EndpointDescription::from((
v,
constants::SECURITY_POLICY_NONE_URI,
MessageSecurityMode::None,
))
}
}
impl<'a> From<(&'a str, &'a str, MessageSecurityMode)> for EndpointDescription {
fn from(v: (&'a str, &'a str, MessageSecurityMode)) -> Self {
EndpointDescription::from((v.0, v.1, v.2, None))
}
}
impl<'a> From<(&'a str, &'a str, MessageSecurityMode, UserTokenPolicy)> for EndpointDescription {
fn from(v: (&'a str, &'a str, MessageSecurityMode, UserTokenPolicy)) -> Self {
EndpointDescription::from((v.0, v.1, v.2, Some(vec![v.3])))
}
}
impl<'a> From<(&'a str, &'a str, MessageSecurityMode, Vec<UserTokenPolicy>)>
for EndpointDescription
{
fn from(v: (&'a str, &'a str, MessageSecurityMode, Vec<UserTokenPolicy>)) -> Self {
EndpointDescription::from((v.0, v.1, v.2, Some(v.3)))
}
}
impl<'a>
From<(
&'a str,
&'a str,
MessageSecurityMode,
Option<Vec<UserTokenPolicy>>,
)> for EndpointDescription
{
fn from(
v: (
&'a str,
&'a str,
MessageSecurityMode,
Option<Vec<UserTokenPolicy>>,
),
) -> Self {
EndpointDescription {
endpoint_url: UAString::from(v.0),
security_policy_uri: UAString::from(v.1),
security_mode: v.2,
server: ApplicationDescription::default(),
security_level: 0,
server_certificate: ByteString::null(),
transport_profile_uri: UAString::null(),
user_identity_tokens: v.3,
}
}
}
impl From<String> for EndpointDescription {
fn from(v: String) -> Self {
EndpointDescription::from(v.as_str())
}
}
const MESSAGE_SECURITY_MODE_NONE: &str = "None";
const MESSAGE_SECURITY_MODE_SIGN: &str = "Sign";
const MESSAGE_SECURITY_MODE_SIGN_AND_ENCRYPT: &str = "SignAndEncrypt";
impl fmt::Display for MessageSecurityMode {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let name = match self {
MessageSecurityMode::None => MESSAGE_SECURITY_MODE_NONE,
MessageSecurityMode::Sign => MESSAGE_SECURITY_MODE_SIGN,
MessageSecurityMode::SignAndEncrypt => MESSAGE_SECURITY_MODE_SIGN_AND_ENCRYPT,
_ => "",
};
write!(f, "{name}")
}
}
impl From<MessageSecurityMode> for String {
fn from(security_mode: MessageSecurityMode) -> Self {
security_mode.to_string()
}
}
impl<'a> From<&'a str> for MessageSecurityMode {
fn from(str: &'a str) -> Self {
match str {
MESSAGE_SECURITY_MODE_NONE => MessageSecurityMode::None,
MESSAGE_SECURITY_MODE_SIGN => MessageSecurityMode::Sign,
MESSAGE_SECURITY_MODE_SIGN_AND_ENCRYPT => MessageSecurityMode::SignAndEncrypt,
_ => {
error!("Specified security mode \"{}\" is not recognized", str);
MessageSecurityMode::Invalid
}
}
}
}
impl From<(&str, DataTypeId)> for Argument {
fn from(v: (&str, DataTypeId)) -> Self {
Argument {
name: UAString::from(v.0),
data_type: v.1.into(),
value_rank: -1,
array_dimensions: None,
description: LocalizedText::null(),
}
}
}
impl ServiceCounterDataType {
pub fn success(&mut self) {
self.total_count += 1;
}
pub fn error(&mut self) {
self.total_count += 1;
self.error_count += 1;
}
}
#[allow(clippy::derivable_impls, reason = "This is for generated code")]
impl Default for PerformUpdateType {
fn default() -> Self {
Self::Insert
}
}
#[allow(clippy::derivable_impls, reason = "This is for generated code")]
impl Default for HistoryUpdateType {
fn default() -> Self {
Self::Insert
}
}
#[allow(clippy::derivable_impls, reason = "This is for generated code")]
impl Default for IdentityCriteriaType {
fn default() -> Self {
Self::Anonymous
}
}
impl WriteValue {
pub fn new(
node_id: NodeId,
attribute_id: AttributeId,
index_range: NumericRange,
value: DataValue,
) -> Self {
Self {
node_id,
attribute_id: attribute_id as u32,
index_range,
value,
}
}
pub fn value_attr(node_id: NodeId, val: Variant) -> Self {
Self {
node_id,
attribute_id: AttributeId::Value as u32,
index_range: NumericRange::None,
value: val.into(),
}
}
}