@@ -8,6 +8,7 @@ use crate::actor::IdDownloadRequest;
8
8
use crate :: dynamic_discovery:: DiscoverOp ;
9
9
use crate :: error:: ConversionError ;
10
10
use crate :: json;
11
+ use anyhow:: anyhow;
11
12
use anyhow:: Context ;
12
13
use c8y_api:: http_proxy:: C8yEndPoint ;
13
14
use c8y_api:: json_c8y:: C8yCreateEvent ;
@@ -926,9 +927,27 @@ impl CumulocityConverter {
926
927
vec ! [ ]
927
928
}
928
929
929
- Channel :: CommandMetadata {
930
- operation : OperationType :: Restart ,
931
- } => self . register_restart_operation ( & source) . await ?,
930
+ Channel :: CommandMetadata { operation } => {
931
+ self . validate_operation_supported ( operation, & source) ?;
932
+ match operation {
933
+ OperationType :: Restart => self . register_restart_operation ( & source) . await ?,
934
+ OperationType :: SoftwareList => {
935
+ self . register_software_list_operation ( & source) . await ?
936
+ }
937
+ OperationType :: SoftwareUpdate => {
938
+ self . register_software_update_operation ( & source) . await ?
939
+ }
940
+ OperationType :: LogUpload => self . convert_log_metadata ( & source, message) ?,
941
+ OperationType :: ConfigSnapshot => {
942
+ self . convert_config_snapshot_metadata ( & source, message) ?
943
+ }
944
+ OperationType :: ConfigUpdate => {
945
+ self . convert_config_update_metadata ( & source, message) ?
946
+ }
947
+ _ => vec ! [ ] ,
948
+ }
949
+ }
950
+
932
951
Channel :: Command {
933
952
operation : OperationType :: Restart ,
934
953
cmd_id,
@@ -937,19 +956,13 @@ impl CumulocityConverter {
937
956
. await ?
938
957
}
939
958
940
- Channel :: CommandMetadata {
941
- operation : OperationType :: SoftwareList ,
942
- } => self . register_software_list_operation ( & source) . await ?,
943
959
Channel :: Command {
944
960
operation : OperationType :: SoftwareList ,
945
961
cmd_id,
946
962
} if self . command_id . is_generator_of ( cmd_id) => {
947
963
self . publish_software_list ( & source, cmd_id, message) . await ?
948
964
}
949
965
950
- Channel :: CommandMetadata {
951
- operation : OperationType :: SoftwareUpdate ,
952
- } => self . register_software_update_operation ( & source) . await ?,
953
966
Channel :: Command {
954
967
operation : OperationType :: SoftwareUpdate ,
955
968
cmd_id,
@@ -958,10 +971,6 @@ impl CumulocityConverter {
958
971
. await ?
959
972
}
960
973
961
- Channel :: CommandMetadata {
962
- operation : OperationType :: LogUpload ,
963
- } => self . convert_log_metadata ( & source, message) ?,
964
-
965
974
Channel :: Command {
966
975
operation : OperationType :: LogUpload ,
967
976
cmd_id,
@@ -970,9 +979,6 @@ impl CumulocityConverter {
970
979
. await ?
971
980
}
972
981
973
- Channel :: CommandMetadata {
974
- operation : OperationType :: ConfigSnapshot ,
975
- } => self . convert_config_snapshot_metadata ( & source, message) ?,
976
982
Channel :: Command {
977
983
operation : OperationType :: ConfigSnapshot ,
978
984
cmd_id,
@@ -981,9 +987,6 @@ impl CumulocityConverter {
981
987
. await ?
982
988
}
983
989
984
- Channel :: CommandMetadata {
985
- operation : OperationType :: ConfigUpdate ,
986
- } => self . convert_config_update_metadata ( & source, message) ?,
987
990
Channel :: Command {
988
991
operation : OperationType :: ConfigUpdate ,
989
992
cmd_id,
@@ -1000,6 +1003,29 @@ impl CumulocityConverter {
1000
1003
Ok ( registration_messages)
1001
1004
}
1002
1005
1006
+ fn validate_operation_supported (
1007
+ & self ,
1008
+ op_type : & OperationType ,
1009
+ topic_id : & EntityTopicId ,
1010
+ ) -> Result < ( ) , ConversionError > {
1011
+ let target = self . entity_store . try_get ( topic_id) ?;
1012
+
1013
+ match target. r#type {
1014
+ EntityType :: MainDevice => Ok ( ( ) ) ,
1015
+ EntityType :: ChildDevice => match & target. parent {
1016
+ Some ( parent) if !parent. is_default_main_device ( ) => {
1017
+ Err ( ConversionError :: UnexpectedError ( anyhow ! (
1018
+ "{op_type} operation for nested child devices are currently unsupported"
1019
+ ) ) )
1020
+ }
1021
+ _ => Ok ( ( ) ) ,
1022
+ } ,
1023
+ EntityType :: Service => Err ( ConversionError :: UnexpectedError ( anyhow ! (
1024
+ "{op_type} operation for services are currently unsupported"
1025
+ ) ) ) ,
1026
+ }
1027
+ }
1028
+
1003
1029
pub fn register_and_convert_entity (
1004
1030
& mut self ,
1005
1031
registration_message : & EntityRegistrationMessage ,
@@ -2766,6 +2792,128 @@ pub(crate) mod tests {
2766
2792
assert_eq ! ( smartrest_fields. next( ) . unwrap( ) , "up" ) ;
2767
2793
}
2768
2794
2795
+ #[ test_case( "restart" ) ]
2796
+ #[ test_case( "software_list" ) ]
2797
+ #[ test_case( "software_update" ) ]
2798
+ #[ test_case( "log_upload" ) ]
2799
+ #[ test_case( "config_snapshot" ) ]
2800
+ #[ test_case( "config_update" ) ]
2801
+ #[ test_case( "custom_op" ) ]
2802
+ #[ tokio:: test]
2803
+ async fn operations_not_supported_for_nested_child_devices ( op_type : & str ) {
2804
+ let tmp_dir = TempTedgeDir :: new ( ) ;
2805
+ let ( mut converter, _http_proxy) = create_c8y_converter ( & tmp_dir) . await ;
2806
+
2807
+ // Register immediate child device and nested child device
2808
+ let reg_message = Message :: new (
2809
+ & Topic :: new_unchecked ( "te/device/immediate_child//" ) ,
2810
+ json ! ( {
2811
+ "@type" : "child-device" ,
2812
+ "@parent" : "device/main//" ,
2813
+ "@id" : "immediate_child"
2814
+ } )
2815
+ . to_string ( ) ,
2816
+ ) ;
2817
+ let _ = converter. convert ( & reg_message) . await ;
2818
+ let reg_message = Message :: new (
2819
+ & Topic :: new_unchecked ( "te/device/nested_child//" ) ,
2820
+ json ! ( {
2821
+ "@type" : "child-device" ,
2822
+ "@parent" : "device/immediate_child//" ,
2823
+ "@id" : "nested_child"
2824
+ } )
2825
+ . to_string ( ) ,
2826
+ ) ;
2827
+ let _ = converter. convert ( & reg_message) . await ;
2828
+
2829
+ let capability_msg = Message :: new (
2830
+ & Topic :: new_unchecked ( & format ! ( "te/device/nested_child///cmd/{op_type}" ) ) ,
2831
+ "[]" ,
2832
+ ) ;
2833
+ let messages = converter. convert ( & capability_msg) . await ;
2834
+
2835
+ assert_messages_matching (
2836
+ & messages,
2837
+ [ (
2838
+ "te/errors" ,
2839
+ "operation for nested child devices are currently unsupported" . into ( ) ,
2840
+ ) ] ,
2841
+ ) ;
2842
+ }
2843
+
2844
+ #[ test_case( "restart" ) ]
2845
+ #[ test_case( "software_list" ) ]
2846
+ #[ test_case( "software_update" ) ]
2847
+ #[ test_case( "log_upload" ) ]
2848
+ #[ test_case( "config_snapshot" ) ]
2849
+ #[ test_case( "config_update" ) ]
2850
+ #[ test_case( "custom_op" ) ]
2851
+ #[ tokio:: test]
2852
+ async fn operations_not_supported_for_services ( op_type : & str ) {
2853
+ let tmp_dir = TempTedgeDir :: new ( ) ;
2854
+ let ( mut converter, _http_proxy) = create_c8y_converter ( & tmp_dir) . await ;
2855
+
2856
+ // Register main device service
2857
+ let _ = converter
2858
+ . convert ( & Message :: new (
2859
+ & Topic :: new_unchecked ( "te/device/main/service/dummy" ) ,
2860
+ json ! ( {
2861
+ "@type" : "service" ,
2862
+ } )
2863
+ . to_string ( ) ,
2864
+ ) )
2865
+ . await ;
2866
+ // Register immediate child device service
2867
+ let _ = converter
2868
+ . convert ( & Message :: new (
2869
+ & Topic :: new_unchecked ( "te/device/immediate_child/service/dummy" ) ,
2870
+ json ! ( {
2871
+ "@type" : "service" ,
2872
+ } )
2873
+ . to_string ( ) ,
2874
+ ) )
2875
+ . await ;
2876
+ // Register nested child device
2877
+ let _ = converter
2878
+ . convert ( & Message :: new (
2879
+ & Topic :: new_unchecked ( "te/device/nested_child//" ) ,
2880
+ json ! ( {
2881
+ "@type" : "child-device" ,
2882
+ "@parent" : "device/immediate_child//" ,
2883
+ } )
2884
+ . to_string ( ) ,
2885
+ ) )
2886
+ . await ;
2887
+ // Register nested child device service
2888
+ let _ = converter
2889
+ . convert ( & Message :: new (
2890
+ & Topic :: new_unchecked ( "te/device/nested_child/service/dummy" ) ,
2891
+ json ! ( {
2892
+ "@type" : "service" ,
2893
+ } )
2894
+ . to_string ( ) ,
2895
+ ) )
2896
+ . await ;
2897
+
2898
+ for device_id in [ "main" , "immediate_child" , "nested_child" ] {
2899
+ let messages = converter
2900
+ . convert ( & Message :: new (
2901
+ & Topic :: new_unchecked ( & format ! (
2902
+ "te/device/{device_id}/service/dummy/cmd/{op_type}"
2903
+ ) ) ,
2904
+ "[]" ,
2905
+ ) )
2906
+ . await ;
2907
+ assert_messages_matching (
2908
+ & messages,
2909
+ [ (
2910
+ "te/errors" ,
2911
+ "operation for services are currently unsupported" . into ( ) ,
2912
+ ) ] ,
2913
+ ) ;
2914
+ }
2915
+ }
2916
+
2769
2917
pub ( crate ) async fn create_c8y_converter (
2770
2918
tmp_dir : & TempTedgeDir ,
2771
2919
) -> (
0 commit comments