tdl-xoa-driver 1.0.0b1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- tdl_xoa_driver-1.0.0b1.dist-info/LICENSE +202 -0
- tdl_xoa_driver-1.0.0b1.dist-info/METADATA +177 -0
- tdl_xoa_driver-1.0.0b1.dist-info/RECORD +325 -0
- tdl_xoa_driver-1.0.0b1.dist-info/WHEEL +5 -0
- tdl_xoa_driver-1.0.0b1.dist-info/top_level.txt +1 -0
- xoa_driver/__init__.py +2 -0
- xoa_driver/enums.py +399 -0
- xoa_driver/exceptions.py +77 -0
- xoa_driver/functions/__init__.py +0 -0
- xoa_driver/functions/anlt.py +744 -0
- xoa_driver/functions/anlt_ll_debug.py +429 -0
- xoa_driver/functions/cli.py +581 -0
- xoa_driver/functions/exceptions.py +72 -0
- xoa_driver/functions/headers.py +608 -0
- xoa_driver/functions/mgmt.py +515 -0
- xoa_driver/functions/tools.py +256 -0
- xoa_driver/hlfuncs.py +18 -0
- xoa_driver/internals/__init__.py +0 -0
- xoa_driver/internals/commands/__init__.py +31 -0
- xoa_driver/internals/commands/c_commands.py +2041 -0
- xoa_driver/internals/commands/enums.py +3289 -0
- xoa_driver/internals/commands/m4_commands.py +700 -0
- xoa_driver/internals/commands/m4e_commands.py +107 -0
- xoa_driver/internals/commands/m_commands.py +1875 -0
- xoa_driver/internals/commands/p4_commands.py +2221 -0
- xoa_driver/internals/commands/p4e_commands.py +160 -0
- xoa_driver/internals/commands/p4g_commands.py +7253 -0
- xoa_driver/internals/commands/p_commands.py +6000 -0
- xoa_driver/internals/commands/pc_commands.py +335 -0
- xoa_driver/internals/commands/pd_commands.py +355 -0
- xoa_driver/internals/commands/pe_commands.py +1018 -0
- xoa_driver/internals/commands/pec_commands.py +265 -0
- xoa_driver/internals/commands/ped_commands.py +1034 -0
- xoa_driver/internals/commands/pef_commands.py +2216 -0
- xoa_driver/internals/commands/pf_commands.py +379 -0
- xoa_driver/internals/commands/pl1_commands.py +1588 -0
- xoa_driver/internals/commands/pl_commands.py +178 -0
- xoa_driver/internals/commands/pm_commands.py +256 -0
- xoa_driver/internals/commands/pp_commands.py +2341 -0
- xoa_driver/internals/commands/pr_commands.py +812 -0
- xoa_driver/internals/commands/ps_commands.py +2311 -0
- xoa_driver/internals/commands/pt_commands.py +370 -0
- xoa_driver/internals/commands/px_commands.py +303 -0
- xoa_driver/internals/commands/subtypes.py +86 -0
- xoa_driver/internals/core/__init__.py +0 -0
- xoa_driver/internals/core/builders.py +39 -0
- xoa_driver/internals/core/exceptions.py +69 -0
- xoa_driver/internals/core/funcs.py +81 -0
- xoa_driver/internals/core/funcs.pyi +1072 -0
- xoa_driver/internals/core/interfaces.py +47 -0
- xoa_driver/internals/core/token.py +44 -0
- xoa_driver/internals/core/transporter/__init__.py +0 -0
- xoa_driver/internals/core/transporter/_processor.py +83 -0
- xoa_driver/internals/core/transporter/_publisher.py +101 -0
- xoa_driver/internals/core/transporter/_request_id_counter.py +28 -0
- xoa_driver/internals/core/transporter/_stream.py +99 -0
- xoa_driver/internals/core/transporter/_typings.py +43 -0
- xoa_driver/internals/core/transporter/exceptions.py +44 -0
- xoa_driver/internals/core/transporter/handler.py +127 -0
- xoa_driver/internals/core/transporter/logger/__init__.py +10 -0
- xoa_driver/internals/core/transporter/logger/__logger.py +94 -0
- xoa_driver/internals/core/transporter/logger/__state_off.py +32 -0
- xoa_driver/internals/core/transporter/logger/__state_on_default.py +70 -0
- xoa_driver/internals/core/transporter/logger/__state_on_loguru.py +51 -0
- xoa_driver/internals/core/transporter/logger/__state_on_user.py +48 -0
- xoa_driver/internals/core/transporter/protocol/__init__.py +0 -0
- xoa_driver/internals/core/transporter/protocol/_constants.py +77 -0
- xoa_driver/internals/core/transporter/protocol/_utils.py +59 -0
- xoa_driver/internals/core/transporter/protocol/exceptions.py +271 -0
- xoa_driver/internals/core/transporter/protocol/payload/__init__.py +70 -0
- xoa_driver/internals/core/transporter/protocol/payload/base_struct.py +283 -0
- xoa_driver/internals/core/transporter/protocol/payload/descriptor.py +119 -0
- xoa_driver/internals/core/transporter/protocol/payload/exceptions.py +20 -0
- xoa_driver/internals/core/transporter/protocol/payload/field.py +296 -0
- xoa_driver/internals/core/transporter/protocol/payload/types.py +173 -0
- xoa_driver/internals/core/transporter/protocol/payload/utils.py +53 -0
- xoa_driver/internals/core/transporter/protocol/struct_header.py +123 -0
- xoa_driver/internals/core/transporter/protocol/struct_request.py +65 -0
- xoa_driver/internals/core/transporter/protocol/struct_response.py +89 -0
- xoa_driver/internals/core/transporter/registry.py +43 -0
- xoa_driver/internals/exceptions/__init__.py +9 -0
- xoa_driver/internals/exceptions/modules.py +13 -0
- xoa_driver/internals/exceptions/testers.py +21 -0
- xoa_driver/internals/hli_v1/__init__.py +0 -0
- xoa_driver/internals/hli_v1/indices/__init__.py +0 -0
- xoa_driver/internals/hli_v1/indices/base_index.py +39 -0
- xoa_driver/internals/hli_v1/indices/connection_group/__init__.py +0 -0
- xoa_driver/internals/hli_v1/indices/connection_group/cg.py +186 -0
- xoa_driver/internals/hli_v1/indices/connection_group/histogram.py +78 -0
- xoa_driver/internals/hli_v1/indices/connection_group/l2.py +94 -0
- xoa_driver/internals/hli_v1/indices/connection_group/l3.py +130 -0
- xoa_driver/internals/hli_v1/indices/connection_group/raw.py +200 -0
- xoa_driver/internals/hli_v1/indices/connection_group/replay.py +109 -0
- xoa_driver/internals/hli_v1/indices/connection_group/tcp.py +314 -0
- xoa_driver/internals/hli_v1/indices/connection_group/tls.py +198 -0
- xoa_driver/internals/hli_v1/indices/connection_group/udp.py +133 -0
- xoa_driver/internals/hli_v1/indices/connection_group/user_state.py +28 -0
- xoa_driver/internals/hli_v1/indices/filter/__init__.py +0 -0
- xoa_driver/internals/hli_v1/indices/filter/base_filter.py +65 -0
- xoa_driver/internals/hli_v1/indices/filter/genuine_filter.py +20 -0
- xoa_driver/internals/hli_v1/indices/length_term.py +49 -0
- xoa_driver/internals/hli_v1/indices/macsecscs/__init__.py +0 -0
- xoa_driver/internals/hli_v1/indices/macsecscs/base_macsecsc.py +224 -0
- xoa_driver/internals/hli_v1/indices/macsecscs/genuine_macsecsc.py +72 -0
- xoa_driver/internals/hli_v1/indices/match_term.py +64 -0
- xoa_driver/internals/hli_v1/indices/port_dataset.py +72 -0
- xoa_driver/internals/hli_v1/indices/streams/__init__.py +0 -0
- xoa_driver/internals/hli_v1/indices/streams/base_stream.py +405 -0
- xoa_driver/internals/hli_v1/indices/streams/genuine_stream.py +64 -0
- xoa_driver/internals/hli_v1/modules/__init__.py +0 -0
- xoa_driver/internals/hli_v1/modules/__interfaces.py +21 -0
- xoa_driver/internals/hli_v1/modules/base_module.py +138 -0
- xoa_driver/internals/hli_v1/modules/module_chimera.py +366 -0
- xoa_driver/internals/hli_v1/modules/module_l23ve.py +73 -0
- xoa_driver/internals/hli_v1/modules/module_l47.py +397 -0
- xoa_driver/internals/hli_v1/modules/module_l47ve.py +9 -0
- xoa_driver/internals/hli_v1/modules/modules_l23/__init__.py +0 -0
- xoa_driver/internals/hli_v1/modules/modules_l23/family_combi.py +83 -0
- xoa_driver/internals/hli_v1/modules/modules_l23/family_d.py +75 -0
- xoa_driver/internals/hli_v1/modules/modules_l23/family_e.py +85 -0
- xoa_driver/internals/hli_v1/modules/modules_l23/family_f.py +145 -0
- xoa_driver/internals/hli_v1/modules/modules_l23/family_g.py +84 -0
- xoa_driver/internals/hli_v1/modules/modules_l23/family_h.py +40 -0
- xoa_driver/internals/hli_v1/modules/modules_l23/family_i.py +25 -0
- xoa_driver/internals/hli_v1/modules/modules_l23/family_j.py +25 -0
- xoa_driver/internals/hli_v1/modules/modules_l23/family_k.py +39 -0
- xoa_driver/internals/hli_v1/modules/modules_l23/family_l.py +55 -0
- xoa_driver/internals/hli_v1/modules/modules_l23/family_l1.py +800 -0
- xoa_driver/internals/hli_v1/modules/modules_l23/family_m.py +25 -0
- xoa_driver/internals/hli_v1/modules/modules_l23/family_n.py +40 -0
- xoa_driver/internals/hli_v1/modules/modules_l23/module_l23_base.py +383 -0
- xoa_driver/internals/hli_v1/ports/__init__.py +0 -0
- xoa_driver/internals/hli_v1/ports/base_port.py +125 -0
- xoa_driver/internals/hli_v1/ports/port_l23/__init__.py +0 -0
- xoa_driver/internals/hli_v1/ports/port_l23/bases/__init__.py +0 -0
- xoa_driver/internals/hli_v1/ports/port_l23/bases/port_capture.py +70 -0
- xoa_driver/internals/hli_v1/ports/port_l23/bases/port_l23.py +527 -0
- xoa_driver/internals/hli_v1/ports/port_l23/bases/port_l23_genuine.py +229 -0
- xoa_driver/internals/hli_v1/ports/port_l23/bases/port_reception_statistics.py +231 -0
- xoa_driver/internals/hli_v1/ports/port_l23/bases/port_transceiver.py +117 -0
- xoa_driver/internals/hli_v1/ports/port_l23/bases/port_transmission_statistics.py +131 -0
- xoa_driver/internals/hli_v1/ports/port_l23/chimera/__init__.py +0 -0
- xoa_driver/internals/hli_v1/ports/port_l23/chimera/filter_definition/__init__.py +0 -0
- xoa_driver/internals/hli_v1/ports/port_l23/chimera/filter_definition/_utils.py +15 -0
- xoa_driver/internals/hli_v1/ports/port_l23/chimera/filter_definition/general.py +396 -0
- xoa_driver/internals/hli_v1/ports/port_l23/chimera/filter_definition/shadow.py +104 -0
- xoa_driver/internals/hli_v1/ports/port_l23/chimera/filter_definition/working.py +36 -0
- xoa_driver/internals/hli_v1/ports/port_l23/chimera/pe_custom_distribution.py +125 -0
- xoa_driver/internals/hli_v1/ports/port_l23/chimera/pe_distribution.py +174 -0
- xoa_driver/internals/hli_v1/ports/port_l23/chimera/port_chimera.py +119 -0
- xoa_driver/internals/hli_v1/ports/port_l23/chimera/port_emulation.py +244 -0
- xoa_driver/internals/hli_v1/ports/port_l23/chimera/reception_statistics.py +24 -0
- xoa_driver/internals/hli_v1/ports/port_l23/chimera/transmission_statistics.py +24 -0
- xoa_driver/internals/hli_v1/ports/port_l23/family_combi.py +37 -0
- xoa_driver/internals/hli_v1/ports/port_l23/family_d.py +51 -0
- xoa_driver/internals/hli_v1/ports/port_l23/family_e.py +107 -0
- xoa_driver/internals/hli_v1/ports/port_l23/family_f.py +151 -0
- xoa_driver/internals/hli_v1/ports/port_l23/family_g.py +77 -0
- xoa_driver/internals/hli_v1/ports/port_l23/family_h.py +67 -0
- xoa_driver/internals/hli_v1/ports/port_l23/family_i.py +84 -0
- xoa_driver/internals/hli_v1/ports/port_l23/family_j.py +68 -0
- xoa_driver/internals/hli_v1/ports/port_l23/family_k.py +73 -0
- xoa_driver/internals/hli_v1/ports/port_l23/family_l.py +82 -0
- xoa_driver/internals/hli_v1/ports/port_l23/family_l1.py +166 -0
- xoa_driver/internals/hli_v1/ports/port_l23/family_m.py +29 -0
- xoa_driver/internals/hli_v1/ports/port_l23/fault_jkl.py +24 -0
- xoa_driver/internals/hli_v1/ports/port_l23/freya_l1.py +722 -0
- xoa_driver/internals/hli_v1/ports/port_l23/pcs_pma_ghijkl.py +369 -0
- xoa_driver/internals/hli_v1/ports/port_l23/pcs_pma_ijkl_chimera.py +60 -0
- xoa_driver/internals/hli_v1/ports/port_l23/pcs_pma_l.py +78 -0
- xoa_driver/internals/hli_v1/ports/port_l23/port_l23ve.py +101 -0
- xoa_driver/internals/hli_v1/ports/port_l47/__init__.py +0 -0
- xoa_driver/internals/hli_v1/ports/port_l47/counters.py +174 -0
- xoa_driver/internals/hli_v1/ports/port_l47/main.py +228 -0
- xoa_driver/internals/hli_v1/ports/port_l47/packet_engine.py +31 -0
- xoa_driver/internals/hli_v1/revisions.py +11 -0
- xoa_driver/internals/hli_v1/testers/__init__.py +0 -0
- xoa_driver/internals/hli_v1/testers/_base_tester.py +259 -0
- xoa_driver/internals/hli_v1/testers/genuine/__init__.py +0 -0
- xoa_driver/internals/hli_v1/testers/genuine/l_23/__init__.py +0 -0
- xoa_driver/internals/hli_v1/testers/genuine/l_23/health.py +16 -0
- xoa_driver/internals/hli_v1/testers/genuine/l_23/rest_api.py +38 -0
- xoa_driver/internals/hli_v1/testers/genuine/l_23/time_keeper.py +57 -0
- xoa_driver/internals/hli_v1/testers/genuine/l_23/upload_file.py +29 -0
- xoa_driver/internals/hli_v1/testers/genuine/management_interface.py +42 -0
- xoa_driver/internals/hli_v1/testers/l23_tester.py +196 -0
- xoa_driver/internals/hli_v1/testers/l23ve_tester.py +114 -0
- xoa_driver/internals/hli_v1/testers/l47_tester.py +106 -0
- xoa_driver/internals/hli_v1/testers/l47ve_tester.py +54 -0
- xoa_driver/internals/hli_v2/__init__.py +0 -0
- xoa_driver/internals/hli_v2/indices/__init__.py +0 -0
- xoa_driver/internals/hli_v2/indices/base_index.py +39 -0
- xoa_driver/internals/hli_v2/indices/connection_group/__init__.py +0 -0
- xoa_driver/internals/hli_v2/indices/connection_group/cg.py +115 -0
- xoa_driver/internals/hli_v2/indices/connection_group/histogram.py +59 -0
- xoa_driver/internals/hli_v2/indices/connection_group/l2.py +71 -0
- xoa_driver/internals/hli_v2/indices/connection_group/l3.py +96 -0
- xoa_driver/internals/hli_v2/indices/connection_group/raw.py +148 -0
- xoa_driver/internals/hli_v2/indices/connection_group/replay.py +89 -0
- xoa_driver/internals/hli_v2/indices/connection_group/tcp.py +261 -0
- xoa_driver/internals/hli_v2/indices/connection_group/tls.py +166 -0
- xoa_driver/internals/hli_v2/indices/connection_group/udp.py +112 -0
- xoa_driver/internals/hli_v2/indices/connection_group/user_state.py +25 -0
- xoa_driver/internals/hli_v2/indices/filter/__init__.py +0 -0
- xoa_driver/internals/hli_v2/indices/filter/base_filter.py +50 -0
- xoa_driver/internals/hli_v2/indices/filter/genuine_filter.py +17 -0
- xoa_driver/internals/hli_v2/indices/length_term.py +44 -0
- xoa_driver/internals/hli_v2/indices/match_term.py +49 -0
- xoa_driver/internals/hli_v2/indices/port_dataset.py +53 -0
- xoa_driver/internals/hli_v2/indices/streams/__init__.py +0 -0
- xoa_driver/internals/hli_v2/indices/streams/base_stream.py +234 -0
- xoa_driver/internals/hli_v2/indices/streams/genuine_stream.py +32 -0
- xoa_driver/internals/hli_v2/modules/__init__.py +0 -0
- xoa_driver/internals/hli_v2/modules/__interfaces.py +21 -0
- xoa_driver/internals/hli_v2/modules/base_module.py +125 -0
- xoa_driver/internals/hli_v2/modules/module_chimera.py +358 -0
- xoa_driver/internals/hli_v2/modules/module_l23ve.py +58 -0
- xoa_driver/internals/hli_v2/modules/module_l47.py +230 -0
- xoa_driver/internals/hli_v2/modules/module_l47ve.py +8 -0
- xoa_driver/internals/hli_v2/modules/modules_l23/__init__.py +0 -0
- xoa_driver/internals/hli_v2/modules/modules_l23/family_combi.py +73 -0
- xoa_driver/internals/hli_v2/modules/modules_l23/family_d.py +75 -0
- xoa_driver/internals/hli_v2/modules/modules_l23/family_e.py +85 -0
- xoa_driver/internals/hli_v2/modules/modules_l23/family_f.py +144 -0
- xoa_driver/internals/hli_v2/modules/modules_l23/family_g.py +84 -0
- xoa_driver/internals/hli_v2/modules/modules_l23/family_h.py +40 -0
- xoa_driver/internals/hli_v2/modules/modules_l23/family_i.py +25 -0
- xoa_driver/internals/hli_v2/modules/modules_l23/family_j.py +25 -0
- xoa_driver/internals/hli_v2/modules/modules_l23/family_k.py +39 -0
- xoa_driver/internals/hli_v2/modules/modules_l23/family_l.py +55 -0
- xoa_driver/internals/hli_v2/modules/modules_l23/family_l1.py +797 -0
- xoa_driver/internals/hli_v2/modules/modules_l23/family_m.py +25 -0
- xoa_driver/internals/hli_v2/modules/modules_l23/family_n.py +40 -0
- xoa_driver/internals/hli_v2/modules/modules_l23/module_l23_base.py +339 -0
- xoa_driver/internals/hli_v2/ports/__init__.py +0 -0
- xoa_driver/internals/hli_v2/ports/base_port.py +105 -0
- xoa_driver/internals/hli_v2/ports/port_l23/__init__.py +0 -0
- xoa_driver/internals/hli_v2/ports/port_l23/bases/__init__.py +0 -0
- xoa_driver/internals/hli_v2/ports/port_l23/bases/port_capture.py +64 -0
- xoa_driver/internals/hli_v2/ports/port_l23/bases/port_l23.py +441 -0
- xoa_driver/internals/hli_v2/ports/port_l23/bases/port_l23_genuine.py +172 -0
- xoa_driver/internals/hli_v2/ports/port_l23/bases/port_reception_statistics.py +156 -0
- xoa_driver/internals/hli_v2/ports/port_l23/bases/port_transceiver.py +117 -0
- xoa_driver/internals/hli_v2/ports/port_l23/bases/port_transmission_statistics.py +59 -0
- xoa_driver/internals/hli_v2/ports/port_l23/chimera/__init__.py +0 -0
- xoa_driver/internals/hli_v2/ports/port_l23/chimera/filter_definition/__init__.py +0 -0
- xoa_driver/internals/hli_v2/ports/port_l23/chimera/filter_definition/_utils.py +15 -0
- xoa_driver/internals/hli_v2/ports/port_l23/chimera/filter_definition/general.py +340 -0
- xoa_driver/internals/hli_v2/ports/port_l23/chimera/filter_definition/shadow.py +99 -0
- xoa_driver/internals/hli_v2/ports/port_l23/chimera/filter_definition/working.py +36 -0
- xoa_driver/internals/hli_v2/ports/port_l23/chimera/pe_custom_distribution.py +116 -0
- xoa_driver/internals/hli_v2/ports/port_l23/chimera/pe_distribution.py +102 -0
- xoa_driver/internals/hli_v2/ports/port_l23/chimera/port_chimera.py +113 -0
- xoa_driver/internals/hli_v2/ports/port_l23/chimera/port_emulation.py +420 -0
- xoa_driver/internals/hli_v2/ports/port_l23/chimera/reception_statistics.py +22 -0
- xoa_driver/internals/hli_v2/ports/port_l23/chimera/transmission_statistics.py +22 -0
- xoa_driver/internals/hli_v2/ports/port_l23/family_combi.py +36 -0
- xoa_driver/internals/hli_v2/ports/port_l23/family_d.py +49 -0
- xoa_driver/internals/hli_v2/ports/port_l23/family_e.py +96 -0
- xoa_driver/internals/hli_v2/ports/port_l23/family_f.py +144 -0
- xoa_driver/internals/hli_v2/ports/port_l23/family_g.py +77 -0
- xoa_driver/internals/hli_v2/ports/port_l23/family_h.py +60 -0
- xoa_driver/internals/hli_v2/ports/port_l23/family_i.py +66 -0
- xoa_driver/internals/hli_v2/ports/port_l23/family_j.py +53 -0
- xoa_driver/internals/hli_v2/ports/port_l23/family_k.py +58 -0
- xoa_driver/internals/hli_v2/ports/port_l23/family_l.py +67 -0
- xoa_driver/internals/hli_v2/ports/port_l23/family_l1.py +149 -0
- xoa_driver/internals/hli_v2/ports/port_l23/family_m.py +28 -0
- xoa_driver/internals/hli_v2/ports/port_l23/fault_jkl.py +22 -0
- xoa_driver/internals/hli_v2/ports/port_l23/pcs_pma_ghijkl.py +342 -0
- xoa_driver/internals/hli_v2/ports/port_l23/pcs_pma_ijkl_chimera.py +50 -0
- xoa_driver/internals/hli_v2/ports/port_l23/pcs_pma_l.py +65 -0
- xoa_driver/internals/hli_v2/ports/port_l23/port_l23ve.py +81 -0
- xoa_driver/internals/hli_v2/ports/port_l47/__init__.py +0 -0
- xoa_driver/internals/hli_v2/ports/port_l47/counters.py +146 -0
- xoa_driver/internals/hli_v2/ports/port_l47/main.py +137 -0
- xoa_driver/internals/hli_v2/ports/port_l47/packet_engine.py +20 -0
- xoa_driver/internals/hli_v2/revisions.py +11 -0
- xoa_driver/internals/hli_v2/testers/__init__.py +0 -0
- xoa_driver/internals/hli_v2/testers/_base_tester.py +207 -0
- xoa_driver/internals/hli_v2/testers/genuine/__init__.py +0 -0
- xoa_driver/internals/hli_v2/testers/genuine/l_23/__init__.py +0 -0
- xoa_driver/internals/hli_v2/testers/genuine/l_23/health.py +16 -0
- xoa_driver/internals/hli_v2/testers/genuine/l_23/rest_api.py +34 -0
- xoa_driver/internals/hli_v2/testers/genuine/l_23/time_keeper.py +50 -0
- xoa_driver/internals/hli_v2/testers/genuine/l_23/upload_file.py +26 -0
- xoa_driver/internals/hli_v2/testers/genuine/management_interface.py +38 -0
- xoa_driver/internals/hli_v2/testers/l23_tester.py +159 -0
- xoa_driver/internals/hli_v2/testers/l23ve_tester.py +98 -0
- xoa_driver/internals/hli_v2/testers/l47_tester.py +95 -0
- xoa_driver/internals/hli_v2/testers/l47ve_tester.py +50 -0
- xoa_driver/internals/state_storage/__init__.py +0 -0
- xoa_driver/internals/state_storage/_speed_detector.py +121 -0
- xoa_driver/internals/state_storage/modules_state.py +128 -0
- xoa_driver/internals/state_storage/ports_state.py +154 -0
- xoa_driver/internals/state_storage/testers_state.py +104 -0
- xoa_driver/internals/utils/__init__.py +0 -0
- xoa_driver/internals/utils/attributes.py +33 -0
- xoa_driver/internals/utils/cap_id.py +63 -0
- xoa_driver/internals/utils/con_traffic_light.py +88 -0
- xoa_driver/internals/utils/indices/__init__.py +0 -0
- xoa_driver/internals/utils/indices/_interfaces.py +26 -0
- xoa_driver/internals/utils/indices/header_modifier_manager.py +56 -0
- xoa_driver/internals/utils/indices/index_manager.py +95 -0
- xoa_driver/internals/utils/indices/observer.py +17 -0
- xoa_driver/internals/utils/kind.py +19 -0
- xoa_driver/internals/utils/managers/__init__.py +0 -0
- xoa_driver/internals/utils/managers/abc.py +44 -0
- xoa_driver/internals/utils/managers/exceptions.py +22 -0
- xoa_driver/internals/utils/managers/modules_manager.py +118 -0
- xoa_driver/internals/utils/managers/ports_manager.py +116 -0
- xoa_driver/internals/utils/rev_tool.py +21 -0
- xoa_driver/internals/utils/session.py +117 -0
- xoa_driver/internals/warn.py +32 -0
- xoa_driver/lli.py +15 -0
- xoa_driver/misc.py +57 -0
- xoa_driver/modules.py +448 -0
- xoa_driver/ports.py +332 -0
- xoa_driver/testers.py +37 -0
- xoa_driver/utils.py +12 -0
- xoa_driver/v2/__init__.py +11 -0
- xoa_driver/v2/misc.py +77 -0
- xoa_driver/v2/modules.py +308 -0
- xoa_driver/v2/ports.py +232 -0
- xoa_driver/v2/testers.py +24 -0
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
import typing as t
|
|
3
|
+
if t.TYPE_CHECKING:
|
|
4
|
+
from asyncio import Future
|
|
5
|
+
from .transporter._typings import ICommand
|
|
6
|
+
from .transporter.protocol.struct_request import Request
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
# The defenition of generic Types
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
T_ = t.TypeVar("T_", covariant=True)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class IsDataclass(t.Protocol):
|
|
16
|
+
__dataclass_fields__: t.Dict[str, t.Any]
|
|
17
|
+
def __init__(self, *args, **kwargs) -> None: ... # noqa: E704
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
Inst = t.TypeVar('Inst')
|
|
21
|
+
CallbackType = t.Callable[[Inst, t.Optional[IsDataclass]], t.Awaitable[None]]
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class IConnection(t.Protocol):
|
|
25
|
+
"""Representation of TransportationHandler"""
|
|
26
|
+
|
|
27
|
+
@property
|
|
28
|
+
def is_connected(self) -> bool:
|
|
29
|
+
...
|
|
30
|
+
|
|
31
|
+
def send(self, data: bytes | bytearray | memoryview) -> None:
|
|
32
|
+
...
|
|
33
|
+
|
|
34
|
+
def close(self) -> None:
|
|
35
|
+
...
|
|
36
|
+
|
|
37
|
+
async def prepare_data(self, request: "Request") -> t.Tuple[bytes, "Future"]:
|
|
38
|
+
...
|
|
39
|
+
|
|
40
|
+
def subscribe(self, xmc_cls: "ICommand", callback: "t.Callable") -> None:
|
|
41
|
+
...
|
|
42
|
+
|
|
43
|
+
def on_disconnected(self, callback: "t.Callable") -> None:
|
|
44
|
+
...
|
|
45
|
+
|
|
46
|
+
def set_outdated(self) -> None:
|
|
47
|
+
...
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
from typing import (
|
|
3
|
+
Any,
|
|
4
|
+
Awaitable,
|
|
5
|
+
TypeVar,
|
|
6
|
+
# Generic,
|
|
7
|
+
Generator
|
|
8
|
+
)
|
|
9
|
+
from dataclasses import dataclass
|
|
10
|
+
|
|
11
|
+
from . import interfaces
|
|
12
|
+
from .transporter.protocol.struct_request import Request
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
AwaitableDataType = TypeVar("AwaitableDataType", covariant=True)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@dataclass(frozen=True)
|
|
19
|
+
class Token(Awaitable[AwaitableDataType]):
|
|
20
|
+
"""
|
|
21
|
+
A wrapper of connection and request.
|
|
22
|
+
Which can be used for await an single command or organized in to the ordered
|
|
23
|
+
sequence of the commands which will be send to the server in single request.
|
|
24
|
+
"""
|
|
25
|
+
__slots__ = ('connection', 'request',)
|
|
26
|
+
|
|
27
|
+
connection: interfaces.IConnection
|
|
28
|
+
request: Request
|
|
29
|
+
|
|
30
|
+
def __await__(self) -> Generator[Any, None, AwaitableDataType]:
|
|
31
|
+
return self.__ask().__await__()
|
|
32
|
+
|
|
33
|
+
async def __ask(self) -> AwaitableDataType:
|
|
34
|
+
(
|
|
35
|
+
data,
|
|
36
|
+
fut
|
|
37
|
+
) = await self.connection.prepare_data(self.request)
|
|
38
|
+
self.connection.send(data)
|
|
39
|
+
try:
|
|
40
|
+
result = await fut
|
|
41
|
+
except Exception as e:
|
|
42
|
+
raise e
|
|
43
|
+
else:
|
|
44
|
+
return result
|
|
File without changes
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
import asyncio
|
|
3
|
+
from typing import (
|
|
4
|
+
AsyncIterator,
|
|
5
|
+
Callable,
|
|
6
|
+
Type,
|
|
7
|
+
)
|
|
8
|
+
from collections import UserDict
|
|
9
|
+
from . import registry
|
|
10
|
+
from . import exceptions
|
|
11
|
+
from ._typings import XoaCommandType
|
|
12
|
+
from .protocol.struct_header import ResponseHeader
|
|
13
|
+
from .protocol.struct_response import Response
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def create_response_obj(cmd: Type[XoaCommandType], header: ResponseHeader, data: bytes) -> Response:
|
|
17
|
+
"""Parse bytes retrieved from server to Response structure."""
|
|
18
|
+
return Response(
|
|
19
|
+
class_name=cmd.__name__,
|
|
20
|
+
header=header,
|
|
21
|
+
buffer=data,
|
|
22
|
+
response_struct=getattr(cmd, "GetDataAttr", None)
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class CommandsCodeMapper(UserDict):
|
|
27
|
+
data: dict[int, int]
|
|
28
|
+
|
|
29
|
+
def add_code(self, req_id: int, cmd_code: int) -> None:
|
|
30
|
+
self.data[req_id] = cmd_code
|
|
31
|
+
|
|
32
|
+
def pop_code(self, req_id: int) -> int:
|
|
33
|
+
if command_idx := self.data.pop(req_id, None):
|
|
34
|
+
return command_idx
|
|
35
|
+
raise exceptions.RepeatedRequestID(req_id)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
Publisher = Callable[[Response], None]
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class PacketsProcessor:
|
|
42
|
+
"""Process reading packets from he stream and create a response object for each packet"""
|
|
43
|
+
|
|
44
|
+
__slots__ = ("__stream", "__cm_mapper", "__evt_do_job", "__consumer", "__publish",)
|
|
45
|
+
|
|
46
|
+
def __init__(self, stream: AsyncIterator[tuple[ResponseHeader, bytes]], publish_func: Publisher) -> None:
|
|
47
|
+
self.__stream = stream
|
|
48
|
+
self.__cm_mapper = CommandsCodeMapper()
|
|
49
|
+
self.__evt_do_job = asyncio.Event()
|
|
50
|
+
self.__consumer: asyncio.Task | None = None
|
|
51
|
+
self.__publish = publish_func
|
|
52
|
+
|
|
53
|
+
@property
|
|
54
|
+
def is_running(self) -> bool:
|
|
55
|
+
return not (self.__consumer is None or self.__consumer.done())
|
|
56
|
+
|
|
57
|
+
def start(self) -> None:
|
|
58
|
+
if self.is_running:
|
|
59
|
+
return None
|
|
60
|
+
self.__evt_do_job.set()
|
|
61
|
+
self.__consumer = asyncio.create_task(self.__consume())
|
|
62
|
+
|
|
63
|
+
def stop(self) -> None:
|
|
64
|
+
if not self.is_running:
|
|
65
|
+
return None
|
|
66
|
+
self.__evt_do_job.clear()
|
|
67
|
+
self.__consumer.cancel() # type: ignore[ReportOptionalMemberAccess]
|
|
68
|
+
self.__consumer = None
|
|
69
|
+
|
|
70
|
+
def register(self, req_id: int, cmd_code: int) -> None:
|
|
71
|
+
self.__cm_mapper.add_code(req_id=req_id, cmd_code=cmd_code)
|
|
72
|
+
|
|
73
|
+
async def __task(self, header: ResponseHeader, body_bytes: bytes) -> None:
|
|
74
|
+
command_idx = header.cmd_code if header.is_pushed else self.__cm_mapper.pop_code(header.request_identifier)
|
|
75
|
+
xmc_type = registry.get_command(command_idx)
|
|
76
|
+
response = create_response_obj(xmc_type, header, body_bytes)
|
|
77
|
+
self.__publish(response)
|
|
78
|
+
|
|
79
|
+
async def __consume(self) -> None:
|
|
80
|
+
async for header, body_bytes in self.__stream:
|
|
81
|
+
asyncio.create_task(self.__task(header, body_bytes))
|
|
82
|
+
if not self.__evt_do_job.is_set():
|
|
83
|
+
return None
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
import asyncio
|
|
3
|
+
|
|
4
|
+
from collections import (
|
|
5
|
+
UserDict,
|
|
6
|
+
defaultdict,
|
|
7
|
+
)
|
|
8
|
+
from functools import partialmethod
|
|
9
|
+
from typing import (
|
|
10
|
+
Any,
|
|
11
|
+
Callable,
|
|
12
|
+
Coroutine,
|
|
13
|
+
Final
|
|
14
|
+
)
|
|
15
|
+
from . import exceptions
|
|
16
|
+
from .protocol.struct_response import Response
|
|
17
|
+
|
|
18
|
+
ON_EVT_DISCONNECTED: Final[int] = -1
|
|
19
|
+
|
|
20
|
+
CB = Callable[..., Coroutine[Any, None, None]]
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class FuturesMapper(UserDict):
|
|
24
|
+
data: dict[tuple[int, str], asyncio.Future]
|
|
25
|
+
|
|
26
|
+
def make_future(self, req_id: int, cmd_name: str) -> asyncio.Future:
|
|
27
|
+
fut = asyncio.Future()
|
|
28
|
+
self.data[(req_id, cmd_name)] = fut
|
|
29
|
+
return fut
|
|
30
|
+
|
|
31
|
+
def pop_future(self, req_id: int, cmd_name: str) -> asyncio.Future:
|
|
32
|
+
fut = self.data.pop((req_id, cmd_name), None)
|
|
33
|
+
if not fut:
|
|
34
|
+
raise exceptions.XoaLostFuture(req_id, cmd_name)
|
|
35
|
+
return fut
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class EventsObserver:
|
|
39
|
+
__slots__ = ("__events",)
|
|
40
|
+
|
|
41
|
+
def __init__(self) -> None:
|
|
42
|
+
self.__events: dict[int, list[CB]] = defaultdict(list)
|
|
43
|
+
|
|
44
|
+
def dispatch(self, evt: int, *args, **kwargs) -> None:
|
|
45
|
+
for evt_func in self.__events.get(evt, []):
|
|
46
|
+
asyncio.create_task(
|
|
47
|
+
evt_func(*args, **kwargs)
|
|
48
|
+
).add_done_callback(self.__handle_exceptions)
|
|
49
|
+
|
|
50
|
+
def __handle_exceptions(self, fut: asyncio.Future) -> None:
|
|
51
|
+
if fut.cancelled():
|
|
52
|
+
return None
|
|
53
|
+
elif e := fut.exception():
|
|
54
|
+
raise e
|
|
55
|
+
|
|
56
|
+
def subscribe(self, evt: int, func: CB) -> None:
|
|
57
|
+
self.__events[evt].append(func)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
class ResponsePublisher:
|
|
61
|
+
__slots__ = ("__futures_mapper", "__observer", "__logger")
|
|
62
|
+
|
|
63
|
+
def __init__(self, logger) -> None:
|
|
64
|
+
self.__logger = logger
|
|
65
|
+
self.__futures_mapper = FuturesMapper()
|
|
66
|
+
self.__observer = EventsObserver()
|
|
67
|
+
|
|
68
|
+
def register_request(self, req_id: int, cmd_name: str) -> asyncio.Future:
|
|
69
|
+
return self.__futures_mapper.make_future(req_id, cmd_name)
|
|
70
|
+
|
|
71
|
+
def subscribe(self, evt: int, func: CB) -> None:
|
|
72
|
+
self.__observer.subscribe(evt, func)
|
|
73
|
+
|
|
74
|
+
subscribe_connection_lost = partialmethod(subscribe, ON_EVT_DISCONNECTED)
|
|
75
|
+
|
|
76
|
+
def publish(self, response: Response) -> None:
|
|
77
|
+
if response.is_pushed:
|
|
78
|
+
self.__publish_push_response(response)
|
|
79
|
+
else:
|
|
80
|
+
self.__publish_param_response(response)
|
|
81
|
+
|
|
82
|
+
def publish_connection_lost(self, info) -> None:
|
|
83
|
+
self.__observer.dispatch(ON_EVT_DISCONNECTED, info)
|
|
84
|
+
|
|
85
|
+
def __publish_push_response(self, response: Response) -> None:
|
|
86
|
+
self.__observer.dispatch(
|
|
87
|
+
response.cmd_code,
|
|
88
|
+
response
|
|
89
|
+
)
|
|
90
|
+
self.__logger.debug_push(response)
|
|
91
|
+
|
|
92
|
+
def __publish_param_response(self, response: Response) -> None:
|
|
93
|
+
future = self.__futures_mapper.pop_future(
|
|
94
|
+
req_id=response.request_identifier,
|
|
95
|
+
cmd_name=response.class_name
|
|
96
|
+
)
|
|
97
|
+
if exception := response.get_error():
|
|
98
|
+
future.set_exception(exception)
|
|
99
|
+
else:
|
|
100
|
+
future.set_result(response.values)
|
|
101
|
+
self.__logger.debug_response(response)
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
from enum import IntEnum
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class ReservedRequestID(IntEnum):
|
|
6
|
+
PUSH_REQUEST = 0x0
|
|
7
|
+
REQUEST_ID_LIMIT = 0xFFFFFFFF
|
|
8
|
+
|
|
9
|
+
@classmethod
|
|
10
|
+
def started(cls) -> int:
|
|
11
|
+
return max(list(cls)[:-1]).value
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class RequestIdCounter:
|
|
15
|
+
"""Aggrigator of request ID."""
|
|
16
|
+
__slots__ = ("__req_id", "__lock",)
|
|
17
|
+
|
|
18
|
+
def __init__(self) -> None:
|
|
19
|
+
self.__req_id = ReservedRequestID.started()
|
|
20
|
+
self.__lock = asyncio.Lock()
|
|
21
|
+
|
|
22
|
+
async def get_number(self) -> int:
|
|
23
|
+
async with self.__lock:
|
|
24
|
+
if self.__req_id >= ReservedRequestID.REQUEST_ID_LIMIT:
|
|
25
|
+
self.__req_id = ReservedRequestID.started()
|
|
26
|
+
else:
|
|
27
|
+
self.__req_id += 1
|
|
28
|
+
return self.__req_id
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
from asyncio import Future
|
|
3
|
+
from typing import Generic
|
|
4
|
+
from typing_extensions import Self
|
|
5
|
+
from ._typings import HeaderType
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class StreamReader(Generic[HeaderType]):
|
|
9
|
+
__slots__ = ("_buffer", "_eof", "_waiter", "__header_struct")
|
|
10
|
+
|
|
11
|
+
def __init__(self, header_struct: type[HeaderType]) -> None:
|
|
12
|
+
self._buffer = bytearray()
|
|
13
|
+
self._eof = False # Whether we're done.
|
|
14
|
+
self._waiter = None # A future used by _wait_for_data()
|
|
15
|
+
self.__header_struct = header_struct
|
|
16
|
+
|
|
17
|
+
def __aiter__(self) -> Self:
|
|
18
|
+
return self
|
|
19
|
+
|
|
20
|
+
async def __anext__(self) -> tuple[HeaderType, bytes]:
|
|
21
|
+
try:
|
|
22
|
+
val = await self.read_pkt()
|
|
23
|
+
except EOFError:
|
|
24
|
+
raise StopAsyncIteration
|
|
25
|
+
else:
|
|
26
|
+
return val
|
|
27
|
+
|
|
28
|
+
def _wakeup_waiter(self) -> None:
|
|
29
|
+
waiter = self._waiter
|
|
30
|
+
if waiter is not None:
|
|
31
|
+
self._waiter = None
|
|
32
|
+
if not waiter.cancelled():
|
|
33
|
+
waiter.set_result(None)
|
|
34
|
+
|
|
35
|
+
async def _wait_for_data(self, func_name: str) -> None:
|
|
36
|
+
"""Wait until feed_data() or feed_eof() is called.
|
|
37
|
+
If stream was paused, automatically resume it.
|
|
38
|
+
"""
|
|
39
|
+
if self._waiter is not None:
|
|
40
|
+
raise RuntimeError(
|
|
41
|
+
f'{func_name}() called while another coroutine is '
|
|
42
|
+
f'already waiting for incoming data'
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
assert not self._eof, '_wait_for_data after EOF'
|
|
46
|
+
|
|
47
|
+
self._waiter = Future()
|
|
48
|
+
try:
|
|
49
|
+
await self._waiter
|
|
50
|
+
finally:
|
|
51
|
+
self._waiter = None
|
|
52
|
+
|
|
53
|
+
def feed_eof(self) -> None:
|
|
54
|
+
self._eof = True
|
|
55
|
+
self._wakeup_waiter()
|
|
56
|
+
|
|
57
|
+
def at_eof(self) -> bool:
|
|
58
|
+
"""Return True if the buffer is empty and 'feed_eof' was called."""
|
|
59
|
+
return self._eof and not self._buffer
|
|
60
|
+
|
|
61
|
+
def feed_data(self, data: bytes) -> None:
|
|
62
|
+
assert not self._eof, 'feed_data after feed_eof'
|
|
63
|
+
|
|
64
|
+
if not data:
|
|
65
|
+
return None
|
|
66
|
+
|
|
67
|
+
self._buffer.extend(data)
|
|
68
|
+
self._wakeup_waiter()
|
|
69
|
+
|
|
70
|
+
async def readexactly(self, n: int) -> bytes:
|
|
71
|
+
if n < 0:
|
|
72
|
+
raise ValueError('readexactly size can not be less than zero')
|
|
73
|
+
|
|
74
|
+
if n == 0:
|
|
75
|
+
return b''
|
|
76
|
+
|
|
77
|
+
while len(self._buffer) < n:
|
|
78
|
+
if self._eof:
|
|
79
|
+
incomplete = bytes(self._buffer)
|
|
80
|
+
self._buffer.clear()
|
|
81
|
+
raise EOFError(incomplete, n)
|
|
82
|
+
|
|
83
|
+
await self._wait_for_data('readexactly')
|
|
84
|
+
|
|
85
|
+
if len(self._buffer) == n:
|
|
86
|
+
data = bytes(self._buffer)
|
|
87
|
+
self._buffer.clear()
|
|
88
|
+
else:
|
|
89
|
+
data = bytes(self._buffer[:n])
|
|
90
|
+
del self._buffer[:n]
|
|
91
|
+
return data
|
|
92
|
+
|
|
93
|
+
async def read_pkt(self) -> tuple[HeaderType, bytes]:
|
|
94
|
+
h_buff = await self.readexactly(self.__header_struct.size)
|
|
95
|
+
header = self.__header_struct.from_bytes(h_buff)
|
|
96
|
+
if not header:
|
|
97
|
+
raise ValueError("Invalid Header")
|
|
98
|
+
body_bytes = await self.readexactly(header.body_size)
|
|
99
|
+
return (header, body_bytes)
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
import typing as t
|
|
3
|
+
from .protocol.payload.base_struct import (
|
|
4
|
+
RequestBodyStruct,
|
|
5
|
+
ResponseBodyStruct
|
|
6
|
+
)
|
|
7
|
+
from .protocol.struct_header import ResponseHeader
|
|
8
|
+
from ..token import Token
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
# The defenition of generic Types
|
|
12
|
+
|
|
13
|
+
HeaderType = t.TypeVar("HeaderType", bound="ResponseHeader", covariant=True)
|
|
14
|
+
T_ = t.TypeVar("T_", covariant=True)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class IsDataclass(t.Protocol):
|
|
18
|
+
__dataclass_fields__: t.Dict[str, t.Any]
|
|
19
|
+
def __init__(self, *args, **kwargs) -> None: ... # noqa: E704
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class ICommand(t.Protocol):
|
|
23
|
+
code: t.ClassVar[int]
|
|
24
|
+
pushed: t.ClassVar[bool]
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
SetStructType = t.TypeVar("SetStructType", bound="RequestBodyStruct", covariant=True)
|
|
28
|
+
GetStructType = t.TypeVar("GetStructType", bound="ResponseBodyStruct", covariant=True)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class ICmdOnlySet(ICommand, t.Protocol):
|
|
32
|
+
"""A template class which provide only <cmd_set> method."""
|
|
33
|
+
SetDataAttr: t.Type[SetStructType] # type: ignore
|
|
34
|
+
set: t.Callable[..., Token[None]]
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class ICmdOnlyGet(ICommand, t.Protocol):
|
|
38
|
+
"""A template class which provide only <cmd_get> method."""
|
|
39
|
+
GetDataAttr: t.Type[GetStructType] # type: ignore
|
|
40
|
+
get: t.Callable[[], Token[GetStructType]] # type: ignore
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
XoaCommandType = t.Union[ICmdOnlySet, ICmdOnlyGet]
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class XoaException(Exception):
|
|
5
|
+
...
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class TransporterException(XoaException):
|
|
9
|
+
...
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class XoaConnectionTimeoutError(XoaException):
|
|
13
|
+
def __init__(self, host: str, port: int, seconds_timeout: int) -> None:
|
|
14
|
+
self.host = host
|
|
15
|
+
self.port = port
|
|
16
|
+
self.seconds_timeout = seconds_timeout
|
|
17
|
+
self.msg = f"Can't establish the connect to {host}:{port}, in period of {seconds_timeout} sec."
|
|
18
|
+
super().__init__(self.msg)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class XoaConnectionError(XoaException):
|
|
22
|
+
def __init__(self, host: str, port: int) -> None:
|
|
23
|
+
self.host = host
|
|
24
|
+
self.port = port
|
|
25
|
+
self.msg = f"Can't connect to {host}:{port}"
|
|
26
|
+
super().__init__(self.msg)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class RepeatedRequestID(TransporterException):
|
|
30
|
+
def __init__(self, request_identifier: int,) -> None:
|
|
31
|
+
self.msg = f"""
|
|
32
|
+
Got repeated request id {request_identifier}.
|
|
33
|
+
This is a bug of xenaserver returning the same request identifier twice.
|
|
34
|
+
"""
|
|
35
|
+
self.request_identifier = request_identifier
|
|
36
|
+
super().__init__(self.msg)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class XoaLostFuture(XoaException):
|
|
40
|
+
def __init__(self, req_id: int, cls_name: str) -> None:
|
|
41
|
+
self.req_id = req_id
|
|
42
|
+
self.cls_name = cls_name
|
|
43
|
+
self.msg = f"Command was sent but the response handler was not registered {req_id} {cls_name}."
|
|
44
|
+
super().__init__(self.msg)
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
import asyncio
|
|
3
|
+
from typing import Callable
|
|
4
|
+
from uuid import uuid4
|
|
5
|
+
from .logger import (
|
|
6
|
+
TransportationLogger,
|
|
7
|
+
CustomLogger
|
|
8
|
+
)
|
|
9
|
+
from .protocol.struct_request import Request
|
|
10
|
+
from .protocol.struct_header import ResponseHeader
|
|
11
|
+
from ._request_id_counter import RequestIdCounter
|
|
12
|
+
from ._stream import StreamReader
|
|
13
|
+
from ._processor import PacketsProcessor
|
|
14
|
+
from ._publisher import ResponsePublisher
|
|
15
|
+
from ._typings import ICommand
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class TransportationHandler(asyncio.Protocol):
|
|
19
|
+
"""Handling sending and receiving of the XMP commands."""
|
|
20
|
+
|
|
21
|
+
__slots__ = (
|
|
22
|
+
"identity",
|
|
23
|
+
"peername",
|
|
24
|
+
"__log",
|
|
25
|
+
"__transport",
|
|
26
|
+
"__id_counter",
|
|
27
|
+
"__stream",
|
|
28
|
+
"__resp_publisher",
|
|
29
|
+
"__pkt_processor"
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
def __init__(self, *, enable_logging: bool = False, custom_logger: CustomLogger | None = None) -> None:
|
|
33
|
+
self.identity = uuid4().hex[:6]
|
|
34
|
+
self.peername: tuple[str, int] | None = None
|
|
35
|
+
self.__transport: asyncio.Transport | None = None
|
|
36
|
+
self.__id_counter = RequestIdCounter()
|
|
37
|
+
self.__log = TransportationLogger(
|
|
38
|
+
cid=self.identity,
|
|
39
|
+
enabled=enable_logging,
|
|
40
|
+
logger=custom_logger
|
|
41
|
+
)
|
|
42
|
+
self.__stream = StreamReader(header_struct=ResponseHeader)
|
|
43
|
+
self.__resp_publisher = ResponsePublisher(logger=self.__log)
|
|
44
|
+
self.__pkt_processor = PacketsProcessor(
|
|
45
|
+
stream=self.__stream,
|
|
46
|
+
publish_func=self.__resp_publisher.publish
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
@property
|
|
50
|
+
def is_connected(self) -> bool:
|
|
51
|
+
return not (self.__transport is None or self.__transport.is_closing())
|
|
52
|
+
|
|
53
|
+
def connection_made(self, transport: asyncio.Transport) -> None:
|
|
54
|
+
self.__transport = transport
|
|
55
|
+
self.peername = transport.get_extra_info("peername")
|
|
56
|
+
self.__pkt_processor.start()
|
|
57
|
+
self.__log.info(f"Connected to {self.peername}")
|
|
58
|
+
|
|
59
|
+
def data_received(self, data: bytes) -> None:
|
|
60
|
+
"""Process received data from xenaserver."""
|
|
61
|
+
try:
|
|
62
|
+
self.__stream.feed_data(data)
|
|
63
|
+
except AssertionError:
|
|
64
|
+
if self.is_connected:
|
|
65
|
+
self.__stream._eof = False
|
|
66
|
+
self.__stream.feed_data(data)
|
|
67
|
+
else:
|
|
68
|
+
self.close()
|
|
69
|
+
|
|
70
|
+
def eof_received(self) -> None:
|
|
71
|
+
self.__stream.feed_eof()
|
|
72
|
+
self.__log.info("EOF received")
|
|
73
|
+
|
|
74
|
+
def connection_lost(self, exc: Exception | None) -> None:
|
|
75
|
+
self.__resp_publisher.publish_connection_lost(self.peername)
|
|
76
|
+
self.__transport = None
|
|
77
|
+
self.__pkt_processor.stop()
|
|
78
|
+
if exc:
|
|
79
|
+
self.__log.error(exc)
|
|
80
|
+
else:
|
|
81
|
+
self.__log.info(f"The server {self.peername} closed the connection")
|
|
82
|
+
|
|
83
|
+
def send(self, data: bytes | bytearray | memoryview) -> None:
|
|
84
|
+
"""
|
|
85
|
+
Send applied commands from sending queue to
|
|
86
|
+
xenaserver and liberate the sending queue.
|
|
87
|
+
"""
|
|
88
|
+
if not self.is_connected:
|
|
89
|
+
raise BrokenPipeError("No socket!")
|
|
90
|
+
self.__transport.write(data) # type: ignore[reportOptionalMemberAccess]
|
|
91
|
+
|
|
92
|
+
def close(self) -> None:
|
|
93
|
+
"""Close connection with xenaserver."""
|
|
94
|
+
if self.is_connected:
|
|
95
|
+
self.__transport.close() # type: ignore[reportOptionalMemberAccess]
|
|
96
|
+
self.__transport = None
|
|
97
|
+
|
|
98
|
+
async def prepare_data(self, request: Request) -> tuple[bytes, asyncio.Future]:
|
|
99
|
+
assert self.is_connected, "Cannot add command because Socket is disconnected"
|
|
100
|
+
request_id_ = await self.__id_counter.get_number()
|
|
101
|
+
request.update_identifier(request_id_)
|
|
102
|
+
self.__pkt_processor.register(
|
|
103
|
+
req_id=request_id_,
|
|
104
|
+
cmd_code=request.cmd_code
|
|
105
|
+
)
|
|
106
|
+
fut_ = self.__resp_publisher.register_request(
|
|
107
|
+
req_id=request_id_,
|
|
108
|
+
cmd_name=request.class_name
|
|
109
|
+
)
|
|
110
|
+
self.__log.debug_request(request)
|
|
111
|
+
return bytes(request), fut_
|
|
112
|
+
|
|
113
|
+
def subscribe(self, xmc_cls: ICommand, callback: Callable) -> None:
|
|
114
|
+
"""Register the callback on the command which supports Server PUSH notification."""
|
|
115
|
+
assert xmc_cls.pushed, "Command is not subscribable."
|
|
116
|
+
assert callback, "Callback function is required."
|
|
117
|
+
self.__resp_publisher.subscribe(
|
|
118
|
+
evt=xmc_cls.code,
|
|
119
|
+
func=callback
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
def on_disconnected(self, callback: Callable) -> None:
|
|
123
|
+
"""Regiser users callback which will be called after connection was terminated."""
|
|
124
|
+
self.__resp_publisher.subscribe_connection_lost(callback)
|
|
125
|
+
|
|
126
|
+
def set_outdated(self) -> None:
|
|
127
|
+
pass
|