use opcua_types::{
AddNodeAttributes, AddNodesItem, AddNodesResult, AddReferencesItem, DeleteNodesItem,
DeleteReferencesItem, DiagnosticBits, DiagnosticInfo, ExpandedNodeId, NodeClass, NodeId,
QualifiedName, StatusCode,
};
use super::IntoResult;
#[derive(Debug, Clone)]
pub struct AddNodeItem {
parent_node_id: ExpandedNodeId,
reference_type_id: NodeId,
requested_new_node_id: NodeId,
browse_name: QualifiedName,
node_class: NodeClass,
node_attributes: AddNodeAttributes,
type_definition_id: ExpandedNodeId,
diagnostic_bits: DiagnosticBits,
result_node_id: NodeId,
status: StatusCode,
diagnostic_info: Option<DiagnosticInfo>,
}
impl AddNodeItem {
pub(crate) fn new(item: AddNodesItem, diagnostic_bits: DiagnosticBits) -> Self {
let mut status = StatusCode::BadNotSupported;
let attributes = match AddNodeAttributes::from_extension_object(item.node_attributes) {
Ok(attr) => attr,
Err(e) => {
status = e;
AddNodeAttributes::None
}
};
if item.requested_new_node_id.server_index != 0 {
status = StatusCode::BadNodeIdRejected;
}
Self::validate_attributes(item.node_class, &attributes, &mut status);
if item.reference_type_id.is_null() {
status = StatusCode::BadReferenceTypeIdInvalid;
}
if item.parent_node_id.is_null() {
status = StatusCode::BadParentNodeIdInvalid;
}
match (item.node_class, item.type_definition.is_null()) {
(NodeClass::Object | NodeClass::Variable, true) => {
status = StatusCode::BadTypeDefinitionInvalid
}
(NodeClass::Object | NodeClass::Variable, false) => (),
(_, false) => status = StatusCode::BadTypeDefinitionInvalid,
_ => (),
}
Self {
parent_node_id: item.parent_node_id,
reference_type_id: item.reference_type_id,
requested_new_node_id: item.requested_new_node_id.node_id,
browse_name: item.browse_name,
node_class: item.node_class,
node_attributes: attributes,
type_definition_id: item.type_definition,
result_node_id: NodeId::null(),
status,
diagnostic_info: None,
diagnostic_bits,
}
}
fn validate_attributes(
node_class: NodeClass,
attributes: &AddNodeAttributes,
status: &mut StatusCode,
) {
match (node_class, attributes) {
(NodeClass::Object, AddNodeAttributes::Object(_))
| (NodeClass::Variable, AddNodeAttributes::Variable(_))
| (NodeClass::Method, AddNodeAttributes::Method(_))
| (NodeClass::ObjectType, AddNodeAttributes::ObjectType(_))
| (NodeClass::VariableType, AddNodeAttributes::VariableType(_))
| (NodeClass::ReferenceType, AddNodeAttributes::ReferenceType(_))
| (NodeClass::DataType, AddNodeAttributes::DataType(_))
| (NodeClass::View, AddNodeAttributes::View(_)) => {}
(NodeClass::Unspecified, _) => *status = StatusCode::BadNodeClassInvalid,
(_, AddNodeAttributes::None | AddNodeAttributes::Generic(_)) => {}
_ => *status = StatusCode::BadNodeAttributesInvalid,
}
}
pub fn set_result(&mut self, node_id: NodeId, status: StatusCode) {
self.result_node_id = node_id;
self.status = status;
}
pub fn parent_node_id(&self) -> &ExpandedNodeId {
&self.parent_node_id
}
pub fn reference_type_id(&self) -> &NodeId {
&self.reference_type_id
}
pub fn requested_new_node_id(&self) -> &NodeId {
&self.requested_new_node_id
}
pub fn browse_name(&self) -> &QualifiedName {
&self.browse_name
}
pub fn node_class(&self) -> NodeClass {
self.node_class
}
pub fn node_attributes(&self) -> &AddNodeAttributes {
&self.node_attributes
}
pub fn type_definition_id(&self) -> &ExpandedNodeId {
&self.type_definition_id
}
pub fn status(&self) -> StatusCode {
self.status
}
pub fn diagnostic_bits(&self) -> DiagnosticBits {
self.diagnostic_bits
}
pub fn set_diagnostic_info(&mut self, diagnostic_info: DiagnosticInfo) {
self.diagnostic_info = Some(diagnostic_info);
}
}
impl IntoResult for AddNodeItem {
type Result = AddNodesResult;
fn into_result(self) -> (Self::Result, Option<DiagnosticInfo>) {
(
AddNodesResult {
status_code: self.status,
added_node_id: self.result_node_id,
},
self.diagnostic_info,
)
}
}
#[derive(Debug, Clone)]
pub struct AddReferenceItem {
source_node_id: NodeId,
reference_type_id: NodeId,
target_node_id: ExpandedNodeId,
is_forward: bool,
diagnostic_bits: DiagnosticBits,
source_status: StatusCode,
target_status: StatusCode,
diagnostic_info: Option<DiagnosticInfo>,
}
impl AddReferenceItem {
pub(crate) fn new(item: AddReferencesItem, diagnostic_bits: DiagnosticBits) -> Self {
let mut status = StatusCode::BadNotSupported;
if item.source_node_id.is_null() {
status = StatusCode::BadSourceNodeIdInvalid;
}
if item.target_node_id.is_null() {
status = StatusCode::BadTargetNodeIdInvalid;
}
if item.reference_type_id.is_null() {
status = StatusCode::BadReferenceTypeIdInvalid;
}
if !item.target_server_uri.is_null() || item.target_node_id.server_index != 0 {
status = StatusCode::BadReferenceLocalOnly;
}
Self {
source_node_id: item.source_node_id,
reference_type_id: item.reference_type_id,
target_node_id: item.target_node_id,
is_forward: item.is_forward,
source_status: status,
target_status: status,
diagnostic_bits,
diagnostic_info: None,
}
}
pub fn source_node_id(&self) -> &NodeId {
&self.source_node_id
}
pub fn reference_type_id(&self) -> &NodeId {
&self.reference_type_id
}
pub fn target_node_id(&self) -> &ExpandedNodeId {
&self.target_node_id
}
pub(crate) fn result_status(&self) -> StatusCode {
if self.source_status.is_good() {
return self.source_status;
}
if self.target_status.is_good() {
return self.target_status;
}
self.source_status
}
pub fn set_source_result(&mut self, status: StatusCode) {
self.source_status = status;
}
pub fn set_target_result(&mut self, status: StatusCode) {
self.target_status = status;
}
pub fn is_forward(&self) -> bool {
self.is_forward
}
pub fn target_status(&self) -> StatusCode {
self.target_status
}
pub fn source_status(&self) -> StatusCode {
self.source_status
}
pub fn diagnostic_bits(&self) -> DiagnosticBits {
self.diagnostic_bits
}
pub fn set_diagnostic_info(&mut self, diagnostic_info: DiagnosticInfo) {
self.diagnostic_info = Some(diagnostic_info);
}
}
impl IntoResult for AddReferenceItem {
type Result = StatusCode;
fn into_result(self) -> (Self::Result, Option<DiagnosticInfo>) {
(self.result_status(), self.diagnostic_info)
}
}
#[derive(Debug)]
pub struct DeleteNodeItem {
node_id: NodeId,
delete_target_references: bool,
diagnostic_bits: DiagnosticBits,
status: StatusCode,
diagnostic_info: Option<DiagnosticInfo>,
}
impl DeleteNodeItem {
pub(crate) fn new(item: DeleteNodesItem, diagnostic_bits: DiagnosticBits) -> Self {
let mut status = StatusCode::BadNodeIdUnknown;
if item.node_id.is_null() {
status = StatusCode::BadNodeIdInvalid;
}
Self {
node_id: item.node_id,
delete_target_references: item.delete_target_references,
status,
diagnostic_bits,
diagnostic_info: None,
}
}
pub fn status(&self) -> StatusCode {
self.status
}
pub fn set_result(&mut self, status: StatusCode) {
self.status = status;
}
pub fn delete_target_references(&self) -> bool {
self.delete_target_references
}
pub fn node_id(&self) -> &NodeId {
&self.node_id
}
pub fn diagnostic_bits(&self) -> DiagnosticBits {
self.diagnostic_bits
}
pub fn set_diagnostic_info(&mut self, diagnostic_info: DiagnosticInfo) {
self.diagnostic_info = Some(diagnostic_info);
}
}
impl IntoResult for DeleteNodeItem {
type Result = StatusCode;
fn into_result(self) -> (Self::Result, Option<DiagnosticInfo>) {
(self.status(), self.diagnostic_info)
}
}
#[derive(Debug)]
pub struct DeleteReferenceItem {
source_node_id: NodeId,
reference_type_id: NodeId,
is_forward: bool,
target_node_id: ExpandedNodeId,
delete_bidirectional: bool,
diagnostic_bits: DiagnosticBits,
source_status: StatusCode,
target_status: StatusCode,
diagnostic_info: Option<DiagnosticInfo>,
}
impl DeleteReferenceItem {
pub(crate) fn new(item: DeleteReferencesItem, diagnostic_bits: DiagnosticBits) -> Self {
let mut status = StatusCode::BadNotSupported;
if item.source_node_id.is_null() {
status = StatusCode::BadSourceNodeIdInvalid;
}
if item.target_node_id.is_null() {
status = StatusCode::BadTargetNodeIdInvalid;
}
if item.reference_type_id.is_null() {
status = StatusCode::BadReferenceTypeIdInvalid;
}
if item.target_node_id.server_index != 0 {
status = StatusCode::BadReferenceLocalOnly;
}
Self {
source_node_id: item.source_node_id,
reference_type_id: item.reference_type_id,
is_forward: item.is_forward,
target_node_id: item.target_node_id,
delete_bidirectional: item.delete_bidirectional,
diagnostic_bits,
source_status: status,
target_status: status,
diagnostic_info: None,
}
}
pub fn source_node_id(&self) -> &NodeId {
&self.source_node_id
}
pub fn reference_type_id(&self) -> &NodeId {
&self.reference_type_id
}
pub fn target_node_id(&self) -> &ExpandedNodeId {
&self.target_node_id
}
pub(crate) fn result_status(&self) -> StatusCode {
if self.source_status.is_good() {
return self.source_status;
}
if self.target_status.is_good() {
return self.target_status;
}
self.source_status
}
pub fn set_source_result(&mut self, status: StatusCode) {
self.source_status = status;
}
pub fn set_target_result(&mut self, status: StatusCode) {
self.target_status = status;
}
pub fn is_forward(&self) -> bool {
self.is_forward
}
pub fn target_status(&self) -> StatusCode {
self.target_status
}
pub fn source_status(&self) -> StatusCode {
self.source_status
}
pub fn delete_bidirectional(&self) -> bool {
self.delete_bidirectional
}
pub fn diagnostic_bits(&self) -> DiagnosticBits {
self.diagnostic_bits
}
pub fn set_diagnostic_info(&mut self, diagnostic_info: DiagnosticInfo) {
self.diagnostic_info = Some(diagnostic_info);
}
}
impl IntoResult for DeleteReferenceItem {
type Result = StatusCode;
fn into_result(self) -> (Self::Result, Option<DiagnosticInfo>) {
(self.result_status(), self.diagnostic_info)
}
}