From 625ed57a508e248ad5c71006265e5f6f7b6b3024 Mon Sep 17 00:00:00 2001 From: TsMask <340112800@qq.com> Date: Wed, 10 Jul 2024 14:18:48 +0800 Subject: [PATCH] =?UTF-8?q?merge:=20=20=E5=90=88=E5=B9=B6OMC=E5=88=86?= =?UTF-8?q?=E6=94=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- features/cdr/cdrevent.go | 234 +++- features/cm/license.go | 93 +- features/cm/ne.go | 32 +- features/cm/param.go | 11 +- features/cm/software.go | 59 +- features/dbrest/dbrest.go | 87 +- features/event/event.go | 48 +- features/file/file.go | 2 +- features/fm/alarm.go | 91 +- features/fm/smsforward.go | 218 +-- features/fm/ucpcli.go | 61 - features/handle/handle.go | 2 +- features/lm/logbak.go | 23 +- features/maintenance/maintenance.go | 314 ----- features/mml/mml.go | 58 +- features/monitor/monitor/model.go | 55 - features/monitor/monitor/monitor.go | 163 --- features/monitor/monitor/task.go | 234 ---- features/monitor/psnet/psnet.go | 94 -- features/nbi/nbi.go | 2 +- features/pm/performance.go | 175 ++- features/security/account.go | 253 +--- features/security/service/service_account.go | 56 - features/state/getstate.go | 9 +- features/sys_config/api_sys_config.go | 230 ---- features/sys_config/model/sys_config.go | 25 - .../sys_config/service/repo_sys_config.go | 336 ----- .../sys_config/service/service_sys_config.go | 155 --- features/sys_dict_data/api_sys_dict_data.go | 247 ---- features/sys_dict_data/model/sys_dict_data.go | 31 - .../sys_dict_data/repo/repo_sys_dict_data.go | 369 ----- .../service/service_sys_dict_data.go | 111 -- features/sys_dict_type/api_sys_dict_type.go | 253 ---- features/sys_dict_type/model/sys_dict_type.go | 23 - .../sys_dict_type/repo/repo_sys_dict_type.go | 330 ----- .../service/service_sys_dict_type.go | 211 --- features/sys_menu/api_sys_menu.go | 354 ----- features/sys_menu/consts/consts_menu.go | 24 - features/sys_menu/model/sys_menu.go | 46 - features/sys_menu/service/repo_sys_menu.go | 475 ------- features/sys_menu/service/service_sys_menu.go | 408 ------ features/sys_role/api_sys_role.go | 368 ----- features/sys_role/model/sys_role.go | 38 - features/sys_role/service/repo_sys_role.go | 362 ----- features/sys_role/service/service_sys_role.go | 165 --- features/sys_role_menu/model_sys_role_menu.go | 15 - features/sys_role_menu/repo_sys_role_menu.go | 86 -- features/sys_user/api_sys_user.go | 323 ----- features/sys_user/model/sys_user.go | 42 - features/sys_user/service/repo_sys_user.go | 578 -------- features/sys_user/service/service_sys_user.go | 150 -- features/sys_user_role/model_sys_user_role.go | 15 - features/sys_user_role/repo_sys_user_role.go | 87 -- features/trace/tcpdump.go | 339 ----- features/udm_user/api_udm_user.go | 1211 ----------------- features/udm_user/model/udm_auth_user.go | 13 - features/udm_user/model/udm_sub_user.go | 29 - features/udm_user/repo/repo_udm_auth_user.go | 276 ---- features/udm_user/repo/repo_udm_sub_user.go | 450 ------ .../udm_user/service/service_redis_data.go | 119 -- .../udm_user/service/service_udm_auth_user.go | 151 -- .../udm_user/service/service_udm_sub_user.go | 231 ---- features/ue/ue.go | 79 +- go.mod | 45 +- go.sum | 110 +- lib/core/account/account.go | 54 - lib/core/constants/cachekey/cachekey.go | 24 - lib/core/{utils => }/ctx/ctx.go | 56 +- lib/core/datasource/datasource.go | 50 - lib/core/datasource/repo.go | 126 -- lib/core/mml_client/mml_client.go | 87 -- lib/core/mml_client/send.go | 105 -- lib/core/utils/date/date.go | 70 - lib/core/utils/parse/parse.go | 139 -- lib/core/utils/regular/regular.go | 54 - lib/core/utils/scan/scan.go | 31 - lib/core/vo/login_user.go | 2 - lib/core/vo/router.go | 17 - lib/core/vo/router_meta.go | 17 - lib/core/vo/treeselect.go | 36 - lib/dborm/dborm.go | 136 +- lib/global/kits.go | 30 + lib/midware/arrow_ip_addr.go | 77 -- lib/midware/authorize.go | 228 ---- lib/midware/cors.go | 66 - lib/midware/mml_log.go | 20 +- lib/midware/operate_log.go | 12 +- lib/routes/routes.go | 108 +- lib/wsinfo/client.go | 45 - lib/wsinfo/process_data.go | 383 ------ omc/config/config.go | 180 ++- omc/etc/omc.yaml | 79 +- omc/etc/restconf-t.yaml | 134 -- omc/makefile | 8 +- omc/omc.go | 34 +- src/app.go | 18 +- src/framework/config/config.go | 6 +- .../config/config/config.default.yaml | 6 +- src/framework/constants/admin/admin.go | 10 +- src/framework/constants/common/common.go | 3 + .../constants/uploadsubpath/uploadsubpath.go | 4 + src/framework/logger/writer.go | 2 +- .../middleware/collectlogs/operate_log.go | 3 + src/framework/middleware/pre_authorize.go | 1 + src/framework/utils/crypto/aes.go | 87 +- src/framework/utils/ctx/ctx.go | 11 +- src/framework/utils/date/date.go | 11 +- src/framework/utils/file/csv.go | 2 +- src/framework/utils/file/excel.go | 2 +- src/framework/utils/file/file.go | 15 +- src/framework/utils/file/json.go | 4 +- src/framework/utils/file/txt.go | 2 +- src/framework/utils/file/utils.go | 4 +- src/framework/utils/machine/launch.go | 178 +++ src/framework/utils/parse/parse.go | 86 ++ src/framework/utils/regular/regular.go | 2 +- src/framework/utils/repo/repo.go | 6 +- src/framework/utils/ssh/files.go | 21 +- src/framework/utils/ssh/scp.go | 44 - src/framework/utils/ssh/sftp.go | 203 +++ src/framework/utils/ssh/ssh.go | 167 +-- src/framework/utils/ssh/ssh_session.go | 73 + src/framework/utils/telnet/parse.go | 77 ++ src/framework/utils/telnet/telnet.go | 158 +-- src/framework/utils/telnet/telnet_session.go | 74 + src/framework/utils/token/token.go | 5 +- src/lib_features/account/account.go | 39 - src/lib_features/config/config.go | 2 +- src/lib_features/readme.md | 5 +- src/lib_features/session/session.go | 29 - src/modules/common/common.go | 8 + src/modules/common/controller/account.go | 4 - src/modules/common/controller/bootloader.go | 182 +++ src/modules/common/controller/file.go | 16 +- src/modules/common/service/commont.impl.go | 13 + .../deleteExpiredRecord.go | 22 +- .../genNeStateAlarm/genNeStateAlarm.go | 14 +- .../getStateFromNE/getStateFromNE.go | 13 +- src/modules/monitor/controller/sys_job.go | 46 +- src/modules/monitor/controller/sys_job_log.go | 46 +- .../monitor/repository/sys_job_log.impl.go | 7 +- .../controller/{alarm.go => all_alarm.go} | 0 .../controller/{perf_kpi.go => all_kpi.go} | 2 +- src/modules/network_data/controller/amf.go | 150 +- src/modules/network_data/controller/ims.go | 150 +- src/modules/network_data/controller/mme.go | 201 +++ src/modules/network_data/controller/smf.go | 259 ++++ .../controller/udm_auth.go | 271 ++-- .../controller/udm_sub.go | 374 ++--- src/modules/network_data/model/cdr_event.go | 28 - .../network_data/model/cdr_event_ims.go | 30 + .../network_data/model/cdr_event_smf.go | 40 + src/modules/network_data/model/udm_auth.go | 17 + .../model/udm_sub.go | 7 +- .../model/{ue_event.go => ue_event_amf.go} | 13 +- .../network_data/model/ue_event_mme.go | 30 + src/modules/network_data/network_data.go | 160 ++- .../{cdr_event.go => cdr_event_ims.go} | 8 +- ...dr_event.impl.go => cdr_event_ims.impl.go} | 53 +- .../network_data/repository/cdr_event_smf.go | 15 + .../repository/cdr_event_smf.impl.go | 185 +++ .../network_data/repository/perf_kpi.go | 6 + .../network_data/repository/perf_kpi.impl.go | 138 ++ .../network_data/repository/udm_auth.go | 26 + .../repository/udm_auth.impl.go | 49 +- .../network_data/repository/udm_sub.go | 26 + .../repository/udm_sub.impl.go | 149 +- .../{ue_event.go => ue_event_amf.go} | 8 +- ...{ue_event.impl.go => ue_event_amf.impl.go} | 47 +- .../network_data/repository/ue_event_mme.go | 15 + .../repository/ue_event_mme.impl.go | 175 +++ .../{cdr_event.go => cdr_event_ims.go} | 6 +- .../service/cdr_event_ims.impl.go | 40 + .../network_data/service/cdr_event_smf.go | 12 + ...dr_event.impl.go => cdr_event_smf.impl.go} | 15 +- .../network_data/service/perf_kpi.impl.go | 6 +- src/modules/network_data/service/udm_auth.go | 28 + .../network_data/service/udm_auth.impl.go | 146 ++ src/modules/network_data/service/udm_sub.go | 28 + .../network_data/service/udm_sub.impl.go | 164 +++ .../service/{ue_event.go => ue_event_amf.go} | 6 +- ...{ue_event.impl.go => ue_event_amf.impl.go} | 16 +- .../network_data/service/ue_event_mme.go | 12 + .../network_data/service/ue_event_mme.impl.go | 40 + .../controller/{ne_action.go => action.go} | 114 +- .../network_element/controller/ne_config.go | 203 +++ .../network_element/controller/ne_host.go | 107 +- .../network_element/controller/ne_info.go | 288 +++- .../network_element/controller/ne_license.go | 226 +++ .../network_element/controller/ne_software.go | 85 +- .../network_element/controller/ne_version.go | 102 +- .../ne_config.go} | 61 +- .../network_element/fetch_link/ne_state.go | 56 + .../network_element/model/ne_config.go | 21 + src/modules/network_element/model/ne_host.go | 2 +- src/modules/network_element/model/ne_info.go | 34 +- .../network_element/model/ne_license.go | 27 + .../network_element/model/ne_software.go | 24 +- .../network_element/model/ne_version.go | 30 +- src/modules/network_element/model/udm_auth.go | 17 - .../network_element/network_element.go | 184 ++- .../network_element/repository/ne_config.go | 24 + .../repository/ne_config.impl.go | 254 ++++ .../repository/ne_host.impl.go | 46 +- .../repository/ne_info.impl.go | 45 +- .../network_element/repository/ne_license.go | 24 + .../repository/ne_license.impl.go | 297 ++++ .../network_element/repository/ne_software.go | 4 +- .../repository/ne_software.impl.go | 84 +- .../network_element/repository/ne_version.go | 3 - .../repository/ne_version.impl.go | 120 +- .../network_element/repository/udm_auth.go | 26 - .../network_element/repository/udm_sub.go | 35 - .../network_element/service/ne_config.go | 33 + .../network_element/service/ne_config.impl.go | 151 ++ .../network_element/service/ne_info.go | 33 +- .../network_element/service/ne_info.impl.go | 666 +++++++-- .../network_element/service/ne_license.go | 34 + .../service/ne_license.impl.go | 191 +++ .../network_element/service/ne_software.go | 11 +- .../service/ne_software.impl.go | 96 +- .../network_element/service/ne_version.go | 10 +- .../service/ne_version.impl.go | 576 +++++++- .../network_element/service/udm_auth.go | 37 - .../network_element/service/udm_auth.impl.go | 179 --- .../network_element/service/udm_sub.go | 37 - .../network_element/service/udm_sub.impl.go | 195 --- src/modules/system/controller/sys_config.go | 19 +- src/modules/system/controller/sys_dept.go | 13 +- .../system/controller/sys_dict_data.go | 33 +- .../system/controller/sys_dict_type.go | 15 +- .../system/controller/sys_log_login.go | 50 +- .../system/controller/sys_log_operate.go | 86 +- src/modules/system/controller/sys_menu.go | 4 +- src/modules/system/controller/sys_post.go | 32 +- src/modules/system/controller/sys_profile.go | 2 +- src/modules/system/controller/sys_role.go | 42 +- src/modules/system/controller/sys_user.go | 66 +- .../system/repository/sys_config.impl.go | 7 +- .../system/repository/sys_dict_type.impl.go | 7 +- .../system/repository/sys_log_login.go | 2 +- .../system/repository/sys_log_login.impl.go | 26 +- .../system/repository/sys_log_operate.go | 2 +- .../system/repository/sys_log_operate.impl.go | 27 +- .../system/repository/sys_role.impl.go | 9 +- .../system/repository/sys_user.impl.go | 14 +- src/modules/system/service/sys_log_login.go | 2 +- .../system/service/sys_log_login.impl.go | 4 +- src/modules/system/service/sys_log_operate.go | 2 +- .../system/service/sys_log_operate.impl.go | 4 +- src/modules/system/service/sys_user.impl.go | 2 +- src/modules/system/system.go | 2 +- src/modules/trace/service/tcpdump.impl.go | 60 +- src/modules/trace/trace.go | 4 +- src/modules/ws/controller/ws.go | 43 +- src/modules/ws/processor/cdr_connect.go | 26 +- src/modules/ws/processor/ne_state.go | 3 +- src/modules/ws/processor/ue_connect.go | 28 +- src/modules/ws/service/ws_receive.impl.go | 18 +- src/modules/ws/service/ws_send.impl.go | 4 + 260 files changed, 9167 insertions(+), 14857 deletions(-) delete mode 100644 features/fm/ucpcli.go delete mode 100644 features/maintenance/maintenance.go delete mode 100644 features/monitor/monitor/model.go delete mode 100644 features/monitor/monitor/monitor.go delete mode 100644 features/monitor/monitor/task.go delete mode 100644 features/monitor/psnet/psnet.go delete mode 100644 features/security/service/service_account.go delete mode 100644 features/sys_config/api_sys_config.go delete mode 100644 features/sys_config/model/sys_config.go delete mode 100644 features/sys_config/service/repo_sys_config.go delete mode 100644 features/sys_config/service/service_sys_config.go delete mode 100644 features/sys_dict_data/api_sys_dict_data.go delete mode 100644 features/sys_dict_data/model/sys_dict_data.go delete mode 100644 features/sys_dict_data/repo/repo_sys_dict_data.go delete mode 100644 features/sys_dict_data/service/service_sys_dict_data.go delete mode 100644 features/sys_dict_type/api_sys_dict_type.go delete mode 100644 features/sys_dict_type/model/sys_dict_type.go delete mode 100644 features/sys_dict_type/repo/repo_sys_dict_type.go delete mode 100644 features/sys_dict_type/service/service_sys_dict_type.go delete mode 100644 features/sys_menu/api_sys_menu.go delete mode 100644 features/sys_menu/consts/consts_menu.go delete mode 100644 features/sys_menu/model/sys_menu.go delete mode 100644 features/sys_menu/service/repo_sys_menu.go delete mode 100644 features/sys_menu/service/service_sys_menu.go delete mode 100644 features/sys_role/api_sys_role.go delete mode 100644 features/sys_role/model/sys_role.go delete mode 100644 features/sys_role/service/repo_sys_role.go delete mode 100644 features/sys_role/service/service_sys_role.go delete mode 100644 features/sys_role_menu/model_sys_role_menu.go delete mode 100644 features/sys_role_menu/repo_sys_role_menu.go delete mode 100644 features/sys_user/api_sys_user.go delete mode 100644 features/sys_user/model/sys_user.go delete mode 100644 features/sys_user/service/repo_sys_user.go delete mode 100644 features/sys_user/service/service_sys_user.go delete mode 100644 features/sys_user_role/model_sys_user_role.go delete mode 100644 features/sys_user_role/repo_sys_user_role.go delete mode 100644 features/trace/tcpdump.go delete mode 100644 features/udm_user/api_udm_user.go delete mode 100644 features/udm_user/model/udm_auth_user.go delete mode 100644 features/udm_user/model/udm_sub_user.go delete mode 100644 features/udm_user/repo/repo_udm_auth_user.go delete mode 100644 features/udm_user/repo/repo_udm_sub_user.go delete mode 100644 features/udm_user/service/service_redis_data.go delete mode 100644 features/udm_user/service/service_udm_auth_user.go delete mode 100644 features/udm_user/service/service_udm_sub_user.go delete mode 100644 lib/core/account/account.go delete mode 100644 lib/core/constants/cachekey/cachekey.go rename lib/core/{utils => }/ctx/ctx.go (74%) delete mode 100644 lib/core/datasource/datasource.go delete mode 100644 lib/core/datasource/repo.go delete mode 100644 lib/core/mml_client/mml_client.go delete mode 100644 lib/core/mml_client/send.go delete mode 100644 lib/core/utils/date/date.go delete mode 100644 lib/core/utils/parse/parse.go delete mode 100644 lib/core/utils/regular/regular.go delete mode 100644 lib/core/utils/scan/scan.go delete mode 100644 lib/core/vo/router.go delete mode 100644 lib/core/vo/router_meta.go delete mode 100644 lib/core/vo/treeselect.go delete mode 100644 lib/midware/arrow_ip_addr.go delete mode 100644 lib/midware/authorize.go delete mode 100644 lib/midware/cors.go delete mode 100644 lib/wsinfo/client.go delete mode 100644 lib/wsinfo/process_data.go delete mode 100644 omc/etc/restconf-t.yaml create mode 100644 src/framework/utils/machine/launch.go delete mode 100644 src/framework/utils/ssh/scp.go create mode 100644 src/framework/utils/ssh/sftp.go create mode 100644 src/framework/utils/ssh/ssh_session.go create mode 100644 src/framework/utils/telnet/parse.go create mode 100644 src/framework/utils/telnet/telnet_session.go delete mode 100644 src/lib_features/account/account.go delete mode 100644 src/lib_features/session/session.go create mode 100644 src/modules/common/controller/bootloader.go rename src/modules/network_data/controller/{alarm.go => all_alarm.go} (100%) rename src/modules/network_data/controller/{perf_kpi.go => all_kpi.go} (98%) create mode 100644 src/modules/network_data/controller/mme.go create mode 100644 src/modules/network_data/controller/smf.go rename src/modules/{network_element => network_data}/controller/udm_auth.go (60%) rename src/modules/{network_element => network_data}/controller/udm_sub.go (62%) delete mode 100644 src/modules/network_data/model/cdr_event.go create mode 100644 src/modules/network_data/model/cdr_event_ims.go create mode 100644 src/modules/network_data/model/cdr_event_smf.go create mode 100644 src/modules/network_data/model/udm_auth.go rename src/modules/{network_element => network_data}/model/udm_sub.go (86%) rename src/modules/network_data/model/{ue_event.go => ue_event_amf.go} (79%) create mode 100644 src/modules/network_data/model/ue_event_mme.go rename src/modules/network_data/repository/{cdr_event.go => cdr_event_ims.go} (54%) rename src/modules/network_data/repository/{cdr_event.impl.go => cdr_event_ims.impl.go} (73%) create mode 100644 src/modules/network_data/repository/cdr_event_smf.go create mode 100644 src/modules/network_data/repository/cdr_event_smf.impl.go create mode 100644 src/modules/network_data/repository/udm_auth.go rename src/modules/{network_element => network_data}/repository/udm_auth.impl.go (80%) create mode 100644 src/modules/network_data/repository/udm_sub.go rename src/modules/{network_element => network_data}/repository/udm_sub.impl.go (58%) rename src/modules/network_data/repository/{ue_event.go => ue_event_amf.go} (55%) rename src/modules/network_data/repository/{ue_event.impl.go => ue_event_amf.impl.go} (75%) create mode 100644 src/modules/network_data/repository/ue_event_mme.go create mode 100644 src/modules/network_data/repository/ue_event_mme.impl.go rename src/modules/network_data/service/{cdr_event.go => cdr_event_ims.go} (60%) create mode 100644 src/modules/network_data/service/cdr_event_ims.impl.go create mode 100644 src/modules/network_data/service/cdr_event_smf.go rename src/modules/network_data/service/{cdr_event.impl.go => cdr_event_smf.impl.go} (55%) create mode 100644 src/modules/network_data/service/udm_auth.go create mode 100644 src/modules/network_data/service/udm_auth.impl.go create mode 100644 src/modules/network_data/service/udm_sub.go create mode 100644 src/modules/network_data/service/udm_sub.impl.go rename src/modules/network_data/service/{ue_event.go => ue_event_amf.go} (60%) rename src/modules/network_data/service/{ue_event.impl.go => ue_event_amf.impl.go} (58%) create mode 100644 src/modules/network_data/service/ue_event_mme.go create mode 100644 src/modules/network_data/service/ue_event_mme.impl.go rename src/modules/network_element/controller/{ne_action.go => action.go} (55%) create mode 100644 src/modules/network_element/controller/ne_config.go create mode 100644 src/modules/network_element/controller/ne_license.go rename src/modules/network_element/{service/ne_direct_link.go => fetch_link/ne_config.go} (59%) create mode 100644 src/modules/network_element/fetch_link/ne_state.go create mode 100644 src/modules/network_element/model/ne_config.go create mode 100644 src/modules/network_element/model/ne_license.go delete mode 100644 src/modules/network_element/model/udm_auth.go create mode 100644 src/modules/network_element/repository/ne_config.go create mode 100644 src/modules/network_element/repository/ne_config.impl.go create mode 100644 src/modules/network_element/repository/ne_license.go create mode 100644 src/modules/network_element/repository/ne_license.impl.go delete mode 100644 src/modules/network_element/repository/udm_auth.go delete mode 100644 src/modules/network_element/repository/udm_sub.go create mode 100644 src/modules/network_element/service/ne_config.go create mode 100644 src/modules/network_element/service/ne_config.impl.go create mode 100644 src/modules/network_element/service/ne_license.go create mode 100644 src/modules/network_element/service/ne_license.impl.go delete mode 100644 src/modules/network_element/service/udm_auth.go delete mode 100644 src/modules/network_element/service/udm_auth.impl.go delete mode 100644 src/modules/network_element/service/udm_sub.go delete mode 100644 src/modules/network_element/service/udm_sub.impl.go diff --git a/features/cdr/cdrevent.go b/features/cdr/cdrevent.go index de4f6af..73fbe7d 100644 --- a/features/cdr/cdrevent.go +++ b/features/cdr/cdrevent.go @@ -4,6 +4,7 @@ import ( "encoding/json" "io" "net/http" + "time" "nms_cxy/lib/dborm" "nms_cxy/lib/global" @@ -14,13 +15,197 @@ import ( ) var ( - UriCDREvent = config.DefaultUriPrefix + "/cdrManagement/v1/elementType/{elementTypeValue}/objectType/cdrEvent" - UriCDRFile = config.DefaultUriPrefix + "/cdrManagement/v1/elementType/{elementTypeValue}/objectType/cdrFile" + UriIMSCDREvent = config.DefaultUriPrefix + "/cdrManagement/v1/elementType/ims/objectType/cdrEvent" + UriIMSCDRFile = config.DefaultUriPrefix + "/cdrManagement/v1/elementType/ims/objectType/cdrFile" + UriSMFCDREvent = config.DefaultUriPrefix + "/cdrManagement/v1/elementType/smf/objectType/cdrEvent" + UriSMFCDRFile = config.DefaultUriPrefix + "/cdrManagement/v1/elementType/smf/objectType/cdrFile" - CustomUriCDREvent = config.UriPrefix + "/cdrManagement/v1/elementType/{elementTypeValue}/objectType/cdrEvent" - CustomUriCDRFile = config.UriPrefix + "/cdrManagement/v1/elementType/{elementTypeValue}/objectType/cdrFile" + CustomUriIMSCDREvent = config.UriPrefix + "/cdrManagement/v1/elementType/ims/objectType/cdrEvent" + CustomUriIMSCDRFile = config.UriPrefix + "/cdrManagement/v1/elementType/ims/objectType/cdrFile" + CustomUriSMFCDREvent = config.UriPrefix + "/cdrManagement/v1/elementType/ims/objectType/cdrEvent" + CustomUriSMFCDRFile = config.UriPrefix + "/cdrManagement/v1/elementType/ims/objectType/cdrFile" ) +// SMF CDR +type CdrSubscriptionID struct { + SubscriptionIDType string `json:"subscriptionIDType"` + SubscriptionIDData string `json:"subscriptionIDData"` +} + +type CdrNetWorkFuctionInfomation struct { + NetworkFunctionality string `json:"networkFunctionality"` + NetworkFunctionName string `json:"networkFunctionName,omitempty"` + NetworkFunctionIPv4Address string `json:"networkFunctionIPv4Address,omitempty"` + NetworkFunctionIPv6Address string `json:"networkFunctionIPv6Address,omitempty"` +} + +type SMFTrigger string + +const ( + TimeThresholdReached SMFTrigger = "timeThresholdReached" + VolumeThresholdReached SMFTrigger = "volumeThresholdReached" + UnitThresholdReached SMFTrigger = "unitThresholdReached" + TimeQuotaExhausted SMFTrigger = "timeQuotaExhausted" + VolumeQuotaExhausted SMFTrigger = "volumeQuotaExhausted" + UnitQuotaExhausted SMFTrigger = "unitQuotaExhausted" + ExpiryOfQuotaValidityTime SMFTrigger = "expiryOfQuotaValidityTime" + ExpiryOfQuotaHoldingTime SMFTrigger = "expiryOfQuotaHoldingTime" + EndOfPDUSession SMFTrigger = "endOfPDUSession" +) + +type CdrSMFTrigger struct { + SMFTrigger SMFTrigger `json:"sMFTrigger"` +} + +type CdrQuotaManagementIndicator string + +// List of QuotaManagementIndicator +const ( + Cdr_QMI_ONLINE_CHARGING CdrQuotaManagementIndicator = "ONLINE_CHARGING" + Cdr_QMI_OFFLINE_CHARGING CdrQuotaManagementIndicator = "OFFLINE_CHARGING" + Cdr_QMI_QUOTA_MANAGEMENT_SUSPENDED CdrQuotaManagementIndicator = "QUOTA_MANAGEMENT_SUSPENDED" +) + +type CdrUsedUnitContainer struct { + ServiceIdentifier *int32 `json:"serviceIdentifier,omitempty"` + QuotaManagementIndicatorExt CdrQuotaManagementIndicator `json:"quotaManagementIndicatorExt,omitempty"` + Triggers []SMFTrigger `json:"triggers,omitempty"` + TriggerTimestamp *time.Time `json:"triggerTimestamp,omitempty"` + Time *uint32 `json:"time,omitempty"` + DataTotalVolume *uint64 `json:"dataTotalVolume,omitempty"` + DataVolumeUplink *uint64 `json:"dataVolumeUplink,omitempty"` + DataVolumeDownlink *uint64 `json:"dataVolumeDownlink,omitempty"` + ServiceSpecificUnits *uint64 `json:"serviceSpecificUnits,omitempty"` + EventTimeStamp *time.Time `json:"eventTimeStamp,omitempty"` + LocalSequenceNumber int32 `json:"localSequenceNumber"` + //PDUContainerInformation *PduContainerInformation `json:"pDUContainerInformation,omitempty"` + //NSPAContainerInformation *NspaContainerInformation `json:"nSPAContainerInformation,omitempty"` +} + +type CdrMultipleUnitUsage struct { + RatingGroup uint32 `json:"ratingGroup" yaml:"ratingGroup" bson:"ratingGroup" mapstructure:"RatingGroup"` + UsedUnitContainer []CdrUsedUnitContainer `json:"usedUnitContainer,omitempty" yaml:"usedUnitContainer" bson:"usedUnitContainer" mapstructure:"UsedUnitContainer"` + //UPFID string `json:"uPFID,omitempty" yaml:"uPFID" bson:"uPFID" mapstructure:"UPFID"` +} + +type CdrSubscriberEquipmentNumber struct { + SubscriberEquipmentNumberType string `json:"subscriberEquipmentNumberType"` + SubscriberEquipmentNumberData string `json:"subscriberEquipmentNumberData"` +} + +type CdrNetworkSliceInstanceID struct { + SST int32 `json:"sST"` + + SD string `json:"sD,omitempty"` +} + +type CdrPduAddress struct { + PDUIPv4Address string `json:"pDUIPv4Address,omitempty"` + PDUIPv6AddresswithPrefix string `json:"pDUIPv6AddresswithPrefix,omitempty"` + IPV4dynamicAddressFlag bool `json:"iPV4dynamicAddressFlag,omitempty"` + IPV6dynamicPrefixFlag bool `json:"iPv6dynamicPrefixFlag,omitempty"` +} + +type CdrArp struct { + PriorityLevel int32 `json:"priorityLevel"` + PreemptionCapability string `json:"preemptionCapability"` + PreemptionVulnerability string `json:"preemptionVulnerability"` +} + +type CdrAuthorizedQosInformation struct { + FiveQi int `json:"fiveQi"` + ARP *CdrArp `json:"aRP,omitempty"` + PriorityLevel *int32 `json:"priorityLevel,omitempty"` + AverWindow *int32 `json:"averWindow,omitempty"` + MaxDataBurstVol *int32 `json:"maxDataBurstVol,omitempty"` +} + +type CdrSubscribedDefaultQos struct { + FiveQi int32 `json:"fiveQi,omitempty"` + ARP CdrArp `json:"aRP,omitempty"` + PriorityLevel *int32 `json:"priorityLevel,omitempty"` +} + +type CdrSessionAmbr struct { + Uplink string `json:"uplink"` + + Downlink string `json:"downlink"` +} + +type CdrPDUSessionChargingInformation struct { + PDUSessionChargingID int32 `json:"pDUSessionChargingID"` + UserIdentifier string `json:"userIdentifier,omitempty"` // isdn + UserEquipmentInfo *CdrSubscriberEquipmentNumber `json:"userEquipmentInfo,omitempty"` // imei/imeisv + //UserLocationInfomation *UserLocation `json:"userLocationinfo,omitempty"` + UserRoamerInOut string `json:"userRoamerInOut,omitempty"` + PDUSessionId int32 `json:"pDUSessionId"` + NetworkSliceInstanceID *CdrNetworkSliceInstanceID `json:"networkSliceInstanceID,omitempty"` + //PDUType PduSessionType `json:"pDUType,omitempty"` + SSCMode string `json:"sSCMode,omitempty"` + DNNID string `json:"dNNID"` + SUPIPLMNIdentifier string `json:"sUPIPLMNIdentifier,omitempty"` + //ServingNetworkFunctionID *ServingNetworkFunctionId `json:"servingNetworkFunctionID,omitempty"` + //RATType RatType `json:"rATType,omitempty"` + DataNetworkNameIdentifier string `json:"dataNetworkNameIdentifier,omitempty"` + PDUAddress CdrPduAddress `json:"pDUAddress,omitempty"` + AuthorizedQoSInformation *CdrAuthorizedQosInformation `json:"authorizedQoSInformation,omitempty"` + UETimeZone string `json:"uETimeZone,omitempty"` + PDUSessionstartTime *time.Time `json:"pDUSessionstartTime,omitempty"` + PDUSessionstopTime *time.Time `json:"pDUSessionstopTime,omitempty"` + Diagnostics *int `json:"diagnostics,omitempty"` + ChargingCharacteristics string `json:"chargingCharacteristics,omitempty"` + ChChSelectionMode string `json:"chChSelectionMode,omitempty"` + ThreeGPPPSDataOffStatus string `json:"threeGPPPSDataOffStatus,omitempty"` + //RANSecondaryRATUsageReport *RanSecondaryRatUsageReport `json:"rANSecondaryRATUsageReport,omitempty"` + SubscribedQoSInformation *CdrSubscribedDefaultQos `json:"subscribedQoSInformation,omitempty"` + AuthorizedSessionAMBR *CdrSessionAmbr `json:"authorizedSessionAMBR,omitempty"` + SubscribedSessionAMBR *CdrSessionAmbr `json:"subscribedSessionAMBR,omitempty"` + ServingCNPLMNID string `json:"servingCNPLMNID,omitempty"` + DnnSelectionMode string `json:"dnnSelectionMode,omitempty"` + HomeProvidedChargingID int32 `json:"homeProvidedChargingID,omitempty"` + + //MAPDUNon3GPPUserLocationInfo *UserLocation `json:"mAPDUNon3GPPUserLocationInfo,omitempty" yaml:"mAPDUNon3GPPUserLocationInfo" bson:"mAPDUNon3GPPUserLocationInfo" mapstructure:"MAPDUNon3GPPUserLocationInfo"` + //PresenceReportingAreaInformation map[string]PresenceInfo `json:"presenceReportingAreaInformation,omitempty" yaml:"presenceReportingAreaInformation" bson:"presenceReportingAreaInformation" mapstructure:"PresenceReportingAreaInformation"` +} + +type CauseForRecordClosing string + +const ( + NormalRelease CauseForRecordClosing = "normalRelease" + PartialRecord CauseForRecordClosing = "partialRecord" + AbnormalRelease CauseForRecordClosing = "abnormalRelease" + CAMELInitCallRelease CauseForRecordClosing = "cAMELInitCallRelease" + VolumeLimit CauseForRecordClosing = "volumeLimit" + TimeLimit CauseForRecordClosing = "timeLimit" + ServingNodeChange CauseForRecordClosing = "servingNodeChange" + MaxChangeCond CauseForRecordClosing = "maxChangeCond" + ManagementIntervention CauseForRecordClosing = "managementIntervention" + IntraSGSNIntersystemChange CauseForRecordClosing = "intraSGSNIntersystemChange" + RATChange CauseForRecordClosing = "rATChange" + MSTimeZoneChange CauseForRecordClosing = "mSTimeZoneChange" + SGSNPLMNIDChange CauseForRecordClosing = "sGSNPLMNIDChange " + SGWChange CauseForRecordClosing = "sGWChange" + APNAMBRChange CauseForRecordClosing = "aPNAMBRChange" +) + +type ChargingRecord struct { + RecordType string `json:"recordType"` + ChargingID int `json:"chargingID"` + RecordingNetworkFunctionID string `json:"recordingNetworkFunctionID"` // UUID + SubscriberIdentifier CdrSubscriptionID `json:"subscriberIdentifier,omitempty"` + NFunctionConsumerInformation CdrNetWorkFuctionInfomation `json:"nFunctionConsumerInformation"` + Triggers []CdrSMFTrigger `json:"triggers,omitempty"` + ListOfMultipleUnitUsage []CdrMultipleUnitUsage `json:"listOfMultipleUnitUsage,omitempty"` + RecordOpeningTime string `json:"recordOpeningTime"` + Duration int `json:"duration"` + RecordSequenceNumber int `json:"recordSequenceNumber,omitempty"` + CauseForRecClosing CauseForRecordClosing `json:"causeForRecClosing"` + Diagnostics *int `json:"diagnostics,omitempty"` + LocalRecordSequenceNumber int `json:"localRecordSequenceNumber,omitempty"` + PDUSessionChargingInformation CdrPDUSessionChargingInformation `json:"pDUSessionChargingInformation,omitempty"` + InvocationTimestamp string `json:"invocationTimestamp,omitempty"` +} + type CDREvent struct { NeType string `json:"neType" xorm:"ne_type"` NeName string `json:"neName" xorm:"ne_name"` @@ -29,8 +214,8 @@ type CDREvent struct { CDR map[string]any `json:"CDR" xorm:"cdr_json"` } -func PostCDREventFromNF(w http.ResponseWriter, r *http.Request) { - log.Info("PostCDREventFromNF processing... ") +func PostCDREventFromIMS(w http.ResponseWriter, r *http.Request) { + log.Info("PostCDREventFromIMS processing... ") // body, err := io.ReadAll(io.LimitReader(r.Body, global.RequestBodyMaxLen)) body, err := io.ReadAll(io.LimitReader(r.Body, global.RequestBodyMaxLen)) @@ -49,9 +234,9 @@ func PostCDREventFromNF(w http.ResponseWriter, r *http.Request) { } log.Trace("cdrEvent:", cdrEvent) - affected, err := dborm.XormInsertTableOne("cdr_event", cdrEvent) + affected, err := dborm.XormInsertTableOne("cdr_event_ims", cdrEvent) if err != nil && affected <= 0 { - log.Error("Failed to insert cdr_event:", err) + log.Error("Failed to insert cdr_event_ims:", err) services.ResponseInternalServerError500ProcessError(w, err) return } @@ -65,3 +250,36 @@ func PostCDREventFromNF(w http.ResponseWriter, r *http.Request) { services.ResponseStatusOK204NoContent(w) } + +func PostCDREventFromSMF(w http.ResponseWriter, r *http.Request) { + log.Info("PostCDREventFromSMF processing... ") + + // body, err := io.ReadAll(io.LimitReader(r.Body, global.RequestBodyMaxLen)) + body, err := io.ReadAll(io.LimitReader(r.Body, global.RequestBodyMaxLen)) + if err != nil { + log.Error("Faile to io.ReadAll: ", err) + services.ResponseNotFound404UriNotExist(w, r) + return + } + + cdrEvent := new(CDREvent) + err = json.Unmarshal(body, &cdrEvent) + if cdrEvent.NeType == "" || err != nil { + log.Error("Failed to Unmarshal cdrEvent:", err) + services.ResponseInternalServerError500ProcessError(w, err) + return + } + log.Trace("cdrEvent:", cdrEvent) + + affected, err := dborm.XormInsertTableOne("cdr_event_smf", cdrEvent) + if err != nil && affected <= 0 { + log.Error("Failed to insert cdr_event_smf:", err) + services.ResponseInternalServerError500ProcessError(w, err) + return + } + + // 推送到ws订阅组 + wsService.NewWSSendImpl.ByGroupID(wsService.GROUP_SMF_CDR, cdrEvent) + + services.ResponseStatusOK204NoContent(w) +} diff --git a/features/cm/license.go b/features/cm/license.go index 84785b5..09419da 100644 --- a/features/cm/license.go +++ b/features/cm/license.go @@ -7,12 +7,14 @@ import ( "os" "os/exec" "strings" - "time" + "nms_cxy/lib/core/ctx" "nms_cxy/lib/dborm" "nms_cxy/lib/log" "nms_cxy/lib/services" "nms_cxy/omc/config" + neModel "nms_cxy/src/modules/network_element/model" + neService "nms_cxy/src/modules/network_element/service" "github.com/gorilla/mux" ) @@ -154,21 +156,21 @@ func DeleteLcenseFile(w http.ResponseWriter, r *http.Request) { services.ResponseStatusOK204NoContent(w) } -type MMLRequest struct { - MML []string `json:"mml"` -} +// type MMLRequest struct { +// MML []string `json:"mml"` +// } -var TIME_DELAY_AFTER_WRITE time.Duration = 200 -var TIME_DEAD_LINE time.Duration = 10 +// var TIME_DELAY_AFTER_WRITE time.Duration = 200 +// var TIME_DEAD_LINE time.Duration = 10 -func init() { - if config.GetYamlConfig().MML.Sleep != 0 { - TIME_DELAY_AFTER_WRITE = time.Duration(config.GetYamlConfig().MML.Sleep) - } - if config.GetYamlConfig().MML.DeadLine != 0 { - TIME_DEAD_LINE = time.Duration(config.GetYamlConfig().MML.DeadLine) - } -} +// func init() { +// if config.GetYamlConfig().MML.Sleep != 0 { +// TIME_DELAY_AFTER_WRITE = time.Duration(config.GetYamlConfig().MML.Sleep) +// } +// if config.GetYamlConfig().MML.DeadLine != 0 { +// TIME_DEAD_LINE = time.Duration(config.GetYamlConfig().MML.DeadLine) +// } +// } func UploadLicenseFileData(w http.ResponseWriter, r *http.Request) { log.Info("UploadLicenseFileData processing... ") @@ -274,12 +276,13 @@ func UploadLicenseFileData(w http.ResponseWriter, r *http.Request) { } // backup system.ini to system.ini.bak sshHost := fmt.Sprintf("%s@%s", config.GetYamlConfig().NE.User, neInfo.Ip) - cpCmd := fmt.Sprintf("sudo cp -f %s/system.ini %s/system.ini.bak", neLicensePath, neLicensePath) + cpCmd := fmt.Sprintf("sudo test -f %s/system.ini && cp -f %s/system.ini %s/system.ini.bak||echo 0", + neLicensePath, neLicensePath, neLicensePath) cmd = exec.Command("ssh", sshHost, cpCmd) out, err = cmd.CombinedOutput() log.Debugf("Exec output: %v", string(out)) if err != nil { - log.Error("Faile to execute cp command:", err) + log.Errorf("Faile to execute cp command:%v, cmd:%s", err, cpCmd) services.ResponseInternalServerError500ProcessError(w, err) return } @@ -503,22 +506,54 @@ func UploadLicenseFileData(w http.ResponseWriter, r *http.Request) { } } */ - neLicense := dborm.NeLicense{ - NeType: neTypeUpper, - NeID: neId, - Status: "ACTIVE", - Path: licensePath, - FileName: licenseFileName, - Comment: comment, + + // neLicense := dborm.NeLicense{ + // NeType: neTypeUpper, + // NeID: neId, + // Status: "ACTIVE", + // Path: licensePath, + // FileName: licenseFileName, + // Comment: comment, + // } + + // log.Debug("neLicense:", neLicense) + // _, err = dborm.XormInsertTableOne("ne_license", neLicense) + // if err != nil { + // log.Error("Faile to XormInsertTableOne:", err) + // services.ResponseInternalServerError500ProcessError(w, err) + // } + + neLicense := neModel.NeLicense{ + NeType: neTypeUpper, + NeId: neId, + Status: "0", + LicensePath: neFilePath, + Remark: comment, } log.Debug("neLicense:", neLicense) - _, err = dborm.XormInsertTableOne("ne_license", neLicense) - if err != nil { - log.Error("Faile to XormInsertTableOne:", err) - services.ResponseInternalServerError500ProcessError(w, err) - return + + // 检查是否存在授权记录 + neLicense2 := neService.NewNeLicenseImpl.SelectByNeTypeAndNeID(neTypeUpper, neId) + if neLicense2.NeId != neId { + // 读取授权码 + code, _ := neService.NewNeLicenseImpl.ReadLicenseInfo(neLicense) + neLicense.ActivationRequestCode = code + + neLicense.CreateBy = ctx.LoginUserToUserName(r) + insertId := neService.NewNeLicenseImpl.Insert(neLicense) + if insertId != "" { + services.ResponseStatusOK204NoContent(w) + return + } + } else { + neLicense2.UpdateBy = ctx.LoginUserToUserName(r) + upRows := neService.NewNeLicenseImpl.Update(neLicense2) + if upRows > 0 { + services.ResponseStatusOK204NoContent(w) + return + } } - services.ResponseStatusOK204NoContent(w) + services.ResponseInternalServerError500ProcessError(w, err) } diff --git a/features/cm/ne.go b/features/cm/ne.go index 04708c0..88fbcbf 100644 --- a/features/cm/ne.go +++ b/features/cm/ne.go @@ -142,7 +142,8 @@ func PostNeInfo(w http.ResponseWriter, r *http.Request) { services.ResponseInternalServerError500ProcessError(w, err) return } - neInfo.UpdateTime = time.Now().Format(time.DateTime) + //neInfo.UpdateTime = time.Now().Format(time.DateTime) + neInfo.UpdateTime = time.Now() log.Debug("NE info:", neInfo) //if !config.GetYamlConfig().OMC.Chk2Ne { @@ -166,7 +167,7 @@ func PostNeInfo(w http.ResponseWriter, r *http.Request) { } else { hostUri := global.CombineHostUri(neInfo.Ip, neInfo.Port) //hostUri := fmt.Sprintf("http://%s:%v", neInfo.Ip, neInfo.Port) - apiUri := fmt.Sprintf("%s/systemManagement/v1/elementType/%s/objectType/config/omcNeConfig", config.DefaultUriPrefix, strings.ToLower(neInfo.NeType)) + apiUri := fmt.Sprintf("%s/systemManagement/v1/elementType/%s/objectType/config/omcNeConfig?ne_id=%s", config.DefaultUriPrefix, strings.ToLower(neInfo.NeType), neInfo.NeId) requestURI2NF := fmt.Sprintf("%s%s", hostUri, apiUri) log.Debug("requestURI2NF:", requestURI2NF) @@ -252,7 +253,7 @@ func PutNeInfo(w http.ResponseWriter, r *http.Request) { neInfo := new(dborm.NeInfo) _ = json.Unmarshal(body, neInfo) neInfo.NeType = strings.ToUpper(neType) - neInfo.UpdateTime = time.Now().Format(time.DateTime) + neInfo.UpdateTime = time.Now() log.Debug("NE info:", neInfo) //if !config.GetYamlConfig().OMC.Chk2Ne { @@ -276,7 +277,7 @@ func PutNeInfo(w http.ResponseWriter, r *http.Request) { } else { hostUri := global.CombineHostUri(neInfo.Ip, neInfo.Port) //hostUri := fmt.Sprintf("http://%s:%v", neInfo.Ip, neInfo.Port) - apiUri := fmt.Sprintf("%s/systemManagement/v1/elementType/%s/objectType/config/omcNeConfig", config.DefaultUriPrefix, neTypeLower) + apiUri := fmt.Sprintf("%s/systemManagement/v1/elementType/%s/objectType/config/omcNeConfig?ne_id=%s", config.DefaultUriPrefix, neTypeLower, neInfo.NeId) requestURI2NF := fmt.Sprintf("%s%s", hostUri, apiUri) log.Debug("requestURI2NF:", requestURI2NF) @@ -858,15 +859,20 @@ func PostNeServiceAction(w http.ResponseWriter, r *http.Request) { sshHost := fmt.Sprintf("%s@%s", config.GetYamlConfig().NE.User, neInfo.Ip) switch neTypeLower { case "omc": - actionCmd := fmt.Sprintf("sudo %s/bin/omcsvc.sh %s", config.GetYamlConfig().NE.OmcDir, action) - cmd := exec.Command("ssh", sshHost, actionCmd) - out, err := cmd.CombinedOutput() - log.Debugf("Exec output: %v", string(out)) - if err != nil { - log.Errorf("Faile to execute ssh %s omc:%v", action, err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } + // send 204 to fe firstly + services.ResponseStatusOK204NoContent(w) + //actionCmd := fmt.Sprintf("sudo %s/bin/omcsvc.sh %s", config.GetYamlConfig().NE.OmcDir, action) + actionCmd := fmt.Sprintf("sudo systemctl %s restagent", action) + go RunSSHCmd(sshHost, actionCmd) + return + // cmd := exec.Command("ssh", sshHost, actionCmd) + // out, err := cmd.CombinedOutput() + // log.Debugf("Exec output: %v", string(out)) + // if err != nil { + // log.Errorf("Faile to execute ssh %s omc:%v", action, err) + // services.ResponseInternalServerError500ProcessError(w, err) + // return + // } case "ims": switch action { case "start", "stop": diff --git a/features/cm/param.go b/features/cm/param.go index 532dcad..275437c 100644 --- a/features/cm/param.go +++ b/features/cm/param.go @@ -3,7 +3,7 @@ package cm import ( "strings" - "nms_cxy/lib/core/utils/ctx" + "nms_cxy/lib/core/ctx" "nms_cxy/lib/global" "nms_cxy/lib/log" "nms_cxy/lib/services" @@ -13,6 +13,7 @@ import ( "fmt" "io" "net/http" + neService "nms_cxy/src/modules/network_element/service" "github.com/go-resty/resty/v2" @@ -41,7 +42,7 @@ func GetParamConfigFromNF(w http.ResponseWriter, r *http.Request) { neInfo := neService.NewNeInfoImpl.SelectNeInfoByNeTypeAndNeID(neType, neId) var response services.DataResponse - if neInfo.NeId == neId { + if neInfo.NeId == neId && neInfo.NeId != "" { requestURI2NF := fmt.Sprintf("http://%s:%v%s", neInfo.IP, neInfo.Port, r.RequestURI) log.Debug("requestURI2NF:", requestURI2NF) @@ -77,7 +78,7 @@ func PostParamConfigToNF(w http.ResponseWriter, r *http.Request) { neInfo := neService.NewNeInfoImpl.SelectNeInfoByNeTypeAndNeID(neType, neId) - if neInfo.NeId != neId { + if neInfo.NeId != neId || neInfo.NeId == "" { log.Error("neId is empty") services.ResponseInternalServerError500DatabaseOperationFailed(w) return @@ -129,7 +130,7 @@ func PutParamConfigToNF(w http.ResponseWriter, r *http.Request) { neId := ctx.GetQuery(r, "ne_id") neInfo := neService.NewNeInfoImpl.SelectNeInfoByNeTypeAndNeID(neType, neId) - if neInfo.NeId != neId { + if neInfo.NeId != neId || neInfo.NeId == "" { log.Error("neId is empty") services.ResponseInternalServerError500DatabaseOperationFailed(w) return @@ -182,7 +183,7 @@ func DeleteParamConfigToNF(w http.ResponseWriter, r *http.Request) { neId := ctx.GetQuery(r, "ne_id") neInfo := neService.NewNeInfoImpl.SelectNeInfoByNeTypeAndNeID(neType, neId) - if neInfo.NeId != neId { + if neInfo.NeId != neId || neInfo.NeId == "" { log.Error("neId is empty") services.ResponseInternalServerError500DatabaseOperationFailed(w) return diff --git a/features/cm/software.go b/features/cm/software.go index 2347ab5..2d28356 100644 --- a/features/cm/software.go +++ b/features/cm/software.go @@ -20,9 +20,9 @@ import ( ) const ( - SoftwareStatusUploaded = "Uploaded" - SoftwareStatusInactive = "Inactive" - SoftwareStatusActive = "Active" + SoftwareStatusUploaded = "3" + SoftwareStatusInactive = "3" + SoftwareStatusActive = "1" DigestsSignOkString = "digests signatures OK" SoftwareVerifiedOk = "Verified OK" ) @@ -213,6 +213,17 @@ func UploadSoftwareMultiFile(w http.ResponseWriter, r *http.Request) { services.ResponseNotFound404UriNotExist(w, r) return } + + sql := fmt.Sprintf("select * from ne_software where ne_type='%s' and version='%s'", neTypeUpper, version) + neSoftwareInfo, _ := dborm.XormGetDataBySQL(sql) + if len(*neSoftwareInfo) >= 1 { + services.ResponseWithJson(w, 200, map[string]any{ + "code": 0, + "msg": "Software version already exists", + }) + return + } + md5Param := services.GetUriParamString(r, "md5Sum", ",", false, false) softwarePath := fmt.Sprintf("%s/%s", config.GetYamlConfig().OMC.Software, neTypeLower) @@ -314,7 +325,7 @@ func UploadSoftwareMultiFile(w http.ResponseWriter, r *http.Request) { result := verify_signature(config.GetYamlConfig().Auth.PublicKey, cmsFilePath, rpmFilePath) log.Debug("result:", result.String()) if !strings.Contains(result.String(), SoftwareVerifiedOk) { - err := global.ErrCMNotMatchSignFile + err = global.ErrCMNotMatchSignFile log.Error(err) services.ResponseInternalServerError500ProcessError(w, err) return @@ -408,7 +419,7 @@ func DownloadSoftwareFile(w http.ResponseWriter, r *http.Request) { return } - fileName := (*neSoftware)[0]["file_name"] + fileName := (*neSoftware)[0]["name"] path := (*neSoftware)[0]["path"] md5Sum := (*neSoftware)[0]["md5_sum"] @@ -462,7 +473,7 @@ func DeleteSoftwareFile(w http.ResponseWriter, r *http.Request) { return } - fileName := (*neSoftware)[0]["file_name"] + fileName := (*neSoftware)[0]["name"] path := (*neSoftware)[0]["path"] filePath := fmt.Sprintf("%s/%s", path, fileName) err = os.Remove(filePath) @@ -549,7 +560,7 @@ func DistributeSoftwareToNF(w http.ResponseWriter, r *http.Request) { return } - fileName := (*neSoftware)[0]["file_name"] + fileName := (*neSoftware)[0]["name"] path := (*neSoftware)[0]["path"] srcFile := fmt.Sprintf("%s/%s", path, fileName) @@ -600,7 +611,7 @@ func DistributeSoftwareToNF(w http.ResponseWriter, r *http.Request) { Version: (*neSoftware)[0]["version"], FilePath: fmt.Sprintf("%s/software/%s/%s", config.GetYamlConfig().NE.OmcDir, neTypeLower, fileName), PreVersion: (*neVersion)[0]["version"], - PreFile: (*neVersion)[0]["file_path"], + PreFile: (*neVersion)[0]["path"], Status: SoftwareStatusInactive, } @@ -684,21 +695,29 @@ func ActiveSoftwareToNF(w http.ResponseWriter, r *http.Request) { log.Trace("neVersion:", neVersion) if !config.GetYamlConfig().OMC.TestMode { - filePath := (*neVersion)[0]["file_path"] + filePath := (*neVersion)[0]["path"] sshHost := fmt.Sprintf("%s@%s", config.GetYamlConfig().NE.User, neInfo.Ip) - srcFile := fmt.Sprintf("%s/actpkg.sh", config.GetYamlConfig().OMC.BinDir) + runCmd := fmt.Sprintf("sudo rm -f %s/actpkg.sh", config.GetYamlConfig().NE.ScpDir) + err = RunSSHCmd(sshHost, runCmd) + if err != nil { + log.Errorf("Failed to run cmd: %s", runCmd) + services.ResponseInternalServerError500ProcessError(w, err) + return + } + + srcFile := fmt.Sprintf("%s/actpkg.sh", config.GetYamlConfig().OMC.BinDir) scpDir := fmt.Sprintf("%s@%s:%s", config.GetYamlConfig().NE.User, neInfo.Ip, config.GetYamlConfig().NE.ScpDir) cmd := exec.Command("scp", "-r", srcFile, scpDir) _, err := cmd.CombinedOutput() if err != nil { - log.Errorf("Faile to scp NF: neType=%s, neId=%s, ip=%s", neType, neId, neInfo.Ip) + log.Errorf("Failed to scp NF: neType=%s, neId=%s, ip=%s", neType, neId, neInfo.Ip) services.ResponseInternalServerError500ProcessError(w, err) return } - runCmd := fmt.Sprintf("sudo %s/actpkg.sh '%s' %s", + runCmd = fmt.Sprintf("sudo %s/actpkg.sh '%s' %s", config.GetYamlConfig().NE.ScpDir, filePath, neTypeUpper) if neTypeLower == "omc" { idNeVersion, _ := strconv.Atoi((*neVersion)[0]["id"]) @@ -886,6 +905,14 @@ func RollBackSoftwareToNF(w http.ResponseWriter, r *http.Request) { if !config.GetYamlConfig().OMC.TestMode { sshHost := fmt.Sprintf("%s@%s", config.GetYamlConfig().NE.User, neInfo.Ip) + runCmd := fmt.Sprintf("sudo rm -f %s/rbkpkg.sh", config.GetYamlConfig().NE.ScpDir) + err = RunSSHCmd(sshHost, runCmd) + if err != nil { + log.Errorf("Failed to run cmd: %s", runCmd) + services.ResponseInternalServerError500ProcessError(w, err) + return + } + srcFile := fmt.Sprintf("%s/rbkpkg.sh", config.GetYamlConfig().OMC.BinDir) scpDir := fmt.Sprintf("%s@%s:%s", config.GetYamlConfig().NE.User, @@ -898,7 +925,7 @@ func RollBackSoftwareToNF(w http.ResponseWriter, r *http.Request) { return } - runCmd := fmt.Sprintf("sudo %s/rbkpkg.sh '%s' %s", + runCmd = fmt.Sprintf("sudo %s/rbkpkg.sh '%s' %s", config.GetYamlConfig().NE.ScpDir, filePath, neTypeUpper) if neTypeLower == "omc" { idNeVersion, _ := strconv.Atoi((*neVersion)[0]["id"]) @@ -908,7 +935,7 @@ func RollBackSoftwareToNF(w http.ResponseWriter, r *http.Request) { PreVersion: "-", PreFile: "-", NewVersion: (*neVersion)[0]["version"], - NewFile: (*neVersion)[0]["file_path"], + NewFile: (*neVersion)[0]["path"], Status: SoftwareStatusActive, } @@ -919,7 +946,7 @@ func RollBackSoftwareToNF(w http.ResponseWriter, r *http.Request) { return } services.ResponseStatusOK204NoContent(w) - RunSSHCmd(sshHost, runCmd) + go RunSSHCmd(sshHost, runCmd) return } err = RunSSHCmd(sshHost, runCmd) @@ -1010,7 +1037,7 @@ func RollBackSoftwareToNF(w http.ResponseWriter, r *http.Request) { PreVersion: "-", PreFile: "-", NewVersion: (*neVersion)[0]["version"], - NewFile: (*neVersion)[0]["file_path"], + NewFile: (*neVersion)[0]["path"], Status: SoftwareStatusActive, } diff --git a/features/dbrest/dbrest.go b/features/dbrest/dbrest.go index 44fbd55..729b7f1 100644 --- a/features/dbrest/dbrest.go +++ b/features/dbrest/dbrest.go @@ -9,7 +9,7 @@ import ( "strings" "time" - "nms_cxy/lib/core/utils/ctx" + "nms_cxy/lib/core/ctx" "nms_cxy/lib/dborm" "nms_cxy/lib/global" "nms_cxy/lib/log" @@ -77,18 +77,20 @@ type DatabaseClient struct { var DbClient DatabaseClient -func InitDbClient(dbType, dbUser, dbPassword, dbHost, dbPort, dbName string) error { - DbClient.dbUrl = fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8mb4&collation=utf8mb4_general_ci&parseTime=true&loc=Local", - dbUser, dbPassword, dbHost, dbPort, dbName) +func InitDbClient(dbType, dbUser, dbPassword, dbHost, dbPort, dbName, dbParam string) error { + // DbClient.dbUrl = fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8mb4&collation=utf8mb4_general_ci&parseTime=true&loc=Local", + // dbUser, dbPassword, dbHost, dbPort, dbName) + DbClient.dbUrl = fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?%s", + dbUser, dbPassword, dbHost, dbPort, dbName, dbParam) DbClient.dbType = dbType DbClient.dbConnMaxLifetime = 0 DbClient.dbMaxIdleConns = 0 DbClient.dbMaxOpenConns = 0 + if log.GetLevel() == log.LOG_TRACE { DbClient.IsShowSQL = true } - log.Debugf("dbType:%s dbUrl:%s:******@tcp(%s:%s)/%s??charset=utf8mb4&collation=utf8mb4_general_ci&parseTime=true&loc=Local", - dbType, dbUser, dbHost, dbPort, dbName) + log.Debugf("dbType:%s dbUrl:%s:", dbType, DbClient.dbUrl) var err error DbClient.XEngine, err = xorm.NewEngine(DbClient.dbType, DbClient.dbUrl) @@ -99,6 +101,8 @@ func InitDbClient(dbType, dbUser, dbPassword, dbHost, dbPort, dbName string) err DbClient.XEngine.SetConnMaxLifetime(DbClient.dbConnMaxLifetime) DbClient.XEngine.SetMaxIdleConns(DbClient.dbMaxIdleConns) DbClient.XEngine.SetMaxOpenConns(DbClient.dbMaxOpenConns) + DbClient.XEngine.DatabaseTZ = time.Local // 必须 + DbClient.XEngine.TZLocation = time.Local // 必须 if DbClient.IsShowSQL { //DbClient.XEngine.SetLogger(&log.Elogger) DbClient.XEngine.ShowSQL(true) @@ -188,13 +192,13 @@ func ExtDatabaseExecSQL(w http.ResponseWriter, r *http.Request) { log.Debug("ExtDatabaseExecSQL processing... ") var sql []string - var err error + // var err error - _, err = services.CheckExtValidRequest(w, r) - if err != nil { - log.Error("Request error:", err) - return - } + // _, err = services.CheckExtValidRequest(w, r) + // if err != nil { + // log.Error("Request error:", err) + // return + // } //vars := mux.Vars(r) //tblName := vars["objectTypeValue"] @@ -249,11 +253,11 @@ func ExtDatabaseGetData(w http.ResponseWriter, r *http.Request) { log.Debug("ExtDatabaseGetData processing... ") var sql []string - token, err := services.CheckExtValidRequest(w, r) - if err != nil { - log.Error("Request error:", err) - return - } + // token, err := services.CheckExtValidRequest(w, r) + // if err != nil { + // log.Error("Request error:", err) + // return + // } pack := "dbrest" vars := mux.Vars(r) @@ -261,7 +265,7 @@ func ExtDatabaseGetData(w http.ResponseWriter, r *http.Request) { dbname := vars["elementTypeValue"] tbname := vars["objectTypeValue"] - log.Debugf("token:%s, method:%s, module:%s, dbname:%s, tbname:%s, pack:%s", token, r.Method, module, dbname, tbname, pack) + log.Debugf("method:%s, module:%s, dbname:%s, tbname:%s, pack:%s", r.Method, module, dbname, tbname, pack) // exist, err := services.CheckUserPermission(token, strings.ToLower(r.Method), module, dbname, tbname, pack) // if err != nil { @@ -295,12 +299,11 @@ func ExtDatabaseGetData(w http.ResponseWriter, r *http.Request) { for i, s := range sql { log.Tracef("SQL[%d]: %s", i, sql[i]) - rows := make([]map[string]interface{}, 0) mapRows := make(map[string]interface{}) if s != "" { // err = XEngine.SQL(s).Find(&rows) - if IsQuerySQL(s) == false { + if !IsQuerySQL(s) { services.ResponseNotAcceptable406QuerySQLError(w) return } @@ -310,7 +313,7 @@ func ExtDatabaseGetData(w http.ResponseWriter, r *http.Request) { querySQL = querySQL + " " + ls } log.Debug("querySQL:", querySQL) - rows, err = DbClient.XEngine.QueryInterface(querySQL) + rows, err := DbClient.XEngine.QueryInterface(querySQL) if err != nil { log.Error("SQL failed:", err) services.ResponseInternalServerError500DatabaseOperationFailed(w) @@ -332,11 +335,11 @@ func ExtDatabaseGetData(w http.ResponseWriter, r *http.Request) { func ExtDatabaseInsertData(w http.ResponseWriter, r *http.Request) { log.Debug("ExtDatabaseInsertData processing... ") - token, err := services.CheckExtValidRequest(w, r) - if err != nil { - log.Error("Request error:", err) - return - } + // token, err := services.CheckExtValidRequest(w, r) + // if err != nil { + // log.Error("Request error:", err) + // return + // } body, err := io.ReadAll(io.LimitReader(r.Body, global.RequestBodyMaxLen)) //io.LimitReader限制大小 if err != nil { @@ -351,7 +354,7 @@ func ExtDatabaseInsertData(w http.ResponseWriter, r *http.Request) { tbname := vars["objectTypeValue"] pack := "dbrest" - log.Debugf("token:%s, method:%s, module:%s, dbname:%s, tbname:%s, pack:%s", token, r.Method, module, dbname, tbname, pack) + log.Debugf("method:%s, module:%s, dbname:%s, tbname:%s, pack:%s", r.Method, module, dbname, tbname, pack) // exist, err := services.CheckUserPermission(token, strings.ToLower(r.Method), module, dbname, tbname, pack) // if err != nil { @@ -396,11 +399,11 @@ func ExtDatabaseInsertData(w http.ResponseWriter, r *http.Request) { func ExtDatabaseUpdateData(w http.ResponseWriter, r *http.Request) { log.Debug("ExtDatabaseUpdateData processing... ") - token, err := services.CheckExtValidRequest(w, r) - if err != nil { - log.Error("Request error:", err) - return - } + // token, err := services.CheckExtValidRequest(w, r) + // if err != nil { + // log.Error("Request error:", err) + // return + // } vars := mux.Vars(r) module := "" @@ -408,7 +411,7 @@ func ExtDatabaseUpdateData(w http.ResponseWriter, r *http.Request) { tbname := vars["objectTypeValue"] pack := "dbrest" - log.Debugf("token:%s, method:%s, module:%s, dbname:%s, tbname:%s, pack:%s", token, r.Method, module, dbname, tbname, pack) + log.Debugf("method:%s, module:%s, dbname:%s, tbname:%s, pack:%s", r.Method, module, dbname, tbname, pack) // exist, err := services.CheckUserPermission(token, strings.ToLower(r.Method), module, dbname, tbname, pack) // if err != nil { @@ -460,11 +463,11 @@ func ExtDatabaseUpdateData(w http.ResponseWriter, r *http.Request) { func ExtDatabaseDeleteData(w http.ResponseWriter, r *http.Request) { log.Debug("ExtDatabaseDeleteData processing... ") - token, err := services.CheckExtValidRequest(w, r) - if err != nil { - log.Error("Request error:", err) - return - } + // token, err := services.CheckExtValidRequest(w, r) + // if err != nil { + // log.Error("Request error:", err) + // return + // } vars := mux.Vars(r) module := "" @@ -472,7 +475,7 @@ func ExtDatabaseDeleteData(w http.ResponseWriter, r *http.Request) { tbname := vars["objectTypeValue"] pack := "dbreset" - log.Debugf("token:%s, method:%s, module:%, dbname:%s, tbname:%s pack:%s", token, r.Method, module, dbname, tbname, pack) + log.Debugf("method:%s, module:%, dbname:%s, tbname:%s pack:%s", r.Method, module, dbname, tbname, pack) // exist, err := services.CheckUserPermission(token, strings.ToLower(r.Method), module, dbname, tbname, pack) // if err != nil { @@ -548,7 +551,7 @@ func DatabaseGetData(w http.ResponseWriter, r *http.Request) { if s != "" { // err = XEngine.SQL(s).Find(&rows) - if IsQuerySQL(s) == false { + if !IsQuerySQL(s) { services.ResponseNotAcceptable406QuerySQLError(w) return } @@ -560,8 +563,8 @@ func DatabaseGetData(w http.ResponseWriter, r *http.Request) { log.Debug("querySQL:", querySQL) rows, err = DbClient.XEngine.QueryInterface(querySQL) if err != nil { - log.Error("SQL failed:", err) - services.ResponseInternalServerError500DatabaseOperationFailed(w) + log.Error("QueryInterface failed:", err) + services.ResponseInternalServerError500ProcessError(w, err) return } tableName := GetTableName(s) diff --git a/features/event/event.go b/features/event/event.go index 864c183..df43aff 100644 --- a/features/event/event.go +++ b/features/event/event.go @@ -2,27 +2,36 @@ package event import ( "encoding/json" + "fmt" "io" + "net/http" + "strings" "time" + "nms_cxy/lib/core/ctx" "nms_cxy/lib/dborm" "nms_cxy/lib/global" "nms_cxy/lib/log" "nms_cxy/lib/services" + "nms_cxy/omc/config" wsService "nms_cxy/src/modules/ws/service" "github.com/gin-gonic/gin" ) var ( - UriUEEvent = "/upload-ue/v1/:eventType" + // 走Gin + UriUEEventAMF = "/upload-ue/v1/:eventType" + // 走Mux + UriUEEvent = config.DefaultUriPrefix + "/logManagement/v1/elementType/{elementTypeValue}/objectType/ueEvent" + CustomUriUEEvent = config.UriPrefix + "/logManagement/v1/elementType/{elementTypeValue}/objectType/ueEvent" ) type UEEvent struct { NeType string `json:"neType" xorm:"ne_type"` NeName string `json:"neName" xorm:"ne_name"` RmUID string `json:"rmUID" xorm:"rm_uid"` - Timestamp int `json:"timestamp" xorm:"timestamp"` + Timestamp int64 `json:"timestamp" xorm:"timestamp"` EventType string `json:"eventType" xorm:"event_type"` EventJson map[string]any `json:"eventJSON" xorm:"event_json"` } @@ -52,13 +61,13 @@ func PostUEEventFromAMF(c *gin.Context) { return } ueEvent.NeType = "AMF" - ueEvent.Timestamp = int(time.Now().Unix()) + ueEvent.Timestamp = time.Now().Unix() ueEvent.EventType = eventType - log.Trace("ueEvent:", ueEvent) + log.Trace("ueEvent AMF:", ueEvent) - affected, err := dborm.XormInsertTableOne("ue_event", ueEvent) + affected, err := dborm.XormInsertTableOne("ue_event_amf", ueEvent) if err != nil && affected <= 0 { - log.Error("Failed to insert ue_event:", err) + log.Error("Failed to insert ue_event_amf:", err) services.ResponseInternalServerError500ProcessError(c.Writer, err) return } @@ -68,3 +77,30 @@ func PostUEEventFromAMF(c *gin.Context) { services.ResponseStatusOK204NoContent(c.Writer) } + +func PostUEEvent(w http.ResponseWriter, r *http.Request) { + log.Info("PostUEEvent processing... ") + + neType := ctx.GetParam(r, "elementTypeValue") + var ueEvent UEEvent + if err := ctx.ShouldBindJSON(r, &ueEvent); err != nil { + services.ResponseInternalServerError500ProcessError(w, err) + return + } + + ueEvent.NeType = strings.ToUpper(neType) + tableName := fmt.Sprintf("ue_event_%s", strings.ToLower(neType)) + affected, err := dborm.XormInsertTableOne(tableName, ueEvent) + if err != nil && affected <= 0 { + log.Error("Failed to insert "+tableName, err) + services.ResponseInternalServerError500ProcessError(w, err) + return + } + + // 推送到ws订阅组 + if ueEvent.NeType == "MME" { + wsService.NewWSSendImpl.ByGroupID(wsService.GROUP_MME_UE, ueEvent) + } + + services.ResponseStatusOK204NoContent(w) +} diff --git a/features/file/file.go b/features/file/file.go index 60f341c..603257c 100644 --- a/features/file/file.go +++ b/features/file/file.go @@ -5,7 +5,7 @@ import ( "net/http" "path/filepath" - "nms_cxy/lib/core/utils/ctx" + "nms_cxy/lib/core/ctx" "nms_cxy/lib/dborm" "nms_cxy/lib/file" "nms_cxy/lib/log" diff --git a/features/fm/alarm.go b/features/fm/alarm.go index 60aece3..7e857e7 100644 --- a/features/fm/alarm.go +++ b/features/fm/alarm.go @@ -15,9 +15,6 @@ import ( "nms_cxy/lib/log" "nms_cxy/lib/services" "nms_cxy/omc/config" - "nms_cxy/src/framework/utils/date" - neDataModel "nms_cxy/src/modules/network_data/model" - nmsCXYService "nms_cxy/src/modules/nms_cxy/service" "xorm.io/xorm" @@ -155,9 +152,9 @@ type DatabaseClient struct { var DbClient DatabaseClient -func InitDbClient(dbType, dbUser, dbPassword, dbHost, dbPort, dbName string) error { - DbClient.dbUrl = fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8mb4&collation=utf8mb4_general_ci&parseTime=true&loc=Local", - dbUser, dbPassword, dbHost, dbPort, dbName) +func InitDbClient(dbType, dbUser, dbPassword, dbHost, dbPort, dbName, dbParam string) error { + DbClient.dbUrl = fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?%s", + dbUser, dbPassword, dbHost, dbPort, dbName, dbParam) DbClient.dbType = dbType DbClient.dbConnMaxLifetime = 0 DbClient.dbMaxIdleConns = 0 @@ -165,8 +162,7 @@ func InitDbClient(dbType, dbUser, dbPassword, dbHost, dbPort, dbName string) err if log.GetLevel() == log.LOG_TRACE { DbClient.IsShowSQL = true } - log.Debugf("dbType:%s dbUrl:%s:******@tcp(%s:%s)/%s??charset=utf8mb4&collation=utf8mb4_general_ci&parseTime=true&loc=Local", - dbType, dbUser, dbHost, dbPort, dbName) + log.Debugf("dbType:%s dbUrl:%s:", dbType, DbClient.dbUrl) var err error DbClient.XEngine, err = xorm.NewEngine(DbClient.dbType, DbClient.dbUrl) @@ -177,6 +173,8 @@ func InitDbClient(dbType, dbUser, dbPassword, dbHost, dbPort, dbName string) err DbClient.XEngine.SetConnMaxLifetime(DbClient.dbConnMaxLifetime) DbClient.XEngine.SetMaxIdleConns(DbClient.dbMaxIdleConns) DbClient.XEngine.SetMaxOpenConns(DbClient.dbMaxOpenConns) + DbClient.XEngine.DatabaseTZ = time.Local // 必须 + DbClient.XEngine.TZLocation = time.Local // 必须 if DbClient.IsShowSQL { DbClient.XEngine.ShowSQL(true) } @@ -287,9 +285,6 @@ func PostAlarmFromNF(w http.ResponseWriter, r *http.Request) { services.ResponseInternalServerError500DatabaseOperationFailed(w) continue } - - // - pushKafka(alarmData) } else { affected, err := session.Where("ne_type=? and ne_id=? and alarm_id=? and alarm_status=1", alarmData.NeType, alarmData.NeId, alarmData.AlarmId). Cols("alarm_status", "clear_type", "clear_time"). @@ -299,9 +294,6 @@ func PostAlarmFromNF(w http.ResponseWriter, r *http.Request) { services.ResponseInternalServerError500DatabaseOperationFailed(w) continue } - - // - pushKafka(alarmData) } log.Trace("alarmData:", alarmData) var currentSeq string @@ -444,11 +436,20 @@ func PostAlarmFromNF(w http.ResponseWriter, r *http.Request) { SetAlarmAckInfo(valueJson, &alarmData) } log.Debug("alarmData:", alarmData) - affected, err := session.Insert(alarmData) - if err != nil && affected <= 0 { - log.Error("Failed to insert alarm data:", err) - services.ResponseInternalServerError500DatabaseOperationFailed(w) - continue + if alarmData.OrigSeverity == "Event" && config.GetYamlConfig().Alarm.SplitEventAlarm { + affected, err := xEngine.Table("alarm_event").InsertOne(alarmData) + if err != nil && affected <= 0 { + log.Error("Failed to insert alarm_event:", err) + services.ResponseInternalServerError500ProcessError(w, err) + continue + } + } else { + affected, err := session.Insert(alarmData) + if err != nil && affected <= 0 { + log.Error("Failed to insert alarm data:", err) + services.ResponseInternalServerError500DatabaseOperationFailed(w) + continue + } } alarmLog := new(AlarmLog) alarmLog.NeType = alarmData.NeType @@ -460,21 +461,18 @@ func PostAlarmFromNF(w http.ResponseWriter, r *http.Request) { alarmLog.EventTime = eventTime log.Trace("alarmLog:", alarmLog) - affected, err = session.Insert(alarmLog) + affected, err := session.Insert(alarmLog) if err != nil && affected <= 0 { log.Error("Failed to insert alarm_log:", err) } session.Commit() - - // - pushKafka(alarmData) } if config.GetYamlConfig().Alarm.ForwardAlarm { if err = AlarmEmailForward(&alarmData); err != nil { log.Error("Failed to AlarmEmailForward:", err) } - if err = AlarmForwardBySMSC(&alarmData); err != nil { - log.Error("Failed to AlarmForwardBySMSC:", err) + if err = AlarmSMSForward(&alarmData); err != nil { + log.Error("Failed to AlarmSMSForward:", err) } } } @@ -482,25 +480,26 @@ func PostAlarmFromNF(w http.ResponseWriter, r *http.Request) { services.ResponseStatusOK200Null(w) } -// pushKafka 告警推送kafka -func pushKafka(alarmData Alarm) { - neAlarm := neDataModel.Alarm{ - AlarmSeq: fmt.Sprint(alarmData.AlarmSeq), - AlarmTitle: alarmData.AlarmTitle, - AlarmStatus: fmt.Sprint(alarmData.AlarmStatus), - AlarmType: alarmData.AlarmType, - OrigSeverity: alarmData.OrigSeverity, - EventTime: date.ParseStrToDate(alarmData.EventTime, date.YYYY_MM_DD_HH_MM_SS), - ID: alarmData.AlarmId, - AlarmCode: fmt.Sprint(alarmData.AlarmCode), - SpecificProblem: alarmData.SpecificProblem, - ObjectUid: alarmData.ObjectUid, - NeName: alarmData.NeName, - AlarmId: alarmData.ObjectUid, - ObjectName: alarmData.ObjectName, - AddInfo: alarmData.AddInfo, - } - nmsCXYService.NewAlarmImpl.KafkaPush(neAlarm) +type AlarmEvent struct { + AlarmSeq int `json:"alarmSeq"` + AlarmId string `json:"alarmId" xorm:"alarm_id"` + NeId string `json:"neId"` + AlarmCode int `json:"alarmCode"` + AlarmTitle string `json:"alarmTitle"` + EventTime string `json:"eventTime"` + AlarmType string `json:"alarmType"` + OrigSeverity string `json:"origSeverity"` + PVFlag string `json:"pvFlag" xorm:"pv_flag"` + NeName string `json:"neName"` + NeType string `json:"neType"` + ObjectUid string `json:"objectUid" xorm:"object_uid"` + ObjectName string `json:"objectName" xorm:"object_name"` + ObjectType string `json:"objectType" xorm:"object_type"` + LocationInfo string `json:"locationInfo"` + Province string `json:"province"` + SpecificProblem string `json:"specificProblem"` + SpecificProblemID string `json:"specificProblemID" xorm:"specific_problem_id"` + AddInfo string `json:"addInfo"` } // process alarm get from NFs @@ -768,8 +767,8 @@ func GetAlarmFromNF(w http.ResponseWriter, r *http.Request) { if err = AlarmEmailForward(&alarmData); err != nil { log.Error("Failed to AlarmEmailForward:", err) } - if err = AlarmForwardBySMSC(&alarmData); err != nil { - log.Error("Failed to AlarmForwardBySMSC:", err) + if err = AlarmSMSForward(&alarmData); err != nil { + log.Error("Failed to AlarmSMSForward:", err) } } } diff --git a/features/fm/smsforward.go b/features/fm/smsforward.go index 8e277ad..4746436 100644 --- a/features/fm/smsforward.go +++ b/features/fm/smsforward.go @@ -5,6 +5,7 @@ import ( "fmt" "net/http" "net/url" + "strings" "time" "nms_cxy/lib/dborm" @@ -16,7 +17,24 @@ import ( "github.com/linxGnu/gosmpp/pdu" ) -func AlarmForwardBySMS(alarmData *Alarm) error { +func AlarmSMSForward(alarmData *Alarm) error { + switch config.GetYamlConfig().Alarm.SMProxy { + case "sms": + users, err := AlarmForwardBySMS(alarmData) + writeLog(alarmData, users, "SMS", err) + return err + case "smsc": + users, err := AlarmForwardBySMPP(alarmData) + writeLog(alarmData, users, "SMS", err) + return err + default: + users, err := AlarmForwardBySMPP(alarmData) + writeLog(alarmData, users, "SMS", err) + return err + } +} + +func AlarmForwardBySMS(alarmData *Alarm) (string, error) { log.Info("AlarmForwardBySMS processing... ") SMSFforwardconfig := config.GetYamlConfig().Alarm.SMS @@ -30,91 +48,74 @@ func AlarmForwardBySMS(alarmData *Alarm) error { toUsers, err := dborm.XormGetAlarmForward("SMS") if err != nil { log.Error("Failed to XormGetAlarmForward:", err) - return err + return "", err } else if toUsers == nil { err := errors.New("not found forward phone number") log.Error(err) - return err + return "", err + } + userList := strings.Join(*toUsers, ",") + + // 短信相关参数 + params := url.Values{} + params.Set("PhoneNumbers", userList) + params.Set("SignName", SMSFforwardconfig.SignName) + params.Set("TemplateCode", SMSFforwardconfig.TemplateCode) + params.Set("TemplateParam", `{"message":"alarm"}`) + + // 构建请求URL + reqURL := apiURL + "?Action=SendSms&" + params.Encode() + + // 创建HTTP请求 + req, err := http.NewRequest("GET", reqURL, nil) + if err != nil { + log.Error("Failed to create request:", err) + return userList, err } - for _, toUser := range *toUsers { - // 短信相关参数 - params := url.Values{} - params.Set("PhoneNumbers", toUser) - params.Set("SignName", SMSFforwardconfig.SignName) - params.Set("TemplateCode", SMSFforwardconfig.TemplateCode) - params.Set("TemplateParam", `{"message":"alarm"}`) + // 添加请求头部 + req.Header.Set("Content-Type", "application/x-www-form-urlencoded") + req.Header.Set("Authorization", "APPCODE "+accessKeySecret) - // 构建请求URL - reqURL := apiURL + "?Action=SendSms&" + params.Encode() - - // 创建HTTP请求 - req, err := http.NewRequest("GET", reqURL, nil) - if err != nil { - log.Error("Failed to create request:", err) - return err - } - - // 添加请求头部 - req.Header.Set("Content-Type", "application/x-www-form-urlencoded") - req.Header.Set("Authorization", "APPCODE "+accessKeySecret) - - forwardLog := &dborm.AlarmForwardLog{ - NeType: alarmData.NeType, - NeID: alarmData.NeId, - AlarmID: alarmData.AlarmId, - AlarmTitle: alarmData.AlarmTitle, - AlarmSeq: alarmData.AlarmSeq, - EventTime: alarmData.EventTime, - ToUser: toUser, - } - // 发送请求 - client := &http.Client{} - resp, err := client.Do(req) - if err != nil { - operResult := fmt.Sprintf("Failed to send request:%v", err) - log.Error(operResult) - forwardLog.OperResult = operResult - affected, err := dborm.XormInsertAlarmForwardLog(forwardLog) - if err != nil && affected <= 0 { - log.Error("Failed to insert data:", err) - } - continue - } - defer resp.Body.Close() - - // 解析响应 - if resp.StatusCode == http.StatusOK { - operResult := "SMS sent successfully!" - log.Info(operResult) - forwardLog.OperResult = operResult - affected, err := dborm.XormInsertAlarmForwardLog(forwardLog) - if err != nil && affected <= 0 { - log.Error("Failed to insert data:", err) - continue - } - } else { - operResult := fmt.Sprintf("Failed to send SMS, StatusCode=%d", resp.StatusCode) - log.Error(operResult) - forwardLog.OperResult = operResult - affected, err := dborm.XormInsertAlarmForwardLog(forwardLog) - if err != nil && affected <= 0 { - log.Error("Failed to insert data:", err) - continue - } - } + // 发送请求 + client := &http.Client{} + resp, err := client.Do(req) + if err != nil { + log.Error("Failed to send request:%v", err) + return userList, err + } + defer resp.Body.Close() + + // 解析响应 + switch resp.StatusCode { + case http.StatusOK, http.StatusAccepted, http.StatusNoContent, http.StatusCreated: + return userList, nil + default: + err := fmt.Errorf("Failed to send SMS: %s(Code=%d)", resp.Status, resp.StatusCode) + log.Error(err) + return userList, err } - return nil } -func AlarmForwardBySMPP(alarmData *Alarm) error { +func AlarmForwardBySMPP(alarmData *Alarm) (string, error) { log.Info("AlarmForwardBySMPP processing... ") + toUsers, err := dborm.XormGetAlarmForward("SMS") + if err != nil { + log.Error("Failed to XormGetAlarmForward:", err) + return "", err + } else if toUsers == nil { + err := errors.New("not found forward phone number") + log.Error(err) + return "", err + } + userList := strings.Join(*toUsers, ",") + auth := gosmpp.Auth{ SMSC: config.GetYamlConfig().Alarm.SMSC.Addr, - SystemID: config.GetYamlConfig().Alarm.SMSC.UserName, + SystemID: config.GetYamlConfig().Alarm.SMSC.SystemID, Password: config.GetYamlConfig().Alarm.SMSC.Password, - SystemType: "", + SystemType: config.GetYamlConfig().Alarm.SMSC.SystemType, } // conn, err := gosmpp.NonTLSDialer(auth.SMSC) @@ -142,49 +143,50 @@ func AlarmForwardBySMPP(alarmData *Alarm) error { }, }, -1) if err != nil { - log.Error(err) - return err + log.Error("Failed to create SMPP new session:", err) + return userList, err } defer func() { _ = trans.Close() }() - toUsers, err := dborm.XormGetAlarmForward("SMS") - if err != nil { - log.Error("Failed to XormGetAlarmForward:", err) - return err - } else if toUsers == nil { - err := errors.New("not found forward phone number") - log.Error(err) - return err - } // sending SMS(s) - for _, toUser := range *toUsers { - forwardLog := &dborm.AlarmForwardLog{ - NeType: alarmData.NeType, - NeID: alarmData.NeId, - AlarmID: alarmData.AlarmId, - AlarmTitle: alarmData.AlarmTitle, - AlarmSeq: alarmData.AlarmSeq, - EventTime: alarmData.EventTime, - ToUser: toUser, - } - message := alarmData.AlarmTitle + "from" + alarmData.NeType + alarmData.NeId + "at" + alarmData.EventTime - if err = trans.Transceiver().Submit(newSubmitSM(toUser, message)); err != nil { - operResult := fmt.Sprintf("Failed to submit short message:%v", err) - log.Error(operResult) - forwardLog.OperResult = operResult - } else { - operResult := "SMS sent successfully!" - log.Trace(operResult) - forwardLog.OperResult = operResult - } + // var results []string + // for _, toUser := range *toUsers { + message := "Alarm Notification: " + alarmData.AlarmTitle + " from " + alarmData.NeType + " " + alarmData.NeId + " at " + alarmData.EventTime + if err = trans.Transceiver().Submit(newSubmitSM(userList, message)); err != nil { + // result := fmt.Sprintf("Failed to submit %s hort message:%s", toUser, err.Error()) + // results = append(results, result) + log.Error("Failed to submit hort message:", err) + return userList, err + } + // } + return userList, nil +} - affected, err := dborm.XormInsertAlarmForwardLog(forwardLog) - if err != nil && affected <= 0 { - log.Error("Failed to insert data:", err) - continue - } +func writeLog(alarmData *Alarm, toUser, forwardBy string, err error) error { + var result string + if err == nil { + result = "SMS sent successfully" + } else { + result = err.Error() + } + forwardLog := &dborm.AlarmForwardLog{ + NeType: alarmData.NeType, + NeID: alarmData.NeId, + AlarmID: alarmData.AlarmId, + AlarmTitle: alarmData.AlarmTitle, + AlarmSeq: alarmData.AlarmSeq, + EventTime: alarmData.EventTime, + Interface: forwardBy, + ToUser: toUser, + OperResult: result, + } + + affected, err := dborm.XormInsertAlarmForwardLog(forwardLog) + if err != nil && affected <= 0 { + log.Error("Failed to insert data:", err) + return err } return nil } diff --git a/features/fm/ucpcli.go b/features/fm/ucpcli.go deleted file mode 100644 index 9e34a86..0000000 --- a/features/fm/ucpcli.go +++ /dev/null @@ -1,61 +0,0 @@ -package fm - -import ( - "fmt" - "strings" - - "nms_cxy/lib/log" - "nms_cxy/omc/config" - - "github.com/chzyer/readline" - "github.com/go-gsm/ucp" -) - -func AlarmForwardBySMSC(alarmData *Alarm) error { - opt := &ucp.Options{ - Addr: config.GetYamlConfig().Alarm.SMSC.Addr, - User: config.GetYamlConfig().Alarm.SMSC.UserName, - Password: config.GetYamlConfig().Alarm.SMSC.Password, - AccessCode: "", - } - - client := ucp.New(opt) - if err := client.Connect(); err != nil { - log.Error("Failed to connect:", err) - return err - } - defer client.Close() - - reader, _ := readline.New(">>> ") - defer reader.Close() - - for { - fmt.Print(">>> ") - lines, _ := reader.Readline() - fields := strings.Fields(lines) - - if len(fields) == 1 { - // exit CLI - if fields[0] == "exit" { - return nil - } - // display help message - if fields[0] == "help" { - log.Trace("\n\tSend a 'message' to 'receiver' with a 'sender' mask\n\t>>> sender receiver message\n\n\tExit the cli\n\t>>> exit\n") - } - } - - // sender receiver message... - if len(fields) >= 3 { - sender := fields[0] - receiver := fields[1] - message := strings.Join(fields[2:], " ") - ids, err := client.Send(sender, receiver, message) - if err != nil { - log.Error(err) - } else { - log.Debug("%v", ids) - } - } - } -} diff --git a/features/handle/handle.go b/features/handle/handle.go index eb3bcf3..a037c04 100644 --- a/features/handle/handle.go +++ b/features/handle/handle.go @@ -45,7 +45,7 @@ type ApiResponse struct { ResultMessage interface{} } -var globalSession = session.NewSessManager("omc") +var globalSession = session.NewSessManager("restagent") func init() { conf := config.GetYamlConfig() diff --git a/features/lm/logbak.go b/features/lm/logbak.go index 77ea3c4..1de8658 100644 --- a/features/lm/logbak.go +++ b/features/lm/logbak.go @@ -50,9 +50,9 @@ var DbClient DatabaseClient // conf.Database.Host, conf.Database.Port, conf.Database.Name) // } -func InitDbClient(dbType, dbUser, dbPassword, dbHost, dbPort, dbName string) error { - DbClient.dbUrl = fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8mb4&collation=utf8mb4_general_ci&parseTime=true&loc=Local", - dbUser, dbPassword, dbHost, dbPort, dbName) +func InitDbClient(dbType, dbUser, dbPassword, dbHost, dbPort, dbName, dbParam string) error { + DbClient.dbUrl = fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?%s", + dbUser, dbPassword, dbHost, dbPort, dbName, dbParam) DbClient.dbType = dbType DbClient.dbConnMaxLifetime = 0 DbClient.dbMaxIdleConns = 0 @@ -60,8 +60,7 @@ func InitDbClient(dbType, dbUser, dbPassword, dbHost, dbPort, dbName string) err if log.GetLevel() == log.LOG_TRACE { DbClient.IsShowSQL = true } - log.Debugf("dbType:%s dbUrl:%s:******@tcp(%s:%s)/%s??charset=utf8mb4&collation=utf8mb4_general_ci&parseTime=true&loc=Local", - dbType, dbUser, dbHost, dbPort, dbName) + log.Debugf("dbType:%s dbUrl:%s:", dbType, DbClient.dbUrl) var err error DbClient.XEngine, err = xorm.NewEngine(DbClient.dbType, DbClient.dbUrl) @@ -72,6 +71,8 @@ func InitDbClient(dbType, dbUser, dbPassword, dbHost, dbPort, dbName string) err DbClient.XEngine.SetConnMaxLifetime(DbClient.dbConnMaxLifetime) DbClient.XEngine.SetMaxIdleConns(DbClient.dbMaxIdleConns) DbClient.XEngine.SetMaxOpenConns(DbClient.dbMaxOpenConns) + DbClient.XEngine.DatabaseTZ = time.Local // 必须 + DbClient.XEngine.TZLocation = time.Local // 必须 if DbClient.IsShowSQL { DbClient.XEngine.ShowSQL(true) } @@ -83,18 +84,18 @@ func InitDbClient(dbType, dbUser, dbPassword, dbHost, dbPort, dbName string) err func ExtDatabaseBackupData(w http.ResponseWriter, r *http.Request) { log.Debug("ExtDatabaseBackupData processing... ") - token, err := services.CheckExtValidRequest(w, r) - if err != nil { - log.Error("Request error:", err) - return - } + // token, err := services.CheckExtValidRequest(w, r) + // if err != nil { + // log.Error("Request error:", err) + // return + // } vars := mux.Vars(r) module := vars["managementModule"] dbname := vars["dataStorage"] tbname := vars["dataObject"] pack := "lm" - log.Debugf("token:%s, method:%s, module:%s dbname:%s, tbname:%s pack:%s", token, r.Method, module, dbname, tbname, pack) + log.Debugf("method:%s, module:%s dbname:%s, tbname:%s pack:%s", r.Method, module, dbname, tbname, pack) // exist, err := services.CheckUserPermission(token, strings.ToLower(r.Method), module, dbname, tbname, pack) // if err != nil { // log.Error("Failed to get permission:", err) diff --git a/features/maintenance/maintenance.go b/features/maintenance/maintenance.go deleted file mode 100644 index ff83490..0000000 --- a/features/maintenance/maintenance.go +++ /dev/null @@ -1,314 +0,0 @@ -package maintenance - -import ( - "encoding/json" - "fmt" - "net/http" - "os" - "os/exec" - "path" - "runtime" - "time" - - "nms_cxy/lib/core/utils/ctx" - "nms_cxy/lib/dborm" - "nms_cxy/lib/log" - "nms_cxy/lib/services" - "nms_cxy/omc/config" - - "github.com/shirou/gopsutil/cpu" - "github.com/shirou/gopsutil/disk" - "github.com/shirou/gopsutil/mem" -) - -// (1) OMC能够对相关的文件系统资源、内存、CPU资源、数据存储空间、数据库空间等系统指标进行监控管理; -// 对于虚拟化部署OMC系统,能够对虚机内存、虚机CPU、虚拟存储空间、文件系统资源、数据库空间等指标进行监控,提供界面截图 ; - -// (2) 系统监控指标的采样时间和阈值可由用户设定,超过阈值将产生不同级别的告警,提供界面截图 ; - -// (3) OMC能够方便的查询数据库连接情况;并可手工干预数据库的连接,能方便的终结非法的数据库连接 ; - -// (4) 用户能方便的查询系统进程、应用进程等的进程名、进程类型、开始时间、运行主机等信息,提供界面截图 -// (5) 用户能方便的对系统进程、应用进程等做中断或者启动操作,提供界面截图 - -// (6) 对于文件系统资源、内存、CPU资源、数据存储空间、数据库空间等系统指标数据,要求OMC能够保存至少3个月,提供界面截图 ; -// (7) 用户可以按照需求自定义报表模板并生成OMC系统维护数据报表,提供界面截图 ; - -// (8) OMC具备自身告警管理功能,对于传统OMC系统,如:服务器单电源告警,存储硬盘告警、OMC系统软件故障等; -// 对于虚拟化OMC系统,如虚机告警、虚拟硬盘告警等,提供界面截图 。 - -var ( - // parameter config management - Uri = config.UriPrefix + "/maintenance/{apiVersion}/zz" - - // (1) OMC能够对相关的文件系统资源、内存、CPU资源、数据存储空间、数据库空间等系统指标进行监控管理; - UriPref = config.UriPrefix + "/maintenance/{apiVersion}/pref" - - // (6) 对于文件系统资源、内存、CPU资源、数据存储空间、数据库空间等系统指标数据,要求OMC能够保存至少3个月,提供界面截图 ; - UriPrefLog = config.UriPrefix + "/maintenance/{apiVersion}/prefLog" - - // (2) 系统监控指标的采样时间和阈值可由用户设定,超过阈值将产生不同级别的告警,提供界面截图 ; - UriConfig = config.UriPrefix + "/maintenance/{apiVersion}/config" - - // (3) OMC能够方便的查询数据库连接情况;并可手工干预数据库的连接,能方便的终结非法的数据库连接 - UriSqlClient = config.UriPrefix + "/maintenance/{apiVersion}/sqlClient" - - // (4) 用户能方便的查询系统进程、应用进程等的进程名、进程类型、开始时间、运行主机等信息,提供界面截图 - // (5) 用户能方便的对系统进程、应用进程等做中断或者启动操作,提供界面截图 - UriTop = config.UriPrefix + "/maintenance/{apiVersion}/top" -) - -func init() { - // 定時收集 TODO - prefLogSave("") -} - -func List(w http.ResponseWriter, r *http.Request) { - fmt.Println("zz List") - services.ResponseStatusOK200Null(w) -} - -// 性能指標 -func prefInfo(dirName string) map[string]any { - data := make(map[string]any) - - // 显示文件資源目录 - dirPath := "D://" - if runtime.GOOS == "linux" { - dirPath = "/home" - } - // 訪問下級 - if dirName != "" { - dirPath = path.Join(dirPath, dirName) - } - dir_list, e := os.ReadDir(dirPath) - if e != nil { - log.Error(e) - } - list := make([]map[string]any, 0) - for _, v := range dir_list { - o, err := v.Info() - if err != nil { - continue - } - list = append(list, map[string]any{ - "name": o.Name(), - "size": o.Size(), - "mode": o.Mode().String(), - "modTime": o.ModTime().Format("2006-01-02 15:04:05"), - "isDir": o.IsDir(), - }) - } - data["dirList"] = list - - // 文件資源使用率 - u, _ := disk.Usage(dirPath) - usedGB := int(u.Used) / (1024 * 1024 * 1024 * 1) - data["dirUse"] = fmt.Sprintf("%d", usedGB) - - // CPU使用率 - percent, err := cpu.Percent(time.Second, false) - if err != nil { - log.Error(err) - } - data["cpuUse"] = fmt.Sprintf("%.2f", percent[0]) - - // 内存使用率 - memInfo, err := mem.VirtualMemory() - if err != nil { - log.Error(err) - } - data["memUse"] = memInfo.UsedPercent - - // 獲取數據庫占用空間 - if dborm.DbClient.XEngine != nil { - conf := config.GetYamlConfig() - result, err := dborm.DbClient.XEngine.QueryString(`SELECT - CONCAT(TRUNCATE(SUM(data_length)/1024/1024,2),'MB') AS data_size, - CONCAT(TRUNCATE(SUM(max_data_length)/1024/1024,2),'MB') AS max_data_size, - CONCAT(TRUNCATE(SUM(data_free)/1024/1024,2),'MB') AS data_free, - CONCAT(TRUNCATE(SUM(index_length)/1024/1024,2),'MB') AS index_size - FROM information_schema.tables WHERE TABLE_SCHEMA = ?; - `, conf.Database.Name) - if err == nil { - data["dbInfo"] = result[0] - } else { - data["dbInfo"] = map[string]string{} - } - } - return data -} - -// 性能指標存入數據庫 -func prefLogSave(dirName string) { - if dborm.DbClient.XEngine != nil { - data := prefInfo(dirName) - - dirListByte, err := json.Marshal(data["dirList"]) - if err != nil { - log.Error(err) - } - dbInfoByte, err := json.Marshal(data["dbInfo"]) - if err != nil { - log.Error(err) - } - rse, err := dborm.DbClient.XEngine.Exec(`INSERT INTO sys_perf_data - (id, create_time, dir_used, dir_list, db_info, mem_used, cpu_used) - VALUES(NULL, NOW(), ?, ?, ?, ?, ?); - `, data["dirUse"], string(dirListByte), string(dbInfoByte), data["memUse"], data["cpuUse"]) - if err != nil { - log.Error(err) - } - fmt.Println(rse.LastInsertId()) - } -} - -// GET http://192.168.21.183:3040/api/rest/maintenance/v1/pref?dir=true -func Pref(w http.ResponseWriter, r *http.Request) { - // 知道下級文件資源目录 - dirName := r.URL.Query().Get("dirName") - data := prefInfo(dirName) - services.ResponseWithJson(w, http.StatusOK, data) -} - -// POST http://192.168.21.183:3040/api/rest/maintenance/v1/config -func Config(w http.ResponseWriter, r *http.Request) { - // json 請求參數獲取 - var bodyArgs struct { - Key string `json:"key"` - Value string `json:"value"` - } - err := ctx.ShouldBindJSON(r, &bodyArgs) - if err != nil { - log.Error("io.ReadAll is failed:", err) - services.ResponseNotFound404UriNotExist(w, r) - return - } - - // 進行值更新 - if dborm.DbClient.XEngine != nil { - result, err := dborm.DbClient.XEngine.QueryString("SELECT * FROM information_schema.processlist") - if err != nil { - fmt.Println(err) - } - fmt.Println(result) - rse, err := dborm.DbClient.XEngine.Exec("UPDATE sys_config SET value = ? where id = ?", "true", 100) - if err != nil { - fmt.Println(err) - } - fmt.Println(rse) - } - - services.ResponseStatusOK200Null(w) -} - -// http://192.168.21.183:3040/api/rest/maintenance/v1/sqlClient?type=close -// http://192.168.21.183:3040/api/rest/maintenance/v1/sqlClient?type=connet -// http://192.168.21.183:3040/api/rest/maintenance/v1/sqlClient?type=user -func SqlClient(w http.ResponseWriter, r *http.Request) { - // 关闭 - isClose := r.URL.Query().Get("type") - if isClose == "close" && dborm.DbClient.XEngine != nil { - dborm.DbClient.XEngine.Close() - } - - // 重连 - isConnet := r.URL.Query().Get("type") - if isConnet == "connet" && dborm.DbClient.XEngine == nil { - conf := config.GetYamlConfig() - err := dborm.InitDbClient(conf.Database.Type, conf.Database.User, conf.Database.Password, - conf.Database.Host, conf.Database.Port, conf.Database.Name) - if err != nil { - fmt.Println("dborm.initDbClient err:", err) - services.ResponseInternalServerError500DatabaseOperationFailed(w) - return - } - } - - // 查询实例 - isUser := r.URL.Query().Get("type") - if isUser == "user" && dborm.DbClient.XEngine != nil { - result, err := dborm.DbClient.XEngine.QueryString("SELECT * FROM information_schema.processlist") - if err != nil { - fmt.Println(err) - } - fmt.Println(result) - rse, err := dborm.DbClient.XEngine.Exec("KILL CONNECTION CONNECTION_ID()") - if err != nil { - fmt.Println(err) - } - fmt.Println(rse) - } - - // 进行连接测试 - err := dborm.DbClient.XEngine.Ping() - if err != nil { - fmt.Println(err) - } - services.ResponseStatusOK200Null(w) -} - -// GET http://192.168.21.183:3040/api/rest/maintenance/v1/top?grep= -func Top(w http.ResponseWriter, r *http.Request) { - // 過濾命令 - grep := r.URL.Query().Get("grep") - // 命令拼接 - var cmd *exec.Cmd - switch runtime.GOOS { - case "linux": - command := "ps -ef " - if grep != "" { - command += grep - } - cmd = exec.Command(command) - case "windows": - command := "wmic process list brief " - if grep != "" { - command += grep - } - cmd = exec.Command("cmd", "/C", command) - } - - out, err := cmd.CombinedOutput() - fmt.Println(string(out)) - if err != nil { - fmt.Println(err) - } - services.ResponseWithJson(w, http.StatusOK, string(out)) -} - -// PATCH http://192.168.21.183:3040/api/rest/maintenance/v1/top?ops=&name= -func TopOps(w http.ResponseWriter, r *http.Request) { - // json 請求參數獲取 - var bodyArgs struct { - Ops string `json:"ops"` - Pid string `json:"pid"` - } - err := ctx.ShouldBindJSON(r, &bodyArgs) - if err != nil { - log.Error("io.ReadAll is failed:", err) - services.ResponseNotFound404UriNotExist(w, r) - return - } - // 命令拼接 - var cmd *exec.Cmd - switch runtime.GOOS { - case "linux": - switch bodyArgs.Ops { - case "kill": - cmd = exec.Command("kill", "-9", bodyArgs.Pid) - } - case "windows": - switch bodyArgs.Ops { - case "kill": - cmd = exec.Command("cmd", "/C", "taskkill", "-PID", bodyArgs.Pid, "-F") - } - } - - out, err := cmd.CombinedOutput() - fmt.Println(string(out)) - if err != nil { - fmt.Println(err) - } - services.ResponseWithJson(w, http.StatusOK, string(out)) -} diff --git a/features/mml/mml.go b/features/mml/mml.go index 75f6498..e1e2630 100644 --- a/features/mml/mml.go +++ b/features/mml/mml.go @@ -52,16 +52,24 @@ var ( CustomUriOmMmlInt = config.UriPrefix + "/omManagement/{apiVersion}/mml/{neType}/{neId}" ) -var TIME_DELAY_AFTER_WRITE time.Duration = 200 -var TIME_DEAD_LINE time.Duration = 10 +var ( + TIME_DELAY_AFTER_WRITE time.Duration = 200 + TIME_DEAD_LINE time.Duration = 10 + WIN_ROW_SIZE int16 = 200 + WIN_COL_SIZE int16 = 120 + BUFFER_SIZE int = 65535 +) -func init() { +func InitMML() { if config.GetYamlConfig().MML.Sleep != 0 { TIME_DELAY_AFTER_WRITE = time.Duration(config.GetYamlConfig().MML.Sleep) } if config.GetYamlConfig().MML.DeadLine != 0 { TIME_DEAD_LINE = time.Duration(config.GetYamlConfig().MML.DeadLine) } + WIN_ROW_SIZE = config.GetYamlConfig().MML.SizeRow + WIN_COL_SIZE = config.GetYamlConfig().MML.SizeCol + BUFFER_SIZE = config.GetYamlConfig().MML.BufferSize } func PostMML2ToNF(w http.ResponseWriter, r *http.Request) { @@ -79,8 +87,7 @@ func PostMML2ToNF(w http.ResponseWriter, r *http.Request) { return } - var buf [20 * 1024]byte - //buf := make([]byte, 0) + buf := make([]byte, BUFFER_SIZE) var n int var mmlResult []string port2 := 5002 @@ -91,6 +98,7 @@ func PostMML2ToNF(w http.ResponseWriter, r *http.Request) { if neInfo != nil { hostMML := fmt.Sprintf("%s:%d", neInfo.Ip, port2) conn, err := net.Dial("tcp", hostMML) + //conn, err := net.Dial("tcp", hostMML) if err != nil { errMsg := fmt.Sprintf("Failed to dial %s: %v", hostMML, err) log.Error(errMsg) @@ -112,6 +120,15 @@ func PostMML2ToNF(w http.ResponseWriter, r *http.Request) { // return // } + // 发送窗口大小设置命令 + conn.Write([]byte{255, 251, 31}) // 发送WILL WINDOW SIZE + conn.Write([]byte{ + 255, 250, 31, + byte(WIN_COL_SIZE >> 8), byte(WIN_COL_SIZE & 0xFF), + byte(WIN_ROW_SIZE >> 8), byte(WIN_ROW_SIZE & 0xFF), + 255, 240, + }) // 发送设置 WINDOW SIZE + conn.SetDeadline(time.Now().Add(TIME_DEAD_LINE * time.Second)) loginStr := fmt.Sprintf("%s\n%s\n", config.GetYamlConfig().MML.User, config.GetYamlConfig().MML.Password) _, err = conn.Write([]byte(loginStr)) @@ -173,7 +190,7 @@ func PostMML2ToNF(w http.ResponseWriter, r *http.Request) { //re2 := regexp.MustCompile(`\x00`) // 匹配空字符 re2 := regexp.MustCompile(`[\x00-\x08\x0B\x0C\x0E-\x1F\x7F\x1B]`) // 匹配空字符和包含␛的控制字符 //re := regexp.MustCompile(`[\x00-\x1F\x7F]`) - result := re1.ReplaceAllString(string(buf[0:n-len(neType)-2]), "") + result := re1.ReplaceAllString(string(buf[0:n]), "") result = re2.ReplaceAllString(result, "") mmlResult = append(mmlResult, result) } @@ -187,11 +204,11 @@ func PostMML2ToNF(w http.ResponseWriter, r *http.Request) { func PostMMLToNF(w http.ResponseWriter, r *http.Request) { log.Debug("PostMMLToNF processing... ") - token, err := services.CheckExtValidRequest(w, r) - if err != nil { - log.Error("Request error:", err) - return - } + // token, err := services.CheckExtValidRequest(w, r) + // if err != nil { + // log.Error("Request error:", err) + // return + // } // 经过测试,linux下,延时需要大于100ms // var TIME_DELAY_AFTER_WRITE time.Duration = 200 // var TIME_DEAD_LINE time.Duration = 10 @@ -215,8 +232,7 @@ func PostMMLToNF(w http.ResponseWriter, r *http.Request) { } log.Debug("neType:", neType, "neId", neId) - log.Debugf("token:%s, method:%s, managementType:%s dbname:%s, tbname:%s pack:%s", - token, r.Method, module, neType, neId[0], pack) + log.Debugf("method:%s, managementType:%s dbname:%s, tbname:%s pack:%s", r.Method, module, neType, neId[0], pack) var buf [20 * 1024]byte //buf := make([]byte, 0) @@ -251,7 +267,7 @@ func PostMMLToNF(w http.ResponseWriter, r *http.Request) { } neInfo := new(dborm.NeInfo) - neInfo, err = dborm.XormGetNeInfo(neType, neId[0]) + neInfo, err := dborm.XormGetNeInfo(neType, neId[0]) if err != nil { log.Error("dborm.XormGetNeInfo is failed:", err) services.ResponseInternalServerError500DatabaseOperationFailed(w) @@ -632,11 +648,11 @@ func PostMMLToNF(w http.ResponseWriter, r *http.Request) { func PostMMLToOMC(w http.ResponseWriter, r *http.Request) { log.Debug("PostMMLToOMC processing... ") - token, err := services.CheckExtValidRequest(w, r) - if err != nil { - log.Error("Failed to CheckMmlValidRequest:", err) - return - } + // token, err := services.CheckExtValidRequest(w, r) + // if err != nil { + // log.Error("Failed to CheckMmlValidRequest:", err) + // return + // } params := r.URL.Query() neId := params["ne_id"] @@ -647,7 +663,7 @@ func PostMMLToOMC(w http.ResponseWriter, r *http.Request) { } neInfo := new(dborm.NeInfo) - neInfo, err = dborm.XormGetNeInfo("OMC", neId[0]) + neInfo, err := dborm.XormGetNeInfo("OMC", neId[0]) if err != nil { log.Error("dborm.XormGetNeInfo is failed:", err) services.ResponseInternalServerError500DatabaseOperationFailed(w) @@ -671,7 +687,7 @@ func PostMMLToOMC(w http.ResponseWriter, r *http.Request) { MmlHome: config.GetYamlConfig().MML.MmlHome, Limit: 50, User: "", - SessionToken: token, // 旧token + SessionToken: "", // 旧token Authorization: r.Header.Get(tokenConst.HEADER_KEY), // 请求Token HttpUri: hostUri, UserAgent: config.GetDefaultUserAgent(), diff --git a/features/monitor/monitor/model.go b/features/monitor/monitor/model.go deleted file mode 100644 index 8997a22..0000000 --- a/features/monitor/monitor/model.go +++ /dev/null @@ -1,55 +0,0 @@ -package monitor - -import "time" - -type MonitorBase struct { - ID uint `xorm:"id" json:"id"` - CreatedAt time.Time `xorm:"created_at" json:"createdAt"` - UpdatedAt time.Time `xorm:"updated_at" json:"updatedAt"` - - Cpu float64 `xorm:"cpu" json:"cpu"` - - LoadUsage float64 `xorm:"load_usage" json:"loadUsage"` - CpuLoad1 float64 `xorm:"cpu_load1" json:"cpuLoad1"` - CpuLoad5 float64 `xorm:"cpu_load5" json:"cpuLoad5"` - CpuLoad15 float64 `xorm:"cpu_load15" json:"cpuLoad15"` - - Memory float64 `xorm:"memory" json:"memory"` - - DbSize uint `xorm:"db_size" json:"dbSize"` -} - -type MonitorIO struct { - ID uint `xorm:"id" json:"id"` - CreatedAt time.Time `xorm:"created_at" json:"createdAt"` - UpdatedAt time.Time `xorm:"updated_at" json:"updatedAt"` - - Name string `xorm:"name" json:"name"` - Read uint64 `xorm:"read" json:"read"` - Write uint64 `xorm:"write" json:"write"` - Count uint64 `xorm:"count" json:"count"` - Time uint64 `xorm:"time" json:"time"` -} - -type MonitorNetwork struct { - ID uint `xorm:"id" json:"id"` - CreatedAt time.Time `xorm:"created_at" json:"createdAt"` - UpdatedAt time.Time `xorm:"updated_at" json:"updatedAt"` - - Name string `xorm:"name" json:"name"` - Up float64 `xorm:"up" json:"up"` - Down float64 `xorm:"down" json:"down"` -} - -type MonitorSearch struct { - Param string `json:"param" validate:"required,oneof=all cpu memory load io network"` - Info string `json:"info"` - StartTime time.Time `json:"startTime"` - EndTime time.Time `json:"endTime"` -} - -type MonitorData struct { - Param string `json:"param" validate:"required,oneof=cpu memory load io network"` - Date []time.Time `json:"date"` - Value []interface{} `json:"value"` -} diff --git a/features/monitor/monitor/monitor.go b/features/monitor/monitor/monitor.go deleted file mode 100644 index e151763..0000000 --- a/features/monitor/monitor/monitor.go +++ /dev/null @@ -1,163 +0,0 @@ -package monitor - -import ( - "net/http" - "sort" - "strings" - "time" - - "nms_cxy/lib/core/utils/ctx" - "nms_cxy/lib/dborm" - "nms_cxy/lib/services" - "nms_cxy/omc/config" - - "github.com/shirou/gopsutil/disk" - "github.com/shirou/gopsutil/net" -) - -// 点击【主机 - 监控】菜单,进入监控报表,直观的了解服务器的运行状态,包含【平均负载】、【CPU性能监控】、【内存使用监控】、【磁盘IO监控】、【网络IO监控】 - -// 可以查看昨天,今天,最近7天,最近30天,自定义时间的监控指标情况。 -// 默认监控是开启的,可以在【面板设置 - 监控】页面中根据需求对监控进行开启和关闭。 -// 监控数据默认保存30天,可以自行修改,也可手动清理该日志。 - -var ( - // IP地址 - UriIPAddr = config.DefaultUriPrefix + "/monitor/{apiVersion}/monitor/ipaddr" - // 可选网络 - UriNetOpt = config.DefaultUriPrefix + "/monitor/{apiVersion}/monitor/netoptions" - // 可选磁盘 - UriIoOpt = config.DefaultUriPrefix + "/monitor/{apiVersion}/monitor/iooptions" - // 加载 - UriLoad = config.DefaultUriPrefix + "/monitor/{apiVersion}/monitor/load" - - // IP地址 - UriIPAddrOAM = config.UriPrefix + "/monitor/{apiVersion}/monitor/ipaddr" - // 可选网络 - UriNetOptOAM = config.UriPrefix + "/monitor/{apiVersion}/monitor/netoptions" - // 可选磁盘 - UriIoOptOAM = config.UriPrefix + "/monitor/{apiVersion}/monitor/iooptions" - // 加载 - UriLoadOAM = config.UriPrefix + "/monitor/{apiVersion}/monitor/load" -) - -// IPAddr IP地址 -func IPAddr(w http.ResponseWriter, r *http.Request) { - ipAddrs := []map[string]string{} - interfaces, err := net.Interfaces() - if err == nil { - for _, iface := range interfaces { - addrs := map[string]string{} - for _, v := range iface.Addrs { - prefix := strings.Split(v.Addr, "/")[0] - if strings.Contains(prefix, "::") { - addrs["IPv6"] = prefix - } - if strings.Contains(prefix, ".") { - addrs["IPv4"] = prefix - } - } - ipAddrs = append(ipAddrs, addrs) - } - } - services.ResponseWithJson(w, 200, ipAddrs) -} - -// Netoptions 可选网络 -func Netoptions(w http.ResponseWriter, r *http.Request) { - netStat, _ := net.IOCounters(true) - var options []string - options = append(options, "all") - for _, net := range netStat { - options = append(options, net.Name) - } - sort.Strings(options) - services.ResponseWithJson(w, 200, options) -} - -// Iooptions 可选磁盘 -func Iooptions(w http.ResponseWriter, r *http.Request) { - diskStat, _ := disk.IOCounters() - var options []string - options = append(options, "all") - for _, net := range diskStat { - options = append(options, net.Name) - } - sort.Strings(options) - services.ResponseWithJson(w, 200, options) -} - -// LoadMonitor 载入监控 -func LoadMonitor(w http.ResponseWriter, r *http.Request) { - // json 請求參數獲取 - var bodyArgs MonitorSearch - err := ctx.ShouldBindJSON(r, &bodyArgs) - if err != nil || dborm.DbClient.XEngine == nil { - services.ResponseErrorWithJson(w, 400, err.Error()) - return - } - - loc := time.Now().Location() - bodyArgs.StartTime = bodyArgs.StartTime.In(loc) - bodyArgs.EndTime = bodyArgs.EndTime.In(loc) - - var backdatas []MonitorData - if bodyArgs.Param == "all" || bodyArgs.Param == "cpu" || bodyArgs.Param == "memory" || bodyArgs.Param == "load" { - var bases []MonitorBase - err := dborm.DbClient.XEngine.Table("monitor_base"). - Where("created_at > ? AND created_at < ?", bodyArgs.StartTime, bodyArgs.EndTime). - Desc("created_at"). - Find(&bases) - if err != nil { - services.ResponseErrorWithJson(w, 400, err.Error()) - return - } - - var itemData MonitorData - itemData.Param = "base" - for _, base := range bases { - itemData.Date = append(itemData.Date, base.CreatedAt) - itemData.Value = append(itemData.Value, base) - } - backdatas = append(backdatas, itemData) - } - if bodyArgs.Param == "all" || bodyArgs.Param == "io" { - var bases []MonitorIO - err := dborm.DbClient.XEngine.Table("monitor_io"). - Where("created_at > ? AND created_at < ?", bodyArgs.StartTime, bodyArgs.EndTime). - Desc("created_at"). - Find(&bases) - if err != nil { - services.ResponseErrorWithJson(w, 400, err.Error()) - return - } - - var itemData MonitorData - itemData.Param = "io" - for _, base := range bases { - itemData.Date = append(itemData.Date, base.CreatedAt) - itemData.Value = append(itemData.Value, base) - } - backdatas = append(backdatas, itemData) - } - if bodyArgs.Param == "all" || bodyArgs.Param == "network" { - var bases []MonitorNetwork - err := dborm.DbClient.XEngine.Table("monitor_network"). - Where("name = ? AND created_at > ? AND created_at < ?", bodyArgs.Info, bodyArgs.StartTime, bodyArgs.EndTime). - Desc("created_at"). - Find(&bases) - if err != nil { - services.ResponseErrorWithJson(w, 400, err.Error()) - return - } - - var itemData MonitorData - itemData.Param = "network" - for _, base := range bases { - itemData.Date = append(itemData.Date, base.CreatedAt) - itemData.Value = append(itemData.Value, base) - } - backdatas = append(backdatas, itemData) - } - services.ResponseWithJson(w, 200, backdatas) -} diff --git a/features/monitor/monitor/task.go b/features/monitor/monitor/task.go deleted file mode 100644 index d6c7a93..0000000 --- a/features/monitor/monitor/task.go +++ /dev/null @@ -1,234 +0,0 @@ -package monitor - -import ( - "encoding/json" - "fmt" - "strconv" - "time" - - "nms_cxy/lib/dborm" - "nms_cxy/lib/log" - "nms_cxy/omc/config" - - "github.com/robfig/cron/v3" - "github.com/shirou/gopsutil/v3/cpu" - "github.com/shirou/gopsutil/v3/disk" - "github.com/shirou/gopsutil/v3/load" - "github.com/shirou/gopsutil/v3/mem" - "github.com/shirou/gopsutil/v3/net" -) - -type MonitorService struct{} - -type IMonitorService interface { - Run() -} - -func NewIMonitorService() IMonitorService { - return &MonitorService{} -} - -func (m *MonitorService) Run() { - // monitorStatus, _ := dborm.XormGetConfig("SystemMonitor", "MonitorStatus") - // if monitorStatus["value"] == "disable" { - // return - // } - var itemModel MonitorBase - itemModel.CreatedAt = time.Now() - itemModel.UpdatedAt = time.Now() - - totalPercent, _ := cpu.Percent(3*time.Second, false) - if len(totalPercent) == 1 { - itemModel.Cpu = totalPercent[0] - } - cpuCount, _ := cpu.Counts(false) - - loadInfo, _ := load.Avg() - itemModel.CpuLoad1 = loadInfo.Load1 - itemModel.CpuLoad5 = loadInfo.Load5 - itemModel.CpuLoad15 = loadInfo.Load15 - itemModel.LoadUsage = loadInfo.Load1 / (float64(cpuCount*2) * 0.75) * 100 - - memoryInfo, _ := mem.VirtualMemory() - itemModel.Memory = memoryInfo.UsedPercent - - var dataSize int - conf := config.GetYamlConfig() - result, err := dborm.DbClient.XEngine.QueryString("SELECT SUM(data_length) AS data_size FROM information_schema.tables WHERE TABLE_SCHEMA = ?;", conf.Database.Name) - if err != nil { - dataSize = 0 - } else { - v, _ := strconv.Atoi(result[0]["data_size"]) - dataSize = v - } - itemModel.DbSize = uint(dataSize) - - _, errx := dborm.DbClient.XEngine.Table("monitor_base").Insert(itemModel) - if errx != nil { - log.Errorf("Insert basic monitoring data failed, err: %v", err) - } - - go loadDiskIO() - go loadNetIO() - - // 删除保留的记录 - // monitorStoreDays, _ := dborm.XormGetConfig("SystemMonitor", "MonitorStoreDays") - // if monitorStoreDays["value"] != "" { - // return - // } - // storeDays, err := strconv.Atoi(MonitorStoreDays.Value) - // if err != nil { - // timeForDelete := time.Now().AddDate(0, 0, -storeDays) - // DelMonitorBase(timeForDelete) - // DelMonitorIO(timeForDelete) - // DelMonitorNet(timeForDelete) - // } - -} - -func loadDiskIO() { - ioStat, _ := disk.IOCounters() - - time.Sleep(60 * time.Second) - - ioStat2, _ := disk.IOCounters() - var ioList []MonitorIO - for _, io2 := range ioStat2 { - for _, io1 := range ioStat { - if io2.Name == io1.Name { - var itemIO MonitorIO - itemIO.CreatedAt = time.Now() - itemIO.UpdatedAt = time.Now() - - itemIO.Name = io1.Name - if io2.ReadBytes != 0 && io1.ReadBytes != 0 && io2.ReadBytes > io1.ReadBytes { - itemIO.Read = uint64(float64(io2.ReadBytes-io1.ReadBytes) / 60) - } - if io2.WriteBytes != 0 && io1.WriteBytes != 0 && io2.WriteBytes > io1.WriteBytes { - itemIO.Write = uint64(float64(io2.WriteBytes-io1.WriteBytes) / 60) - } - - if io2.ReadCount != 0 && io1.ReadCount != 0 && io2.ReadCount > io1.ReadCount { - itemIO.Count = uint64(float64(io2.ReadCount-io1.ReadCount) / 60) - } - writeCount := uint64(0) - if io2.WriteCount != 0 && io1.WriteCount != 0 && io2.WriteCount > io1.WriteCount { - writeCount = uint64(float64(io2.WriteCount-io1.WriteCount) / 60) - } - if writeCount > itemIO.Count { - itemIO.Count = writeCount - } - - if io2.ReadTime != 0 && io1.ReadTime != 0 && io2.ReadTime > io1.ReadTime { - itemIO.Time = uint64(float64(io2.ReadTime-io1.ReadTime) / 60) - } - writeTime := uint64(0) - if io2.WriteTime != 0 && io1.WriteTime != 0 && io2.WriteTime > io1.WriteTime { - writeTime = uint64(float64(io2.WriteTime-io1.WriteTime) / 60) - } - if writeTime > itemIO.Time { - itemIO.Time = writeTime - } - ioList = append(ioList, itemIO) - break - } - } - } - _, err := dborm.DbClient.XEngine.Table("monitor_io").Insert(ioList) - if err != nil { - log.Errorf("Insert io monitoring data failed, err: %v", err) - } -} - -func loadNetIO() { - netStat, _ := net.IOCounters(true) - netStatAll, _ := net.IOCounters(false) - - time.Sleep(60 * time.Second) - - netStat2, _ := net.IOCounters(true) - var netList []MonitorNetwork - for _, net2 := range netStat2 { - for _, net1 := range netStat { - if net2.Name == net1.Name { - var itemNet MonitorNetwork - itemNet.CreatedAt = time.Now() - itemNet.UpdatedAt = time.Now() - - itemNet.Name = net1.Name - - if net2.BytesSent != 0 && net1.BytesSent != 0 && net2.BytesSent > net1.BytesSent { - itemNet.Up = float64(net2.BytesSent-net1.BytesSent) / 1024 / 60 - } - if net2.BytesRecv != 0 && net1.BytesRecv != 0 && net2.BytesRecv > net1.BytesRecv { - itemNet.Down = float64(net2.BytesRecv-net1.BytesRecv) / 1024 / 60 - } - netList = append(netList, itemNet) - break - } - } - } - netStatAll2, _ := net.IOCounters(false) - for _, net2 := range netStatAll2 { - for _, net1 := range netStatAll { - if net2.Name == net1.Name { - var itemNet MonitorNetwork - itemNet.Name = net1.Name - if net2.BytesSent != 0 && net1.BytesSent != 0 && net2.BytesSent > net1.BytesSent { - itemNet.Up = float64(net2.BytesSent-net1.BytesSent) / 1024 / 60 - } - - if net2.BytesRecv != 0 && net1.BytesRecv != 0 && net2.BytesRecv > net1.BytesRecv { - itemNet.Down = float64(net2.BytesRecv-net1.BytesRecv) / 1024 / 60 - } - netList = append(netList, itemNet) - break - } - } - } - - _, err := dborm.DbClient.XEngine.Table("monitor_network").Insert(netList) - if err != nil { - log.Errorf("Insert network monitoring data failed, err: %v", err) - } -} - -var c *cron.Cron -var monitorCronID int - -func init() { - c = cron.New() - c.Start() - monitorCronID = 0 -} - -// StartMonitor 开始监控任务 removeBefore删除上次任务,间隔interval分钟 -func StartMonitor(removeBefore bool, interval string) error { - if removeBefore { - c.Remove(cron.EntryID(monitorCronID)) - } - - // 读取配置 - if interval == "" { - v, err := dborm.XormGetConfig("SystemMonitor", "sampleTime") - if err != nil { - return err - } - data := make(map[string]any) - err = json.Unmarshal([]byte(v["value_json"].(string)), &data) - if err != nil { - log.Error("json StartMonitor:%s", err.Error()) - return err - } - interval = data["sampleTime"].(string) - } - - imservice := NewIMonitorService() - monitorID, err := c.AddJob(fmt.Sprintf("@every %sm", interval), imservice) - if err != nil { - return err - } - imservice.Run() - monitorCronID = int(monitorID) - return nil -} diff --git a/features/monitor/psnet/psnet.go b/features/monitor/psnet/psnet.go deleted file mode 100644 index a43bf9d..0000000 --- a/features/monitor/psnet/psnet.go +++ /dev/null @@ -1,94 +0,0 @@ -package psnet - -import ( - "fmt" - "net" - "net/http" - "time" - - "nms_cxy/lib/core/utils/ctx" - "nms_cxy/lib/log" - "nms_cxy/lib/services" - "nms_cxy/lib/wsinfo" - "nms_cxy/omc/config" - - "github.com/gorilla/websocket" - "github.com/shirou/gopsutil/process" -) - -var ( - // websockte通信 - UriWs = config.DefaultUriPrefix + "/monitor/{apiVersion}/psnet/ws" - // 停止进程 - UriStop = config.DefaultUriPrefix + "/monitor/{apiVersion}/psnet/stop" - - // 检查ip端口请求 - UriPing = config.DefaultUriPrefix + "/monitor/{apiVersion}/psnet/ping" -) - -// 进程管理 -var wsUpgrade = websocket.Upgrader{ - CheckOrigin: func(r *http.Request) bool { - return true - }, -} - -// ProcessWs -func ProcessWs(w http.ResponseWriter, r *http.Request) { - ws, err := wsUpgrade.Upgrade(w, r, nil) - if err != nil { - return - } - wsClient := wsinfo.NewWsClient("processClient", ws) - go wsClient.Read() - go wsClient.Write() -} - -// 停止进程 {"PID":30040} -func StopProcess(w http.ResponseWriter, r *http.Request) { - // json 請求參數獲取 - var bodyArgs struct { - PID int32 `json:"PID" validate:"required"` - } - err := ctx.ShouldBindJSON(r, &bodyArgs) - if err != nil { - log.Error("io.ReadAll is failed:", err) - services.ResponseErrorWithJson(w, 400, err.Error()) - return - } - - proc, err := process.NewProcess(bodyArgs.PID) - if err != nil { - services.ResponseErrorWithJson(w, 400, err.Error()) - return - } - if err := proc.Kill(); err != nil { - services.ResponseErrorWithJson(w, 400, err.Error()) - return - } - services.ResponseStatusOK200Null(w) -} - -// 检查ip端口请求 -func Ping(w http.ResponseWriter, r *http.Request) { - // json 請求參數獲取 - var bodyArgs struct { - Host string `json:"host" validate:"required"` - Port string `json:"port" validate:"required"` - } - err := ctx.ShouldBindJSON(r, &bodyArgs) - if err != nil { - log.Error("io.ReadAll is failed:", err) - services.ResponseErrorWithJson(w, 400, err.Error()) - return - } - - conn, err := net.DialTimeout("tcp", fmt.Sprintf("%s:%s", bodyArgs.Host, bodyArgs.Port), 3*time.Second) - if err != nil { - services.ResponseErrorWithJson(w, 400, err.Error()) - return - } - defer conn.Close() - services.ResponseStatusOK200Null(w) - -} diff --git a/features/nbi/nbi.go b/features/nbi/nbi.go index 645b542..e715e0f 100644 --- a/features/nbi/nbi.go +++ b/features/nbi/nbi.go @@ -36,7 +36,7 @@ type ApiResponse struct { ResultMessage interface{} } -var globalSession = session.NewSessManager("omc") +var globalSession = session.NewSessManager("restagent") var ( MAX_RMUID_NUM int diff --git a/features/pm/performance.go b/features/pm/performance.go index 0db6892..1e77b1a 100644 --- a/features/pm/performance.go +++ b/features/pm/performance.go @@ -8,6 +8,7 @@ import ( "math" "net/http" "strconv" + "strings" "time" "nms_cxy/lib/dborm" @@ -65,6 +66,26 @@ type GoldKpi struct { Timestamp string `json:"timestamp"` } +type KpiData struct { + ID int `json:"id" xorm:"pk 'id' '<-' autoincr"` + NEType string `json:"neType" xorm:"ne_type"` + NEName string `json:"neName" xorm:"ne_name"` + RmUid string `json:"rmUid" xorm:"rm_uid"` + Date string `json:"date" xorm:"date"` + StartTime string `json:"startTime" xorm:"start_time"` + EndTime string `json:"endTime" xorm:"end_time"` + Index int `json:"index" xorm:"index"` + Granularity int8 `json:"granularity" xorm:"granularity"` + KPIValues []KPIVal `json:"kpiValues" xorm:"json 'kpi_values'"` + //CreatedAt int64 `json:"createdAt" xorm:"created 'created_at'"` + CreatedAt int64 `json:"createdAt" xorm:"'created_at'"` +} +type KPIVal struct { + KPIID string `json:"kpi_id" xorm:"kpi_id"` + Value int64 `json:"value" xorm:"value"` + Err string `json:"err" xorm:"err"` +} + var ( // performance management PerformanceUri = config.DefaultUriPrefix + "/performanceManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/kpiReport/{index}" @@ -98,9 +119,9 @@ type DatabaseClient struct { var DbClient DatabaseClient -func InitDbClient(dbType, dbUser, dbPassword, dbHost, dbPort, dbName string) error { - DbClient.dbUrl = fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8mb4&collation=utf8mb4_general_ci&parseTime=true&loc=Local", - dbUser, dbPassword, dbHost, dbPort, dbName) +func InitDbClient(dbType, dbUser, dbPassword, dbHost, dbPort, dbName, dbParam string) error { + DbClient.dbUrl = fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?%s", + dbUser, dbPassword, dbHost, dbPort, dbName, dbParam) DbClient.dbType = dbType DbClient.dbConnMaxLifetime = 0 DbClient.dbMaxIdleConns = 0 @@ -108,8 +129,7 @@ func InitDbClient(dbType, dbUser, dbPassword, dbHost, dbPort, dbName string) err if log.GetLevel() == log.LOG_TRACE { DbClient.IsShowSQL = true } - log.Debugf("dbType:%s dbUrl:%s:******@tcp(%s:%s)/%s??charset=utf8mb4&collation=utf8mb4_general_ci&parseTime=true&loc=Local", - dbType, dbUser, dbHost, dbPort, dbName) + log.Debugf("dbType:%s dbUrl:%s:", dbType, DbClient.dbUrl) var err error DbClient.XEngine, err = xorm.NewEngine(DbClient.dbType, DbClient.dbUrl) @@ -120,11 +140,28 @@ func InitDbClient(dbType, dbUser, dbPassword, dbHost, dbPort, dbName string) err DbClient.XEngine.SetConnMaxLifetime(DbClient.dbConnMaxLifetime) DbClient.XEngine.SetMaxIdleConns(DbClient.dbMaxIdleConns) DbClient.XEngine.SetMaxOpenConns(DbClient.dbMaxOpenConns) + DbClient.XEngine.DatabaseTZ = time.Local // 必须 + DbClient.XEngine.TZLocation = time.Local // 必须 if DbClient.IsShowSQL { DbClient.XEngine.ShowSQL(true) } xEngine = DbClient.XEngine + // exist, err := xEngine.IsTableExist("kpi_report") + // if err != nil { + // log.Error("Failed to IsTableExist:", err) + // return err + // } + // if exist { + // // 复制表结构到新表 + // sql := fmt.Sprintf("CREATE TABLE IF NOT EXISTS `%s` AS SELECT * FROM kpi_report WHERE 1=0", "kpi_report_amf") + // _, err := xEngine.Exec(sql) + // if err != nil { + // log.Error("Failed to Exec:", err) + // return err + // } + // } + return nil } @@ -155,7 +192,7 @@ func GetDateTimeFromTimeString(fmtString string, timeString string) string { return t.Format(global.DateTime) } -// process alarm post message from NFs +// process KPI report post message from NFs func PostKPIReportFromNF(w http.ResponseWriter, r *http.Request) { log.Debug("PostKPIReportFromNF processing... ") @@ -167,6 +204,91 @@ func PostKPIReportFromNF(w http.ResponseWriter, r *http.Request) { return } + // body, err := io.ReadAll(io.LimitReader(r.Body, global.RequestBodyMaxLen)) + body, err := io.ReadAll(io.LimitReader(r.Body, global.RequestBodyMaxLen)) + if err != nil { + log.Error("Faile to io.ReadAll: ", err) + services.ResponseNotFound404UriNotExist(w, r) + return + } + //log.Trace("Request body:", string(body)) + kpiReport := new(KpiReport) + _ = json.Unmarshal(body, &kpiReport) + //log.Trace("kpiReport:", kpiReport) + + layout := time.RFC3339Nano + //kpiDate := GetDateFromTimeString(layout, kpiReport.Task.Period.StartTime) + kpiIndex, _ := strconv.Atoi(vars["index"]) + startTime := global.GetFmtTimeString(layout, kpiReport.Task.Period.StartTime, time.DateTime) + endTime := global.GetFmtTimeString(layout, kpiReport.Task.Period.EndTime, time.DateTime) + // get time granularity from startTime and endTime + seconds, _ := global.GetSecondDuration(startTime, endTime) + var granularity int8 = 60 + if seconds != 0 && seconds <= math.MaxInt8 && seconds >= math.MinInt8 { + granularity = int8(seconds) + } + + // 黄金指标事件对象 + kpiEvent := map[string]any{ + // kip_id ... + "neType": kpiReport.Task.NE.NeType, + "neName": kpiReport.Task.NE.NEName, + "startIndex": kpiIndex, + "timeGroup": startTime, + } + // insert into new kpi_report_xxx table + kpiData := new(KpiData) + kpiData.Date = startTime + kpiData.Index = kpiIndex + //stime, _ := time.ParseInLocation(time.RFC3339Nano, kpiReport.Task.Period.StartTime, time.Local) + //etime, _ := time.ParseInLocation(time.RFC3339Nano, kpiReport.Task.Period.EndTime, time.Local) + kpiData.StartTime = startTime + kpiData.EndTime = endTime + kpiData.Granularity = granularity + kpiData.NEName = kpiReport.Task.NE.NEName + kpiData.NEType = kpiReport.Task.NE.NeType + kpiData.RmUid = kpiReport.Task.NE.RmUID + kpiVal := new(KPIVal) + kpiData.CreatedAt = time.Now().UnixMilli() + for _, k := range kpiReport.Task.NE.KPIs { + kpiEvent[k.KPIID] = k.Value // kip_id + + kpiVal.KPIID = k.KPIID + kpiVal.Value = int64(k.Value) + kpiVal.Err = k.Err + kpiData.KPIValues = append(kpiData.KPIValues, *kpiVal) + } + + // insert kpi_report table, no session + tableName := "kpi_report_" + strings.ToLower(kpiReport.Task.NE.NeType) + affected, err := xEngine.Table(tableName).Insert(kpiData) + if err != nil && affected <= 0 { + log.Errorf("Failed to insert %s:%v", tableName, err) + services.ResponseInternalServerError500ProcessError(w, err) + return + } + + // 推送到ws订阅组 + wsService.NewWSSendImpl.ByGroupID(wsService.GROUP_KPI, kpiEvent) + if kpiReport.Task.NE.NeType == "UPF" { + wsService.NewWSSendImpl.ByGroupID(wsService.GROUP_KPI_UPF, kpiEvent) + } + + services.ResponseStatusOK204NoContent(w) +} + +// post kpi report from NEs, insert insto gold_kpi table, discard... +func PostGoldKPIFromNF(w http.ResponseWriter, r *http.Request) { + log.Debug("PostKPIReportFromNF processing... ") + + vars := mux.Vars(r) + apiVer := vars["apiVersion"] + if apiVer != global.ApiVersionV1 { + log.Error("Uri api version is invalid. apiVersion:", apiVer) + services.ResponseNotFound404UriNotExist(w, r) + return + } + // body, err := io.ReadAll(io.LimitReader(r.Body, global.RequestBodyMaxLen)) body, err := io.ReadAll(io.LimitReader(r.Body, global.RequestBodyMaxLen)) if err != nil { @@ -205,12 +327,32 @@ func PostKPIReportFromNF(w http.ResponseWriter, r *http.Request) { "startIndex": goldKpi.Index, "timeGroup": goldKpi.StartTime, } + // insert into new kpi_report_xxx table + kpiData := new(KpiData) + kpiData.Date = goldKpi.Date + kpiData.Index = goldKpi.Index + //st, _ := time.ParseInLocation(time.RFC3339Nano, kpiReport.Task.Period.StartTime, time.Local) + //et, _ := time.ParseInLocation(time.RFC3339Nano, kpiReport.Task.Period.EndTime, time.Local) + kpiData.StartTime = goldKpi.StartTime + kpiData.EndTime = goldKpi.EndTime + kpiData.Granularity = goldKpi.Granularity + kpiData.NEName = goldKpi.NEName + kpiData.NEType = goldKpi.NEType + kpiData.RmUid = goldKpi.RmUid + kpiVal := new(KPIVal) + kpiData.CreatedAt = time.Now().UnixMilli() for _, k := range kpiReport.Task.NE.KPIs { kpiEvent[k.KPIID] = k.Value // kip_id goldKpi.KpiId = k.KPIID goldKpi.Value = k.Value goldKpi.Error = k.Err - log.Trace("goldKpi:", goldKpi) + + kpiVal.KPIID = k.KPIID + kpiVal.Value = int64(k.Value) + kpiVal.Err = k.Err + kpiData.KPIValues = append(kpiData.KPIValues, *kpiVal) + + //log.Trace("goldKpi:", goldKpi) // 启动事务 err := session.Begin() @@ -244,13 +386,22 @@ func PostKPIReportFromNF(w http.ResponseWriter, r *http.Request) { } } + // insert kpi_report table, no session + tableName := "kpi_report_" + strings.ToLower(kpiReport.Task.NE.NeType) + affected, err := xEngine.Table(tableName).Insert(kpiData) + if err != nil && affected <= 0 { + log.Errorf("Failed to insert %s:%v", tableName, err) + services.ResponseInternalServerError500ProcessError(w, err) + return + } + // 推送到ws订阅组 wsService.NewWSSendImpl.ByGroupID(wsService.GROUP_KPI, kpiEvent) if goldKpi.NEType == "UPF" { wsService.NewWSSendImpl.ByGroupID(wsService.GROUP_KPI_UPF, kpiEvent) } - services.ResponseStatusOK200Null(w) + services.ResponseStatusOK204NoContent(w) } type MeasureTask struct { @@ -903,9 +1054,9 @@ func PostMeasurementFromNF(w http.ResponseWriter, r *http.Request) { layout := time.RFC3339 measurement.Date = GetDateFromTimeString(layout, measurement.StartTime) measurement.StartTime = GetDateTimeFromTimeString(layout, measurement.StartTime) - affected, err := session.Table("northbound_pm").Insert(measurement) + affected, err := session.Table("nbi_pm").Insert(measurement) if err != nil && affected <= 0 { - log.Error("Failed to insert northbound_pm:", err) + log.Error("Failed to insert nbi_pm:", err) services.ResponseInternalServerError500DatabaseOperationFailed(w) return } @@ -986,9 +1137,9 @@ func GetMeasurementFromNF(w http.ResponseWriter, r *http.Request) { layout := time.RFC3339 measurement.Date = GetDateFromTimeString(layout, measurement.StartTime) measurement.StartTime = GetDateTimeFromTimeString(layout, measurement.StartTime) - affected, err := session.Table("northbound_pm").Insert(measurement) + affected, err := session.Table("nbi_pm").Insert(measurement) if err != nil && affected <= 0 { - log.Error("Failed to insert northbound_pm:", err) + log.Error("Failed to insert nbi_pm:", err) services.ResponseInternalServerError500DatabaseOperationFailed(w) return } diff --git a/features/security/account.go b/features/security/account.go index 0ced4c2..caa20d6 100644 --- a/features/security/account.go +++ b/features/security/account.go @@ -2,56 +2,24 @@ package security import ( "encoding/json" - "fmt" - "image/color" "io" "net/http" - "strconv" "strings" - "time" - "nms_cxy/features/security/service" - sysConfigService "nms_cxy/features/sys_config/service" - "nms_cxy/lib/core/account" - "nms_cxy/lib/core/cache" - "nms_cxy/lib/core/constants/cachekey" - "nms_cxy/lib/core/utils/ctx" - "nms_cxy/lib/core/vo/result" "nms_cxy/lib/dborm" "nms_cxy/lib/global" "nms_cxy/lib/log" "nms_cxy/lib/oauth" "nms_cxy/lib/services" "nms_cxy/omc/config" - srcConfig "nms_cxy/src/framework/config" - "nms_cxy/src/framework/i18n" - "nms_cxy/src/framework/redis" - - "github.com/mojocn/base64Captcha" ) var ( - UriOauthToken2 = config.DefaultUriPrefix + "/securityManagement/{apiVersion}/{elementTypeValue}/token2" + UriOauthToken = config.DefaultUriPrefix + "/securityManagement/{apiVersion}/{elementTypeValue}/token" UriOauthHandshake = config.DefaultUriPrefix + "/securityManagement/{apiVersion}/{elementTypeValue}/handshake" CustomUriOauthToken = config.UriPrefix + "/securityManagement/{apiVersion}/{elementTypeValue}/token" CustomUriOauthHandshake = config.UriPrefix + "/securityManagement/{apiVersion}/{elementTypeValue}/handshake" - - // 系统登录 - UriLogin = config.DefaultUriPrefix + "/securityManagement/{apiVersion}/login" - CustomUriLogin = config.UriPrefix + "/securityManagement/{apiVersion}/login" - - // 获取验证码 - UriCaptchaImage = config.DefaultUriPrefix + "/securityManagement/{apiVersion}/captchaImage" - CustomUriCaptchaImage = config.UriPrefix + "/securityManagement/{apiVersion}/captchaImage" - - // 登录用户信息 - UriUserInfo = config.DefaultUriPrefix + "/securityManagement/{apiVersion}/getUserInfo" - CustomUriUserInfo = config.UriPrefix + "/securityManagement/{apiVersion}/getUserInfo" - - // 登录用户路由信息 - UriRouters = config.DefaultUriPrefix + "/securityManagement/{apiVersion}/getRouters" - CustomUriRouters = config.UriPrefix + "/securityManagement/{apiVersion}/getRouters" ) func LoginFromOMC(w http.ResponseWriter, r *http.Request) { @@ -136,14 +104,8 @@ func LoginFromOMC(w http.ResponseWriter, r *http.Request) { } if user != nil { - // 缓存用户信息 - account.CacheLoginUser(user) - redis.SetByExpire("", "session_token", token, time.Second*1800) - // 角色权限集合,管理员拥有所有权限 - userId := fmt.Sprint(user.Id) - isAdmin := srcConfig.IsAdmin(userId) - roles, perms := service.NewServiceAccount.RoleAndMenuPerms(userId, isAdmin) - services.ResponseStatusOK200LoginWhitRP(w, token, user, roles, perms) + empty := []string{} + services.ResponseStatusOK200LoginWhitRP(w, token, user, empty, empty) return } services.ResponseBadRequest400IncorrectLogin(w) @@ -225,212 +187,3 @@ func HandshakeFromOMC(w http.ResponseWriter, r *http.Request) { } services.ResponseStatusOK200Null(w) } - -// 系统登录 -// -// POST /login -func LoginOMC(w http.ResponseWriter, r *http.Request) { - log.Info("LoginOMC processing... ") - var body struct { - Username string `json:"username" binding:"required"` // Username 用户名 - Password string `json:"password" binding:"required"` // Password 用户密码 - Code string `json:"code"` // Code 验证码 - UUID string `json:"uuid"` // UUID 验证码唯一标识 - } - err := ctx.ShouldBindJSON(r, &body) - if err != nil { - log.Error("Invalid Json Format") - ctx.JSON(w, 400, result.CodeMsg(400, "parameter error")) - return - } - // response 400-5 - if body.Username == "" || body.Password == "" { - log.Error("Wrong parameter value") - ctx.JSON(w, 400, result.CodeMsg(400, "parameter error")) - return - } - - // 校验验证码 - // 从数据库配置获取验证码开关 true开启,false关闭 - captchaEnabledStr := sysConfigService.NewServiceSysConfig.SelectConfigValueByKey("sys.account.captchaEnabled") - captchaEnabled, err := strconv.ParseBool(captchaEnabledStr) - if err != nil { - captchaEnabled = false - } - if captchaEnabled { - if body.Code == "" || body.UUID == "" { - log.Error("Authentication failed, mismatch captcha") - ctx.JSON(w, 400, result.CodeMsg(400, "Verification code information error")) - return - } - verifyKey := cachekey.CAPTCHA_CODE_KEY + body.UUID - captcha, ok := cache.GetLocalTTL(verifyKey) - if captcha == nil || !ok { - log.Error("Authentication failed, captcha emtry") - ctx.JSON(w, 400, result.CodeMsg(400, "The verification code has expired")) - return - } - cache.DeleteLocalTTL(verifyKey) - if captcha.(string) != body.Code { - log.Error("Authentication failed, not match captcha") - ctx.JSON(w, 400, result.CodeMsg(400, "Verification code error")) - return - } - } - - validUser, user, err := dborm.XormCheckLoginUser(body.Username, body.Password, config.GetYamlConfig().Auth.Crypt) - if !validUser || err != nil { - // response 400-4 - log.Error("Authentication failed, mismatch user or password") - ctx.JSON(w, 400, result.CodeMsg(400, err.Error())) - return - } - - token := oauth.GenRandToken("omc") // Generate new token to session ID - sourceAddr := r.RemoteAddr[:strings.Index(r.RemoteAddr, ":")] - affected, err := dborm.XormInsertSession(body.Username, sourceAddr, token, - config.GetExpiresFromConfig(), config.GetYamlConfig().Auth.Session) - if err != nil { - log.Error("Failed to XormInsertSession:", err) - if affected == -1 { - services.ResponseForbidden403MultiLoginNotAllowed(w) - } else { - services.ResponseBadRequest400IncorrectLogin(w) - } - - return - } - - if user != nil { - // 缓存用户信息 - account.CacheLoginUser(user) - redis.SetByExpire("", "session_token", token, time.Second*1800) - ctx.JSON(w, 200, result.OkData(map[string]any{ - "accessToken": token, - })) - return - } - ctx.JSON(w, 200, result.Err(nil)) -} - -// 获取验证码 -// -// GET /captchaImage -func CaptchaImage(w http.ResponseWriter, r *http.Request) { - configService := sysConfigService.NewServiceSysConfig - - // 从数据库配置获取验证码开关 true开启,false关闭 - captchaEnabledStr := configService.SelectConfigValueByKey("sys.account.captchaEnabled") - captchaEnabled, err := strconv.ParseBool(captchaEnabledStr) - if err != nil { - captchaEnabled = false - } - if !captchaEnabled { - ctx.JSON(w, 200, result.Ok(map[string]any{ - "captchaEnabled": captchaEnabled, - })) - return - } - - // 生成唯一标识 - verifyKey := "" - data := map[string]any{ - "captchaEnabled": captchaEnabled, - "uuid": "", - "img": "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7", - } - - // char 字符验证 - driverCaptcha := &base64Captcha.DriverString{ - //Height png height in pixel. - Height: 40, - // Width Captcha png width in pixel. - Width: 120, - //NoiseCount text noise count. - NoiseCount: 4, - //Length random string length. - Length: 4, - //Source is a unicode which is the rand string from. - Source: "023456789abcdefghjkmnprstuvwxyz", - //ShowLineOptions := OptionShowHollowLine | OptionShowSlimeLine | OptionShowSineLine . - ShowLineOptions: base64Captcha.OptionShowHollowLine, - //BgColor captcha image background color (optional) - BgColor: &color.RGBA{ - R: 250, - G: 250, - B: 250, - A: 255, // 不透明 - }, - } - // 验证码生成 - id, question, answer := driverCaptcha.GenerateIdQuestionAnswer() - // 验证码表达式解析输出 - item, err := driverCaptcha.DrawCaptcha(question) - if err != nil { - log.Infof("Generate Id Question Answer %s : %v", question, err) - } else { - data["uuid"] = id - data["img"] = item.EncodeB64string() - verifyKey = cachekey.CAPTCHA_CODE_KEY + id - cache.SetLocalTTL(verifyKey, answer, 120*time.Second) - } - - // 本地开发下返回验证码结果,方便接口调试 - // text, ok := cache.GetLocalTTL(verifyKey) - // if ok { - // data["text"] = text.(string) - // } - - ctx.JSON(w, 200, result.Ok(data)) -} - -// 登录用户信息 -func UserInfo(w http.ResponseWriter, r *http.Request) { - loginUser, err := ctx.LoginUser(r) - if err != nil { - ctx.JSON(w, 200, result.OkData(err.Error())) - } - // 角色权限集合,管理员拥有所有权限 - userId := fmt.Sprint(loginUser.UserID) - isAdmin := srcConfig.IsAdmin(userId) - roles, perms := service.NewServiceAccount.RoleAndMenuPerms(userId, isAdmin) - - ctx.JSON(w, 200, result.OkData(map[string]any{ - "user": loginUser.User, - "roles": roles, - "permissions": perms, - })) -} - -// 登录用户路由信息 -func Routers(w http.ResponseWriter, r *http.Request) { - userID := ctx.LoginUserToUserID(r) - - // 前端路由,管理员拥有所有 - isAdmin := srcConfig.IsAdmin(userID) - buildMenus := service.NewServiceAccount.RouteMenus(userID, isAdmin) - ctx.JSON(w, 200, result.OkData(buildMenus)) -} - -// 鉴权登录接口 -var UriOauthToken = "/api/rest/securityManagement/{apiVersion}/oauth/token" - -// 鉴权登录接口 -func OauthToken(w http.ResponseWriter, r *http.Request) { - language := ctx.AcceptLanguage(r) - var querys struct { - Group string `form:"group" binding:"required"` - Type string `form:"type" binding:"omitempty,oneof=node edge combo"` - } - if err := ctx.ShouldBindQuery(r, &querys); err != nil { - ctx.JSON(w, 400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) - return - } - - apiVersion := ctx.Param(r, "apiVersion") - if apiVersion == "v1" { - ctx.JSON(w, 400, result.CodeMsg(400, "parameter error")) - return - } - ctx.JSON(w, 400, result.CodeMsg(400, "parameter error")) -} diff --git a/features/security/service/service_account.go b/features/security/service/service_account.go deleted file mode 100644 index 39ae80c..0000000 --- a/features/security/service/service_account.go +++ /dev/null @@ -1,56 +0,0 @@ -package service - -import ( - menuService "nms_cxy/features/sys_menu/service" - roleService "nms_cxy/features/sys_role/service" - userService "nms_cxy/features/sys_user/service" - "nms_cxy/lib/core/utils/parse" - "nms_cxy/lib/core/vo" -) - -// 实例化服务层 ServiceAccount 结构体 -var NewServiceAccount = &ServiceAccount{ - sysUserService: userService.NewServiceSysUser, - sysRoleService: roleService.NewServiceSysRole, - sysMenuService: menuService.NewServiceSysMenu, -} - -// 账号身份操作服务 服务层处理 -type ServiceAccount struct { - // 用户信息服务 - sysUserService *userService.ServiceSysUser - // 角色服务 - sysRoleService *roleService.ServiceSysRole - // 菜单服务 - sysMenuService *menuService.ServiceSysMenu -} - -// RoleAndMenuPerms 角色和菜单数据权限 -func (s *ServiceAccount) RoleAndMenuPerms(userId string, isAdmin bool) ([]string, []string) { - if isAdmin { - return []string{"admin"}, []string{"*:*:*"} - } else { - // 角色key - roleGroup := []string{} - roles := s.sysRoleService.SelectRoleListByUserId(userId) - for _, role := range roles { - roleGroup = append(roleGroup, role.RoleKey) - } - // 菜单权限key - perms := s.sysMenuService.SelectMenuPermsByUserId(userId) - return parse.RemoveDuplicates(roleGroup), parse.RemoveDuplicates(perms) - } -} - -// RouteMenus 前端路由所需要的菜单 -func (s *ServiceAccount) RouteMenus(userId string, isAdmin bool) []vo.Router { - var buildMenus []vo.Router - if isAdmin { - menus := s.sysMenuService.SelectMenuTreeByUserId("*") - buildMenus = s.sysMenuService.BuildRouteMenus(menus, "") - } else { - menus := s.sysMenuService.SelectMenuTreeByUserId(userId) - buildMenus = s.sysMenuService.BuildRouteMenus(menus, "") - } - return buildMenus -} diff --git a/features/state/getstate.go b/features/state/getstate.go index 73520eb..9bb7bb7 100644 --- a/features/state/getstate.go +++ b/features/state/getstate.go @@ -510,7 +510,7 @@ func GetOneSysinfoFromNF(w http.ResponseWriter, r *http.Request) { if systemState.OsInfo != "" { osInfo = systemState.OsInfo } - dbInfo := "adb v1.0.1" + dbInfo := "kvdb v1.0.1" if systemState.OsInfo != "" { dbInfo = systemState.DbInfo } @@ -656,7 +656,7 @@ func GetAllSysinfoFromNF(w http.ResponseWriter, r *http.Request) { if systemState.OsInfo != "" { osInfo = systemState.OsInfo } - dbInfo := "adb v1.0.1" + dbInfo := "kvdb v1.0.1" if systemState.OsInfo != "" { dbInfo = systemState.DbInfo } @@ -857,7 +857,8 @@ func GetStateFromNFOld(w http.ResponseWriter, r *http.Request) { case "all": // query all NFs // create rest client - restHostPort := fmt.Sprintf("http://127.0.0.1:%d", config.GetYamlConfig().Rest[0].Port) + + restHostPort := config.GetOMCHostUrl() getNeInfoPattern := fmt.Sprintf(config.DefaultUriPrefix+"/databaseManagement/v1/elementType/%s/objectType/ne_info", config.GetYamlConfig().Database.Name) getNeInfoURI := restHostPort + getNeInfoPattern + "?WHERE=status+in+('0','3')" @@ -878,7 +879,7 @@ func GetStateFromNFOld(w http.ResponseWriter, r *http.Request) { neList, _ = dborm.XormParseResult(resp.Body()) default: - restHostPort := fmt.Sprintf("http://127.0.0.1:%d", config.GetYamlConfig().Rest[0].Port) + restHostPort := config.GetOMCHostUrl() getNeInfoPattern := fmt.Sprintf(config.DefaultUriPrefix+"/databaseManagement/v1/elementType/%s/objectType/ne_info", config.GetYamlConfig().Database.Name) getNeInfoURI := restHostPort + getNeInfoPattern diff --git a/features/sys_config/api_sys_config.go b/features/sys_config/api_sys_config.go deleted file mode 100644 index e62bde1..0000000 --- a/features/sys_config/api_sys_config.go +++ /dev/null @@ -1,230 +0,0 @@ -package sysconfig - -import ( - "fmt" - "net/http" - "strings" - - "nms_cxy/features/sys_config/model" - "nms_cxy/features/sys_config/service" - "nms_cxy/lib/core/utils/ctx" - "nms_cxy/lib/core/utils/parse" - "nms_cxy/lib/core/vo/result" - "nms_cxy/lib/midware" - "nms_cxy/lib/services" - "nms_cxy/omc/config" -) - -// 参数配置信息接口添加到路由 -func Routers() []services.RouterItem { - // 实例化控制层 SysConfigApi 结构体 - var apis = &SysConfigApi{ - sysConfigService: service.NewServiceSysConfig, - } - - rs := [...]services.RouterItem{ - { - Method: "GET", - Pattern: "/configs", - Handler: apis.List, - Middleware: midware.Authorize(nil), - }, - { - Method: "GET", - Pattern: "/config/{configId}", - Handler: apis.Info, - Middleware: midware.Authorize(nil), - }, - { - Method: "POST", - Pattern: "/config", - Handler: apis.Add, - Middleware: midware.Authorize(nil), - }, - { - Method: "PUT", - Pattern: "/config", - Handler: apis.Edit, - Middleware: midware.Authorize(nil), - }, - { - Method: "DELETE", - Pattern: "/config/{configIds}", - Handler: apis.Remove, - Middleware: midware.Authorize(nil), - }, - { - Method: "PUT", - Pattern: "/config/refreshCache", - Handler: apis.RefreshCache, - Middleware: midware.Authorize(nil), - }, - { - Method: "GET", - Pattern: "/config/configKey/{configKey}", - Handler: apis.ConfigKey, - Middleware: midware.Authorize(nil), - }, - // 添加更多的 Router 对象... - } - - // 生成两组前缀路由 - rsPrefix := []services.RouterItem{} - for _, v := range rs { - path := "/configManage/{apiVersion}" + v.Pattern - // 固定前缀 - v.Pattern = config.DefaultUriPrefix + path - rsPrefix = append(rsPrefix, v) - // 可配置 - v.Pattern = config.UriPrefix + path - rsPrefix = append(rsPrefix, v) - } - return rsPrefix -} - -// 参数配置信息 -// -// PATH /configManage -type SysConfigApi struct { - // 参数配置服务 - sysConfigService *service.ServiceSysConfig -} - -// 参数配置列表 -// -// GET /list -func (s *SysConfigApi) List(w http.ResponseWriter, r *http.Request) { - querys := ctx.QueryMap(r) - data := s.sysConfigService.SelectConfigPage(querys) - ctx.JSON(w, 200, result.Ok(data)) -} - -// 参数配置信息 -// -// GET /:configId -func (s *SysConfigApi) Info(w http.ResponseWriter, r *http.Request) { - configId := ctx.Param(r, "configId") - if configId == "" { - ctx.JSON(w, 400, result.CodeMsg(400, "parameter error")) - return - } - data := s.sysConfigService.SelectConfigById(configId) - if data.ConfigID == configId { - ctx.JSON(w, 200, result.OkData(data)) - return - } - ctx.JSON(w, 200, result.Err(nil)) -} - -// 参数配置新增 -// -// POST / -func (s *SysConfigApi) Add(w http.ResponseWriter, r *http.Request) { - var body model.SysConfig - err := ctx.ShouldBindJSON(r, &body) - if err != nil || body.ConfigID != "" { - ctx.JSON(w, 400, result.CodeMsg(400, "parameter error")) - return - } - - // 检查属性值唯一 - uniqueConfigKey := s.sysConfigService.CheckUniqueConfigKey(body.ConfigKey, "") - if !uniqueConfigKey { - msg := fmt.Sprintf("[%s] Parameter key name already exists", body.ConfigKey) - ctx.JSON(w, 200, result.ErrMsg(msg)) - return - } - - body.CreateBy = ctx.LoginUserToUserName(r) - insertId := s.sysConfigService.InsertConfig(body) - if insertId != "" { - ctx.JSON(w, 200, result.Ok(nil)) - return - } - ctx.JSON(w, 200, result.Err(nil)) -} - -// 参数配置修改 -// -// PUT / -func (s *SysConfigApi) Edit(w http.ResponseWriter, r *http.Request) { - var body model.SysConfig - err := ctx.ShouldBindJSON(r, &body) - if err != nil || body.ConfigID == "" { - ctx.JSON(w, 400, result.CodeMsg(400, "parameter error")) - return - } - - // 检查属性值唯一 - uniqueConfigKey := s.sysConfigService.CheckUniqueConfigKey(body.ConfigKey, body.ConfigID) - if !uniqueConfigKey { - msg := fmt.Sprintf("[%s] Parameter key name already exists", body.ConfigKey) - ctx.JSON(w, 200, result.ErrMsg(msg)) - return - } - - // 检查是否存在 - config := s.sysConfigService.SelectConfigById(body.ConfigID) - if config.ConfigID != body.ConfigID { - ctx.JSON(w, 200, result.ErrMsg("No permission to access parameter configuration data!")) - return - } - - body.UpdateBy = ctx.LoginUserToUserName(r) - rows := s.sysConfigService.UpdateConfig(body) - if rows > 0 { - ctx.JSON(w, 200, result.Ok(nil)) - return - } - ctx.JSON(w, 200, result.Err(nil)) -} - -// 参数配置删除 -// -// DELETE /:configIds -func (s *SysConfigApi) Remove(w http.ResponseWriter, r *http.Request) { - configIds := ctx.Param(r, "configIds") - if configIds == "" { - ctx.JSON(w, 400, result.CodeMsg(400, "parameter error")) - return - } - // 处理字符转id数组后去重 - ids := strings.Split(configIds, ",") - uniqueIDs := parse.RemoveDuplicates(ids) - if len(uniqueIDs) <= 0 { - ctx.JSON(w, 200, result.Err(nil)) - return - } - rows, err := s.sysConfigService.DeleteConfigByIds(uniqueIDs) - if err != nil { - ctx.JSON(w, 200, result.ErrMsg(err.Error())) - return - } - msg := fmt.Sprintf("删除成功:%d", rows) - ctx.JSON(w, 200, result.OkMsg(msg)) -} - -// 参数配置刷新缓存 -// -// PUT /refreshCache -func (s *SysConfigApi) RefreshCache(w http.ResponseWriter, r *http.Request) { - s.sysConfigService.ResetConfigCache() - ctx.JSON(w, 200, result.Ok(nil)) -} - -// 参数配置根据参数键名 -// -// GET /configKey/:configKey -func (s *SysConfigApi) ConfigKey(w http.ResponseWriter, r *http.Request) { - configKey := ctx.Param(r, "configKey") - if configKey == "" { - ctx.JSON(w, 400, result.CodeMsg(400, "parameter error")) - return - } - key := s.sysConfigService.SelectConfigValueByKey(configKey) - if key != "" { - ctx.JSON(w, 200, result.OkData(key)) - return - } - ctx.JSON(w, 200, result.Err(nil)) -} diff --git a/features/sys_config/model/sys_config.go b/features/sys_config/model/sys_config.go deleted file mode 100644 index 8949c67..0000000 --- a/features/sys_config/model/sys_config.go +++ /dev/null @@ -1,25 +0,0 @@ -package model - -// 参数配置对象 sys_config -type SysConfig struct { - // 参数主键 - ConfigID string `json:"configId"` - // 参数名称 - ConfigName string `json:"configName" binding:"required"` - // 参数键名 - ConfigKey string `json:"configKey" binding:"required"` - // 参数键值 - ConfigValue string `json:"configValue" binding:"required"` - // 系统内置(Y是 N否) - ConfigType string `json:"configType"` - // 创建者 - CreateBy string `json:"createBy"` - // 创建时间 - CreateTime int64 `json:"createTime"` - // 更新者 - UpdateBy string `json:"updateBy"` - // 更新时间 - UpdateTime int64 `json:"updateTime"` - // 备注 - Remark string `json:"remark"` -} diff --git a/features/sys_config/service/repo_sys_config.go b/features/sys_config/service/repo_sys_config.go deleted file mode 100644 index 51781ef..0000000 --- a/features/sys_config/service/repo_sys_config.go +++ /dev/null @@ -1,336 +0,0 @@ -package service - -import ( - "fmt" - "strings" - "time" - - "nms_cxy/features/sys_config/model" - "nms_cxy/lib/core/datasource" - "nms_cxy/lib/core/utils/date" - "nms_cxy/lib/core/utils/parse" - "nms_cxy/lib/log" -) - -// 实例化数据层 RepoSysConfig 结构体 -var NewRepoSysConfig = &RepoSysConfig{ - selectSql: `select - config_id, config_name, config_key, config_value, config_type, create_by, create_time, update_by, update_time, remark - from sys_config`, - - resultMap: map[string]string{ - "config_id": "ConfigID", - "config_name": "ConfigName", - "config_key": "ConfigKey", - "config_value": "ConfigValue", - "config_type": "ConfigType", - "remark": "Remark", - "create_by": "CreateBy", - "create_time": "CreateTime", - "update_by": "UpdateBy", - "update_time": "UpdateTime", - }, -} - -// RepoSysConfig 参数配置表 数据层处理 -type RepoSysConfig struct { - // 查询视图对象SQL - selectSql string - // 结果字段与实体映射 - resultMap map[string]string -} - -// convertResultRows 将结果记录转实体结果组 -func (r *RepoSysConfig) convertResultRows(rows []map[string]any) []model.SysConfig { - arr := make([]model.SysConfig, 0) - for _, row := range rows { - sysConfig := model.SysConfig{} - for key, value := range row { - if keyMapper, ok := r.resultMap[key]; ok { - datasource.SetFieldValue(&sysConfig, keyMapper, value) - } - } - arr = append(arr, sysConfig) - } - return arr -} - -// SelectDictDataPage 分页查询参数配置列表数据 -func (r *RepoSysConfig) SelectConfigPage(query map[string]any) map[string]any { - // 查询条件拼接 - var conditions []string - var params []any - if v, ok := query["configName"]; ok && v != "" { - conditions = append(conditions, "config_name like concat(?, '%')") - params = append(params, v) - } - if v, ok := query["configType"]; ok && v != "" { - conditions = append(conditions, "config_type = ?") - params = append(params, v) - } - if v, ok := query["configKey"]; ok && v != "" { - conditions = append(conditions, "config_key like concat(?, '%')") - params = append(params, v) - } - beginTime, ok := query["beginTime"] - if !ok { - beginTime, ok = query["params[beginTime]"] - } - if ok && beginTime != "" { - conditions = append(conditions, "create_time >= ?") - beginDate := date.ParseStrToDate(beginTime.(string), date.YYYY_MM_DD) - params = append(params, beginDate.UnixMilli()) - } - endTime, ok := query["endTime"] - if !ok { - endTime, ok = query["params[endTime]"] - } - if ok && endTime != "" { - conditions = append(conditions, "create_time <= ?") - endDate := date.ParseStrToDate(endTime.(string), date.YYYY_MM_DD) - params = append(params, endDate.UnixMilli()) - } - - // 构建查询条件语句 - whereSql := "" - if len(conditions) > 0 { - whereSql += " where " + strings.Join(conditions, " and ") - } - - // 查询数量 长度为0直接返回 - totalSql := "select count(1) as 'total' from sys_config" - totalRows, err := datasource.RawDB("", totalSql+whereSql, params) - if err != nil { - log.Errorf("total err => %v", err) - } - total := parse.Number(totalRows[0]["total"]) - if total == 0 { - return map[string]any{ - "total": total, - "rows": []model.SysConfig{}, - } - } - - // 分页 - pageNum, pageSize := datasource.PageNumSize(query["pageNum"], query["pageSize"]) - pageSql := " limit ?,? " - params = append(params, pageNum*pageSize) - params = append(params, pageSize) - - // 查询数据 - querySql := r.selectSql + whereSql + pageSql - results, err := datasource.RawDB("", querySql, params) - if err != nil { - log.Errorf("query err => %v", err) - } - - // 转换实体 - rows := r.convertResultRows(results) - return map[string]any{ - "total": total, - "rows": rows, - } -} - -// SelectConfigList 查询参数配置列表 -func (r *RepoSysConfig) SelectConfigList(sysConfig model.SysConfig) []model.SysConfig { - // 查询条件拼接 - var conditions []string - var params []any - if sysConfig.ConfigName != "" { - conditions = append(conditions, "config_name like concat(?, '%')") - params = append(params, sysConfig.ConfigName) - } - if sysConfig.ConfigType != "" { - conditions = append(conditions, "config_type = ?") - params = append(params, sysConfig.ConfigType) - } - if sysConfig.ConfigKey != "" { - conditions = append(conditions, "config_key like concat(?, '%')") - params = append(params, sysConfig.ConfigKey) - } - if sysConfig.CreateTime > 0 { - conditions = append(conditions, "create_time >= ?") - params = append(params, sysConfig.CreateTime) - } - - // 构建查询条件语句 - whereSql := "" - if len(conditions) > 0 { - whereSql += " where " + strings.Join(conditions, " and ") - } - - // 查询数据 - querySql := r.selectSql + whereSql - results, err := datasource.RawDB("", querySql, params) - if err != nil { - log.Errorf("query err => %v", err) - return []model.SysConfig{} - } - - // 转换实体 - return r.convertResultRows(results) -} - -// SelectConfigValueByKey 通过参数键名查询参数键值 -func (r *RepoSysConfig) SelectConfigValueByKey(configKey string) string { - querySql := "select config_value as 'str' from sys_config where config_key = ?" - results, err := datasource.RawDB("", querySql, []any{configKey}) - if err != nil { - log.Errorf("query err => %v", err) - return "" - } - if len(results) > 0 { - return fmt.Sprint(results[0]["str"]) - } - return "" -} - -// SelectConfigByIds 通过配置ID查询参数配置信息 -func (r *RepoSysConfig) SelectConfigByIds(configIds []string) []model.SysConfig { - placeholder := datasource.KeyPlaceholderByQuery(len(configIds)) - querySql := r.selectSql + " where config_id in (" + placeholder + ")" - parameters := datasource.ConvertIdsSlice(configIds) - results, err := datasource.RawDB("", querySql, parameters) - if err != nil { - log.Errorf("query err => %v", err) - return []model.SysConfig{} - } - // 转换实体 - return r.convertResultRows(results) -} - -// CheckUniqueConfig 校验配置参数是否唯一 -func (r *RepoSysConfig) CheckUniqueConfig(sysConfig model.SysConfig) string { - // 查询条件拼接 - var conditions []string - var params []any - if sysConfig.ConfigKey != "" { - conditions = append(conditions, "config_key = ?") - params = append(params, sysConfig.ConfigKey) - } - - // 构建查询条件语句 - whereSql := "" - if len(conditions) > 0 { - whereSql += " where " + strings.Join(conditions, " and ") - } else { - return "" - } - - // 查询数据 - querySql := "select config_id as 'str' from sys_config " + whereSql + " limit 1" - results, err := datasource.RawDB("", querySql, params) - if err != nil { - log.Errorf("query err %v", err) - return "" - } - if len(results) > 0 { - return fmt.Sprint(results[0]["str"]) - } - return "" -} - -// InsertConfig 新增参数配置 -func (r *RepoSysConfig) InsertConfig(sysConfig model.SysConfig) string { - // 参数拼接 - params := make(map[string]any) - if sysConfig.ConfigName != "" { - params["config_name"] = sysConfig.ConfigName - } - if sysConfig.ConfigKey != "" { - params["config_key"] = sysConfig.ConfigKey - } - if sysConfig.ConfigValue != "" { - params["config_value"] = sysConfig.ConfigValue - } - if sysConfig.ConfigType != "" { - params["config_type"] = sysConfig.ConfigType - } - if sysConfig.Remark != "" { - params["remark"] = sysConfig.Remark - } - if sysConfig.CreateBy != "" { - params["create_by"] = sysConfig.CreateBy - params["create_time"] = time.Now().UnixMilli() - } - - // 构建执行语句 - keys, placeholder, values := datasource.KeyPlaceholderValueByInsert(params) - sql := "insert into sys_config (" + strings.Join(keys, ",") + ")values(" + placeholder + ")" - - // 执行插入 - results, err := datasource.ExecDB("", sql, values) - if err != nil { - log.Errorf("insert row : %v", err.Error()) - return "" - } - - insertId, err := results.LastInsertId() - if err != nil { - log.Errorf("insert row : %v", err.Error()) - return "" - } - return fmt.Sprint(insertId) -} - -// UpdateConfig 修改参数配置 -func (r *RepoSysConfig) UpdateConfig(sysConfig model.SysConfig) int64 { - // 参数拼接 - params := make(map[string]any) - if sysConfig.ConfigName != "" { - params["config_name"] = sysConfig.ConfigName - } - if sysConfig.ConfigKey != "" { - params["config_key"] = sysConfig.ConfigKey - } - if sysConfig.ConfigValue != "" { - params["config_value"] = sysConfig.ConfigValue - } - if sysConfig.ConfigType != "" { - params["config_type"] = sysConfig.ConfigType - } - if sysConfig.Remark != "" { - params["remark"] = sysConfig.Remark - } - if sysConfig.UpdateBy != "" { - params["update_by"] = sysConfig.UpdateBy - params["update_time"] = time.Now().UnixMilli() - } - - // 构建执行语句 - keys, values := datasource.KeyValueByUpdate(params) - sql := "update sys_config set " + strings.Join(keys, ",") + " where config_id = ?" - - // 执行更新 - values = append(values, sysConfig.ConfigID) - results, err := datasource.ExecDB("", sql, values) - if err != nil { - log.Errorf("update row : %v", err.Error()) - return 0 - } - affected, err := results.RowsAffected() - if err != nil { - log.Errorf("update err => %v", err) - return 0 - } - return affected -} - -// DeleteConfigByIds 批量删除参数配置信息 -func (r *RepoSysConfig) DeleteConfigByIds(configIds []string) int64 { - placeholder := datasource.KeyPlaceholderByQuery(len(configIds)) - sql := "delete from sys_config where config_id in (" + placeholder + ")" - parameters := datasource.ConvertIdsSlice(configIds) - results, err := datasource.ExecDB("", sql, parameters) - if err != nil { - log.Errorf("delete err => %v", err) - return 0 - } - affected, err := results.RowsAffected() - if err != nil { - log.Errorf("delete err => %v", err) - return 0 - } - return affected -} diff --git a/features/sys_config/service/service_sys_config.go b/features/sys_config/service/service_sys_config.go deleted file mode 100644 index a775845..0000000 --- a/features/sys_config/service/service_sys_config.go +++ /dev/null @@ -1,155 +0,0 @@ -package service - -import ( - "errors" - - "nms_cxy/features/sys_config/model" - "nms_cxy/lib/core/cache" - "nms_cxy/lib/core/constants/cachekey" -) - -// 实例化服务层 ServiceSysConfig 结构体 -var NewServiceSysConfig = &ServiceSysConfig{ - sysConfigRepository: NewRepoSysConfig, -} - -// ServiceSysConfig 参数配置 服务层处理 -type ServiceSysConfig struct { - // 参数配置表 - sysConfigRepository *RepoSysConfig -} - -// SelectDictDataPage 分页查询参数配置列表数据 -func (r *ServiceSysConfig) SelectConfigPage(query map[string]any) map[string]any { - return r.sysConfigRepository.SelectConfigPage(query) -} - -// SelectConfigList 查询参数配置列表 -func (r *ServiceSysConfig) SelectConfigList(sysConfig model.SysConfig) []model.SysConfig { - return r.sysConfigRepository.SelectConfigList(sysConfig) -} - -// SelectConfigValueByKey 通过参数键名查询参数键值 -func (r *ServiceSysConfig) SelectConfigValueByKey(configKey string) string { - cacheKey := r.getCacheKey(configKey) - // 从缓存中读取 - cacheValue, ok := cache.GetLocal(cacheKey) - if cacheValue != nil && ok { - return cacheValue.(string) - } - // 无缓存时读取数据放入缓存中 - configValue := r.sysConfigRepository.SelectConfigValueByKey(configKey) - if configValue != "" { - cache.SetLocal(cacheKey, configValue) - return configValue - } - return "" -} - -// SelectConfigById 通过配置ID查询参数配置信息 -func (r *ServiceSysConfig) SelectConfigById(configId string) model.SysConfig { - if configId == "" { - return model.SysConfig{} - } - configs := r.sysConfigRepository.SelectConfigByIds([]string{configId}) - if len(configs) > 0 { - return configs[0] - } - return model.SysConfig{} -} - -// CheckUniqueConfigKey 校验参数键名是否唯一 -func (r *ServiceSysConfig) CheckUniqueConfigKey(configKey, configId string) bool { - uniqueId := r.sysConfigRepository.CheckUniqueConfig(model.SysConfig{ - ConfigKey: configKey, - }) - if uniqueId == configId { - return true - } - return uniqueId == "" -} - -// InsertConfig 新增参数配置 -func (r *ServiceSysConfig) InsertConfig(sysConfig model.SysConfig) string { - configId := r.sysConfigRepository.InsertConfig(sysConfig) - if configId != "" { - r.loadingConfigCache(sysConfig.ConfigKey) - } - return configId -} - -// UpdateConfig 修改参数配置 -func (r *ServiceSysConfig) UpdateConfig(sysConfig model.SysConfig) int64 { - rows := r.sysConfigRepository.UpdateConfig(sysConfig) - if rows > 0 { - r.loadingConfigCache(sysConfig.ConfigKey) - } - return rows -} - -// DeleteConfigByIds 批量删除参数配置信息 -func (r *ServiceSysConfig) DeleteConfigByIds(configIds []string) (int64, error) { - // 检查是否存在 - configs := r.sysConfigRepository.SelectConfigByIds(configIds) - if len(configs) <= 0 { - return 0, errors.New("does not have permission to access parameter configuration data") - } - for _, config := range configs { - // 检查是否为内置参数 - if config.ConfigType == "Y" { - return 0, errors.New(config.ConfigID + " Configuration parameters are built-in parameters and their deletion is prohibited!") - } - // 清除缓存 - r.clearConfigCache(config.ConfigKey) - } - if len(configs) == len(configIds) { - rows := r.sysConfigRepository.DeleteConfigByIds(configIds) - return rows, nil - } - return 0, errors.New("failed to delete parameter configuration information") -} - -// ResetConfigCache 重置参数缓存数据 -func (r *ServiceSysConfig) ResetConfigCache() { - r.clearConfigCache("*") - r.loadingConfigCache("*") -} - -// getCacheKey 组装缓存key -func (r *ServiceSysConfig) getCacheKey(configKey string) string { - return cachekey.SYS_CONFIG_KEY + configKey -} - -// loadingConfigCache 加载参数缓存数据 -func (r *ServiceSysConfig) loadingConfigCache(configKey string) { - // 查询全部参数 - if configKey == "*" { - sysConfigs := r.SelectConfigList(model.SysConfig{}) - for _, v := range sysConfigs { - key := r.getCacheKey(v.ConfigKey) - cache.DeleteLocal(key) - cache.SetLocal(key, v.ConfigValue) - } - return - } - // 指定参数 - if configKey != "" { - cacheValue := r.sysConfigRepository.SelectConfigValueByKey(configKey) - if cacheValue != "" { - key := r.getCacheKey(configKey) - cache.DeleteLocal(key) - cache.SetLocal(key, cacheValue) - } - return - } -} - -// clearConfigCache 清空参数缓存数据 -func (r *ServiceSysConfig) clearConfigCache(configKey string) bool { - key := r.getCacheKey(configKey) - keys := cache.GetLocalKeys(key) - for _, v := range keys { - cache.DeleteLocal(v) - } - return len(keys) > 0 -} diff --git a/features/sys_dict_data/api_sys_dict_data.go b/features/sys_dict_data/api_sys_dict_data.go deleted file mode 100644 index ec81b6f..0000000 --- a/features/sys_dict_data/api_sys_dict_data.go +++ /dev/null @@ -1,247 +0,0 @@ -package sysdictdata - -import ( - "fmt" - "net/http" - "strings" - - "nms_cxy/features/sys_dict_data/model" - sysDictDataService "nms_cxy/features/sys_dict_data/service" - sysDictTypeService "nms_cxy/features/sys_dict_type/service" - "nms_cxy/lib/core/utils/ctx" - "nms_cxy/lib/core/utils/parse" - "nms_cxy/lib/core/vo/result" - "nms_cxy/lib/midware" - "nms_cxy/lib/services" - "nms_cxy/omc/config" -) - -// 字典类型对应的字典数据信息接口添加到路由 -func Routers() []services.RouterItem { - // 实例化控制层 SysDictDataApi 结构体 - var apis = &SysDictDataApi{ - sysDictDataService: sysDictDataService.NewServiceSysDictData, - sysDictTypeService: sysDictTypeService.NewServiceSysDictType, - } - - rs := [...]services.RouterItem{ - { - Method: "GET", - Pattern: "/dictDatas", - Handler: apis.List, - Middleware: midware.Authorize(nil), - }, - { - Method: "GET", - Pattern: "/dictData/{dictCode}", - Handler: apis.Info, - Middleware: midware.Authorize(nil), - }, - { - Method: "POST", - Pattern: "/dictData", - Handler: apis.Add, - Middleware: midware.Authorize(nil), - }, - { - Method: "PUT", - Pattern: "/dictData", - Handler: apis.Edit, - Middleware: midware.Authorize(nil), - }, - { - Method: "DELETE", - Pattern: "/dictData/{dictCodes}", - Handler: apis.Remove, - Middleware: midware.Authorize(nil), - }, - { - Method: "GET", - Pattern: "/dictData/type/{dictType}", - Handler: apis.DictType, - Middleware: midware.Authorize(nil), - }, - // 添加更多的 Router 对象... - } - - // 生成两组前缀路由 - rsPrefix := []services.RouterItem{} - for _, v := range rs { - path := "/dictDataManage/{apiVersion}" + v.Pattern - // 固定前缀 - v.Pattern = config.DefaultUriPrefix + path - rsPrefix = append(rsPrefix, v) - // 可配置 - v.Pattern = config.UriPrefix + path - rsPrefix = append(rsPrefix, v) - } - return rsPrefix -} - -// 字典类型对应的字典数据信息 -// -// PATH /dictDataManage -type SysDictDataApi struct { - // 字典数据服务 - sysDictDataService *sysDictDataService.ServiceSysDictData - // 字典类型服务 - sysDictTypeService *sysDictTypeService.ServiceSysDictType -} - -// 字典数据列表 -// -// GET /list -func (s *SysDictDataApi) List(w http.ResponseWriter, r *http.Request) { - querys := ctx.QueryMap(r) - data := s.sysDictDataService.SelectDictDataPage(querys) - ctx.JSON(w, 200, result.Ok(data)) -} - -// 字典数据详情 -// -// GET /:dictCode -func (s *SysDictDataApi) Info(w http.ResponseWriter, r *http.Request) { - dictCode := ctx.Param(r, "dictCode") - if dictCode == "" { - ctx.JSON(w, 400, result.CodeMsg(400, "parameter error")) - return - } - data := s.sysDictDataService.SelectDictDataByCode(dictCode) - if data.DictCode == dictCode { - ctx.JSON(w, 200, result.OkData(data)) - return - } - ctx.JSON(w, 200, result.Err(nil)) -} - -// 字典数据新增 -// -// POST / -func (s *SysDictDataApi) Add(w http.ResponseWriter, r *http.Request) { - var body model.SysDictData - err := ctx.ShouldBindJSON(r, &body) - if err != nil || body.DictCode != "" { - ctx.JSON(w, 400, result.CodeMsg(400, "parameter error")) - return - } - - // 检查字典类型是否存在 - sysDictType := s.sysDictTypeService.SelectDictTypeByType(body.DictType) - if sysDictType.DictType != body.DictType { - ctx.JSON(w, 200, result.ErrMsg("No permission to access dictionary type data!")) - return - } - - // 检查字典标签唯一 - uniqueDictLabel := s.sysDictDataService.CheckUniqueDictLabel(body.DictType, body.DictLabel, "") - if !uniqueDictLabel { - msg := fmt.Sprintf("[%s] The subscript signature of this dictionary type already exists", body.DictLabel) - ctx.JSON(w, 200, result.ErrMsg(msg)) - return - } - - // 检查字典键值唯一 - uniqueDictValue := s.sysDictDataService.CheckUniqueDictValue(body.DictType, body.DictValue, "") - if !uniqueDictValue { - msg := fmt.Sprintf("[%s] The label value under this dictionary type already exists", body.DictValue) - ctx.JSON(w, 200, result.ErrMsg(msg)) - return - } - - body.CreateBy = ctx.LoginUserToUserName(r) - insertId := s.sysDictDataService.InsertDictData(body) - if insertId != "" { - ctx.JSON(w, 200, result.Ok(nil)) - return - } - ctx.JSON(w, 200, result.Err(nil)) -} - -// 字典类型修改 -// -// PUT / -func (s *SysDictDataApi) Edit(w http.ResponseWriter, r *http.Request) { - var body model.SysDictData - err := ctx.ShouldBindJSON(r, &body) - if err != nil || body.DictCode == "" { - ctx.JSON(w, 400, result.CodeMsg(400, "parameter error")) - return - } - - // 检查字典类型是否存在 - sysDictType := s.sysDictTypeService.SelectDictTypeByType(body.DictType) - if sysDictType.DictType != body.DictType { - ctx.JSON(w, 200, result.ErrMsg("No permission to access dictionary type data!")) - return - } - - // 检查字典编码是否存在 - SysDictDataApi := s.sysDictDataService.SelectDictDataByCode(body.DictCode) - if SysDictDataApi.DictCode != body.DictCode { - ctx.JSON(w, 200, result.ErrMsg("No permission to access dictionary encoding data!")) - return - } - - // 检查字典标签唯一 - uniqueDictLabel := s.sysDictDataService.CheckUniqueDictLabel(body.DictType, body.DictLabel, body.DictCode) - if !uniqueDictLabel { - msg := fmt.Sprintf("Data modification failed for [%s], the dictionary type subscript signature already exists", body.DictLabel) - ctx.JSON(w, 200, result.ErrMsg(msg)) - return - } - - // 检查字典键值唯一 - uniqueDictValue := s.sysDictDataService.CheckUniqueDictValue(body.DictType, body.DictValue, body.DictCode) - if !uniqueDictValue { - msg := fmt.Sprintf("Data modification failed for [%s], label value already exists under this dictionary type", body.DictValue) - ctx.JSON(w, 200, result.ErrMsg(msg)) - return - } - - body.UpdateBy = ctx.LoginUserToUserName(r) - rows := s.sysDictDataService.UpdateDictData(body) - if rows > 0 { - ctx.JSON(w, 200, result.Ok(nil)) - return - } - ctx.JSON(w, 200, result.Err(nil)) -} - -// 字典数据删除 -// -// DELETE /:dictCodes -func (s *SysDictDataApi) Remove(w http.ResponseWriter, r *http.Request) { - dictCodes := ctx.Param(r, "dictCodes") - if dictCodes == "" { - ctx.JSON(w, 400, result.CodeMsg(400, "parameter error")) - return - } - // 处理字符转id数组后去重 - ids := strings.Split(dictCodes, ",") - uniqueIDs := parse.RemoveDuplicates(ids) - if len(uniqueIDs) <= 0 { - ctx.JSON(w, 200, result.Err(nil)) - return - } - rows, err := s.sysDictDataService.DeleteDictDataByCodes(uniqueIDs) - if err != nil { - ctx.JSON(w, 200, result.ErrMsg(err.Error())) - return - } - msg := fmt.Sprintf("Successfully deleted: %d", rows) - ctx.JSON(w, 200, result.OkMsg(msg)) -} - -// 字典数据列表(指定字典类型) -// -// GET /type/:dictType -func (s *SysDictDataApi) DictType(w http.ResponseWriter, r *http.Request) { - dictType := ctx.Param(r, "dictType") - if dictType == "" { - ctx.JSON(w, 400, result.CodeMsg(400, "parameter error")) - return - } - - data := s.sysDictDataService.SelectDictDataByType(dictType) - ctx.JSON(w, 200, result.OkData(data)) -} diff --git a/features/sys_dict_data/model/sys_dict_data.go b/features/sys_dict_data/model/sys_dict_data.go deleted file mode 100644 index 7c8cd06..0000000 --- a/features/sys_dict_data/model/sys_dict_data.go +++ /dev/null @@ -1,31 +0,0 @@ -package model - -// SysDictData 字典数据对象 sys_dict_data -type SysDictData struct { - // 字典编码 - DictCode string `json:"dictCode"` - // 字典排序 - DictSort int `json:"dictSort"` - // 字典标签 - DictLabel string `json:"dictLabel" binding:"required"` - // 字典键值 - DictValue string `json:"dictValue" binding:"required"` - // 字典类型 - DictType string `json:"dictType" binding:"required"` - // 样式属性(样式扩展) - TagClass string `json:"tagClass"` - // 标签类型(预设颜色) - TagType string `json:"tagType"` - // 状态(0停用 1正常) - Status string `json:"status"` - // 创建者 - CreateBy string `json:"createBy"` - // 创建时间 - CreateTime int64 `json:"createTime"` - // 更新者 - UpdateBy string `json:"updateBy"` - // 更新时间 - UpdateTime int64 `json:"updateTime"` - // 备注 - Remark string `json:"remark"` -} diff --git a/features/sys_dict_data/repo/repo_sys_dict_data.go b/features/sys_dict_data/repo/repo_sys_dict_data.go deleted file mode 100644 index dab8409..0000000 --- a/features/sys_dict_data/repo/repo_sys_dict_data.go +++ /dev/null @@ -1,369 +0,0 @@ -package repo - -import ( - "fmt" - "strings" - "time" - - "nms_cxy/features/sys_dict_data/model" - "nms_cxy/lib/core/datasource" - "nms_cxy/lib/core/utils/parse" - "nms_cxy/lib/log" -) - -// 实例化数据层 RepoSysDictData 结构体 -var NewRepoSysDictData = &RepoSysDictData{ - selectSql: `select - dict_code, dict_sort, dict_label, dict_value, dict_type, tag_class, tag_type, status, create_by, create_time, remark - from sys_dict_data`, - - resultMap: map[string]string{ - "dict_code": "DictCode", - "dict_sort": "DictSort", - "dict_label": "DictLabel", - "dict_value": "DictValue", - "dict_type": "DictType", - "tag_class": "TagClass", - "tag_type": "TagType", - "status": "Status", - "remark": "Remark", - "create_by": "CreateBy", - "create_time": "CreateTime", - "update_by": "UpdateBy", - "update_time": "UpdateTime", - }, -} - -// RepoSysDictData 字典类型数据表 数据层处理 -type RepoSysDictData struct { - // 查询视图对象SQL - selectSql string - // 结果字段与实体映射 - resultMap map[string]string -} - -// convertResultRows 将结果记录转实体结果组 -func (r *RepoSysDictData) convertResultRows(rows []map[string]any) []model.SysDictData { - arr := make([]model.SysDictData, 0) - for _, row := range rows { - sysDictData := model.SysDictData{} - for key, value := range row { - if keyMapper, ok := r.resultMap[key]; ok { - datasource.SetFieldValue(&sysDictData, keyMapper, value) - } - } - arr = append(arr, sysDictData) - } - return arr -} - -// SelectDictDataPage 根据条件分页查询字典数据 -func (r *RepoSysDictData) SelectDictDataPage(query map[string]any) map[string]any { - // 查询条件拼接 - var conditions []string - var params []any - if v, ok := query["dictType"]; ok && v != "" { - conditions = append(conditions, "dict_type = ?") - params = append(params, v) - } - if v, ok := query["dictLabel"]; ok && v != "" { - conditions = append(conditions, "dict_label like concat(?, '%')") - params = append(params, v) - } - if v, ok := query["status"]; ok && v != "" { - conditions = append(conditions, "status = ?") - params = append(params, v) - } - - // 构建查询条件语句 - whereSql := "" - if len(conditions) > 0 { - whereSql += " where " + strings.Join(conditions, " and ") - } - - // 查询数量 长度为0直接返回 - totalSql := "select count(1) as 'total' from sys_dict_data" - totalRows, err := datasource.RawDB("", totalSql+whereSql, params) - if err != nil { - log.Errorf("total err => %v", err) - } - total := parse.Number(totalRows[0]["total"]) - if total == 0 { - return map[string]any{ - "total": total, - "rows": []model.SysDictData{}, - } - } - - // 分页 - pageNum, pageSize := datasource.PageNumSize(query["pageNum"], query["pageSize"]) - pageSql := " order by dict_sort asc limit ?,? " - params = append(params, pageNum*pageSize) - params = append(params, pageSize) - - // 查询数据 - querySql := r.selectSql + whereSql + pageSql - results, err := datasource.RawDB("", querySql, params) - if err != nil { - log.Errorf("query err => %v", err) - } - - // 转换实体 - rows := r.convertResultRows(results) - return map[string]any{ - "total": total, - "rows": rows, - } -} - -// SelectDictDataList 根据条件查询字典数据 -func (r *RepoSysDictData) SelectDictDataList(sysDictData model.SysDictData) []model.SysDictData { - // 查询条件拼接 - var conditions []string - var params []any - if sysDictData.DictLabel != "" { - conditions = append(conditions, "dict_label like concat(?, '%')") - params = append(params, sysDictData.DictLabel) - } - if sysDictData.DictType != "" { - conditions = append(conditions, "dict_type = ?") - params = append(params, sysDictData.DictType) - } - if sysDictData.Status != "" { - conditions = append(conditions, "status = ?") - params = append(params, sysDictData.Status) - } - - // 构建查询条件语句 - whereSql := "" - if len(conditions) > 0 { - whereSql += " where " + strings.Join(conditions, " and ") - } - - // 查询数据 - orderSql := " order by dict_sort asc " - querySql := r.selectSql + whereSql + orderSql - results, err := datasource.RawDB("", querySql, params) - if err != nil { - log.Errorf("query err => %v", err) - return []model.SysDictData{} - } - - // 转换实体 - return r.convertResultRows(results) -} - -// SelectDictDataByCodes 根据字典数据编码查询信息 -func (r *RepoSysDictData) SelectDictDataByCodes(dictCodes []string) []model.SysDictData { - placeholder := datasource.KeyPlaceholderByQuery(len(dictCodes)) - querySql := r.selectSql + " where dict_code in (" + placeholder + ")" - parameters := datasource.ConvertIdsSlice(dictCodes) - results, err := datasource.RawDB("", querySql, parameters) - if err != nil { - log.Errorf("query err => %v", err) - return []model.SysDictData{} - } - // 转换实体 - return r.convertResultRows(results) -} - -// CountDictDataByType 查询字典数据 -func (r *RepoSysDictData) CountDictDataByType(dictType string) int64 { - querySql := "select count(1) as 'total' from sys_dict_data where dict_type = ?" - results, err := datasource.RawDB("", querySql, []any{dictType}) - if err != nil { - log.Errorf("query err => %v", err) - return 0 - } - if len(results) > 0 { - return parse.Number(results[0]["total"]) - } - return 0 -} - -// CheckUniqueDictData 校验字典数据是否唯一 -func (r *RepoSysDictData) CheckUniqueDictData(sysDictData model.SysDictData) string { - // 查询条件拼接 - var conditions []string - var params []any - if sysDictData.DictType != "" { - conditions = append(conditions, "dict_type = ?") - params = append(params, sysDictData.DictType) - } - if sysDictData.DictLabel != "" { - conditions = append(conditions, "dict_label = ?") - params = append(params, sysDictData.DictLabel) - } - if sysDictData.DictValue != "" { - conditions = append(conditions, "dict_value = ?") - params = append(params, sysDictData.DictValue) - } - - // 构建查询条件语句 - whereSql := "" - if len(conditions) > 0 { - whereSql += " where " + strings.Join(conditions, " and ") - } else { - return "" - } - - // 查询数据 - querySql := "select dict_code as 'str' from sys_dict_data " + whereSql + " limit 1" - results, err := datasource.RawDB("", querySql, params) - if err != nil { - log.Errorf("query err %v", err) - return "" - } - if len(results) > 0 { - return fmt.Sprint(results[0]["str"]) - } - return "" -} - -// DeleteDictDataByCodes 批量删除字典数据信息 -func (r *RepoSysDictData) DeleteDictDataByCodes(dictCodes []string) int64 { - placeholder := datasource.KeyPlaceholderByQuery(len(dictCodes)) - sql := "delete from sys_dict_data where dict_code in (" + placeholder + ")" - parameters := datasource.ConvertIdsSlice(dictCodes) - results, err := datasource.ExecDB("", sql, parameters) - if err != nil { - log.Errorf("delete err => %v", err) - return 0 - } - affected, err := results.RowsAffected() - if err != nil { - log.Errorf("delete err => %v", err) - return 0 - } - return affected -} - -// InsertDictData 新增字典数据信息 -func (r *RepoSysDictData) InsertDictData(sysDictData model.SysDictData) string { - // 参数拼接 - params := make(map[string]any) - if sysDictData.DictSort > 0 { - params["dict_sort"] = sysDictData.DictSort - } - if sysDictData.DictLabel != "" { - params["dict_label"] = sysDictData.DictLabel - } - if sysDictData.DictValue != "" { - params["dict_value"] = sysDictData.DictValue - } - if sysDictData.DictType != "" { - params["dict_type"] = sysDictData.DictType - } - if sysDictData.TagClass != "" { - params["tag_class"] = sysDictData.TagClass - } - if sysDictData.TagType != "" { - params["tag_type"] = sysDictData.TagType - } - if sysDictData.Status != "" { - params["status"] = sysDictData.Status - } - if sysDictData.Remark != "" { - params["remark"] = sysDictData.Remark - } - if sysDictData.CreateBy != "" { - params["create_by"] = sysDictData.CreateBy - params["create_time"] = time.Now().UnixMilli() - } - - // 构建执行语句 - keys, placeholder, values := datasource.KeyPlaceholderValueByInsert(params) - sql := "insert into sys_dict_data (" + strings.Join(keys, ",") + ")values(" + placeholder + ")" - - // 执行插入 - results, err := datasource.ExecDB("", sql, values) - if err != nil { - log.Errorf("insert row : %v", err.Error()) - return "" - } - insertId, err := results.LastInsertId() - if err != nil { - log.Errorf("insert row : %v", err.Error()) - return "" - } - return fmt.Sprint(insertId) -} - -// UpdateDictData 修改字典数据信息 -func (r *RepoSysDictData) UpdateDictData(sysDictData model.SysDictData) int64 { - // 参数拼接 - params := make(map[string]any) - if sysDictData.DictSort > 0 { - params["dict_sort"] = sysDictData.DictSort - } - if sysDictData.DictLabel != "" { - params["dict_label"] = sysDictData.DictLabel - } - if sysDictData.DictValue != "" { - params["dict_value"] = sysDictData.DictValue - } - if sysDictData.DictType != "" { - params["dict_type"] = sysDictData.DictType - } - if sysDictData.TagClass != "" { - params["tag_class"] = sysDictData.TagClass - } - if sysDictData.TagType != "" { - params["tag_type"] = sysDictData.TagType - } - if sysDictData.Status != "" { - params["status"] = sysDictData.Status - } - if sysDictData.Remark != "" { - params["remark"] = sysDictData.Remark - } - if sysDictData.UpdateBy != "" { - params["update_by"] = sysDictData.UpdateBy - params["update_time"] = time.Now().UnixMilli() - } - - // 构建执行语句 - keys, values := datasource.KeyValueByUpdate(params) - sql := "update sys_dict_data set " + strings.Join(keys, ",") + " where dict_code = ?" - - // 执行更新 - values = append(values, sysDictData.DictCode) - results, err := datasource.ExecDB("", sql, values) - if err != nil { - log.Errorf("update row : %v", err.Error()) - return 0 - } - affected, err := results.RowsAffected() - if err != nil { - log.Errorf("update err => %v", err) - return 0 - } - return affected -} - -// UpdateDictDataType 同步修改字典类型 -func (r *RepoSysDictData) UpdateDictDataType(oldDictType string, newDictType string) int64 { - // 参数拼接 - params := make([]any, 0) - if oldDictType == "" || newDictType == "" { - return 0 - } - params = append(params, newDictType) - params = append(params, oldDictType) - - // 构建执行语句 - sql := "update sys_dict_data set dict_type = ? where dict_type = ?" - - // 执行更新 - results, err := datasource.ExecDB("", sql, params) - if err != nil { - log.Errorf("update row : %v", err.Error()) - return 0 - } - affected, err := results.RowsAffected() - if err != nil { - log.Errorf("update err => %v", err) - return 0 - } - return affected -} diff --git a/features/sys_dict_data/service/service_sys_dict_data.go b/features/sys_dict_data/service/service_sys_dict_data.go deleted file mode 100644 index ad363f8..0000000 --- a/features/sys_dict_data/service/service_sys_dict_data.go +++ /dev/null @@ -1,111 +0,0 @@ -package service - -import ( - "errors" - - "nms_cxy/features/sys_dict_data/model" - "nms_cxy/features/sys_dict_data/repo" - sysDictTypeService "nms_cxy/features/sys_dict_type/service" -) - -// 实例化服务层 ServiceSysDictData 结构体 -var NewServiceSysDictData = &ServiceSysDictData{ - sysDictDataRepository: *repo.NewRepoSysDictData, - sysDictTypeService: *sysDictTypeService.NewServiceSysDictType, -} - -// ServiceSysDictData 字典类型数据 服务层处理 -type ServiceSysDictData struct { - // 字典数据服务 - sysDictDataRepository repo.RepoSysDictData - // 字典类型服务 - sysDictTypeService sysDictTypeService.ServiceSysDictType -} - -// SelectDictDataPage 根据条件分页查询字典数据 -func (r *ServiceSysDictData) SelectDictDataPage(query map[string]any) map[string]any { - return r.sysDictDataRepository.SelectDictDataPage(query) -} - -// SelectDictDataList 根据条件查询字典数据 -func (r *ServiceSysDictData) SelectDictDataList(sysDictData model.SysDictData) []model.SysDictData { - return r.sysDictDataRepository.SelectDictDataList(sysDictData) -} - -// SelectDictDataByCode 根据字典数据编码查询信息 -func (r *ServiceSysDictData) SelectDictDataByCode(dictCode string) model.SysDictData { - if dictCode == "" { - return model.SysDictData{} - } - dictCodes := r.sysDictDataRepository.SelectDictDataByCodes([]string{dictCode}) - if len(dictCodes) > 0 { - return dictCodes[0] - } - return model.SysDictData{} -} - -// SelectDictDataByType 根据字典类型查询信息 -func (r *ServiceSysDictData) SelectDictDataByType(dictType string) []model.SysDictData { - return r.sysDictTypeService.DictDataCache(dictType) -} - -// CheckUniqueDictLabel 校验字典标签是否唯一 -func (r *ServiceSysDictData) CheckUniqueDictLabel(dictType, dictLabel, dictCode string) bool { - uniqueId := r.sysDictDataRepository.CheckUniqueDictData(model.SysDictData{ - DictType: dictType, - DictLabel: dictLabel, - }) - if uniqueId == dictCode { - return true - } - return uniqueId == "" -} - -// CheckUniqueDictValue 校验字典键值是否唯一 -func (r *ServiceSysDictData) CheckUniqueDictValue(dictType, dictValue, dictCode string) bool { - uniqueId := r.sysDictDataRepository.CheckUniqueDictData(model.SysDictData{ - DictType: dictType, - DictValue: dictValue, - }) - if uniqueId == dictCode { - return true - } - return uniqueId == "" -} - -// DeleteDictDataByCodes 批量删除字典数据信息 -func (r *ServiceSysDictData) DeleteDictDataByCodes(dictCodes []string) (int64, error) { - // 检查是否存在 - dictDatas := r.sysDictDataRepository.SelectDictDataByCodes(dictCodes) - if len(dictDatas) <= 0 { - return 0, errors.New("does not have permission to access dictionary-encoded data") - } - if len(dictDatas) == len(dictCodes) { - for _, v := range dictDatas { - // 刷新缓存 - r.sysDictTypeService.ClearDictCache(v.DictType) - r.sysDictTypeService.LoadingDictCache(v.DictType) - } - rows := r.sysDictDataRepository.DeleteDictDataByCodes(dictCodes) - return rows, nil - } - return 0, errors.New("failed to delete dictionary data information") -} - -// InsertDictData 新增字典数据信息 -func (r *ServiceSysDictData) InsertDictData(sysDictData model.SysDictData) string { - insertId := r.sysDictDataRepository.InsertDictData(sysDictData) - if insertId != "" { - r.sysDictTypeService.LoadingDictCache(sysDictData.DictType) - } - return insertId -} - -// UpdateDictData 修改字典数据信息 -func (r *ServiceSysDictData) UpdateDictData(sysDictData model.SysDictData) int64 { - rows := r.sysDictDataRepository.UpdateDictData(sysDictData) - if rows > 0 { - r.sysDictTypeService.LoadingDictCache(sysDictData.DictType) - } - return rows -} diff --git a/features/sys_dict_type/api_sys_dict_type.go b/features/sys_dict_type/api_sys_dict_type.go deleted file mode 100644 index e78d541..0000000 --- a/features/sys_dict_type/api_sys_dict_type.go +++ /dev/null @@ -1,253 +0,0 @@ -package sysdicttype - -import ( - "fmt" - "net/http" - "strings" - - "nms_cxy/features/sys_dict_type/model" - sysDictTypeService "nms_cxy/features/sys_dict_type/service" - "nms_cxy/lib/core/utils/ctx" - "nms_cxy/lib/core/utils/parse" - "nms_cxy/lib/core/vo/result" - "nms_cxy/lib/midware" - "nms_cxy/lib/services" - "nms_cxy/omc/config" -) - -// 字典类型信息接口添加到路由 -func Routers() []services.RouterItem { - // 实例化控制层 SysDictTypeApi 结构体 - var apis = &SysDictTypeApi{ - sysDictTypeService: *sysDictTypeService.NewServiceSysDictType, - } - - rs := [...]services.RouterItem{ - { - Method: "GET", - Pattern: "/dictTypes", - Handler: apis.List, - Middleware: midware.Authorize(nil), - }, - { - Method: "GET", - Pattern: "/dictType/{dictId}", - Handler: apis.Info, - Middleware: midware.Authorize(nil), - }, - { - Method: "POST", - Pattern: "/dictType", - Handler: apis.Add, - Middleware: midware.Authorize(nil), - }, - { - Method: "PUT", - Pattern: "/dictType", - Handler: apis.Edit, - Middleware: midware.Authorize(nil), - }, - { - Method: "DELETE", - Pattern: "/dictType/{dictIds}", - Handler: apis.Remove, - Middleware: midware.Authorize(nil), - }, - { - Method: "PUT", - Pattern: "/dictType/refreshCache", - Handler: apis.RefreshCache, - Middleware: midware.Authorize(nil), - }, - { - Method: "GET", - Pattern: "/dictTypes/optionselect", - Handler: apis.DictOptionselect, - Middleware: midware.Authorize(nil), - }, - // 添加更多的 Router 对象... - } - - // 生成两组前缀路由 - rsPrefix := []services.RouterItem{} - for _, v := range rs { - path := "/dictTypegManage/{apiVersion}" + v.Pattern - // 固定前缀 - v.Pattern = config.DefaultUriPrefix + path - rsPrefix = append(rsPrefix, v) - // 可配置 - v.Pattern = config.UriPrefix + path - rsPrefix = append(rsPrefix, v) - } - return rsPrefix -} - -// 字典类型信息 -// -// PATH /dictTypegManage -type SysDictTypeApi struct { - // 字典类型服务 - sysDictTypeService sysDictTypeService.ServiceSysDictType -} - -// 字典类型列表 -// -// GET /list -func (s *SysDictTypeApi) List(w http.ResponseWriter, r *http.Request) { - querys := ctx.QueryMap(r) - data := s.sysDictTypeService.SelectDictTypePage(querys) - ctx.JSON(w, 200, result.Ok(data)) -} - -// 字典类型信息 -// -// GET /:dictId -func (s *SysDictTypeApi) Info(w http.ResponseWriter, r *http.Request) { - dictId := ctx.Param(r, "dictId") - if dictId == "" { - ctx.JSON(w, 400, result.CodeMsg(400, "parameter error")) - return - } - data := s.sysDictTypeService.SelectDictTypeByID(dictId) - if data.DictID == dictId { - ctx.JSON(w, 200, result.OkData(data)) - return - } - ctx.JSON(w, 200, result.Err(nil)) -} - -// 字典类型新增 -// -// POST / -func (s *SysDictTypeApi) Add(w http.ResponseWriter, r *http.Request) { - var body model.SysDictType - err := ctx.ShouldBindJSON(r, &body) - if err != nil || body.DictID != "" { - ctx.JSON(w, 400, result.CodeMsg(400, "parameter error")) - return - } - - // 检查字典名称唯一 - uniqueDictName := s.sysDictTypeService.CheckUniqueDictName(body.DictName, "") - if !uniqueDictName { - msg := fmt.Sprintf("Failed to add dictionary '%s', dictionary name already exists", body.DictName) - ctx.JSON(w, 200, result.ErrMsg(msg)) - return - } - - // 检查字典类型唯一 - uniqueDictType := s.sysDictTypeService.CheckUniqueDictType(body.DictType, "") - if !uniqueDictType { - msg := fmt.Sprintf("Failed to add dictionary '%s', dictionary type already exists", body.DictType) - ctx.JSON(w, 200, result.ErrMsg(msg)) - return - } - - body.CreateBy = ctx.LoginUserToUserName(r) - insertId := s.sysDictTypeService.InsertDictType(body) - if insertId != "" { - ctx.JSON(w, 200, result.Ok(nil)) - return - } - ctx.JSON(w, 200, result.Err(nil)) -} - -// 字典类型修改 -// -// PUT / -func (s *SysDictTypeApi) Edit(w http.ResponseWriter, r *http.Request) { - var body model.SysDictType - err := ctx.ShouldBindJSON(r, &body) - if err != nil || body.DictID == "" { - ctx.JSON(w, 400, result.CodeMsg(400, "parameter error")) - return - } - - // 检查数据是否存在 - dictInfo := s.sysDictTypeService.SelectDictTypeByID(body.DictID) - if dictInfo.DictID != body.DictID { - ctx.JSON(w, 200, result.ErrMsg("No permission to access dictionary type data!")) - return - } - - // 检查字典名称唯一 - uniqueDictName := s.sysDictTypeService.CheckUniqueDictName(body.DictName, body.DictID) - if !uniqueDictName { - msg := fmt.Sprintf("Dictionary modification failed for [%s], dictionary name already exists", body.DictName) - ctx.JSON(w, 200, result.ErrMsg(msg)) - return - } - - // 检查字典类型唯一 - uniqueDictType := s.sysDictTypeService.CheckUniqueDictType(body.DictType, body.DictID) - if !uniqueDictType { - msg := fmt.Sprintf("Dictionary modification failed for [%s], dictionary type already exists", body.DictType) - ctx.JSON(w, 200, result.ErrMsg(msg)) - return - } - - body.UpdateBy = ctx.LoginUserToUserName(r) - rows := s.sysDictTypeService.UpdateDictType(body) - if rows > 0 { - ctx.JSON(w, 200, result.Ok(nil)) - return - } - ctx.JSON(w, 200, result.Err(nil)) -} - -// 字典类型删除 -// -// DELETE /:dictIds -func (s *SysDictTypeApi) Remove(w http.ResponseWriter, r *http.Request) { - dictIds := ctx.Param(r, "dictIds") - if dictIds == "" { - ctx.JSON(w, 400, result.CodeMsg(400, "parameter error")) - return - } - // 处理字符转id数组后去重 - ids := strings.Split(dictIds, ",") - uniqueIDs := parse.RemoveDuplicates(ids) - if len(uniqueIDs) <= 0 { - ctx.JSON(w, 200, result.Err(nil)) - return - } - rows, err := s.sysDictTypeService.DeleteDictTypeByIDs(uniqueIDs) - if err != nil { - ctx.JSON(w, 200, result.ErrMsg(err.Error())) - return - } - msg := fmt.Sprintf("Successfully deleted: %d", rows) - ctx.JSON(w, 200, result.OkMsg(msg)) -} - -// 字典类型刷新缓存 -// -// PUT /refreshCache -func (s *SysDictTypeApi) RefreshCache(w http.ResponseWriter, r *http.Request) { - s.sysDictTypeService.ResetDictCache() - ctx.JSON(w, 200, result.Ok(nil)) -} - -// 字典类型选择框列表 -// -// GET /getDictOptionselect -func (s *SysDictTypeApi) DictOptionselect(w http.ResponseWriter, r *http.Request) { - data := s.sysDictTypeService.SelectDictTypeList(model.SysDictType{ - Status: "1", - }) - - type labelValue struct { - Label string `json:"label"` - Value string `json:"value"` - } - - // 数据组 - arr := []labelValue{} - for _, v := range data { - arr = append(arr, labelValue{ - Label: v.DictName, - Value: v.DictType, - }) - } - ctx.JSON(w, 200, result.OkData(arr)) -} diff --git a/features/sys_dict_type/model/sys_dict_type.go b/features/sys_dict_type/model/sys_dict_type.go deleted file mode 100644 index 0ad0b1a..0000000 --- a/features/sys_dict_type/model/sys_dict_type.go +++ /dev/null @@ -1,23 +0,0 @@ -package model - -// SysDictType 字典类型对象 sys_dict_type -type SysDictType struct { - // 字典主键 - DictID string `json:"dictId"` - // 字典名称 - DictName string `json:"dictName" binding:"required"` - // 字典类型 - DictType string `json:"dictType" binding:"required"` - // 状态(0停用 1正常) - Status string `json:"status"` - // 创建者 - CreateBy string `json:"createBy"` - // 创建时间 - CreateTime int64 `json:"createTime"` - // 更新者 - UpdateBy string `json:"updateBy"` - // 更新时间 - UpdateTime int64 `json:"updateTime"` - // 备注 - Remark string `json:"remark"` -} diff --git a/features/sys_dict_type/repo/repo_sys_dict_type.go b/features/sys_dict_type/repo/repo_sys_dict_type.go deleted file mode 100644 index 26ef3ef..0000000 --- a/features/sys_dict_type/repo/repo_sys_dict_type.go +++ /dev/null @@ -1,330 +0,0 @@ -package repo - -import ( - "fmt" - "strings" - "time" - - "nms_cxy/features/sys_dict_type/model" - "nms_cxy/lib/core/datasource" - "nms_cxy/lib/core/utils/date" - "nms_cxy/lib/core/utils/parse" - "nms_cxy/lib/log" -) - -// 实例化数据层 RepoSysDictType 结构体 -var NewRepoSysDictType = &RepoSysDictType{ - selectSql: `select - dict_id, dict_name, dict_type, status, create_by, create_time, remark - from sys_dict_type`, - - resultMap: map[string]string{ - "dict_id": "DictID", - "dict_name": "DictName", - "dict_type": "DictType", - "remark": "Remark", - "status": "Status", - "create_by": "CreateBy", - "create_time": "CreateTime", - "update_by": "UpdateBy", - "update_time": "UpdateTime", - }, -} - -// RepoSysDictType 字典类型表 数据层处理 -type RepoSysDictType struct { - // 查询视图对象SQL - selectSql string - // 结果字段与实体映射 - resultMap map[string]string -} - -// convertResultRows 将结果记录转实体结果组 -func (r *RepoSysDictType) convertResultRows(rows []map[string]any) []model.SysDictType { - arr := make([]model.SysDictType, 0) - for _, row := range rows { - sysDictType := model.SysDictType{} - for key, value := range row { - if keyMapper, ok := r.resultMap[key]; ok { - datasource.SetFieldValue(&sysDictType, keyMapper, value) - } - } - arr = append(arr, sysDictType) - } - return arr -} - -// SelectDictTypePage 根据条件分页查询字典类型 -func (r *RepoSysDictType) SelectDictTypePage(query map[string]any) map[string]any { - // 查询条件拼接 - var conditions []string - var params []any - if v, ok := query["dictName"]; ok && v != "" { - conditions = append(conditions, "dict_name like concat(?, '%')") - params = append(params, v) - } - if v, ok := query["dictType"]; ok && v != "" { - conditions = append(conditions, "dict_type like concat(?, '%')") - params = append(params, v) - } - if v, ok := query["status"]; ok && v != "" { - conditions = append(conditions, "status = ?") - params = append(params, v) - } - beginTime, ok := query["beginTime"] - if !ok { - beginTime, ok = query["params[beginTime]"] - } - if ok && beginTime != "" { - conditions = append(conditions, "create_time >= ?") - beginDate := date.ParseStrToDate(beginTime.(string), date.YYYY_MM_DD) - params = append(params, beginDate.UnixMilli()) - } - endTime, ok := query["endTime"] - if !ok { - endTime, ok = query["params[endTime]"] - } - if ok && endTime != "" { - conditions = append(conditions, "create_time <= ?") - endDate := date.ParseStrToDate(endTime.(string), date.YYYY_MM_DD) - params = append(params, endDate.UnixMilli()) - } - - // 构建查询条件语句 - whereSql := "" - if len(conditions) > 0 { - whereSql += " where " + strings.Join(conditions, " and ") - } - - // 查询数量 长度为0直接返回 - totalSql := "select count(1) as 'total' from sys_dict_type" - totalRows, err := datasource.RawDB("", totalSql+whereSql, params) - if err != nil { - log.Errorf("total err => %v", err) - } - total := parse.Number(totalRows[0]["total"]) - if total == 0 { - return map[string]any{ - "total": total, - "rows": []model.SysDictType{}, - } - } - - // 分页 - pageNum, pageSize := datasource.PageNumSize(query["pageNum"], query["pageSize"]) - pageSql := " limit ?,? " - params = append(params, pageNum*pageSize) - params = append(params, pageSize) - - // 查询数据 - querySql := r.selectSql + whereSql + pageSql - results, err := datasource.RawDB("", querySql, params) - if err != nil { - log.Errorf("query err => %v", err) - } - - // 转换实体 - rows := r.convertResultRows(results) - return map[string]any{ - "total": total, - "rows": rows, - } -} - -// SelectDictTypeList 根据条件查询字典类型 -func (r *RepoSysDictType) SelectDictTypeList(sysDictType model.SysDictType) []model.SysDictType { - // 查询条件拼接 - var conditions []string - var params []any - if sysDictType.DictName != "" { - conditions = append(conditions, "dict_name like concat(?, '%')") - params = append(params, sysDictType.DictName) - } - if sysDictType.DictType != "" { - conditions = append(conditions, "dict_type like concat(?, '%')") - params = append(params, sysDictType.DictType) - } - if sysDictType.Status != "" { - conditions = append(conditions, "status = ?") - params = append(params, sysDictType.Status) - } - - // 构建查询条件语句 - whereSql := "" - if len(conditions) > 0 { - whereSql += " where " + strings.Join(conditions, " and ") - } - - // 查询数据 - querySql := r.selectSql + whereSql - results, err := datasource.RawDB("", querySql, params) - if err != nil { - log.Errorf("query err => %v", err) - return []model.SysDictType{} - } - - // 转换实体 - return r.convertResultRows(results) -} - -// SelectDictTypeByIDs 根据字典类型ID查询信息 -func (r *RepoSysDictType) SelectDictTypeByIDs(dictIDs []string) []model.SysDictType { - placeholder := datasource.KeyPlaceholderByQuery(len(dictIDs)) - querySql := r.selectSql + " where dict_id in (" + placeholder + ")" - parameters := datasource.ConvertIdsSlice(dictIDs) - results, err := datasource.RawDB("", querySql, parameters) - if err != nil { - log.Errorf("query err => %v", err) - return []model.SysDictType{} - } - // 转换实体 - return r.convertResultRows(results) -} - -// SelectDictTypeByType 根据字典类型查询信息 -func (r *RepoSysDictType) SelectDictTypeByType(dictType string) model.SysDictType { - querySql := r.selectSql + " where dict_type = ?" - results, err := datasource.RawDB("", querySql, []any{dictType}) - if err != nil { - log.Errorf("query err => %v", err) - return model.SysDictType{} - } - // 转换实体 - rows := r.convertResultRows(results) - if len(rows) > 0 { - return rows[0] - } - return model.SysDictType{} -} - -// CheckUniqueDictType 校验字典是否唯一 -func (r *RepoSysDictType) CheckUniqueDictType(sysDictType model.SysDictType) string { - // 查询条件拼接 - var conditions []string - var params []any - if sysDictType.DictName != "" { - conditions = append(conditions, "dict_name = ?") - params = append(params, sysDictType.DictName) - } - if sysDictType.DictType != "" { - conditions = append(conditions, "dict_type = ?") - params = append(params, sysDictType.DictType) - } - - // 构建查询条件语句 - whereSql := "" - if len(conditions) > 0 { - whereSql += " where " + strings.Join(conditions, " and ") - } else { - return "" - } - - // 查询数据 - querySql := "select dict_id as 'str' from sys_dict_type " + whereSql + " limit 1" - results, err := datasource.RawDB("", querySql, params) - if err != nil { - log.Errorf("query err %v", err) - return "" - } - if len(results) > 0 { - return fmt.Sprint(results[0]["str"]) - } - return "" -} - -// InsertDictType 新增字典类型信息 -func (r *RepoSysDictType) InsertDictType(sysDictType model.SysDictType) string { - // 参数拼接 - params := make(map[string]any) - if sysDictType.DictName != "" { - params["dict_name"] = sysDictType.DictName - } - if sysDictType.DictType != "" { - params["dict_type"] = sysDictType.DictType - } - if sysDictType.Status != "" { - params["status"] = sysDictType.Status - } - if sysDictType.Remark != "" { - params["remark"] = sysDictType.Remark - } - if sysDictType.CreateBy != "" { - params["create_by"] = sysDictType.CreateBy - params["create_time"] = time.Now().UnixMilli() - } - - // 构建执行语句 - keys, placeholder, values := datasource.KeyPlaceholderValueByInsert(params) - sql := "insert into sys_dict_type (" + strings.Join(keys, ",") + ")values(" + placeholder + ")" - - // 执行插入 - results, err := datasource.ExecDB("", sql, values) - if err != nil { - log.Errorf("insert row : %v", err.Error()) - return "" - } - insertId, err := results.LastInsertId() - if err != nil { - log.Errorf("insert row : %v", err.Error()) - return "" - } - return fmt.Sprint(insertId) -} - -// UpdateDictType 修改字典类型信息 -func (r *RepoSysDictType) UpdateDictType(sysDictType model.SysDictType) int64 { - // 参数拼接 - params := make(map[string]any) - if sysDictType.DictName != "" { - params["dict_name"] = sysDictType.DictName - } - if sysDictType.DictType != "" { - params["dict_type"] = sysDictType.DictType - } - if sysDictType.Status != "" { - params["status"] = sysDictType.Status - } - if sysDictType.Remark != "" { - params["remark"] = sysDictType.Remark - } - if sysDictType.UpdateBy != "" { - params["update_by"] = sysDictType.UpdateBy - params["update_time"] = time.Now().UnixMilli() - } - - // 构建执行语句 - keys, values := datasource.KeyValueByUpdate(params) - sql := "update sys_dict_type set " + strings.Join(keys, ",") + " where dict_id = ?" - - // 执行更新 - values = append(values, sysDictType.DictID) - results, err := datasource.ExecDB("", sql, values) - if err != nil { - log.Errorf("update row : %v", err.Error()) - return 0 - } - affected, err := results.RowsAffected() - if err != nil { - log.Errorf("update err => %v", err) - return 0 - } - return affected -} - -// DeleteDictTypeByIDs 批量删除字典类型信息 -func (r *RepoSysDictType) DeleteDictTypeByIDs(dictIDs []string) int64 { - placeholder := datasource.KeyPlaceholderByQuery(len(dictIDs)) - sql := "delete from sys_dict_type where dict_id in (" + placeholder + ")" - parameters := datasource.ConvertIdsSlice(dictIDs) - results, err := datasource.ExecDB("", sql, parameters) - if err != nil { - log.Errorf("delete err => %v", err) - return 0 - } - affected, err := results.RowsAffected() - if err != nil { - log.Errorf("delete err => %v", err) - return 0 - } - return affected -} diff --git a/features/sys_dict_type/service/service_sys_dict_type.go b/features/sys_dict_type/service/service_sys_dict_type.go deleted file mode 100644 index 9aafcf6..0000000 --- a/features/sys_dict_type/service/service_sys_dict_type.go +++ /dev/null @@ -1,211 +0,0 @@ -package service - -import ( - "encoding/json" - "errors" - "fmt" - - sysDictDataModel "nms_cxy/features/sys_dict_data/model" - sysDictDataRepo "nms_cxy/features/sys_dict_data/repo" - sysDictTypeModel "nms_cxy/features/sys_dict_type/model" - "nms_cxy/features/sys_dict_type/repo" - "nms_cxy/lib/core/cache" - "nms_cxy/lib/core/constants/cachekey" -) - -// 实例化服务层 ServiceSysDictType 结构体 -var NewServiceSysDictType = &ServiceSysDictType{ - sysDictTypeRepository: *repo.NewRepoSysDictType, - sysDictDataRepository: *sysDictDataRepo.NewRepoSysDictData, -} - -// ServiceSysDictType 字典类型 服务层处理 -type ServiceSysDictType struct { - // 字典类型服务 - sysDictTypeRepository repo.RepoSysDictType - // 字典数据服务 - sysDictDataRepository sysDictDataRepo.RepoSysDictData -} - -// SelectDictTypePage 根据条件分页查询字典类型 -func (r *ServiceSysDictType) SelectDictTypePage(query map[string]any) map[string]any { - return r.sysDictTypeRepository.SelectDictTypePage(query) -} - -// SelectDictTypeList 根据条件查询字典类型 -func (r *ServiceSysDictType) SelectDictTypeList(sysDictType sysDictTypeModel.SysDictType) []sysDictTypeModel.SysDictType { - return r.sysDictTypeRepository.SelectDictTypeList(sysDictType) -} - -// SelectDictTypeByID 根据字典类型ID查询信息 -func (r *ServiceSysDictType) SelectDictTypeByID(dictID string) sysDictTypeModel.SysDictType { - if dictID == "" { - return sysDictTypeModel.SysDictType{} - } - dictTypes := r.sysDictTypeRepository.SelectDictTypeByIDs([]string{dictID}) - if len(dictTypes) > 0 { - return dictTypes[0] - } - return sysDictTypeModel.SysDictType{} -} - -// SelectDictTypeByType 根据字典类型查询信息 -func (r *ServiceSysDictType) SelectDictTypeByType(dictType string) sysDictTypeModel.SysDictType { - return r.sysDictTypeRepository.SelectDictTypeByType(dictType) -} - -// CheckUniqueDictName 校验字典名称是否唯一 -func (r *ServiceSysDictType) CheckUniqueDictName(dictName, dictID string) bool { - uniqueId := r.sysDictTypeRepository.CheckUniqueDictType(sysDictTypeModel.SysDictType{ - DictName: dictName, - }) - if uniqueId == dictID { - return true - } - return uniqueId == "" -} - -// CheckUniqueDictType 校验字典类型是否唯一 -func (r *ServiceSysDictType) CheckUniqueDictType(dictType, dictID string) bool { - uniqueId := r.sysDictTypeRepository.CheckUniqueDictType(sysDictTypeModel.SysDictType{ - DictType: dictType, - }) - if uniqueId == dictID { - return true - } - return uniqueId == "" -} - -// InsertDictType 新增字典类型信息 -func (r *ServiceSysDictType) InsertDictType(sysDictType sysDictTypeModel.SysDictType) string { - insertId := r.sysDictTypeRepository.InsertDictType(sysDictType) - if insertId != "" { - r.LoadingDictCache(sysDictType.DictType) - } - return insertId -} - -// UpdateDictType 修改字典类型信息 -func (r *ServiceSysDictType) UpdateDictType(sysDictType sysDictTypeModel.SysDictType) int64 { - data := r.sysDictTypeRepository.SelectDictTypeByIDs([]string{sysDictType.DictID}) - if len(data) == 0 { - return 0 - } - // 修改字典类型key时同步更新其字典数据的类型key - oldDictType := data[0].DictType - rows := r.sysDictTypeRepository.UpdateDictType(sysDictType) - if rows > 0 && oldDictType != "" && oldDictType != sysDictType.DictType { - r.sysDictDataRepository.UpdateDictDataType(oldDictType, sysDictType.DictType) - } - // 刷新缓存 - r.ClearDictCache(oldDictType) - r.LoadingDictCache(sysDictType.DictType) - return rows -} - -// DeleteDictTypeByIDs 批量删除字典类型信息 -func (r *ServiceSysDictType) DeleteDictTypeByIDs(dictIDs []string) (int64, error) { - // 检查是否存在 - dictTypes := r.sysDictTypeRepository.SelectDictTypeByIDs(dictIDs) - if len(dictTypes) <= 0 { - return 0, errors.New("no permission to access dictionary type data") - } - for _, v := range dictTypes { - // 字典类型下级含有数据 - useCount := r.sysDictDataRepository.CountDictDataByType(v.DictType) - if useCount > 0 { - msg := fmt.Sprintf("[%s] Dictionary data exists and cannot be deleted. ", v.DictName) - return 0, errors.New(msg) - } - // 清除缓存 - r.ClearDictCache(v.DictType) - } - if len(dictTypes) == len(dictIDs) { - rows := r.sysDictTypeRepository.DeleteDictTypeByIDs(dictIDs) - return rows, nil - } - return 0, errors.New("failed to delete dictionary data information") -} - -// ResetDictCache 重置字典缓存数据 -func (r *ServiceSysDictType) ResetDictCache() { - r.ClearDictCache("*") - r.LoadingDictCache("") -} - -// getCacheKey 组装缓存key -func (r *ServiceSysDictType) getDictCache(dictType string) string { - return cachekey.SYS_DICT_KEY + dictType -} - -// LoadingDictCache 加载字典缓存数据 -func (r *ServiceSysDictType) LoadingDictCache(dictType string) { - sysDictData := sysDictDataModel.SysDictData{ - Status: "1", - } - - // 指定字典类型 - if dictType != "" { - sysDictData.DictType = dictType - // 删除缓存 - key := r.getDictCache(dictType) - cache.DeleteLocal(key) - } - - sysDictDataList := r.sysDictDataRepository.SelectDictDataList(sysDictData) - if len(sysDictDataList) == 0 { - return - } - - // 将字典数据按类型分组 - m := make(map[string][]sysDictDataModel.SysDictData, 0) - for _, v := range sysDictDataList { - key := v.DictType - if item, ok := m[key]; ok { - m[key] = append(item, v) - } else { - m[key] = []sysDictDataModel.SysDictData{v} - } - } - - // 放入缓存 - for k, v := range m { - key := r.getDictCache(k) - values, _ := json.Marshal(v) - cache.SetLocal(key, string(values)) - } -} - -// ClearDictCache 清空字典缓存数据 -func (r *ServiceSysDictType) ClearDictCache(dictType string) bool { - key := r.getDictCache(dictType) - keys := cache.GetLocalKeys(key) - for _, v := range keys { - cache.DeleteLocal(v) - } - return len(keys) > 0 -} - -// DictDataCache 获取字典数据缓存数据 -func (r *ServiceSysDictType) DictDataCache(dictType string) []sysDictDataModel.SysDictData { - data := []sysDictDataModel.SysDictData{} - key := r.getDictCache(dictType) - jsonAny, ok := cache.GetLocal(key) - if jsonAny != nil && ok { - err := json.Unmarshal([]byte(jsonAny.(string)), &data) - if err != nil { - data = []sysDictDataModel.SysDictData{} - } - } else { - data = r.sysDictDataRepository.SelectDictDataList(sysDictDataModel.SysDictData{ - Status: "1", - DictType: dictType, - }) - if len(data) > 0 { - cache.DeleteLocal(key) - values, _ := json.Marshal(data) - cache.SetLocal(key, string(values)) - } - } - return data -} diff --git a/features/sys_menu/api_sys_menu.go b/features/sys_menu/api_sys_menu.go deleted file mode 100644 index ec802af..0000000 --- a/features/sys_menu/api_sys_menu.go +++ /dev/null @@ -1,354 +0,0 @@ -package sysmenu - -import ( - "fmt" - "net/http" - - "nms_cxy/features/sys_menu/consts" - "nms_cxy/features/sys_menu/model" - "nms_cxy/features/sys_menu/service" - "nms_cxy/lib/core/utils/ctx" - "nms_cxy/lib/core/utils/regular" - "nms_cxy/lib/core/vo/result" - "nms_cxy/lib/midware" - "nms_cxy/lib/services" - "nms_cxy/omc/config" - srcConfig "nms_cxy/src/framework/config" -) - -// 菜单接口添加到路由 -func Routers() []services.RouterItem { - // 实例化控制层 SysMenuApi 结构体 - var apis = &SysMenuApi{ - sysMenuService: service.NewServiceSysMenu, - } - - rs := [...]services.RouterItem{ - { - Method: "GET", - Pattern: "/menus", - Handler: apis.List, - Middleware: midware.Authorize(nil), - }, - { - Method: "GET", - Pattern: "/menu/{menuId}", - Handler: apis.Info, - Middleware: midware.Authorize(nil), - }, - { - Method: "POST", - Pattern: "/menu", - Handler: apis.Add, - Middleware: midware.Authorize(nil), - }, - { - Method: "PUT", - Pattern: "/menu", - Handler: apis.Edit, - Middleware: midware.Authorize(nil), - }, - { - Method: "DELETE", - Pattern: "/menu/{menuId}", - Handler: apis.Remove, - Middleware: midware.Authorize(nil), - }, - { - Method: "GET", - Pattern: "/menus/treeSelect", - Handler: apis.TreeSelect, - Middleware: midware.Authorize(nil), - }, - { - Method: "GET", - Pattern: "/menu/roleMenuTreeSelect/{roleId}", - Handler: apis.RoleMenuTreeSelect, - Middleware: midware.Authorize(nil), - }, - // 添加更多的 Router 对象... - } - - // 生成两组前缀路由 - rsPrefix := []services.RouterItem{} - for _, v := range rs { - path := "/menuManage/{apiVersion}" + v.Pattern - // 固定前缀 - v.Pattern = config.DefaultUriPrefix + path - rsPrefix = append(rsPrefix, v) - // 可配置 - v.Pattern = config.UriPrefix + path - rsPrefix = append(rsPrefix, v) - } - return rsPrefix -} - -// // 实例化控制层 SysMenuApi 结构体 -// var NewSysMenu = &SysMenuApi{ -// sysMenuService: NewServiceSysMenu, -// } - -// 菜单信息 -// -// PATH /menuManage -type SysMenuApi struct { - // 菜单服务 - sysMenuService *service.ServiceSysMenu -} - -// 菜单列表 -// -// GET /list -func (s *SysMenuApi) List(w http.ResponseWriter, r *http.Request) { - query := model.SysMenu{} - if v := ctx.GetQuery(r, "menuName"); v != "" { - query.MenuName = v - } - if v := ctx.GetQuery(r, "status"); v != "" { - query.Status = v - } - - userId := ctx.LoginUserToUserID(r) - if srcConfig.IsAdmin(userId) { - userId = "*" - } - data := s.sysMenuService.SelectMenuList(query, userId) - ctx.JSON(w, 200, result.OkData(data)) -} - -// 菜单信息 -// -// GET /:menuId -func (s *SysMenuApi) Info(w http.ResponseWriter, r *http.Request) { - menuId := ctx.Param(r, "menuId") - if menuId == "" { - ctx.JSON(w, 400, result.CodeMsg(400, "parameter error")) - return - } - data := s.sysMenuService.SelectMenuById(menuId) - if data.MenuID == menuId { - ctx.JSON(w, 200, result.OkData(data)) - return - } - ctx.JSON(w, 200, result.Err(nil)) -} - -// 菜单新增 -// -// POST / -func (s *SysMenuApi) Add(w http.ResponseWriter, r *http.Request) { - var body model.SysMenu - err := ctx.ShouldBindJSON(r, &body) - if err != nil || body.MenuID != "" { - ctx.JSON(w, 400, result.CodeMsg(400, "parameter error")) - return - } - - // 目录和菜单检查地址唯一 - if consts.TYPE_DIR == body.MenuType || consts.TYPE_MENU == body.MenuType { - uniqueNenuPath := s.sysMenuService.CheckUniqueMenuPath(body.Path, "") - if !uniqueNenuPath { - msg := fmt.Sprintf("菜单新增【%s】失败,菜单路由地址已存在", body.MenuName) - ctx.JSON(w, 200, result.ErrMsg(msg)) - return - } - } - - // 检查名称唯一 - uniqueNenuName := s.sysMenuService.CheckUniqueMenuName(body.MenuName, body.ParentID, "") - if !uniqueNenuName { - msg := fmt.Sprintf("菜单新增【%s】失败,菜单名称已存在", body.MenuName) - ctx.JSON(w, 200, result.ErrMsg(msg)) - return - } - - // 外链菜单需要符合网站http(s)开头 - if body.IsFrame == "0" && !regular.ValidHttp(body.Path) { - msg := fmt.Sprintf("菜单新增【%s】失败,非内部地址必须以http(s)://开头", body.MenuName) - ctx.JSON(w, 200, result.ErrMsg(msg)) - return - } - - body.CreateBy = ctx.LoginUserToUserName(r) - insertId := s.sysMenuService.InsertMenu(body) - if insertId != "" { - ctx.JSON(w, 200, result.Ok(nil)) - return - } - ctx.JSON(w, 200, result.Err(nil)) -} - -// 菜单修改 -// -// PUT / -func (s *SysMenuApi) Edit(w http.ResponseWriter, r *http.Request) { - var body model.SysMenu - err := ctx.ShouldBindJSON(r, &body) - if err != nil || body.MenuID == "" { - ctx.JSON(w, 400, result.CodeMsg(400, "parameter error")) - return - } - - // 上级菜单不能选自己 - if body.MenuID == body.ParentID { - msg := fmt.Sprintf("Menu modification failed for [%s], parent menu cannot select itself", body.MenuName) - ctx.JSON(w, 200, result.ErrMsg(msg)) - return - } - - // 检查数据是否存在 - menuInfo := s.sysMenuService.SelectMenuById(body.MenuID) - if menuInfo.MenuID != body.MenuID { - ctx.JSON(w, 200, result.ErrMsg("No permission to access menu data")) - return - } - // 父级ID不为0是要检查 - if body.ParentID != "0" { - menuParent := s.sysMenuService.SelectMenuById(body.ParentID) - if menuParent.MenuID != body.ParentID { - ctx.JSON(w, 200, result.ErrMsg("No permission to access menu data")) - return - } - // 禁用菜单时检查父菜单是否使用 - if body.Status == "1" && menuParent.Status == "0" { - ctx.JSON(w, 200, result.ErrMsg("Parent menu not enabled!")) - return - } - } - - // 目录和菜单检查地址唯一 - if consts.TYPE_DIR == body.MenuType || consts.TYPE_MENU == body.MenuType { - uniqueNenuPath := s.sysMenuService.CheckUniqueMenuPath(body.Path, body.MenuID) - if !uniqueNenuPath { - msg := fmt.Sprintf("菜单修改【%s】失败,菜单路由地址已存在", body.MenuName) - ctx.JSON(w, 200, result.ErrMsg(msg)) - return - } - } - - // 检查名称唯一 - uniqueNenuName := s.sysMenuService.CheckUniqueMenuName(body.MenuName, body.ParentID, body.MenuID) - if !uniqueNenuName { - msg := fmt.Sprintf("菜单修改【%s】失败,菜单名称已存在", body.MenuName) - ctx.JSON(w, 200, result.ErrMsg(msg)) - return - } - - // 外链菜单需要符合网站http(s)开头 - if body.IsFrame == "0" && !regular.ValidHttp(body.Path) { - msg := fmt.Sprintf("菜单修改【%s】失败,非内部地址必须以http(s)://开头", body.MenuName) - ctx.JSON(w, 200, result.ErrMsg(msg)) - return - } - - // 禁用菜单时检查子菜单是否使用 - if body.Status == "0" { - hasStatus := s.sysMenuService.HasChildByMenuIdAndStatus(body.MenuID, "1") - if hasStatus > 0 { - msg := fmt.Sprintf("不允许禁用,存在使用子菜单数:%d", hasStatus) - ctx.JSON(w, 200, result.ErrMsg(msg)) - return - } - } - - body.UpdateBy = ctx.LoginUserToUserName(r) - rows := s.sysMenuService.UpdateMenu(body) - if rows > 0 { - ctx.JSON(w, 200, result.Ok(nil)) - return - } - ctx.JSON(w, 200, result.Err(nil)) -} - -// 菜单删除 -// -// DELETE /:menuId -func (s *SysMenuApi) Remove(w http.ResponseWriter, r *http.Request) { - menuId := ctx.Param(r, "menuId") - if menuId == "" { - ctx.JSON(w, 400, result.CodeMsg(400, "parameter error")) - return - } - - // 检查数据是否存在 - menu := s.sysMenuService.SelectMenuById(menuId) - if menu.MenuID != menuId { - ctx.JSON(w, 200, result.ErrMsg("No permission to access menu data!")) - return - } - - // 检查是否存在子菜单 - hasChild := s.sysMenuService.HasChildByMenuIdAndStatus(menuId, "") - if hasChild > 0 { - msg := fmt.Sprintf("Deletion not allowed, there are sub orders: %d", hasChild) - ctx.JSON(w, 200, result.ErrMsg(msg)) - return - } - - // 检查是否分配给角色 - existRole := s.sysMenuService.CheckMenuExistRole(menuId) - if existRole > 0 { - msg := fmt.Sprintf("Deletion not allowed, menu already assigned to roles: %d", existRole) - ctx.JSON(w, 200, result.ErrMsg(msg)) - return - } - - rows := s.sysMenuService.DeleteMenuById(menuId) - if rows > 0 { - msg := fmt.Sprintf("Successfully deleted: %d", rows) - ctx.JSON(w, 200, result.OkMsg(msg)) - return - } - ctx.JSON(w, 200, result.Err(nil)) -} - -// 菜单树结构列表 -// -// GET /treeSelect -func (s *SysMenuApi) TreeSelect(w http.ResponseWriter, r *http.Request) { - query := model.SysMenu{} - if v := ctx.GetQuery(r, "menuName"); v != "" { - query.MenuName = v - } - if v := ctx.GetQuery(r, "status"); v != "" { - query.Status = v - } - - userId := ctx.LoginUserToUserID(r) - if srcConfig.IsAdmin(userId) { - userId = "*" - } - data := s.sysMenuService.SelectMenuTreeSelectByUserId(query, userId) - ctx.JSON(w, 200, result.OkData(data)) - -} - -// 菜单树结构列表(指定角色) -// -// GET /roleMenuTreeSelect/:roleId -func (s *SysMenuApi) RoleMenuTreeSelect(w http.ResponseWriter, r *http.Request) { - roleId := ctx.Param(r, "roleId") - if roleId == "" { - ctx.JSON(w, 400, result.CodeMsg(400, "parameter error")) - return - } - - query := model.SysMenu{} - if v := ctx.GetQuery(r, "menuName"); v != "" { - query.MenuName = v - } - if v := ctx.GetQuery(r, "status"); v != "" { - query.Status = v - } - - userId := ctx.LoginUserToUserID(r) - if srcConfig.IsAdmin(userId) { - userId = "*" - } - menuTreeSelect := s.sysMenuService.SelectMenuTreeSelectByUserId(query, userId) - checkedKeys := s.sysMenuService.SelectMenuListByRoleId(roleId) - ctx.JSON(w, 200, result.OkData(map[string]any{ - "menus": menuTreeSelect, - "checkedKeys": checkedKeys, - })) -} diff --git a/features/sys_menu/consts/consts_menu.go b/features/sys_menu/consts/consts_menu.go deleted file mode 100644 index 6a1dca3..0000000 --- a/features/sys_menu/consts/consts_menu.go +++ /dev/null @@ -1,24 +0,0 @@ -package consts - -// 系统菜单常量信息 - -const ( - // 组件布局类型-基础布局组件标识 - COMPONENT_LAYOUT_BASIC = "BasicLayout" - // 组件布局类型-空白布局组件标识 - COMPONENT_LAYOUT_BLANK = "BlankLayout" - // 组件布局类型-内链接布局组件标识 - COMPONENT_LAYOUT_LINK = "LinkLayout" -) - -const ( - // 菜单类型-目录 - TYPE_DIR = "D" - // 菜单类型-菜单 - TYPE_MENU = "M" - // 菜单类型-按钮 - TYPE_BUTTON = "B" -) - -// 菜单内嵌地址标识-带/前缀 -const PATH_INLINE = "/inline" diff --git a/features/sys_menu/model/sys_menu.go b/features/sys_menu/model/sys_menu.go deleted file mode 100644 index 397e30e..0000000 --- a/features/sys_menu/model/sys_menu.go +++ /dev/null @@ -1,46 +0,0 @@ -package model - -// SysMenu 菜单权限对象 sys_menu -type SysMenu struct { - // 菜单ID - MenuID string `json:"menuId"` - // 菜单名称 - MenuName string `json:"menuName" binding:"required"` - // 父菜单ID 默认0 - ParentID string `json:"parentId" binding:"required"` - // 显示顺序 - MenuSort int `json:"menuSort"` - // 路由地址 - Path string `json:"path"` - // 组件路径 - Component string `json:"component"` - // 是否内部跳转(0否 1是) - IsFrame string `json:"isFrame"` - // 是否缓存(0不缓存 1缓存) - IsCache string `json:"isCache"` - // 菜单类型(D目录 M菜单 B按钮) - MenuType string `json:"menuType" binding:"required"` - // 是否显示(0隐藏 1显示) - Visible string `json:"visible"` - // 菜单状态(0停用 1正常) - Status string `json:"status"` - // 权限标识 - Perms string `json:"perms"` - // 菜单图标(#无图标) - Icon string `json:"icon"` - // 创建者 - CreateBy string `json:"createBy"` - // 创建时间 - CreateTime int64 `json:"createTime"` - // 更新者 - UpdateBy string `json:"updateBy"` - // 更新时间 - UpdateTime int64 `json:"updateTime"` - // 备注 - Remark string `json:"remark"` - - // ====== 非数据库字段属性 ====== - - // 子菜单 - Children []SysMenu `json:"children,omitempty"` -} diff --git a/features/sys_menu/service/repo_sys_menu.go b/features/sys_menu/service/repo_sys_menu.go deleted file mode 100644 index 4af0773..0000000 --- a/features/sys_menu/service/repo_sys_menu.go +++ /dev/null @@ -1,475 +0,0 @@ -package service - -import ( - "fmt" - "strings" - "time" - - "nms_cxy/features/sys_menu/consts" - "nms_cxy/features/sys_menu/model" - "nms_cxy/lib/core/datasource" - "nms_cxy/lib/core/utils/parse" - "nms_cxy/lib/log" -) - -// 实例化数据层 RepoSysMenu 结构体 -var NewRepoSysMenu = &RepoSysMenu{ - selectSql: `select - m.menu_id, m.menu_name, m.parent_id, m.menu_sort, m.path, m.component, m.is_frame, m.is_cache, m.menu_type, m.visible, m.status, ifnull(m.perms,'') as perms, m.icon, m.create_time, m.remark - from sys_menu m`, - - selectSqlByUser: `select distinct - m.menu_id, m.menu_name, m.parent_id, m.menu_sort, m.path, m.component, m.is_frame, m.is_cache, m.menu_type, m.visible, m.status, ifnull(m.perms,'') as perms, m.icon, m.create_time, m.remark - from sys_menu m - left join sys_role_menu rm on m.menu_id = rm.menu_id - left join sys_user_role ur on rm.role_id = ur.role_id - left join sys_role ro on ur.role_id = ro.role_id`, - - resultMap: map[string]string{ - "menu_id": "MenuID", - "menu_name": "MenuName", - "parent_name": "ParentName", - "parent_id": "ParentID", - "path": "Path", - "menu_sort": "MenuSort", - "component": "Component", - "is_frame": "IsFrame", - "is_cache": "IsCache", - "menu_type": "MenuType", - "visible": "Visible", - "status": "Status", - "perms": "Perms", - "icon": "Icon", - "create_by": "CreateBy", - "create_time": "CreateTime", - "update_by": "UpdateBy", - "update_time": "UpdateTime", - "remark": "Remark", - }, -} - -// RepoSysMenu 菜单表 数据层处理 -type RepoSysMenu struct { - // 查询视图对象SQL - selectSql string - // 查询视图用户对象SQL - selectSqlByUser string - // 结果字段与实体映射 - resultMap map[string]string -} - -// convertResultRows 将结果记录转实体结果组 -func (r *RepoSysMenu) convertResultRows(rows []map[string]any) []model.SysMenu { - arr := make([]model.SysMenu, 0) - for _, row := range rows { - sysMenu := model.SysMenu{} - for key, value := range row { - if keyMapper, ok := r.resultMap[key]; ok { - datasource.SetFieldValue(&sysMenu, keyMapper, value) - } - } - arr = append(arr, sysMenu) - } - return arr -} - -// SelectMenuList 查询系统菜单列表 -func (r *RepoSysMenu) SelectMenuList(sysMenu model.SysMenu, userId string) []model.SysMenu { - // 查询条件拼接 - var conditions []string - var params []any - if sysMenu.MenuName != "" { - conditions = append(conditions, "m.menu_name like concat('%', concat(?, '%'))") - params = append(params, sysMenu.MenuName) - } - if sysMenu.Visible != "" { - conditions = append(conditions, "m.visible = ?") - params = append(params, sysMenu.Visible) - } - if sysMenu.Status != "" { - conditions = append(conditions, "m.status = ?") - params = append(params, sysMenu.Status) - } - - fromSql := r.selectSql - - // 个人菜单 - if userId != "*" { - fromSql = r.selectSqlByUser - conditions = append(conditions, "ur.user_id = ?") - params = append(params, userId) - } - - // 构建查询条件语句 - whereSql := "" - if len(conditions) > 0 { - whereSql += " where " + strings.Join(conditions, " and ") - } - - // 查询数据 - orderSql := " order by m.parent_id, m.menu_sort" - querySql := fromSql + whereSql + orderSql - results, err := datasource.RawDB("", querySql, params) - if err != nil { - log.Errorf("query err => %v", err) - return []model.SysMenu{} - } - - // 转换实体 - return r.convertResultRows(results) -} - -// SelectMenuPermsByUserId 根据用户ID查询权限 -func (r *RepoSysMenu) SelectMenuPermsByUserId(userId string) []string { - querySql := `select distinct m.perms as 'str' from sys_menu m - left join sys_role_menu rm on m.menu_id = rm.menu_id - left join sys_user_role ur on rm.role_id = ur.role_id - left join sys_role r on r.role_id = ur.role_id - where m.status = '1' and m.perms != '' and r.status = '1' and ur.user_id = ? ` - - // 查询结果 - results, err := datasource.RawDB("", querySql, []any{userId}) - if err != nil { - log.Errorf("query err => %v", err) - return []string{} - } - - // 读取结果 - rows := make([]string, 0) - for _, m := range results { - rows = append(rows, fmt.Sprintf("%v", m["str"])) - } - return rows -} - -// SelectMenuTreeByUserId 根据用户ID查询菜单 -func (r *RepoSysMenu) SelectMenuTreeByUserId(userId string) []model.SysMenu { - var params []any - var querySql string - - if userId == "*" { - // 管理员全部菜单 - querySql = r.selectSql + ` where - m.menu_type in (?,?) and m.status = '1' - order by m.parent_id, m.menu_sort` - params = append(params, consts.TYPE_DIR) - params = append(params, consts.TYPE_MENU) - } else { - // 用户ID权限 - querySql = r.selectSqlByUser + ` where - m.menu_type in (?, ?) and m.status = '1' - and ur.user_id = ? and ro.status = '1' - order by m.parent_id, m.menu_sort` - params = append(params, consts.TYPE_DIR) - params = append(params, consts.TYPE_MENU) - params = append(params, userId) - } - - // 查询结果 - results, err := datasource.RawDB("", querySql, params) - if err != nil { - log.Errorf("query err => %v", err) - return []model.SysMenu{} - } - - return r.convertResultRows(results) -} - -// SelectMenuListByRoleId 根据角色ID查询菜单树信息 -func (r *RepoSysMenu) SelectMenuListByRoleId(roleId string, menuCheckStrictly bool) []string { - querySql := `select m.menu_id as 'str' from sys_menu m - left join sys_role_menu rm on m.menu_id = rm.menu_id - where rm.role_id = ? ` - var params []any - params = append(params, roleId) - // 展开 - if menuCheckStrictly { - querySql += ` and m.menu_id not in - (select m.parent_id from sys_menu m - inner join sys_role_menu rm on m.menu_id = rm.menu_id - and rm.role_id = ?) ` - params = append(params, roleId) - } - - // 查询结果 - results, err := datasource.RawDB("", querySql, params) - if err != nil { - log.Errorf("query err => %v", err) - return []string{} - } - - if len(results) > 0 { - ids := make([]string, 0) - for _, v := range results { - ids = append(ids, fmt.Sprintf("%v", v["str"])) - } - return ids - } - return []string{} -} - -// SelectMenuByIds 根据菜单ID查询信息 -func (r *RepoSysMenu) SelectMenuByIds(menuIds []string) []model.SysMenu { - placeholder := datasource.KeyPlaceholderByQuery(len(menuIds)) - querySql := r.selectSql + " where m.menu_id in (" + placeholder + ")" - parameters := datasource.ConvertIdsSlice(menuIds) - results, err := datasource.RawDB("", querySql, parameters) - if err != nil { - log.Errorf("query err => %v", err) - return []model.SysMenu{} - } - // 转换实体 - return r.convertResultRows(results) -} - -// HasChildByMenuIdAndStatus 存在菜单子节点数量与状态 -func (r *RepoSysMenu) HasChildByMenuIdAndStatus(menuId, status string) int64 { - querySql := "select count(1) as 'total' from sys_menu where parent_id = ?" - params := []any{menuId} - - // 菜单状态 - if status != "" { - querySql += " and status = ?" - params = append(params, status) - } - - results, err := datasource.RawDB("", querySql, params) - if err != nil { - log.Errorf("query err => %v", err) - return 0 - } - if len(results) > 0 { - return parse.Number(results[0]["total"]) - } - return 0 -} - -// InsertMenu 新增菜单信息 -func (r *RepoSysMenu) InsertMenu(sysMenu model.SysMenu) string { - // 参数拼接 - params := make(map[string]any) - if sysMenu.MenuID != "" { - params["menu_id"] = sysMenu.MenuID - } - if sysMenu.ParentID != "" { - params["parent_id"] = sysMenu.ParentID - } - if sysMenu.MenuName != "" { - params["menu_name"] = sysMenu.MenuName - } - if sysMenu.MenuSort > 0 { - params["menu_sort"] = sysMenu.MenuSort - } - if sysMenu.Path != "" { - params["path"] = sysMenu.Path - } - if sysMenu.Component != "" { - params["component"] = sysMenu.Component - } - if sysMenu.IsFrame != "" { - params["is_frame"] = sysMenu.IsFrame - } - if sysMenu.IsCache != "" { - params["is_cache"] = sysMenu.IsCache - } - if sysMenu.MenuType != "" { - params["menu_type"] = sysMenu.MenuType - } - if sysMenu.Visible != "" { - params["visible"] = sysMenu.Visible - } - if sysMenu.Status != "" { - params["status"] = sysMenu.Status - } - if sysMenu.Perms != "" { - params["perms"] = sysMenu.Perms - } - if sysMenu.Icon != "" { - params["icon"] = sysMenu.Icon - } else { - params["icon"] = "#" - } - if sysMenu.Remark != "" { - params["remark"] = sysMenu.Remark - } - if sysMenu.CreateBy != "" { - params["create_by"] = sysMenu.CreateBy - params["create_time"] = time.Now().UnixMilli() - } - - // 根据菜单类型重置参数 - if sysMenu.MenuType == consts.TYPE_BUTTON { - params["component"] = "" - params["path"] = "" - params["icon"] = "#" - params["is_cache"] = "1" - params["is_frame"] = "1" - params["visible"] = "1" - params["status"] = "1" - } - if sysMenu.MenuType == consts.TYPE_DIR { - params["component"] = "" - params["perms"] = "" - } - - // 构建执行语句 - keys, placeholder, values := datasource.KeyPlaceholderValueByInsert(params) - sql := "insert into sys_menu (" + strings.Join(keys, ",") + ")values(" + placeholder + ")" - - // 执行插入 - results, err := datasource.ExecDB("", sql, values) - if err != nil { - log.Errorf("insert row : %v", err.Error()) - return "" - } - - insertId, err := results.LastInsertId() - if err != nil { - log.Errorf("insert row : %v", err.Error()) - return "" - } - return fmt.Sprint(insertId) -} - -// UpdateMenu 修改菜单信息 -func (r *RepoSysMenu) UpdateMenu(sysMenu model.SysMenu) int64 { - // 参数拼接 - params := make(map[string]any) - if sysMenu.MenuID != "" { - params["menu_id"] = sysMenu.MenuID - } - if sysMenu.ParentID != "" { - params["parent_id"] = sysMenu.ParentID - } - if sysMenu.MenuName != "" { - params["menu_name"] = sysMenu.MenuName - } - if sysMenu.MenuSort > 0 { - params["menu_sort"] = sysMenu.MenuSort - } - if sysMenu.Path != "" { - params["path"] = sysMenu.Path - } - if sysMenu.Component != "" { - params["component"] = sysMenu.Component - } - if sysMenu.IsFrame != "" { - params["is_frame"] = sysMenu.IsFrame - } - if sysMenu.IsCache != "" { - params["is_cache"] = sysMenu.IsCache - } - if sysMenu.MenuType != "" { - params["menu_type"] = sysMenu.MenuType - } - if sysMenu.Visible != "" { - params["visible"] = sysMenu.Visible - } - if sysMenu.Status != "" { - params["status"] = sysMenu.Status - } - if sysMenu.Perms != "" { - params["perms"] = sysMenu.Perms - } - if sysMenu.Icon != "" { - params["icon"] = sysMenu.Icon - } else { - params["icon"] = "#" - } - if sysMenu.Remark != "" { - params["remark"] = sysMenu.Remark - } - if sysMenu.UpdateBy != "" { - params["update_by"] = sysMenu.UpdateBy - params["update_time"] = time.Now().UnixMilli() - } - - // 根据菜单类型重置参数 - if sysMenu.MenuType == consts.TYPE_BUTTON { - params["component"] = "" - params["path"] = "" - params["icon"] = "#" - params["is_cache"] = "1" - params["is_frame"] = "1" - params["visible"] = "1" - params["status"] = "1" - } - if sysMenu.MenuType == consts.TYPE_DIR { - params["component"] = "" - params["perms"] = "" - } - - // 构建执行语句 - keys, values := datasource.KeyValueByUpdate(params) - sql := "update sys_menu set " + strings.Join(keys, ",") + " where menu_id = ?" - - // 执行更新 - values = append(values, sysMenu.MenuID) - results, err := datasource.ExecDB("", sql, values) - if err != nil { - log.Errorf("update row : %v", err.Error()) - return 0 - } - affected, err := results.RowsAffected() - if err != nil { - log.Errorf("update err => %v", err) - return 0 - } - return affected -} - -// DeleteMenuById 删除菜单管理信息 -func (r *RepoSysMenu) DeleteMenuById(menuId string) int64 { - sql := "delete from sys_menu where menu_id = ?" - results, err := datasource.ExecDB("", sql, []any{menuId}) - if err != nil { - log.Errorf("delete err => %v", err) - return 0 - } - affected, err := results.RowsAffected() - if err != nil { - log.Errorf("delete err => %v", err) - return 0 - } - return affected -} - -// CheckUniqueMenu 校验菜单是否唯一 -func (r *RepoSysMenu) CheckUniqueMenu(sysMenu model.SysMenu) string { - // 查询条件拼接 - var conditions []string - var params []any - if sysMenu.MenuName != "" { - conditions = append(conditions, "menu_name = ?") - params = append(params, sysMenu.MenuName) - } - if sysMenu.ParentID != "" { - conditions = append(conditions, "parent_id = ?") - params = append(params, sysMenu.ParentID) - } - if sysMenu.Path != "" { - conditions = append(conditions, "path = ?") - params = append(params, sysMenu.Path) - } - - // 构建查询条件语句 - whereSql := "" - if len(conditions) > 0 { - whereSql += " where " + strings.Join(conditions, " and ") - } - if whereSql == "" { - return "" - } - - // 查询数据 - querySql := "select menu_id as 'str' from sys_menu " + whereSql + " limit 1" - results, err := datasource.RawDB("", querySql, params) - if err != nil { - log.Errorf("query err %v", err) - return "" - } - if len(results) > 0 { - return fmt.Sprint(results[0]["str"]) - } - return "" -} diff --git a/features/sys_menu/service/service_sys_menu.go b/features/sys_menu/service/service_sys_menu.go deleted file mode 100644 index 95f93b0..0000000 --- a/features/sys_menu/service/service_sys_menu.go +++ /dev/null @@ -1,408 +0,0 @@ -package service - -import ( - "encoding/base64" - "strings" - - "nms_cxy/features/sys_menu/consts" - "nms_cxy/features/sys_menu/model" - sysRoleService "nms_cxy/features/sys_role/service" - sysrolemenu "nms_cxy/features/sys_role_menu" - "nms_cxy/lib/core/utils/parse" - "nms_cxy/lib/core/utils/regular" - "nms_cxy/lib/core/vo" -) - -// 实例化服务层 ServiceSysMenu 结构体 -var NewServiceSysMenu = &ServiceSysMenu{ - sysMenuRepository: NewRepoSysMenu, - sysRoleMenuRepository: sysrolemenu.NewRepoSysRoleMenu, - sysRoleRepository: sysRoleService.NewRepoSysRole, -} - -// ServiceSysMenu 菜单 服务层处理 -type ServiceSysMenu struct { - // 菜单服务 - sysMenuRepository *RepoSysMenu - // 角色与菜单关联服务 - sysRoleMenuRepository *sysrolemenu.RepoSysRoleMenu - // 角色服务 - sysRoleRepository *sysRoleService.RepoSysRole -} - -// SelectMenuList 查询系统菜单列表 -func (r *ServiceSysMenu) SelectMenuList(sysMenu model.SysMenu, userId string) []model.SysMenu { - return r.sysMenuRepository.SelectMenuList(sysMenu, userId) -} - -// SelectMenuPermsByUserId 根据用户ID查询权限 -func (r *ServiceSysMenu) SelectMenuPermsByUserId(userId string) []string { - return r.sysMenuRepository.SelectMenuPermsByUserId(userId) -} - -// SelectMenuTreeByUserId 根据用户ID查询菜单 -func (r *ServiceSysMenu) SelectMenuTreeByUserId(userId string) []model.SysMenu { - sysMenus := r.sysMenuRepository.SelectMenuTreeByUserId(userId) - return r.parseDataToTree(sysMenus) -} - -// SelectMenuTreeSelectByUserId 根据用户ID查询菜单树结构信息 -func (r *ServiceSysMenu) SelectMenuTreeSelectByUserId(sysMenu model.SysMenu, userId string) []vo.TreeSelect { - sysMenus := r.sysMenuRepository.SelectMenuList(sysMenu, userId) - - // 过滤旧前端菜单 - sysMenusF := []model.SysMenu{} - for _, v := range sysMenus { - if v.Perms != "page" { - continue - } - sysMenusF = append(sysMenusF, v) - } - - menus := r.parseDataToTree(sysMenusF) - tree := make([]vo.TreeSelect, 0) - for _, menu := range menus { - tree = append(tree, sysMenuTreeSelect(menu)) - } - return tree -} - -// sysMenuTreeSelect 使用给定的 SysMenu 对象解析为 TreeSelect 对象 -func sysMenuTreeSelect(sysMenu model.SysMenu) vo.TreeSelect { - t := vo.TreeSelect{} - t.ID = sysMenu.MenuID - t.Label = sysMenu.MenuName - t.Title = sysMenu.MenuName - - if len(sysMenu.Children) > 0 { - for _, menu := range sysMenu.Children { - child := sysMenuTreeSelect(menu) - t.Children = append(t.Children, child) - } - } else { - t.Children = []vo.TreeSelect{} - } - - return t -} - -// SelectMenuListByRoleId 根据角色ID查询菜单树信息 TODO -func (r *ServiceSysMenu) SelectMenuListByRoleId(roleId string) []string { - roles := r.sysRoleRepository.SelectRoleByIds([]string{roleId}) - if len(roles) > 0 { - role := roles[0] - if role.RoleID == roleId { - return r.sysMenuRepository.SelectMenuListByRoleId( - role.RoleID, - role.MenuCheckStrictly == "1", - ) - } - } - return []string{} -} - -// SelectMenuById 根据菜单ID查询信息 -func (r *ServiceSysMenu) SelectMenuById(menuId string) model.SysMenu { - if menuId == "" { - return model.SysMenu{} - } - menus := r.sysMenuRepository.SelectMenuByIds([]string{menuId}) - if len(menus) > 0 { - return menus[0] - } - return model.SysMenu{} -} - -// HasChildByMenuIdAndStatus 存在菜单子节点数量与状态 -func (r *ServiceSysMenu) HasChildByMenuIdAndStatus(menuId, status string) int64 { - return r.sysMenuRepository.HasChildByMenuIdAndStatus(menuId, status) -} - -// CheckMenuExistRole 查询菜单是否存在角色 -func (r *ServiceSysMenu) CheckMenuExistRole(menuId string) int64 { - return r.sysRoleMenuRepository.CheckMenuExistRole(menuId) -} - -// InsertMenu 新增菜单信息 -func (r *ServiceSysMenu) InsertMenu(sysMenu model.SysMenu) string { - return r.sysMenuRepository.InsertMenu(sysMenu) -} - -// UpdateMenu 修改菜单信息 -func (r *ServiceSysMenu) UpdateMenu(sysMenu model.SysMenu) int64 { - return r.sysMenuRepository.UpdateMenu(sysMenu) -} - -// DeleteMenuById 删除菜单管理信息 -func (r *ServiceSysMenu) DeleteMenuById(menuId string) int64 { - // 删除菜单与角色关联 - r.sysRoleMenuRepository.DeleteMenuRole([]string{menuId}) - return r.sysMenuRepository.DeleteMenuById(menuId) -} - -// CheckUniqueMenuName 校验菜单名称是否唯一 -func (r *ServiceSysMenu) CheckUniqueMenuName(menuName, parentId, menuId string) bool { - uniqueId := r.sysMenuRepository.CheckUniqueMenu(model.SysMenu{ - MenuName: menuName, - ParentID: parentId, - }) - if uniqueId == menuId { - return true - } - return uniqueId == "" -} - -// CheckUniqueMenuPath 校验路由地址是否唯一(针对目录和菜单) -func (r *ServiceSysMenu) CheckUniqueMenuPath(path, menuId string) bool { - uniqueId := r.sysMenuRepository.CheckUniqueMenu(model.SysMenu{ - Path: path, - }) - if uniqueId == menuId { - return true - } - return uniqueId == "" -} - -// BuildRouteMenus 构建前端路由所需要的菜单 -func (r *ServiceSysMenu) BuildRouteMenus(sysMenus []model.SysMenu, prefix string) []vo.Router { - routers := []vo.Router{} - for _, item := range sysMenus { - router := vo.Router{} - router.Name = r.getRouteName(item) - router.Path = r.getRouterPath(item) - router.Component = r.getComponent(item) - router.Meta = r.getRouteMeta(item) - - // 子项菜单 目录类型 非路径链接 - cMenus := item.Children - if len(cMenus) > 0 && item.MenuType == consts.TYPE_DIR && !regular.ValidHttp(item.Path) { - // 获取重定向地址 - redirectPrefix, redirectPath := r.getRouteRedirect( - cMenus, - router.Path, - prefix, - ) - router.Redirect = redirectPath - // 子菜单进入递归 - router.Children = r.BuildRouteMenus(cMenus, redirectPrefix) - } else if item.ParentID == "0" && item.IsFrame == "1" && item.MenuType == consts.TYPE_MENU { - // 父菜单 内部跳转 菜单类型 - menuPath := "/" + item.MenuID - childPath := menuPath + r.getRouterPath(item) - children := vo.Router{ - Name: r.getRouteName(item), - Path: childPath, - Component: item.Component, - Meta: r.getRouteMeta(item), - } - router.Meta.HideChildInMenu = true - router.Children = append(router.Children, children) - router.Name = item.MenuID - router.Path = menuPath - router.Redirect = childPath - router.Component = consts.COMPONENT_LAYOUT_BASIC - } else if item.ParentID == "0" && item.IsFrame == "1" && regular.ValidHttp(item.Path) { - // 父菜单 内部跳转 路径链接 - menuPath := "/" + item.MenuID - childPath := menuPath + r.getRouterPath(item) - children := vo.Router{ - Name: r.getRouteName(item), - Path: childPath, - Component: consts.COMPONENT_LAYOUT_LINK, - Meta: r.getRouteMeta(item), - } - router.Meta.HideChildInMenu = true - router.Children = append(router.Children, children) - router.Name = item.MenuID - router.Path = menuPath - router.Redirect = childPath - router.Component = consts.COMPONENT_LAYOUT_BASIC - } - - routers = append(routers, router) - } - return routers -} - -// getRouteName 获取路由名称 路径英文首字母大写 -func (r *ServiceSysMenu) getRouteName(sysMenu model.SysMenu) string { - routerName := parse.FirstUpper(sysMenu.Path) - // 路径链接 - if regular.ValidHttp(sysMenu.Path) { - return routerName[:5] + "Link" + sysMenu.MenuID - } - return routerName -} - -// getRouterPath 获取路由地址 -func (r *ServiceSysMenu) getRouterPath(sysMenu model.SysMenu) string { - routerPath := sysMenu.Path - - // 显式路径 - if routerPath == "" || strings.HasPrefix(routerPath, "/") { - return routerPath - } - - // 路径链接 内部跳转 - if regular.ValidHttp(routerPath) && sysMenu.IsFrame == "1" { - routerPath = regular.Replace(routerPath, `/^http(s)?:\/\/+/`, "") - routerPath = base64.StdEncoding.EncodeToString([]byte(routerPath)) - } - - // 父菜单 内部跳转 - if sysMenu.ParentID == "0" && sysMenu.IsFrame == "1" { - routerPath = "/" + routerPath - } - - return routerPath -} - -// getComponent 获取组件信息 -func (r *ServiceSysMenu) getComponent(sysMenu model.SysMenu) string { - // 内部跳转 路径链接 - if sysMenu.IsFrame == "1" && regular.ValidHttp(sysMenu.Path) { - return consts.COMPONENT_LAYOUT_LINK - } - - // 非父菜单 目录类型 - if sysMenu.ParentID != "0" && sysMenu.MenuType == consts.TYPE_DIR { - return consts.COMPONENT_LAYOUT_BLANK - } - - // 组件路径 内部跳转 菜单类型 - if sysMenu.Component != "" && sysMenu.IsFrame == "1" && sysMenu.MenuType == consts.TYPE_MENU { - // 父菜单套外层布局 - if sysMenu.ParentID == "0" { - return consts.COMPONENT_LAYOUT_BASIC - } - return sysMenu.Component - } - - return consts.COMPONENT_LAYOUT_BASIC -} - -// getRouteMeta 获取路由元信息 -func (r *ServiceSysMenu) getRouteMeta(sysMenu model.SysMenu) vo.RouterMeta { - meta := vo.RouterMeta{} - if sysMenu.Icon == "#" { - meta.Icon = "" - } else { - meta.Icon = sysMenu.Icon - } - meta.Title = sysMenu.MenuName - meta.HideChildInMenu = false - meta.HideInMenu = sysMenu.Visible == "0" - meta.Cache = sysMenu.IsCache == "1" - meta.Target = "" - - // 路径链接 非内部跳转 - if regular.ValidHttp(sysMenu.Path) && sysMenu.IsFrame == "0" { - meta.Target = "_blank" - } - - return meta -} - -// getRouteRedirect 获取路由重定向地址(针对目录) -// -// cMenus 子菜单数组 -// routerPath 当前菜单路径 -// prefix 菜单重定向路径前缀 -func (r *ServiceSysMenu) getRouteRedirect(cMenus []model.SysMenu, routerPath string, prefix string) (string, string) { - redirectPath := "" - - // 重定向为首个显示并启用的子菜单 - var firstChild *model.SysMenu - for _, item := range cMenus { - if item.IsFrame == "1" && item.Visible == "1" { - firstChild = &item - break - } - } - - // 检查内嵌隐藏菜单是否可做重定向 - if firstChild == nil { - for _, item := range cMenus { - if item.IsFrame == "1" && item.Visible == "1" && strings.Contains(item.Path, consts.PATH_INLINE) { - firstChild = &item - break - } - } - } - - if firstChild != nil { - firstChildPath := r.getRouterPath(*firstChild) - if strings.HasPrefix(firstChildPath, "/") { - redirectPath = firstChildPath - } else { - // 拼接追加路径 - if !strings.HasPrefix(routerPath, "/") { - prefix += "/" - } - prefix = prefix + routerPath - redirectPath = prefix + "/" + firstChildPath - } - } - - return prefix, redirectPath -} - -// parseDataToTree 将数据解析为树结构,构建前端所需要下拉树结构 -func (r *ServiceSysMenu) parseDataToTree(sysMenus []model.SysMenu) []model.SysMenu { - // 节点分组 - nodesMap := make(map[string][]model.SysMenu) - // 节点id - treeIds := []string{} - // 树节点 - tree := []model.SysMenu{} - - for _, item := range sysMenus { - parentID := item.ParentID - // 分组 - mapItem, ok := nodesMap[parentID] - if !ok { - mapItem = []model.SysMenu{} - } - mapItem = append(mapItem, item) - nodesMap[parentID] = mapItem - // 记录节点ID - treeIds = append(treeIds, item.MenuID) - } - - for key, value := range nodesMap { - // 选择不是节点ID的作为树节点 - found := false - for _, id := range treeIds { - if id == key { - found = true - break - } - } - if !found { - tree = append(tree, value...) - } - } - - for i, node := range tree { - iN := r.parseDataToTreeComponet(node, &nodesMap) - tree[i] = iN - } - - return tree -} - -// parseDataToTreeComponet 递归函数处理子节点 -func (r *ServiceSysMenu) parseDataToTreeComponet(node model.SysMenu, nodesMap *map[string][]model.SysMenu) model.SysMenu { - id := node.MenuID - children, ok := (*nodesMap)[id] - if ok { - node.Children = children - } - if len(node.Children) > 0 { - for i, child := range node.Children { - icN := r.parseDataToTreeComponet(child, nodesMap) - node.Children[i] = icN - } - } - return node -} diff --git a/features/sys_role/api_sys_role.go b/features/sys_role/api_sys_role.go deleted file mode 100644 index 01061a5..0000000 --- a/features/sys_role/api_sys_role.go +++ /dev/null @@ -1,368 +0,0 @@ -package sysrole - -import ( - "fmt" - "net/http" - "strings" - - "nms_cxy/features/sys_role/model" - "nms_cxy/features/sys_role/service" - userService "nms_cxy/features/sys_user/service" - "nms_cxy/lib/core/utils/ctx" - "nms_cxy/lib/core/utils/parse" - "nms_cxy/lib/core/vo/result" - "nms_cxy/lib/midware" - "nms_cxy/lib/services" - "nms_cxy/omc/config" -) - -// 角色接口添加到路由 -func Routers() []services.RouterItem { - // 实例化控制层 SysRoleApi 结构体 - var apis = &SysRoleApi{ - sysRoleService: service.NewServiceSysRole, - sysUserService: userService.NewServiceSysUser, - } - - rs := [...]services.RouterItem{ - { - Method: "GET", - Pattern: "/roles", - Handler: apis.List, - Middleware: midware.Authorize(nil), - }, - { - Method: "GET", - Pattern: "/role/{roleId}", - Handler: apis.Info, - Middleware: midware.Authorize(nil), - }, - { - Method: "POST", - Pattern: "/role", - Handler: apis.Add, - Middleware: midware.Authorize(nil), - }, - { - Method: "PUT", - Pattern: "/role", - Handler: apis.Edit, - Middleware: midware.Authorize(nil), - }, - { - Method: "DELETE", - Pattern: "/role/{roleIds}", - Handler: apis.Remove, - Middleware: midware.Authorize(nil), - }, - { - Method: "PUT", - Pattern: "/role/changeStatus", - Handler: apis.Status, - Middleware: midware.Authorize(nil), - }, - { - Method: "GET", - Pattern: "/role/authUser/allocatedList", - Handler: apis.AuthUserAllocatedList, - Middleware: midware.Authorize(nil), - }, - { - Method: "PUT", - Pattern: "/role/authUser/checked", - Handler: apis.AuthUserChecked, - Middleware: midware.Authorize(nil), - }, - // 添加更多的 Router 对象... - } - - // 生成两组前缀路由 - rsPrefix := []services.RouterItem{} - for _, v := range rs { - path := "/roleManage/{apiVersion}" + v.Pattern - // 固定前缀 - v.Pattern = config.DefaultUriPrefix + path - rsPrefix = append(rsPrefix, v) - // 可配置 - v.Pattern = config.UriPrefix + path - rsPrefix = append(rsPrefix, v) - } - return rsPrefix -} - -// // 实例化控制层 SysRoleApi 结构体 -// var NewSysRole = &SysRoleApi{ -// sysRoleService: sysrole.NewServiceSysRole, -// sysUserService: sysuser.NewServiceSysUser, -// } - -// 角色信息 -// -// PATH /roleManage -type SysRoleApi struct { - // 角色服务 - sysRoleService *service.ServiceSysRole - // 用户服务 - sysUserService *userService.ServiceSysUser -} - -// 角色列表 -// -// GET /list -func (s *SysRoleApi) List(w http.ResponseWriter, r *http.Request) { - querys := ctx.QueryMap(r) - data := s.sysRoleService.SelectRolePage(querys) - ctx.JSON(w, 200, result.Ok(data)) -} - -// 角色信息详情 -// -// GET /:roleId -func (s *SysRoleApi) Info(w http.ResponseWriter, r *http.Request) { - roleId := ctx.Param(r, "roleId") - if roleId == "" { - ctx.JSON(w, 400, result.CodeMsg(400, "parameter error")) - return - } - data := s.sysRoleService.SelectRoleById(roleId) - if data.RoleID == roleId { - ctx.JSON(w, 200, result.OkData(data)) - return - } - ctx.JSON(w, 200, result.Err(nil)) -} - -// 角色信息新增 -// -// POST / -func (s *SysRoleApi) Add(w http.ResponseWriter, r *http.Request) { - var body model.SysRole - err := ctx.ShouldBindJSON(r, &body) - if err != nil || body.RoleID != "" { - ctx.JSON(w, 400, result.CodeMsg(400, "parameter error")) - return - } - - // 判断角色名称是否唯一 - uniqueRoleName := s.sysRoleService.CheckUniqueRoleName(body.RoleName, "") - if !uniqueRoleName { - msg := fmt.Sprintf("[%s] Role name already exists", body.RoleName) - ctx.JSON(w, 200, result.ErrMsg(msg)) - return - } - - // 判断角色键值是否唯一 - uniqueRoleKey := s.sysRoleService.CheckUniqueRoleKey(body.RoleKey, "") - if !uniqueRoleKey { - msg := fmt.Sprintf("[%s] The role key value already exists", body.RoleName) - ctx.JSON(w, 200, result.ErrMsg(msg)) - return - } - - body.CreateBy = ctx.LoginUserToUserName(r) - insertId := s.sysRoleService.InsertRole(body) - if insertId != "" { - ctx.JSON(w, 200, result.Ok(nil)) - return - } - ctx.JSON(w, 200, result.Err(nil)) -} - -// 角色信息修改 -// -// PUT / -func (s *SysRoleApi) Edit(w http.ResponseWriter, r *http.Request) { - var body model.SysRole - err := ctx.ShouldBindJSON(r, &body) - if err != nil || body.RoleID == "" { - ctx.JSON(w, 400, result.CodeMsg(400, "parameter error")) - return - } - - // 检查是否管理员角色 - if body.RoleID == "1" { - ctx.JSON(w, 200, result.ErrMsg("Operation of administrator role is not allowed")) - return - } - - // 检查是否存在 - role := s.sysRoleService.SelectRoleById(body.RoleID) - if role.RoleID != body.RoleID { - ctx.JSON(w, 200, result.ErrMsg("No permission to access role data!")) - return - } - - // 判断角色名称是否唯一 - uniqueRoleName := s.sysRoleService.CheckUniqueRoleName(body.RoleName, body.RoleID) - if !uniqueRoleName { - msg := fmt.Sprintf("[%s] Role name already exists", body.RoleName) - ctx.JSON(w, 200, result.ErrMsg(msg)) - return - } - - // 判断角色键值是否唯一 - uniqueRoleKey := s.sysRoleService.CheckUniqueRoleKey(body.RoleKey, body.RoleID) - if !uniqueRoleKey { - msg := fmt.Sprintf("[%s] The role key value already exists", body.RoleName) - ctx.JSON(w, 200, result.ErrMsg(msg)) - return - } - - body.UpdateBy = ctx.LoginUserToUserName(r) - rows := s.sysRoleService.UpdateRole(body) - if rows > 0 { - ctx.JSON(w, 200, result.Ok(nil)) - return - } - ctx.JSON(w, 200, result.Err(nil)) -} - -// 角色信息删除 -// -// DELETE /:roleIds -func (s *SysRoleApi) Remove(w http.ResponseWriter, r *http.Request) { - roleIds := ctx.Param(r, "roleIds") - if roleIds == "" { - ctx.JSON(w, 400, result.CodeMsg(400, "parameter error")) - return - } - // 处理字符转id数组后去重 - ids := strings.Split(roleIds, ",") - uniqueIDs := parse.RemoveDuplicates(ids) - if len(uniqueIDs) <= 0 { - ctx.JSON(w, 200, result.Err(nil)) - return - } - // 检查是否管理员角色 - for _, id := range uniqueIDs { - if id == "1" { - ctx.JSON(w, 200, result.ErrMsg("Operation of administrator role is not allowed")) - return - } - } - rows, err := s.sysRoleService.DeleteRoleByIds(uniqueIDs) - if err != nil { - ctx.JSON(w, 200, result.ErrMsg(err.Error())) - return - } - msg := fmt.Sprintf("Successfully deleted: %d", rows) - ctx.JSON(w, 200, result.OkMsg(msg)) -} - -// 角色状态变更 -// -// PUT /changeStatus -func (s *SysRoleApi) Status(w http.ResponseWriter, r *http.Request) { - var body struct { - // 角色ID - RoleID string `json:"roleId" binding:"required"` - // 状态 - Status string `json:"status" binding:"required"` - } - err := ctx.ShouldBindJSON(r, &body) - if err != nil { - ctx.JSON(w, 400, result.CodeMsg(400, "parameter error")) - return - } - - // 检查是否管理员角色 - if body.RoleID == "1" { - ctx.JSON(w, 200, result.ErrMsg("Operation of administrator role is not allowed")) - return - } - - // 检查是否存在 - role := s.sysRoleService.SelectRoleById(body.RoleID) - if role.RoleID != body.RoleID { - ctx.JSON(w, 200, result.ErrMsg("No permission to access role data!")) - return - } - - // 与旧值相等不变更 - if role.Status == body.Status { - ctx.JSON(w, 200, result.ErrMsg("Change status equals old value!")) - return - } - - // 更新状态不刷新缓存 - userName := ctx.LoginUserToUserName(r) - SysRoleApi := model.SysRole{ - RoleID: body.RoleID, - Status: body.Status, - UpdateBy: userName, - } - rows := s.sysRoleService.UpdateRole(SysRoleApi) - if rows > 0 { - ctx.JSON(w, 200, result.Ok(nil)) - return - } - ctx.JSON(w, 200, result.Err(nil)) -} - -// 角色分配用户列表 -// -// GET /authUser/allocatedList -func (s *SysRoleApi) AuthUserAllocatedList(w http.ResponseWriter, r *http.Request) { - querys := ctx.QueryMap(r) - roleId, ok := querys["roleId"] - if !ok || roleId == "" { - ctx.JSON(w, 400, result.CodeMsg(400, "parameter error")) - return - } - - // 检查是否存在 - role := s.sysRoleService.SelectRoleById(roleId.(string)) - if role.RoleID != roleId { - ctx.JSON(w, 200, result.ErrMsg("No permission to access role data!")) - return - } - - data := s.sysUserService.SelectAllocatedPage(querys) - ctx.JSON(w, 200, result.Ok(data)) -} - -// 角色分配选择授权 -// -// PUT /authUser/checked -func (s *SysRoleApi) AuthUserChecked(w http.ResponseWriter, r *http.Request) { - var body struct { - // 角色ID - RoleID string `json:"roleId" binding:"required"` - // 用户ID组 - UserIDs string `json:"userIds" binding:"required"` - // 选择操作 添加true 取消false - Checked bool `json:"checked"` - } - err := ctx.ShouldBindJSON(r, &body) - if err != nil { - ctx.JSON(w, 400, result.CodeMsg(400, "parameter error")) - return - } - - // 处理字符转id数组后去重 - ids := strings.Split(body.UserIDs, ",") - uniqueIDs := parse.RemoveDuplicates(ids) - if len(uniqueIDs) <= 0 { - ctx.JSON(w, 200, result.Err(nil)) - return - } - - // 检查是否存在 - role := s.sysRoleService.SelectRoleById(body.RoleID) - if role.RoleID != body.RoleID { - ctx.JSON(w, 200, result.ErrMsg("No permission to access role data!")) - return - } - - var rows int64 - if body.Checked { - rows = s.sysRoleService.InsertAuthUsers(body.RoleID, uniqueIDs) - } else { - rows = s.sysRoleService.DeleteAuthUsers(body.RoleID, uniqueIDs) - } - if rows > 0 { - ctx.JSON(w, 200, result.Ok(nil)) - return - } - ctx.JSON(w, 200, result.Err(nil)) -} diff --git a/features/sys_role/model/sys_role.go b/features/sys_role/model/sys_role.go deleted file mode 100644 index 921fd25..0000000 --- a/features/sys_role/model/sys_role.go +++ /dev/null @@ -1,38 +0,0 @@ -package model - -// SysRole 角色对象 sys_role -type SysRole struct { - // 角色ID - RoleID string `json:"roleId"` - // 角色名称 - RoleName string `json:"roleName" binding:"required"` - // 角色键值 - RoleKey string `json:"roleKey" binding:"required"` - // 显示顺序 - RoleSort int `json:"roleSort"` - // 菜单树选择项是否关联显示(0:父子不互相关联显示 1:父子互相关联显示) - MenuCheckStrictly string `json:"menuCheckStrictly"` - // 部门树选择项是否关联显示(0:父子不互相关联显示 1:父子互相关联显示) - DeptCheckStrictly string `json:"deptCheckStrictly"` - // 角色状态(0停用 1正常) - Status string `json:"status"` - // 删除标志(0代表存在 1代表删除) - DelFlag string `json:"delFlag"` - // 创建者 - CreateBy string `json:"createBy"` - // 创建时间 - CreateTime int64 `json:"createTime"` - // 更新者 - UpdateBy string `json:"updateBy"` - // 更新时间 - UpdateTime int64 `json:"updateTime"` - // 备注 - Remark string `json:"remark"` - - // ====== 非数据库字段属性 ====== - - // 菜单组 - MenuIds []string `json:"menuIds,omitempty"` - // 部门组(数据权限) - DeptIds []string `json:"deptIds,omitempty"` -} diff --git a/features/sys_role/service/repo_sys_role.go b/features/sys_role/service/repo_sys_role.go deleted file mode 100644 index 1fa9e6a..0000000 --- a/features/sys_role/service/repo_sys_role.go +++ /dev/null @@ -1,362 +0,0 @@ -package service - -import ( - "fmt" - "strings" - "time" - - "nms_cxy/features/sys_role/model" - "nms_cxy/lib/core/datasource" - "nms_cxy/lib/core/utils/date" - "nms_cxy/lib/core/utils/parse" - "nms_cxy/lib/log" -) - -// 实例化数据层 RepoSysRole 结构体 -var NewRepoSysRole = &RepoSysRole{ - selectSql: `select distinct - r.role_id, r.role_name, r.role_key, r.role_sort, r.menu_check_strictly, - r.dept_check_strictly, r.status, r.del_flag, r.create_time, r.remark - from sys_role r - left join sys_user_role ur on ur.role_id = r.role_id - left join user u on u.id = ur.user_id`, - - resultMap: map[string]string{ - "role_id": "RoleID", - "role_name": "RoleName", - "role_key": "RoleKey", - "role_sort": "RoleSort", - "menu_check_strictly": "MenuCheckStrictly", - "dept_check_strictly": "DeptCheckStrictly", - "status": "Status", - "del_flag": "DelFlag", - "create_by": "CreateBy", - "create_time": "CreateTime", - "update_by": "UpdateBy", - "update_time": "UpdateTime", - "remark": "Remark", - }, -} - -// RepoSysRole 角色表 数据层处理 -type RepoSysRole struct { - // 查询视图对象SQL - selectSql string - // 结果字段与实体映射 - resultMap map[string]string -} - -// convertResultRows 将结果记录转实体结果组 -func (r *RepoSysRole) convertResultRows(rows []map[string]any) []model.SysRole { - arr := make([]model.SysRole, 0) - for _, row := range rows { - sysRole := model.SysRole{} - for key, value := range row { - if keyMapper, ok := r.resultMap[key]; ok { - datasource.SetFieldValue(&sysRole, keyMapper, value) - } - } - arr = append(arr, sysRole) - } - return arr -} - -// SelectRolePage 根据条件分页查询角色数据 -func (r *RepoSysRole) SelectRolePage(query map[string]any) map[string]any { - // 查询条件拼接 - var conditions []string - var params []any - if v, ok := query["roleId"]; ok && v != "" { - conditions = append(conditions, "r.role_id = ?") - params = append(params, v) - } - if v, ok := query["roleName"]; ok && v != "" { - conditions = append(conditions, "r.role_name like concat('%', concat(?, '%'))") - params = append(params, v) - } - if v, ok := query["roleKey"]; ok && v != "" { - conditions = append(conditions, "r.role_key like concat('%', concat(?, '%'))") - params = append(params, v) - } - if v, ok := query["status"]; ok && v != "" { - conditions = append(conditions, "r.status = ?") - params = append(params, v) - } - beginTime, ok := query["beginTime"] - if !ok { - beginTime, ok = query["params[beginTime]"] - } - if ok && beginTime != "" { - conditions = append(conditions, "r.create_time >= ?") - beginDate := date.ParseStrToDate(beginTime.(string), date.YYYY_MM_DD) - params = append(params, beginDate.UnixMilli()) - } - endTime, ok := query["endTime"] - if !ok { - endTime, ok = query["params[endTime]"] - } - if ok && endTime != "" { - conditions = append(conditions, "r.create_time <= ?") - endDate := date.ParseStrToDate(endTime.(string), date.YYYY_MM_DD) - params = append(params, endDate.UnixMilli()) - } - - // 构建查询条件语句 - whereSql := " where r.del_flag = '0' " - if len(conditions) > 0 { - whereSql += " and " + strings.Join(conditions, " and ") - } - - // 查询数量 长度为0直接返回 - totalSql := `select count(distinct r.role_id) as 'total' from sys_role r - left join sys_user_role ur on ur.role_id = r.role_id - left join user u on u.id = ur.user_id` - totalRows, err := datasource.RawDB("", totalSql+whereSql, params) - if err != nil { - log.Errorf("total err => %v", err) - } - total := parse.Number(totalRows[0]["total"]) - if total == 0 { - return map[string]any{ - "total": total, - "rows": []model.SysRole{}, - } - } - - // 分页 - pageNum, pageSize := datasource.PageNumSize(query["pageNum"], query["pageSize"]) - pageSql := " order by r.role_sort asc limit ?,? " - params = append(params, pageNum*pageSize) - params = append(params, pageSize) - - // 查询数据 - querySql := r.selectSql + whereSql + pageSql - results, err := datasource.RawDB("", querySql, params) - if err != nil { - log.Errorf("query err => %v", err) - } - - // 转换实体 - rows := r.convertResultRows(results) - return map[string]any{ - "total": total, - "rows": rows, - } -} - -// SelectRoleList 根据条件查询角色数据 -func (r *RepoSysRole) SelectRoleList(sysRole model.SysRole) []model.SysRole { - // 查询条件拼接 - var conditions []string - var params []any - if sysRole.RoleID != "" { - conditions = append(conditions, "r.role_id = ?") - params = append(params, sysRole.RoleID) - } - if sysRole.RoleKey != "" { - conditions = append(conditions, "r.role_key like concat('%', concat(?, '%'))") - params = append(params, sysRole.RoleKey) - } - if sysRole.RoleName != "" { - conditions = append(conditions, "r.role_name like concat('%', concat(?, '%'))") - params = append(params, sysRole.RoleName) - } - if sysRole.Status != "" { - conditions = append(conditions, "r.status = ?") - params = append(params, sysRole.Status) - } - - // 构建查询条件语句 - whereSql := " where r.del_flag = '0' " - if len(conditions) > 0 { - whereSql += " and " + strings.Join(conditions, " and ") - } - - // 查询数据 - orderSql := " order by r.role_sort" - querySql := r.selectSql + whereSql + orderSql - rows, err := datasource.RawDB("", querySql, params) - if err != nil { - log.Errorf("query err => %v", err) - return []model.SysRole{} - } - return r.convertResultRows(rows) -} - -// SelectRoleListByUserId 根据用户ID获取角色选择框列表 -func (r *RepoSysRole) SelectRoleListByUserId(userId string) []model.SysRole { - querySql := r.selectSql + " where r.del_flag = '0' and ur.user_id = ?" - results, err := datasource.RawDB("", querySql, []any{userId}) - if err != nil { - log.Errorf("query err => %v", err) - return []model.SysRole{} - } - return r.convertResultRows(results) -} - -// SelectRoleByIds 通过角色ID查询角色 -func (r *RepoSysRole) SelectRoleByIds(roleIds []string) []model.SysRole { - placeholder := datasource.KeyPlaceholderByQuery(len(roleIds)) - querySql := r.selectSql + " where r.role_id in (" + placeholder + ")" - parameters := datasource.ConvertIdsSlice(roleIds) - results, err := datasource.RawDB("", querySql, parameters) - if err != nil { - log.Errorf("query err => %v", err) - return []model.SysRole{} - } - // 转换实体 - return r.convertResultRows(results) -} - -// UpdateRole 修改角色信息 -func (r *RepoSysRole) UpdateRole(sysRole model.SysRole) int64 { - // 参数拼接 - params := make(map[string]any) - if sysRole.RoleName != "" { - params["role_name"] = sysRole.RoleName - } - if sysRole.RoleKey != "" { - params["role_key"] = sysRole.RoleKey - } - if sysRole.RoleSort > 0 { - params["role_sort"] = sysRole.RoleSort - } - if sysRole.MenuCheckStrictly != "" { - params["menu_check_strictly"] = sysRole.MenuCheckStrictly - } - if sysRole.DeptCheckStrictly != "" { - params["dept_check_strictly"] = sysRole.DeptCheckStrictly - } - if sysRole.Status != "" { - params["status"] = sysRole.Status - } - if sysRole.Remark != "" { - params["remark"] = sysRole.Remark - } - if sysRole.UpdateBy != "" { - params["update_by"] = sysRole.UpdateBy - params["update_time"] = time.Now().UnixMilli() - } - - // 构建执行语句 - keys, values := datasource.KeyValueByUpdate(params) - sql := "update sys_role set " + strings.Join(keys, ",") + " where role_id = ?" - - // 执行更新 - values = append(values, sysRole.RoleID) - results, err := datasource.ExecDB("", sql, values) - if err != nil { - log.Errorf("update row : %v", err.Error()) - return 0 - } - affected, err := results.RowsAffected() - if err != nil { - log.Errorf("update err => %v", err) - return 0 - } - return affected -} - -// InsertRole 新增角色信息 -func (r *RepoSysRole) InsertRole(sysRole model.SysRole) string { - // 参数拼接 - params := make(map[string]any) - if sysRole.RoleID != "" { - params["role_id"] = sysRole.RoleID - } - if sysRole.RoleName != "" { - params["role_name"] = sysRole.RoleName - } - if sysRole.RoleKey != "" { - params["role_key"] = sysRole.RoleKey - } - if sysRole.RoleSort > 0 { - params["role_sort"] = sysRole.RoleSort - } - if sysRole.MenuCheckStrictly != "" { - params["menu_check_strictly"] = sysRole.MenuCheckStrictly - } - if sysRole.DeptCheckStrictly != "" { - params["dept_check_strictly"] = sysRole.DeptCheckStrictly - } - if sysRole.Status != "" { - params["status"] = sysRole.Status - } - if sysRole.Remark != "" { - params["remark"] = sysRole.Remark - } - if sysRole.CreateBy != "" { - params["create_by"] = sysRole.CreateBy - params["create_time"] = time.Now().UnixMilli() - } - - // 构建执行语句 - keys, placeholder, values := datasource.KeyPlaceholderValueByInsert(params) - sql := "insert into sys_role (" + strings.Join(keys, ",") + ")values(" + placeholder + ")" - - // 执行插入 - results, err := datasource.ExecDB("", sql, values) - if err != nil { - log.Errorf("insert row : %v", err.Error()) - return "" - } - insertId, err := results.LastInsertId() - if err != nil { - log.Errorf("insert row : %v", err.Error()) - return "" - } - return fmt.Sprint(insertId) -} - -// DeleteRoleByIds 批量删除角色信息 -func (r *RepoSysRole) DeleteRoleByIds(roleIds []string) int64 { - placeholder := datasource.KeyPlaceholderByQuery(len(roleIds)) - sql := "update sys_role set del_flag = '1' where role_id in (" + placeholder + ")" - parameters := datasource.ConvertIdsSlice(roleIds) - results, err := datasource.ExecDB("", sql, parameters) - if err != nil { - log.Errorf("delete err => %v", err) - return 0 - } - affected, err := results.RowsAffected() - if err != nil { - log.Errorf("delete err => %v", err) - return 0 - } - return affected -} - -// CheckUniqueRole 校验角色是否唯一 -func (r *RepoSysRole) CheckUniqueRole(sysRole model.SysRole) string { - // 查询条件拼接 - var conditions []string - var params []any - if sysRole.RoleName != "" { - conditions = append(conditions, "r.role_name = ?") - params = append(params, sysRole.RoleName) - } - if sysRole.RoleKey != "" { - conditions = append(conditions, "r.role_key = ?") - params = append(params, sysRole.RoleKey) - } - - // 构建查询条件语句 - whereSql := "" - if len(conditions) > 0 { - whereSql += " where " + strings.Join(conditions, " and ") - } else { - return "" - } - - // 查询数据 - querySql := "select role_id as 'str' from sys_role r " + whereSql + " and r.del_flag = '0' limit 1" - results, err := datasource.RawDB("", querySql, params) - if err != nil { - log.Errorf("query err %v", err) - return "" - } - if len(results) > 0 { - return fmt.Sprint(results[0]["str"]) - } - return "" -} diff --git a/features/sys_role/service/service_sys_role.go b/features/sys_role/service/service_sys_role.go deleted file mode 100644 index 7e4cc3b..0000000 --- a/features/sys_role/service/service_sys_role.go +++ /dev/null @@ -1,165 +0,0 @@ -package service - -import ( - "errors" - "fmt" - - "nms_cxy/features/sys_role/model" - sysrolemenu "nms_cxy/features/sys_role_menu" - sysuserrole "nms_cxy/features/sys_user_role" -) - -// 实例化服务层 ServiceSysRole 结构体 -var NewServiceSysRole = &ServiceSysRole{ - sysRoleRepository: NewRepoSysRole, - sysUserRoleRepository: sysuserrole.NewRepoSysUserRole, - sysRoleMenuRepository: sysrolemenu.NewRepoSysRoleMenu, -} - -// ServiceSysRole 角色 服务层处理 -type ServiceSysRole struct { - // 角色服务 - sysRoleRepository *RepoSysRole - // 用户与角色关联服务 - sysUserRoleRepository *sysuserrole.RepoSysUserRole - // 角色与菜单关联服务 - sysRoleMenuRepository *sysrolemenu.RepoSysRoleMenu -} - -// SelectRolePage 根据条件分页查询角色数据 -func (r *ServiceSysRole) SelectRolePage(query map[string]any) map[string]any { - return r.sysRoleRepository.SelectRolePage(query) -} - -// SelectRoleList 根据条件查询角色数据 -func (r *ServiceSysRole) SelectRoleList(sysRole model.SysRole) []model.SysRole { - return r.sysRoleRepository.SelectRoleList(sysRole) -} - -// SelectRoleListByUserId 根据用户ID获取角色选择框列表 -func (r *ServiceSysRole) SelectRoleListByUserId(userId string) []model.SysRole { - return r.sysRoleRepository.SelectRoleListByUserId(userId) -} - -// SelectRoleById 通过角色ID查询角色 -func (r *ServiceSysRole) SelectRoleById(roleId string) model.SysRole { - if roleId == "" { - return model.SysRole{} - } - posts := r.sysRoleRepository.SelectRoleByIds([]string{roleId}) - if len(posts) > 0 { - return posts[0] - } - return model.SysRole{} -} - -// UpdateRole 修改角色信息 -func (r *ServiceSysRole) UpdateRole(sysRole model.SysRole) int64 { - rows := r.sysRoleRepository.UpdateRole(sysRole) - if rows > 0 { - // 删除角色与菜单关联 - r.sysRoleMenuRepository.DeleteRoleMenu([]string{sysRole.RoleID}) - if len(sysRole.MenuIds) > 0 { - r.insertRoleMenu(sysRole.RoleID, sysRole.MenuIds) - } - } - return rows -} - -// InsertRole 新增角色信息 -func (r *ServiceSysRole) InsertRole(sysRole model.SysRole) string { - insertId := r.sysRoleRepository.InsertRole(sysRole) - if insertId != "" && len(sysRole.MenuIds) > 0 { - r.insertRoleMenu(insertId, sysRole.MenuIds) - } - return insertId -} - -// insertRoleMenu 新增角色菜单信息 -func (r *ServiceSysRole) insertRoleMenu(roleId string, menuIds []string) int64 { - if roleId == "" || len(menuIds) <= 0 { - return 0 - } - - sysRoleMenus := []sysrolemenu.SysRoleMenu{} - for _, menuId := range menuIds { - if menuId == "" { - continue - } - sysRoleMenus = append(sysRoleMenus, sysrolemenu.NewSysRoleMenu(roleId, menuId)) - } - - return r.sysRoleMenuRepository.BatchRoleMenu(sysRoleMenus) -} - -// DeleteRoleByIds 批量删除角色信息 -func (r *ServiceSysRole) DeleteRoleByIds(roleIds []string) (int64, error) { - // 检查是否存在 - roles := r.sysRoleRepository.SelectRoleByIds(roleIds) - if len(roles) <= 0 { - return 0, errors.New("no permission to access role data") - } - for _, role := range roles { - // 检查是否为已删除 - if role.DelFlag == "1" { - return 0, errors.New(role.RoleID + " The character information has been deleted") - } - // 检查分配用户 - userCount := r.sysUserRoleRepository.CountUserRoleByRoleId(role.RoleID) - if userCount > 0 { - msg := fmt.Sprintf("[%s] has been assigned to a user and cannot be deleted", role.RoleName) - return 0, errors.New(msg) - } - } - if len(roles) == len(roleIds) { - // 删除角色与菜单关联 - r.sysRoleMenuRepository.DeleteRoleMenu(roleIds) - rows := r.sysRoleRepository.DeleteRoleByIds(roleIds) - return rows, nil - } - return 0, errors.New("failed to delete role information") -} - -// CheckUniqueRoleName 校验角色名称是否唯一 -func (r *ServiceSysRole) CheckUniqueRoleName(roleName, roleId string) bool { - uniqueId := r.sysRoleRepository.CheckUniqueRole(model.SysRole{ - RoleName: roleName, - }) - if uniqueId == roleId { - return true - } - return uniqueId == "" -} - -// CheckUniqueRoleKey 校验角色权限是否唯一 -func (r *ServiceSysRole) CheckUniqueRoleKey(roleKey, roleId string) bool { - uniqueId := r.sysRoleRepository.CheckUniqueRole(model.SysRole{ - RoleKey: roleKey, - }) - if uniqueId == roleId { - return true - } - return uniqueId == "" -} - -// DeleteAuthUsers 批量取消授权用户角色 -func (r *ServiceSysRole) DeleteAuthUsers(roleId string, userIds []string) int64 { - return r.sysUserRoleRepository.DeleteUserRoleByRoleId(roleId, userIds) -} - -// InsertAuthUsers 批量新增授权用户角色 -func (r *ServiceSysRole) InsertAuthUsers(roleId string, userIds []string) int64 { - if roleId == "" || len(userIds) <= 0 { - return 0 - } - - sysUserRoles := []sysuserrole.SysUserRole{} - for _, userId := range userIds { - if userId == "" { - continue - } - sysUserRoles = append(sysUserRoles, sysuserrole.NewSysUserRole(userId, roleId)) - } - - return r.sysUserRoleRepository.BatchUserRole(sysUserRoles) -} diff --git a/features/sys_role_menu/model_sys_role_menu.go b/features/sys_role_menu/model_sys_role_menu.go deleted file mode 100644 index 755e66d..0000000 --- a/features/sys_role_menu/model_sys_role_menu.go +++ /dev/null @@ -1,15 +0,0 @@ -package sysrolemenu - -// SysRoleMenu 角色和菜单关联对象 sys_role_menu -type SysRoleMenu struct { - RoleID string `json:"roleId"` // 角色ID - MenuID string `json:"menuId"` // 菜单ID -} - -// NewSysRoleMenu 创建角色和菜单关联对象的构造函数 -func NewSysRoleMenu(roleID string, menuID string) SysRoleMenu { - return SysRoleMenu{ - RoleID: roleID, - MenuID: menuID, - } -} diff --git a/features/sys_role_menu/repo_sys_role_menu.go b/features/sys_role_menu/repo_sys_role_menu.go deleted file mode 100644 index cd8b9d7..0000000 --- a/features/sys_role_menu/repo_sys_role_menu.go +++ /dev/null @@ -1,86 +0,0 @@ -package sysrolemenu - -import ( - "fmt" - "strings" - - "nms_cxy/lib/core/datasource" - "nms_cxy/lib/core/utils/parse" - "nms_cxy/lib/log" -) - -// 实例化数据层 RepoSysRoleMenu 结构体 -var NewRepoSysRoleMenu = &RepoSysRoleMenu{} - -// RepoSysRoleMenu 角色与菜单关联表 数据层处理 -type RepoSysRoleMenu struct{} - -// CheckMenuExistRole 查询菜单分配给角色使用数量 -func (r *RepoSysRoleMenu) CheckMenuExistRole(menuId string) int64 { - querySql := "select count(1) as 'total' from sys_role_menu where menu_id = ?" - results, err := datasource.RawDB("", querySql, []any{menuId}) - if err != nil { - log.Errorf("query err => %v", err) - return 0 - } - if len(results) > 0 { - return parse.Number(results[0]["total"]) - } - return 0 -} - -// DeleteRoleMenu 批量删除角色和菜单关联 -func (r *RepoSysRoleMenu) DeleteRoleMenu(roleIds []string) int64 { - placeholder := datasource.KeyPlaceholderByQuery(len(roleIds)) - sql := "delete from sys_role_menu where role_id in (" + placeholder + ")" - parameters := datasource.ConvertIdsSlice(roleIds) - results, err := datasource.ExecDB("", sql, parameters) - if err != nil { - log.Errorf("delete err => %v", err) - return 0 - } - affected, err := results.RowsAffected() - if err != nil { - log.Errorf("delete err => %v", err) - return 0 - } - return affected -} - -// DeleteMenuRole 批量删除菜单和角色关联 -func (r *RepoSysRoleMenu) DeleteMenuRole(menuIds []string) int64 { - placeholder := datasource.KeyPlaceholderByQuery(len(menuIds)) - sql := "delete from sys_role_menu where menu_id in (" + placeholder + ")" - parameters := datasource.ConvertIdsSlice(menuIds) - results, err := datasource.ExecDB("", sql, parameters) - if err != nil { - log.Errorf("delete err => %v", err) - return 0 - } - affected, err := results.RowsAffected() - if err != nil { - log.Errorf("delete err => %v", err) - return 0 - } - return affected -} - -// BatchRoleMenu 批量新增角色菜单信息 -func (r *RepoSysRoleMenu) BatchRoleMenu(sysRoleMenus []SysRoleMenu) int64 { - keyValues := make([]string, 0) - for _, item := range sysRoleMenus { - keyValues = append(keyValues, fmt.Sprintf("(%s,%s)", item.RoleID, item.MenuID)) - } - sql := "insert into sys_role_menu(role_id, menu_id) values " + strings.Join(keyValues, ",") - results, err := datasource.ExecDB("", sql, nil) - if err != nil { - log.Errorf("insert err => %v", err) - return 0 - } - insertId, err := results.LastInsertId() - if err != nil { - log.Errorf("insert row : %v", err.Error()) - return 0 - } - return insertId -} diff --git a/features/sys_user/api_sys_user.go b/features/sys_user/api_sys_user.go deleted file mode 100644 index 7432db2..0000000 --- a/features/sys_user/api_sys_user.go +++ /dev/null @@ -1,323 +0,0 @@ -package sysuser - -import ( - "fmt" - "net/http" - "strings" - - sysRoleModel "nms_cxy/features/sys_role/model" - sysRoleService "nms_cxy/features/sys_role/service" - sysUserModel "nms_cxy/features/sys_user/model" - "nms_cxy/features/sys_user/service" - "nms_cxy/lib/core/utils/ctx" - "nms_cxy/lib/core/utils/parse" - "nms_cxy/lib/core/vo/result" - "nms_cxy/lib/midware" - "nms_cxy/lib/services" - "nms_cxy/omc/config" - srcConfig "nms_cxy/src/framework/config" -) - -// 用户接口添加到路由 -func Routers() []services.RouterItem { - // 实例化控制层 SysUserApi 结构体 - var apis = &SysUserApi{ - sysUserService: service.NewServiceSysUser, - sysRoleService: sysRoleService.NewServiceSysRole, - } - - rs := [...]services.RouterItem{ - { - Method: "GET", - Pattern: "/users", - Handler: apis.List, - Middleware: midware.Authorize(nil), - }, - { - Method: "GET", - Pattern: "/user/{userId}", - Handler: apis.Info, - Middleware: midware.Authorize(nil), - }, - { - Method: "POST", - Pattern: "/user", - Handler: apis.Add, - Middleware: midware.Authorize(nil), - }, - { - Method: "PUT", - Pattern: "/user", - Handler: apis.Edit, - Middleware: midware.Authorize(nil), - }, - { - Method: "DELETE", - Pattern: "/user/{userIds}", - Handler: apis.Remove, - Middleware: midware.Authorize(nil), - }, - // 添加更多的 Router 对象... - } - - // 生成两组前缀路由 - rsPrefix := []services.RouterItem{} - for _, v := range rs { - path := "/userManage/{apiVersion}" + v.Pattern - // 固定前缀 - v.Pattern = config.DefaultUriPrefix + path - rsPrefix = append(rsPrefix, v) - // 可配置 - v.Pattern = config.UriPrefix + path - rsPrefix = append(rsPrefix, v) - } - return rsPrefix -} - -// // 实例化控制层 SysUserApi 结构体 -// var NewSysUser = &SysUserApi{ -// sysUserService: service.NewSysUserImpl, -// sysRoleService: service.NewSysRoleImpl, -// sysPostService: service.NewSysPostImpl, -// sysDictDataService: service.NewSysDictDataImpl, -// } - -// 用户信息 -// -// PATH /system/user -type SysUserApi struct { - // 用户服务 - sysUserService *service.ServiceSysUser - // 角色服务 - sysRoleService *sysRoleService.ServiceSysRole -} - -// 用户信息列表 -// -// GET /list -func (s *SysUserApi) List(w http.ResponseWriter, r *http.Request) { - querys := ctx.QueryMap(r) - data := s.sysUserService.SelectUserPage(querys) - ctx.JSON(w, 200, result.Ok(data)) -} - -// 用户信息详情 -// -// GET /:userId -func (s *SysUserApi) Info(w http.ResponseWriter, r *http.Request) { - userId := ctx.Param(r, "userId") - if userId == "" { - ctx.JSON(w, 400, result.CodeMsg(400, "parameter error")) - return - } - // 查询系统角色列表 - roles := s.sysRoleService.SelectRoleList(sysRoleModel.SysRole{}) - - // 不是系统指定管理员需要排除其角色 - if !srcConfig.IsAdmin(userId) { - rolesFilter := make([]sysRoleModel.SysRole, 0) - for _, r := range roles { - if r.RoleID != "1" { - rolesFilter = append(rolesFilter, r) - } - } - roles = rolesFilter - } - - // 新增用户时,用户ID为0 - if userId == "0" { - ctx.JSON(w, 200, result.OkData(map[string]any{ - "user": map[string]any{}, - "roleIds": []string{}, - "roles": roles, - })) - return - } - - // 检查用户是否存在 - user := s.sysUserService.SelectUserById(userId) - if user.Id != userId { - ctx.JSON(w, 200, result.ErrMsg("No permission to access user data!")) - return - } - - // 角色ID组 - roleIds := make([]string, 0) - for _, r := range user.Roles { - roleIds = append(roleIds, r.RoleID) - } - - ctx.JSON(w, 200, result.OkData(map[string]any{ - "user": user, - "roleIds": roleIds, - "roles": roles, - })) -} - -// 用户信息新增 -// -// POST / -func (s *SysUserApi) Add(w http.ResponseWriter, r *http.Request) { - var body sysUserModel.SysUser - err := ctx.ShouldBindJSON(r, &body) - if err != nil || body.Id != "" { - ctx.JSON(w, 400, result.CodeMsg(400, "parameter error")) - return - } - - // 检查用户登录账号是否唯一 - uniqueUserName := s.sysUserService.CheckUniqueUserName(body.AccountId, "") - if !uniqueUserName { - msg := fmt.Sprintf("[%s] Login account already exists", body.AccountId) - ctx.JSON(w, 200, result.ErrMsg(msg)) - return - } - - insertId := s.sysUserService.InsertUser(body) - if insertId != "" { - ctx.JSON(w, 200, result.Ok(nil)) - return - } - ctx.JSON(w, 200, result.Err(nil)) -} - -// 用户信息修改 -// -// POST / -func (s *SysUserApi) Edit(w http.ResponseWriter, r *http.Request) { - var body sysUserModel.SysUser - err := ctx.ShouldBindJSON(r, &body) - if err != nil || body.Id == "" { - ctx.JSON(w, 400, result.CodeMsg(400, "parameter error")) - return - } - - // 检查是否管理员用户 - // if srcConfig.IsAdmin(body.Id) { - // ctx.JSON(w, 200, result.ErrMsg("不允许操作管理员用户")) - // return - // } - - user := s.sysUserService.SelectUserById(body.Id) - if user.Id != body.Id { - ctx.JSON(w, 200, result.ErrMsg("No permission to access user data!")) - return - } - - // 检查用户登录账号是否唯一 - uniqueUserName := s.sysUserService.CheckUniqueUserName(body.AccountId, body.Id) - if !uniqueUserName { - msg := fmt.Sprintf("[%s] Login account already exists", body.AccountId) - ctx.JSON(w, 200, result.ErrMsg(msg)) - return - } - - body.AccountId = "" // 忽略修改登录用户名称 - // body.Password = "" // 忽略修改密码 - rows := s.sysUserService.UpdateUserAndRolePost(body) - if rows > 0 { - ctx.JSON(w, 200, result.Ok(nil)) - return - } - ctx.JSON(w, 200, result.Err(nil)) -} - -// 用户信息删除 -// -// DELETE /:userIds -func (s *SysUserApi) Remove(w http.ResponseWriter, r *http.Request) { - userIds := ctx.Param(r, "userIds") - if userIds == "" { - ctx.JSON(w, 400, result.CodeMsg(400, "parameter error")) - return - } - // 处理字符转id数组后去重 - ids := strings.Split(userIds, ",") - uniqueIDs := parse.RemoveDuplicates(ids) - if len(uniqueIDs) <= 0 { - ctx.JSON(w, 200, result.Err(nil)) - return - } - rows, err := s.sysUserService.DeleteUserByIds(uniqueIDs) - if err != nil { - ctx.JSON(w, 200, result.ErrMsg(err.Error())) - return - } - msg := fmt.Sprintf("Successfully deleted: %d", rows) - ctx.JSON(w, 200, result.OkMsg(msg)) -} - -// 用户重置密码 -// -// PUT /resetPwd -func (s *SysUserApi) ResetPwd(w http.ResponseWriter, r *http.Request) { - var body struct { - UserID string `json:"userId" binding:"required"` - Password string `json:"password" binding:"required"` - } - if err := ctx.ShouldBindJSON(r, &body); err != nil { - ctx.JSON(w, 400, result.CodeMsg(400, "parameter error")) - return - } - - // 检查是否管理员用户 - if srcConfig.IsAdmin(body.UserID) { - ctx.JSON(w, 200, result.ErrMsg("No permission to access user data!")) - return - } - - user := s.sysUserService.SelectUserById(body.UserID) - if user.Id != body.UserID { - ctx.JSON(w, 200, result.ErrMsg("No permission to access user data!")) - return - } - - SysUserApi := sysUserModel.SysUser{ - Id: body.UserID, - Password: body.Password, - } - rows := s.sysUserService.UpdateUser(SysUserApi) - if rows > 0 { - ctx.JSON(w, 200, result.Ok(nil)) - return - } - ctx.JSON(w, 200, result.Err(nil)) -} - -// 用户状态修改 -// -// PUT /changeStatus -func (s *SysUserApi) Status(w http.ResponseWriter, r *http.Request) { - var body struct { - UserID string `json:"userId" binding:"required"` - Status string `json:"status" binding:"required"` - } - if err := ctx.ShouldBindJSON(r, &body); err != nil { - ctx.JSON(w, 400, result.CodeMsg(400, "parameter error")) - return - } - - // 检查是否存在 - user := s.sysUserService.SelectUserById(body.UserID) - if user.Id != body.UserID { - ctx.JSON(w, 200, result.ErrMsg("No permission to access user data!")) - return - } - - // 与旧值相等不变更 - if user.Status == body.Status { - ctx.JSON(w, 200, result.ErrMsg("Change status equals old value!")) - return - } - - SysUserApi := sysUserModel.SysUser{ - Id: body.UserID, - Status: body.Status, - } - rows := s.sysUserService.UpdateUser(SysUserApi) - if rows > 0 { - ctx.JSON(w, 200, result.Ok(nil)) - return - } - ctx.JSON(w, 200, result.Err(nil)) -} diff --git a/features/sys_user/model/sys_user.go b/features/sys_user/model/sys_user.go deleted file mode 100644 index 793f1ed..0000000 --- a/features/sys_user/model/sys_user.go +++ /dev/null @@ -1,42 +0,0 @@ -package model - -import "nms_cxy/features/sys_role/model" - -type SysUser struct { - Id string `json:"id" xorm:"pk 'id' autoincr"` - AccountId string `json:"accountId" xorm:"account_id"` - Name string `json:"name" xorm:"name"` - Sn string `json:"sn"` - Gender string `json:"gender"` - Description string `json:"description"` - TelephoneNumber string `json:"telephoneNumber" xorm:"telephone_number"` - Mobile string `json:"mobile"` - Email string `json:"email" xorm:"email"` - StartTime string `json:"startTime" xorm:"start_time"` - EndTime string `json:"endTime" xorm:"end_time"` - IdCardNumber string `json:"idCardNumber"` - EmployeeNumber string `json:"employeeNumber"` - Organize string `json:"organize"` - EmployeeType string `json:"employeeType"` - SupporterCorpName string `json:"supporterCorpName"` - RealName string `json:"realName" xorm:"real_name"` - Password string `json:"password" xorm:"-"` - PasswordSha512 string `json:"-" xorm:"-"` - ChangePasswordFlag int `json:"changePasswordFlag"` - PasswordExpiration string `json:"passwordExpiration" xorm:"password_expiration"` - Status string `json:"status"` - UserExpiration string `json:"userExpiration" xorm:"user_expiration"` - GroupName string `json:"groupName" xorm:"group_name"` - Profile string `json:"-" xorm:"profile"` - Phone string `json:"phone" xorm:"phone"` - CreateTime string `json:"createTime" xorm:"create_time"` - UpdateTime string `json:"updateTime" xorm:"update_time"` - Unit string `json:"unit" xorm:"unit"` - - // 角色对象组 - Roles []model.SysRole `json:"roles"` - // 角色ID - 参数提交绑定 - RoleID string `json:"roleId,omitempty"` - // 角色组 - 参数提交绑定 - RoleIDs []string `json:"roleIds,omitempty"` -} diff --git a/features/sys_user/service/repo_sys_user.go b/features/sys_user/service/repo_sys_user.go deleted file mode 100644 index acd9b4d..0000000 --- a/features/sys_user/service/repo_sys_user.go +++ /dev/null @@ -1,578 +0,0 @@ -package service - -import ( - "fmt" - "strings" - "time" - - sysRoleModel "nms_cxy/features/sys_role/model" - sysUserModel "nms_cxy/features/sys_user/model" - "nms_cxy/lib/core/datasource" - "nms_cxy/lib/core/utils/date" - "nms_cxy/lib/core/utils/parse" - "nms_cxy/lib/log" - "nms_cxy/src/framework/utils/crypto" -) - -// 实例化数据层 RepoSysUser 结构体 -var NewRepoSysUser = &RepoSysUser{ - selectSql: `select u.id, - u.account_id, u.name, u.sn, u.gender, u.description, u.telephone_number, u.mobile, u.email, - u.start_time, u.end_time, u.id_card_number, u.employee_number, - u.organize, u.employee_type, u.supporter_corp_name, u.real_name, u.password, u.password_sha512, - u.change_password_flag,u.password_expiration, u.status, u.user_expiration, u.group_name, - u.profile, u.phone, u.create_time, u.update_time, u.unit, - r.role_id, r.role_name, r.role_key, r.role_sort, r.data_scope, r.status as role_status - from user u - left join sys_user_role ur on u.id = ur.user_id - left join sys_role r on r.role_id = ur.role_id`, - - sysUserMap: map[string]string{ - "id": "Id", - "account_id": "AccountId", - "name": "Name", - "sn": "Sn", - "gender": "Gender", - "description": "Description", - "telephone_number": "TelephoneNumber", - "mobile": "Mobile", - "email": "Email", - "start_time": "StartTime", - "end_time": "EndTime", - "id_card_number": "IdCardNumber", - "employee_number": "EmployeeNumber", - "organize": "Organize", - "employee_type": "EmployeeType", - "supporter_corp_name": "SupporterCorpName", - "real_name": "RealName", - "password": "Password", - "password_sha512": "PasswordSha512", - "change_password_flag": "ChangePasswordFlag", - "password_expiration": "PasswordExpiration", - "status": "Status", - "user_expiration": "UserExpiration", - "group_name": "GroupName", - "profile": "Profile", - "phone": "Phone", - "create_time": "CreateTime", - "update_time": "UpdateTime", - "unit": "Unit", - }, - - sysRoleMap: map[string]string{ - "role_id": "RoleID", - "role_name": "RoleName", - "role_key": "RoleKey", - "role_sort": "RoleSort", - "data_scope": "DataScope", - "role_status": "Status", - }, -} - -// RepoSysUser 用户表 数据层处理 -type RepoSysUser struct { - // 查询视图对象SQL - selectSql string - // 用户信息实体映射 - sysUserMap map[string]string - // 用户角色实体映射 一对多 - sysRoleMap map[string]string -} - -// convertResultRows 将结果记录转实体结果组 -func (r *RepoSysUser) convertResultRows(rows []map[string]any) []sysUserModel.SysUser { - arr := make([]sysUserModel.SysUser, 0) - - for _, row := range rows { - sysUser := sysUserModel.SysUser{} - sysRole := sysRoleModel.SysRole{} - sysUser.Roles = []sysRoleModel.SysRole{} - - for key, value := range row { - if keyMapper, ok := r.sysUserMap[key]; ok { - datasource.SetFieldValue(&sysUser, keyMapper, value) - } - if keyMapper, ok := r.sysRoleMap[key]; ok { - datasource.SetFieldValue(&sysRole, keyMapper, value) - } - } - - if sysRole.RoleKey != "" { - sysUser.Roles = append(sysUser.Roles, sysRole) - } - - one := true - for i, a := range arr { - if a.Id == sysUser.Id { - arrUser := &arr[i] - arrUser.Roles = append(arrUser.Roles, sysUser.Roles...) - one = false - break - } - } - if one { - arr = append(arr, sysUser) - } - } - - return arr -} - -// SelectUserPage 根据条件分页查询用户列表 -func (r *RepoSysUser) SelectUserPage(query map[string]any) map[string]any { - selectUserSql := `select u.id, - u.account_id, u.name, u.sn, u.gender, u.description, u.telephone_number, u.mobile, u.email, - u.start_time, u.end_time, u.id_card_number, u.employee_number, - u.organize, u.employee_type, u.supporter_corp_name, u.real_name, - u.change_password_flag,u.password_expiration, u.status, u.user_expiration, u.group_name, - u.profile, u.phone, u.create_time, u.update_time, u.unit - from user u` - selectUserTotalSql := `select count(distinct u.id) as 'total' from user u` - - // 查询条件拼接 - var conditions []string - var params []any - if v, ok := query["accountId"]; ok && v != "" { - conditions = append(conditions, "u.account_id = ?") - params = append(params, v) - } - if v, ok := query["name"]; ok && v != "" { - conditions = append(conditions, "u.name concat('%', concat(?, '%'))") - params = append(params, v) - } - if v, ok := query["status"]; ok && v != "" { - conditions = append(conditions, "u.status = ?") - params = append(params, v) - } - if v, ok := query["phonenumber"]; ok && v != "" { - conditions = append(conditions, "u.phonenumber like concat('%', concat(?, '%'))") - params = append(params, v) - } - beginTime, ok := query["beginTime"] - if !ok { - beginTime, ok = query["params[beginTime]"] - } - if ok && beginTime != "" { - conditions = append(conditions, "u.login_date >= ?") - beginDate := date.ParseStrToDate(beginTime.(string), date.YYYY_MM_DD) - params = append(params, beginDate.UnixMilli()) - } - endTime, ok := query["endTime"] - if !ok { - endTime, ok = query["params[endTime]"] - } - if ok && endTime != "" { - conditions = append(conditions, "u.login_date <= ?") - endDate := date.ParseStrToDate(endTime.(string), date.YYYY_MM_DD) - params = append(params, endDate.UnixMilli()) - } - if v, ok := query["deptId"]; ok && v != "" { - conditions = append(conditions, "(u.dept_id = ? or u.dept_id in ( select t.dept_id from sys_dept t where find_in_set(?, ancestors) ))") - params = append(params, v) - params = append(params, v) - } - - // 构建查询条件语句 - whereSql := "" - if len(conditions) > 0 { - whereSql += " where " + strings.Join(conditions, " and ") - } - - // 查询数量 长度为0直接返回 - totalSql := selectUserTotalSql + whereSql - totalRows, err := datasource.RawDB("", totalSql, params) - if err != nil { - log.Errorf("total err => %v", err) - } - total := parse.Number(totalRows[0]["total"]) - if total == 0 { - return map[string]any{ - "total": total, - "rows": []sysUserModel.SysUser{}, - } - } - - // 分页 - pageNum, pageSize := datasource.PageNumSize(query["pageNum"], query["pageSize"]) - pageSql := " limit ?,? " - params = append(params, pageNum*pageSize) - params = append(params, pageSize) - - // 查询数据 - querySql := selectUserSql + whereSql + pageSql - results, err := datasource.RawDB("", querySql, params) - if err != nil { - log.Errorf("query err => %v", err) - } - - // 转换实体 - rows := r.convertResultRows(results) - return map[string]any{ - "total": total, - "rows": rows, - } -} - -// SelectAllocatedPage 根据条件分页查询分配用户角色列表 -func (r *RepoSysUser) SelectAllocatedPage(query map[string]any) map[string]any { - // 查询条件拼接 - var conditions []string - var params []any - if v, ok := query["name"]; ok && v != "" { - conditions = append(conditions, "u.name like concat('%', concat(?, '%'))") - params = append(params, v) - } - if v, ok := query["phone"]; ok && v != "" { - conditions = append(conditions, "u.phone like concat('%', concat(?, '%'))") - params = append(params, v) - } - if v, ok := query["status"]; ok && v != "" { - conditions = append(conditions, "u.status = ?") - params = append(params, v) - } - // 分配角色用户 - if allocated, ok := query["allocated"]; ok && allocated != "" { - if roleId, ok := query["roleId"]; ok && roleId != "" { - if parse.Boolean(allocated) { - conditions = append(conditions, "r.role_id = ?") - params = append(params, roleId) - } else { - conditions = append(conditions, `(r.role_id != ? or r.role_id IS NULL) - and u.id not in ( - select u.id from user u - inner join sys_user_role ur on u.id = ur.user_id - and ur.role_id = ? - )`) - params = append(params, roleId) - params = append(params, roleId) - } - - } - } - - // 构建查询条件语句 - whereSql := "" - if len(conditions) > 0 { - whereSql += " where " + strings.Join(conditions, " and ") - } - - // 查询数量 长度为0直接返回 - totalSql := `select count(distinct u.id) as 'total' from user u - left join sys_user_role ur on u.id = ur.user_id - left join sys_role r on r.role_id = ur.role_id` - totalRows, err := datasource.RawDB("", totalSql+whereSql, params) - if err != nil { - log.Errorf("total err => %v", err) - } - total := parse.Number(totalRows[0]["total"]) - if total == 0 { - return map[string]any{ - "total": total, - "rows": []sysUserModel.SysUser{}, - } - } - - // 分页 - pageNum, pageSize := datasource.PageNumSize(query["pageNum"], query["pageSize"]) - pageSql := " limit ?,? " - params = append(params, pageNum*pageSize) - params = append(params, pageSize) - - // 查询数据 - querySql := `select distinct - u.id, u.account_id, u.name, u.gender, u.email, - u.phone, u.status, u.create_time, u.real_name - from user u - left join sys_user_role ur on u.id = ur.user_id - left join sys_role r on r.role_id = ur.role_id` - querySql = querySql + whereSql + pageSql - results, err := datasource.RawDB("", querySql, params) - if err != nil { - log.Errorf("query err => %v", err) - } - - // 转换实体 - rows := r.convertResultRows(results) - return map[string]any{ - "total": total, - "rows": rows, - } -} - -// SelectUserList 根据条件查询用户列表 -func (r *RepoSysUser) SelectUserList(sysUser sysUserModel.SysUser, dataScopeSQL string) []sysUserModel.SysUser { - selectUserSql := `select - u.id, u.account_id, u.name, u.real_name, u.email, u.gender, u.phone, u.create_time, u.status, u.description - from user u` - - // 查询条件拼接 - var conditions []string - var params []any - if sysUser.AccountId != "" { - conditions = append(conditions, "u.account_id = ?") - params = append(params, sysUser.AccountId) - } - if sysUser.Name != "" { - conditions = append(conditions, "u.name like concat('%', concat(?, '%'))") - params = append(params, sysUser.Name) - } - if sysUser.Status != "" { - conditions = append(conditions, "u.status = ?") - params = append(params, sysUser.Status) - } - if sysUser.Phone != "" { - conditions = append(conditions, "u.phone like concat('%', concat(?, '%'))") - params = append(params, sysUser.Phone) - } - - // 构建查询条件语句 - whereSql := "" - if len(conditions) > 0 { - whereSql += " where " + strings.Join(conditions, " and ") - } - - // 查询数据 - querySql := selectUserSql + whereSql + dataScopeSQL - rows, err := datasource.RawDB("", querySql, params) - if err != nil { - log.Errorf("query err => %v", err) - return []sysUserModel.SysUser{} - } - return r.convertResultRows(rows) -} - -// SelectUserByIds 通过用户ID查询用户 -func (r *RepoSysUser) SelectUserByIds(userIds []string) []sysUserModel.SysUser { - placeholder := datasource.KeyPlaceholderByQuery(len(userIds)) - querySql := r.selectSql + " where u.id in (" + placeholder + ")" - parameters := datasource.ConvertIdsSlice(userIds) - results, err := datasource.RawDB("", querySql, parameters) - if err != nil { - log.Errorf("query err => %v", err) - return []sysUserModel.SysUser{} - } - // 转换实体 - return r.convertResultRows(results) -} - -// SelectUserByUserName 通过用户登录账号查询用户 -func (r *RepoSysUser) SelectUserByUserName(userName string) sysUserModel.SysUser { - querySql := r.selectSql + " where u.name = ?" - results, err := datasource.RawDB("", querySql, []any{userName}) - if err != nil { - log.Errorf("query err => %v", err) - return sysUserModel.SysUser{} - } - // 转换实体 - rows := r.convertResultRows(results) - if len(rows) > 0 { - return rows[0] - } - return sysUserModel.SysUser{} -} - -// InsertUser 新增用户信息 -func (r *RepoSysUser) InsertUser(sysUser sysUserModel.SysUser) string { - // 参数拼接 - params := make(map[string]any) - if sysUser.AccountId != "" { - params["account_id"] = sysUser.AccountId - } - if sysUser.Name != "" { - params["name"] = sysUser.Name - } - if sysUser.Sn != "" { - params["sn"] = sysUser.Sn - } else { - params["sn"] = "" - } - if sysUser.RealName != "" { - params["real_name"] = sysUser.RealName - } else { - params["real_name"] = "" - } - if sysUser.Gender != "" { - params["gender"] = sysUser.Gender - } - if sysUser.Email != "" { - params["email"] = sysUser.Email - } else { - params["email"] = "" - } - if sysUser.Phone != "" { - params["phone"] = sysUser.Phone - } else { - params["phone"] = "" - } - if sysUser.Unit != "" { - params["unit"] = sysUser.Unit - } else { - params["unit"] = "" - } - - if sysUser.Organize != "" { - params["organize"] = sysUser.Organize - } - if sysUser.Password != "" { - password := crypto.BcryptHash(sysUser.Password) - params["password"] = password - } - if sysUser.Status != "" { - params["status"] = sysUser.Status - } - if sysUser.PasswordExpiration != "" { - params["password_expiration"] = sysUser.PasswordExpiration - } - if sysUser.UserExpiration != "" { - params["user_expiration"] = sysUser.UserExpiration - } - if sysUser.GroupName != "" { - params["group_name"] = sysUser.GroupName - } - params["create_time"] = time.Now() - - // 构建执行语句 - keys, placeholder, values := datasource.KeyPlaceholderValueByInsert(params) - sql := "insert into user (" + strings.Join(keys, ",") + ")values(" + placeholder + ")" - - // 执行插入 - results, err := datasource.ExecDB("", sql, values) - if err != nil { - log.Errorf("insert row : %v", err.Error()) - return "" - } - insertId, err := results.LastInsertId() - if err != nil { - log.Errorf("insert row : %v", err.Error()) - return "" - } - return fmt.Sprint(insertId) -} - -// UpdateUser 修改用户信息 -func (r *RepoSysUser) UpdateUser(sysUser sysUserModel.SysUser) int64 { - // 参数拼接 - params := make(map[string]any) - if sysUser.Name != "" { - params["name"] = sysUser.Name - } - if sysUser.Sn != "" { - params["sn"] = sysUser.Sn - } else { - params["sn"] = "" - } - if sysUser.RealName != "" { - params["real_name"] = sysUser.RealName - } else { - params["real_name"] = "" - } - if sysUser.Gender != "" { - params["gender"] = sysUser.Gender - } - if sysUser.Email != "" { - params["email"] = sysUser.Email - } else { - params["email"] = "" - } - if sysUser.Phone != "" { - params["phone"] = sysUser.Phone - } else { - params["phone"] = "" - } - if sysUser.Unit != "" { - params["unit"] = sysUser.Unit - } else { - params["unit"] = "" - } - - if sysUser.Organize != "" { - params["organize"] = sysUser.Organize - } - if sysUser.Password != "" { - password := crypto.BcryptHash(sysUser.Password) - params["password"] = password - } - if sysUser.Status != "" { - params["status"] = sysUser.Status - } - if sysUser.PasswordExpiration != "" { - params["password_expiration"] = sysUser.PasswordExpiration - } - if sysUser.UserExpiration != "" { - params["user_expiration"] = sysUser.UserExpiration - } - if sysUser.GroupName != "" { - params["group_name"] = sysUser.GroupName - } - params["update_time"] = time.Now() - - // 构建执行语句 - keys, values := datasource.KeyValueByUpdate(params) - sql := "update user set " + strings.Join(keys, ",") + " where id = ?" - - // 执行更新 - values = append(values, sysUser.Id) - results, err := datasource.ExecDB("", sql, values) - if err != nil { - log.Errorf("update row : %v", err.Error()) - return 0 - } - affected, err := results.RowsAffected() - if err != nil { - log.Errorf("update err => %v", err) - return 0 - } - return affected -} - -// DeleteUserByIds 批量删除用户信息 -func (r *RepoSysUser) DeleteUserByIds(userIds []string) int64 { - placeholder := datasource.KeyPlaceholderByQuery(len(userIds)) - sql := "delete from user where id in (" + placeholder + ")" - parameters := datasource.ConvertIdsSlice(userIds) - results, err := datasource.ExecDB("", sql, parameters) - if err != nil { - log.Errorf("delete err => %v", err) - return 0 - } - affected, err := results.RowsAffected() - if err != nil { - log.Errorf("delete err => %v", err) - return 0 - } - return affected -} - -// CheckUniqueUser 校验用户信息是否唯一 -func (r *RepoSysUser) CheckUniqueUser(sysUser sysUserModel.SysUser) string { - // 查询条件拼接 - var conditions []string - var params []any - if sysUser.Name != "" { - conditions = append(conditions, "name = ?") - params = append(params, sysUser.Name) - } - if sysUser.AccountId != "" { - conditions = append(conditions, "account_id = ?") - params = append(params, sysUser.AccountId) - } - - // 构建查询条件语句 - whereSql := "" - if len(conditions) > 0 { - whereSql += " where " + strings.Join(conditions, " and ") - } else { - return "" - } - - // 查询数据 - querySql := "select id as 'str' from user " + whereSql + " limit 1" - results, err := datasource.RawDB("", querySql, params) - if err != nil { - log.Errorf("query err %v", err) - } - if len(results) > 0 { - return fmt.Sprint(results[0]["str"]) - } - return "" -} diff --git a/features/sys_user/service/service_sys_user.go b/features/sys_user/service/service_sys_user.go deleted file mode 100644 index d89e3d0..0000000 --- a/features/sys_user/service/service_sys_user.go +++ /dev/null @@ -1,150 +0,0 @@ -package service - -import ( - "errors" - "fmt" - - sysUserModel "nms_cxy/features/sys_user/model" - sysuserrole "nms_cxy/features/sys_user_role" -) - -// 实例化服务层 ServiceSysUser 结构体 -var NewServiceSysUser = &ServiceSysUser{ - sysUserRepository: NewRepoSysUser, - sysUserRoleRepository: sysuserrole.NewRepoSysUserRole, -} - -// ServiceSysUser 用户 服务层处理 -type ServiceSysUser struct { - // 用户服务 - sysUserRepository *RepoSysUser - // 用户与角色服务 - sysUserRoleRepository *sysuserrole.RepoSysUserRole -} - -// SelectUserPage 根据条件分页查询用户列表 -func (r *ServiceSysUser) SelectUserPage(query map[string]any) map[string]any { - return r.sysUserRepository.SelectUserPage(query) -} - -// SelectUserList 根据条件查询用户列表 -func (r *ServiceSysUser) SelectUserList(sysUser sysUserModel.SysUser) []sysUserModel.SysUser { - return []sysUserModel.SysUser{} -} - -// SelectAllocatedPage 根据条件分页查询分配用户角色列表 -func (r *ServiceSysUser) SelectAllocatedPage(query map[string]any) map[string]any { - return r.sysUserRepository.SelectAllocatedPage(query) -} - -// SelectUserByUserName 通过用户名查询用户 -func (r *ServiceSysUser) SelectUserByUserName(userName string) sysUserModel.SysUser { - return r.sysUserRepository.SelectUserByUserName(userName) -} - -// SelectUserById 通过用户ID查询用户 -func (r *ServiceSysUser) SelectUserById(userId string) sysUserModel.SysUser { - if userId == "" { - return sysUserModel.SysUser{} - } - users := r.sysUserRepository.SelectUserByIds([]string{userId}) - if len(users) > 0 { - return users[0] - } - return sysUserModel.SysUser{} -} - -// InsertUser 新增用户信息 -func (r *ServiceSysUser) InsertUser(sysUser sysUserModel.SysUser) string { - // 新增用户信息 - insertId := r.sysUserRepository.InsertUser(sysUser) - if insertId != "" { - // 新增用户角色信息 - r.insertUserRole(insertId, sysUser.RoleIDs) - } - return insertId -} - -// insertUserRole 新增用户角色信息 -func (r *ServiceSysUser) insertUserRole(userId string, roleIds []string) int64 { - if userId == "" || len(roleIds) <= 0 { - return 0 - } - - sysUserRoles := []sysuserrole.SysUserRole{} - for _, roleId := range roleIds { - // 管理员角色禁止操作,只能通过配置指定用户ID分配 - if roleId == "" || roleId == "1" { - continue - } - sysUserRoles = append(sysUserRoles, sysuserrole.NewSysUserRole(userId, roleId)) - } - - return r.sysUserRoleRepository.BatchUserRole(sysUserRoles) -} - -// UpdateUser 修改用户信息 -func (r *ServiceSysUser) UpdateUser(sysUser sysUserModel.SysUser) int64 { - return r.sysUserRepository.UpdateUser(sysUser) -} - -// UpdateUserAndRolePost 修改用户信息同时更新角色和岗位 -func (r *ServiceSysUser) UpdateUserAndRolePost(sysUser sysUserModel.SysUser) int64 { - userId := fmt.Sprint(sysUser.Id) - // 删除用户与角色关联 - r.sysUserRoleRepository.DeleteUserRole([]string{userId}) - // 新增用户角色信息 - r.insertUserRole(userId, sysUser.RoleIDs) - return r.sysUserRepository.UpdateUser(sysUser) -} - -// DeleteUserByIds 批量删除用户信息 -func (r *ServiceSysUser) DeleteUserByIds(userIds []string) (int64, error) { - // 检查是否存在 - users := r.sysUserRepository.SelectUserByIds(userIds) - if len(users) <= 0 { - return 0, errors.New("no permission to access user data") - } - if len(users) == len(userIds) { - // 删除用户与角色关联 - r.sysUserRoleRepository.DeleteUserRole(userIds) - // ... 注意其他userId进行关联的表 - // 删除用户 - rows := r.sysUserRepository.DeleteUserByIds(userIds) - return rows, nil - } - return 0, errors.New("failed to delete user information") -} - -// CheckUniqueUserName 校验用户名称是否唯一 -func (r *ServiceSysUser) CheckUniqueUserName(accountId, userId string) bool { - uniqueId := r.sysUserRepository.CheckUniqueUser(sysUserModel.SysUser{ - AccountId: accountId, - }) - if uniqueId == userId { - return true - } - return uniqueId == "" -} - -// CheckUniquePhone 校验手机号码是否唯一 -func (r *ServiceSysUser) CheckUniquePhone(phonenumber, userId string) bool { - uniqueId := r.sysUserRepository.CheckUniqueUser(sysUserModel.SysUser{ - Phone: phonenumber, - }) - if uniqueId == userId { - return true - } - return uniqueId == "" -} - -// CheckUniqueEmail 校验email是否唯一 -func (r *ServiceSysUser) CheckUniqueEmail(email, userId string) bool { - uniqueId := r.sysUserRepository.CheckUniqueUser(sysUserModel.SysUser{ - Email: email, - }) - if uniqueId == userId { - return true - } - return uniqueId == "" -} diff --git a/features/sys_user_role/model_sys_user_role.go b/features/sys_user_role/model_sys_user_role.go deleted file mode 100644 index bc493eb..0000000 --- a/features/sys_user_role/model_sys_user_role.go +++ /dev/null @@ -1,15 +0,0 @@ -package sysuserrole - -// SysUserRole 用户和角色关联对象 sys_user_role -type SysUserRole struct { - UserID string `json:"userId"` // 用户ID - RoleID string `json:"roleId"` // 角色ID -} - -// NewSysUserRole 创建用户和角色关联对象的构造函数 -func NewSysUserRole(userID string, roleID string) SysUserRole { - return SysUserRole{ - UserID: userID, - RoleID: roleID, - } -} diff --git a/features/sys_user_role/repo_sys_user_role.go b/features/sys_user_role/repo_sys_user_role.go deleted file mode 100644 index d06db86..0000000 --- a/features/sys_user_role/repo_sys_user_role.go +++ /dev/null @@ -1,87 +0,0 @@ -package sysuserrole - -import ( - "fmt" - "strings" - - "nms_cxy/lib/core/datasource" - "nms_cxy/lib/core/utils/parse" - "nms_cxy/lib/log" -) - -// 实例化数据层 RepoSysUserRole 结构体 -var NewRepoSysUserRole = &RepoSysUserRole{} - -// RepoSysUserRole 用户与角色关联表 数据层处理 -type RepoSysUserRole struct{} - -// CountUserRoleByRoleId 通过角色ID查询角色使用数量 -func (r *RepoSysUserRole) CountUserRoleByRoleId(roleId string) int64 { - querySql := "select count(1) as total from sys_user_role where role_id = ?" - results, err := datasource.RawDB("", querySql, []any{roleId}) - if err != nil { - log.Errorf("query err => %v", err) - return 0 - } - if len(results) > 0 { - return parse.Number(results[0]["total"]) - } - return 0 -} - -// BatchUserRole 批量新增用户角色信息 -func (r *RepoSysUserRole) BatchUserRole(sysUserRoles []SysUserRole) int64 { - keyValues := make([]string, 0) - for _, item := range sysUserRoles { - keyValues = append(keyValues, fmt.Sprintf("(%s,%s)", item.UserID, item.RoleID)) - } - sql := "insert into sys_user_role(user_id, role_id) values " + strings.Join(keyValues, ",") - results, err := datasource.ExecDB("", sql, nil) - if err != nil { - log.Errorf("delete err => %v", err) - return 0 - } - affected, err := results.RowsAffected() - if err != nil { - log.Errorf("delete err => %v", err) - return 0 - } - return affected -} - -// DeleteUserRole 批量删除用户和角色关联 -func (r *RepoSysUserRole) DeleteUserRole(userIds []string) int64 { - placeholder := datasource.KeyPlaceholderByQuery(len(userIds)) - sql := "delete from sys_user_role where user_id in (" + placeholder + ")" - parameters := datasource.ConvertIdsSlice(userIds) - results, err := datasource.ExecDB("", sql, parameters) - if err != nil { - log.Errorf("delete err => %v", err) - return 0 - } - affected, err := results.RowsAffected() - if err != nil { - log.Errorf("delete err => %v", err) - return 0 - } - return affected -} - -// DeleteUserRoleByRoleId 批量取消授权用户角色 -func (r *RepoSysUserRole) DeleteUserRoleByRoleId(roleId string, userIds []string) int64 { - placeholder := datasource.KeyPlaceholderByQuery(len(userIds)) - sql := "delete from sys_user_role where role_id= ? and user_id in (" + placeholder + ")" - parameters := datasource.ConvertIdsSlice(userIds) - parameters = append([]any{roleId}, parameters...) - results, err := datasource.ExecDB("", sql, parameters) - if err != nil { - log.Errorf("delete err => %v", err) - return 0 - } - affected, err := results.RowsAffected() - if err != nil { - log.Errorf("delete err => %v", err) - return 0 - } - return affected -} diff --git a/features/trace/tcpdump.go b/features/trace/tcpdump.go deleted file mode 100644 index fb9ed08..0000000 --- a/features/trace/tcpdump.go +++ /dev/null @@ -1,339 +0,0 @@ -package trace - -import ( - "fmt" - "net" - "net/http" - "strings" - "time" - - "nms_cxy/lib/core/conf" - "nms_cxy/lib/core/utils/ctx" - "nms_cxy/lib/core/vo/result" - "nms_cxy/lib/dborm" - "nms_cxy/lib/log" - "nms_cxy/omc/config" - "nms_cxy/src/framework/utils/cmd" - "nms_cxy/src/framework/utils/ssh" -) - -var ( - UriTcpdumpTask = config.DefaultUriPrefix + "/traceManagement/{apiVersion}/tcpdumpNeTask" - CustomUriTcpdumpTask = config.UriPrefix + "/traceManagement/{apiVersion}/tcpdumpNeTask" // decode message api - - UriTcpdumpPcapDownload = config.DefaultUriPrefix + "/traceManagement/{apiVersion}/tcpdumpPcapDownload" - CustomUriTcpdumpPcapDownload = config.UriPrefix + "/traceManagement/{apiVersion}/tcpdumpPcapDownload" // decode message api - - UriTcpdumpNeUPFTask = config.DefaultUriPrefix + "/traceManagement/{apiVersion}/tcpdumpNeUPFTask" - CustomUriTcpdumpNeUPFTask = config.UriPrefix + "/traceManagement/{apiVersion}/tcpdumpNeUPFTask" // decode message api -) - -// NeInfo 网元信息 -func NeInfo(neType, neId string) (*dborm.NeInfo, error) { - neInfo, err := dborm.XormGetNeInfo(neType, neId) - if err != nil { - log.Error("dborm.XormGetNeInfo is failed:", err) - return nil, err - } - if neInfo == nil || neInfo.Ip == "" { - return nil, fmt.Errorf("not ne_info or not IP") - } - return neInfo, nil -} - -// TcpdumpNeTask 网元发送执行 pcap -func TcpdumpNeTask(w http.ResponseWriter, r *http.Request) { - var body struct { - NeType string `json:"neType"` // 网元类型 - NeId string `json:"neId"` // 网元ID - Timeout int `json:"timeout"` // 超时时间 - Cmd string `json:"cmd"` // 命令 - } - err := ctx.ShouldBindJSON(r, &body) - if err != nil || body.NeType == "" || body.NeId == "" || body.Timeout < 5 || body.Cmd == "" { - ctx.JSON(w, 400, result.CodeMsg(400, "parameter error")) - return - } - - neInfo, err := NeInfo(body.NeType, body.NeId) - if err != nil { - ctx.JSON(w, 200, result.ErrMsg(err.Error())) - return - } - - filePcapName := fmt.Sprintf("tmp_%s_%s_%d.pcap", body.NeType, body.NeId, time.Now().UnixMilli()) - fileLogName := fmt.Sprintf("tmp_%s_%s_%d.log", body.NeType, body.NeId, time.Now().UnixMilli()) - writeLog := fmt.Sprintf(" >> %s 2>&1 \ncat %s", fileLogName, fileLogName) // 执行信息写入日志文件,放置弹出code 127 - cmdStr := fmt.Sprintf("cd /tmp \nsudo timeout %d tcpdump -i any %s -s0 -w %s", body.Timeout, body.Cmd, filePcapName) - usernameNe := conf.Get("ne.user").(string) // 网元统一用户 - sshHost := fmt.Sprintf("%s@%s", usernameNe, neInfo.Ip) - msg, err := cmd.ExecWithCheck("ssh", sshHost, cmdStr+writeLog) - if err != nil { - ctx.JSON(w, 200, result.ErrMsg(err.Error())) - return - } - - ctx.JSON(w, 200, result.OkData(map[string]any{ - "cmd": cmdStr, - "msg": msg, - "fileName": filePcapName, - })) -} - -// TcpdumpPcapDownload 网元抓包pcap文件下载 -func TcpdumpPcapDownload(w http.ResponseWriter, r *http.Request) { - var body struct { - NeType string `json:"neType"` // 网元类型 - NeId string `json:"neId"` // 网元ID - FileName string `json:"fileName"` // 文件名 - } - err := ctx.ShouldBindJSON(r, &body) - if err != nil || body.NeType == "" || body.NeId == "" || body.FileName == "" { - ctx.JSON(w, 400, result.CodeMsg(400, "parameter error")) - return - } - - neInfo, err := NeInfo(body.NeType, body.NeId) - if err != nil { - ctx.JSON(w, 200, result.ErrMsg(err.Error())) - return - } - - nePath := fmt.Sprintf("/tmp/%s", body.FileName) - localPath := fmt.Sprintf("%s/tcpdump/pcap/%s", conf.Get("ne.omcdir"), body.FileName) - err = ssh.FileSCPNeToLocal(neInfo.Ip, nePath, localPath) - if err != nil { - ctx.JSON(w, 200, result.ErrMsg(err.Error())) - return - } - - ctx.FileAttachment(w, r, localPath, body.FileName) -} - -// TcpdumpNeUPFTask 网元UPF发送执行 pcap -func TcpdumpNeUPFTask(w http.ResponseWriter, r *http.Request) { - var body struct { - NeType string `json:"neType"` // 网元类型 - NeId string `json:"neId"` // 网元ID - Cmd string `json:"cmd"` // 命令 - RunType string `json:"runType"` // 执行开始start还是停止stop - } - err := ctx.ShouldBindJSON(r, &body) - if err != nil || body.NeType != "UPF" || body.NeId == "" || body.Cmd == "" { - ctx.JSON(w, 400, result.CodeMsg(400, "parameter error")) - return - } - - neInfo, err := NeInfo(body.NeType, body.NeId) - if err != nil { - ctx.JSON(w, 200, result.ErrMsg(err.Error())) - return - } - - // 开始telnet - if body.RunType == "start_telnet" { - // 创建TCP连接 - conn, err := net.Dial("tcp", fmt.Sprintf("%s:%d", neInfo.Ip, 5002)) - if err != nil { - ctx.JSON(w, 200, result.ErrMsg(err.Error())) - return - } - defer conn.Close() - - filePcapName := fmt.Sprintf("tmp_%s_%s.pcap", body.NeType, body.NeId) - cmdStr := fmt.Sprintf("pcap dispatch trace on max 100000 file %s", filePcapName) - - fmt.Fprintln(conn, cmdStr) - - // 读取内容 - time.Sleep(time.Duration(200) * time.Millisecond) - buf := make([]byte, 1024*8) - n, err := conn.Read(buf) - if err != nil { - ctx.JSON(w, 200, result.ErrMsg(err.Error())) - } else { - str := string(buf[0:n]) - s := strings.Index(str, "pcap dispatch trace:") - if s != -1 { - e := strings.Index(str, "\r\nupfd1#") - str = str[s:e] - } else { - str = fmt.Sprintf("Executed, please stop before proceeding %d", n) - } - ctx.JSON(w, 200, result.OkData(map[string]any{ - "cmd": cmdStr, - "msg": str, - "fileName": filePcapName, - })) - } - conn.Close() - return - } - // 停止telnet - if body.RunType == "stop_telnet" { - // 创建TCP连接 - conn, err := net.Dial("tcp", fmt.Sprintf("%s:%d", neInfo.Ip, 5002)) - if err != nil { - ctx.JSON(w, 200, result.ErrMsg(err.Error())) - return - } - defer conn.Close() - - filePcapName := fmt.Sprintf("tmp_%s_%s.pcap", body.NeType, body.NeId) - cmdStr := "pcap dispatch trace off" - - fmt.Fprintln(conn, cmdStr) - - // 读取内容 - time.Sleep(time.Duration(200) * time.Millisecond) - buf := make([]byte, 1024*8) - n, err := conn.Read(buf) - if err != nil { - ctx.JSON(w, 200, result.ErrMsg(err.Error())) - } else { - str := string(buf[0:n]) - s := strings.Index(str, "pcap dispatch trace:") - if s == -1 { - s = strings.Index(str, "Write ") - } - if s != -1 { - e := strings.Index(str, "\r\nupfd1#") - str = str[s:e] - } else { - str = "No stoppable found" - } - - ctx.JSON(w, 200, result.OkData(map[string]any{ - "cmd": cmdStr, - "msg": str, - "fileName": filePcapName, - })) - } - conn.Close() - return - } - - // 开始 -脚本 - if body.RunType == "start2" { - fileLogName := fmt.Sprintf("tmp_%s_%s.log", body.NeType, body.NeId) - filePcapName := fmt.Sprintf("tmp_%s_%s.pcap", body.NeType, body.NeId) - // 复制文件到网元上 - err := ssh.FileSCPLocalToNe(neInfo.Ip, "C:\\AMP\\Probject\\ems_backend\\omc\\backup\\upf_pcap", "/tmp") - if err != nil { - ctx.JSON(w, 200, result.ErrMsg(err.Error())) - return - } - writeLog := fmt.Sprintf(" >> %s 2>&1 \ncat %s", fileLogName, fileLogName) // 执行信息写入日志文件,放置弹出code 127 - cmdStr := fmt.Sprintf("cd /tmp \nchmod +x upf_pcap\n./upf_pcap '192.168.4.139' 'root' 'Admin123@pl' 'pcap dispatch trace on max 100000 file %s' %s ", fileLogName, writeLog) - - usernameNe := conf.Get("ne.user").(string) // 网元统一用户 - sshHost := fmt.Sprintf("%s@%s", usernameNe, neInfo.Ip) - msg, err := cmd.ExecWithCheck("ssh", sshHost, cmdStr) - if err != nil { - ctx.JSON(w, 200, result.ErrMsg(err.Error())) - } else { - ctx.JSON(w, 200, result.OkData(map[string]any{ - "cmd": cmdStr, - "msg": msg, - "fileName": filePcapName, - })) - } - return - } - // 停止 -脚本 - if body.RunType == "stop2" { - fileLogName := fmt.Sprintf("tmp_%s_%s.log", body.NeType, body.NeId) - filePcapName := fmt.Sprintf("tmp_%s_%s.pcap", body.NeType, body.NeId) - // cmdStr := "cd /tmp \nexpect /tmp/cat.sh " - err := ssh.FileSCPLocalToNe(neInfo.Ip, "C:\\AMP\\Probject\\ems_backend\\omc\\backup\\upf_pcap", "/tmp") - if err != nil { - ctx.JSON(w, 200, result.ErrMsg(err.Error())) - return - } - writeLog := fmt.Sprintf(" >> %s 2>&1 \ncat %s", fileLogName, fileLogName) // 执行信息写入日志文件,放置弹出code 127 - cmdStr := fmt.Sprintf("cd /tmp \nchmod +x upf_pcap\n./upf_pcap '192.168.4.139' 'root' 'Admin123@pl' 'pcap dispatch trace off' %s ", writeLog) - - usernameNe := conf.Get("ne.user").(string) // 网元统一用户 - sshHost := fmt.Sprintf("%s@%s", usernameNe, neInfo.Ip) - msg, err := cmd.ExecWithCheck("ssh", sshHost, cmdStr) - if err != nil { - ctx.JSON(w, 200, result.ErrMsg(err.Error())) - } else { - ctx.JSON(w, 200, result.OkData(map[string]any{ - "cmd": cmdStr, - "msg": msg, - "fileName": filePcapName, - })) - } - return - } - - // 开始-脚本字符串 - if body.RunType == "start_str" { - fileLogName := fmt.Sprintf("tmp_%s_%s.log", body.NeType, body.NeId) - filePcapName := fmt.Sprintf("tmp_%s_%s.pcap", body.NeType, body.NeId) - scriptStr := "set capcmd [lindex $argv 0]\nspawn telnet localhost 5002\nexpect \"upfd1# \"\nsend \"$capcmd\\n\"\nexpect \"upfd1# \"\nsend \"quit\\n\"\nexpect \"eof\"" - writeLog := fmt.Sprintf(" > %s 2>&1 \ncat %s", fileLogName, fileLogName) // 执行信息写入日志文件输出,避免弹出code 127 - - capCmdStr := fmt.Sprintf("%s file %s", body.Cmd, filePcapName) - - cmdStr := fmt.Sprintf("cd /tmp\n\necho '%s' > cap.sh\n\nchmod +x cap.sh\n\nexpect ./cap.sh '%s'%s", scriptStr, capCmdStr, writeLog) - usernameNe := conf.Get("ne.user").(string) // 网元统一用户 - sshHost := fmt.Sprintf("%s@%s", usernameNe, neInfo.Ip) - msg, err := cmd.ExecWithCheck("ssh", sshHost, cmdStr) - if err != nil { - ctx.JSON(w, 200, result.ErrMsg(err.Error())) - } else { - s := strings.Index(msg, "pcap dispatch trace:") - if s != -1 { - e := strings.Index(msg, "\r\nupfd1#") - msg = msg[s:e] - } else { - msg = "Executed, please stop before proceeding" - } - ctx.JSON(w, 200, result.OkData(map[string]any{ - "cmd": capCmdStr, - "msg": msg, - "fileName": filePcapName, - })) - } - return - } - // 停止-脚本字符串 - if body.RunType == "stop_str" { - fileLogName := fmt.Sprintf("tmp_%s_%s.log", body.NeType, body.NeId) - filePcapName := fmt.Sprintf("tmp_%s_%s.pcap", body.NeType, body.NeId) - scriptStr := "set capcmd [lindex $argv 0]\nspawn telnet localhost 5002\nexpect \"upfd1# \"\nsend \"$capcmd\\n\"\nexpect \"upfd1# \"\nsend \"quit\\n\"\nexpect \"eof\"" - writeLog := fmt.Sprintf(" > %s 2>&1 \ncat %s", fileLogName, fileLogName) // 执行信息写入日志文件输出,避免弹出code 127 - - capCmdStr := body.Cmd - - cmdStr := fmt.Sprintf("cd /tmp\n\necho '%s' > cap.sh\n\nchmod +x cap.sh\n\nexpect ./cap.sh '%s'%s", scriptStr, capCmdStr, writeLog) - - usernameNe := conf.Get("ne.user").(string) // 网元统一用户 - sshHost := fmt.Sprintf("%s@%s", usernameNe, neInfo.Ip) - msg, err := cmd.ExecWithCheck("ssh", sshHost, cmdStr) - if err != nil { - ctx.JSON(w, 200, result.ErrMsg(err.Error())) - } else { - s := strings.Index(msg, "pcap dispatch trace:") - if s == -1 { - s = strings.Index(msg, "Write ") - } - if s != -1 { - e := strings.Index(msg, "\r\nupfd1#") - msg = msg[s:e] - } else { - msg = "No stoppable found" - } - ctx.JSON(w, 200, result.OkData(map[string]any{ - "cmd": capCmdStr, - "msg": msg, - "fileName": filePcapName, - })) - } - return - } - - ctx.JSON(w, 200, result.ErrMsg("runType is start or stop")) -} diff --git a/features/udm_user/api_udm_user.go b/features/udm_user/api_udm_user.go deleted file mode 100644 index 959ecbe..0000000 --- a/features/udm_user/api_udm_user.go +++ /dev/null @@ -1,1211 +0,0 @@ -package udmuser - -import ( - "fmt" - "net/http" - "strconv" - "strings" - "time" - - "nms_cxy/features/udm_user/model" - "nms_cxy/features/udm_user/service" - "nms_cxy/lib/core/conf" - mmlclient "nms_cxy/lib/core/mml_client" - "nms_cxy/lib/core/utils/ctx" - "nms_cxy/lib/core/vo/result" - "nms_cxy/lib/dborm" - "nms_cxy/lib/log" - "nms_cxy/lib/midware" - "nms_cxy/lib/services" - "nms_cxy/omc/config" - "nms_cxy/src/framework/middleware/collectlogs" - "nms_cxy/src/framework/utils/file" - "nms_cxy/src/framework/utils/ssh" -) - -// UDM 用户信息接口添加到路由 -func Routers() []services.RouterItem { - // 实例化控制层 SysDictTypeApi 结构体 - var apis = &UdmUserApi{ - authUser: *service.NewServiceUdmAuthUser, - subUser: *service.NewServiceUdmSubUser, - } - - rs := [...]services.RouterItem{ - // UDM鉴权用户 - { - Method: "GET", - Pattern: "/auths", - Handler: apis.UdmAuthUserList, - Middleware: midware.Authorize(nil), - }, - { - Method: "POST", - Pattern: "/authSave/{neId}", - Handler: apis.UdmAuthUserSave, - Middleware: midware.LogOperate(collectlogs.OptionNew("UDM Authentication User", collectlogs.BUSINESS_TYPE_INSERT)), - }, - { - Method: "GET", - Pattern: "/auth/{neId}/{imsi}", - Handler: apis.UdmAuthUserInfo, - Middleware: midware.Authorize(nil), - }, - { - Method: "POST", - Pattern: "/auth/{neId}", - Handler: apis.UdmAuthUserAdd, - Middleware: midware.LogOperate(collectlogs.OptionNew("UDM Authentication User", collectlogs.BUSINESS_TYPE_INSERT)), - }, - { - Method: "POST", - Pattern: "/auth/{neId}/{num}", - Handler: apis.UdmAuthUserAdds, - Middleware: midware.LogOperate(collectlogs.OptionNew("UDM Authentication User", collectlogs.BUSINESS_TYPE_INSERT)), - }, - { - Method: "PUT", - Pattern: "/auth/{neId}", - Handler: apis.UdmAuthUserEdit, - Middleware: midware.LogOperate(collectlogs.OptionNew("UDM Authentication User", collectlogs.BUSINESS_TYPE_UPDATE)), - }, - { - Method: "DELETE", - Pattern: "/auth/{neId}/{imsi}", - Handler: apis.UdmAuthUserRemove, - Middleware: midware.LogOperate(collectlogs.OptionNew("UDM Authentication User", collectlogs.BUSINESS_TYPE_DELETE)), - }, - { - Method: "DELETE", - Pattern: "/auth/{neId}/{imsi}/{num}", - Handler: apis.UdmAuthUserRemoves, - Middleware: midware.LogOperate(collectlogs.OptionNew("UDM Authentication User", collectlogs.BUSINESS_TYPE_DELETE)), - }, - { - Method: "POST", - Pattern: "/authExport", - Handler: apis.UdmAuthUserExport, - Middleware: midware.LogOperate(collectlogs.OptionNew("UDM Authentication User", collectlogs.BUSINESS_TYPE_EXPORT)), - }, - { - Method: "POST", - Pattern: "/authImport/{neId}", - Handler: apis.UdmAuthUserImport, - Middleware: midware.LogOperate(collectlogs.OptionNew("UDM Authentication User", collectlogs.BUSINESS_TYPE_IMPORT)), - }, - // UDM签约用户 - { - Method: "GET", - Pattern: "/subs", - Handler: apis.UdmSubUserList, - Middleware: midware.Authorize(nil), - }, - { - Method: "POST", - Pattern: "/subSave/{neId}", - Handler: apis.UdmSubUserSave, - Middleware: midware.LogOperate(collectlogs.OptionNew("UDM Contracted User", collectlogs.BUSINESS_TYPE_INSERT)), - }, - { - Method: "GET", - Pattern: "/subInfo/{neId}/{imsi}", - Handler: apis.UdmSubUserInfo, - Middleware: midware.Authorize(nil), - }, - { - Method: "POST", - Pattern: "/sub/{neId}", - Handler: apis.UdmSubUserAdd, - Middleware: midware.LogOperate(collectlogs.OptionNew("UDM Contracted User", collectlogs.BUSINESS_TYPE_INSERT)), - }, - { - Method: "POST", - Pattern: "/sub/{neId}/{num}", - Handler: apis.UdmSubUserAdds, - Middleware: midware.LogOperate(collectlogs.OptionNew("UDM Contracted User", collectlogs.BUSINESS_TYPE_INSERT)), - }, - { - Method: "PUT", - Pattern: "/sub/{neId}", - Handler: apis.UdmSubUserEdit, - Middleware: midware.LogOperate(collectlogs.OptionNew("UDM Contracted User", collectlogs.BUSINESS_TYPE_UPDATE)), - }, - { - Method: "PUT", - Pattern: "/sub4gIP/{neId}", - Handler: apis.UdmSubUser4GIP, - Middleware: midware.LogOperate(collectlogs.OptionNew("UDM Contracted User", collectlogs.BUSINESS_TYPE_UPDATE)), - }, - { - Method: "PUT", - Pattern: "/subSmData/{neId}", - Handler: apis.UdmSubUserSmData, - Middleware: midware.LogOperate(collectlogs.OptionNew("UDM Contracted User", collectlogs.BUSINESS_TYPE_UPDATE)), - }, - { - Method: "DELETE", - Pattern: "/sub/{neId}/{imsi}", - Handler: apis.UdmSubUserRemove, - Middleware: midware.LogOperate(collectlogs.OptionNew("UDM Contracted User", collectlogs.BUSINESS_TYPE_DELETE)), - }, - { - Method: "DELETE", - Pattern: "/sub/{neId}/{imsi}/{num}", - Handler: apis.UdmSubUserRemoves, - Middleware: midware.LogOperate(collectlogs.OptionNew("UDM Contracted User", collectlogs.BUSINESS_TYPE_DELETE)), - }, - { - Method: "POST", - Pattern: "/subExport", - Handler: apis.UdmSubUserExport, - Middleware: midware.LogOperate(collectlogs.OptionNew("UDM Contracted User", collectlogs.BUSINESS_TYPE_EXPORT)), - }, - { - Method: "POST", - Pattern: "/subImport/{neId}", - Handler: apis.UdmSubUserImport, - Middleware: midware.LogOperate(collectlogs.OptionNew("UDM Contracted User", collectlogs.BUSINESS_TYPE_IMPORT)), - }, - // 添加更多的 Router 对象... - } - - // 生成两组前缀路由 - rsPrefix := []services.RouterItem{} - for _, v := range rs { - path := "/udmUserManage/{apiVersion}" + v.Pattern - // 固定前缀 - v.Pattern = config.DefaultUriPrefix + path - rsPrefix = append(rsPrefix, v) - // 可配置 - v.Pattern = config.UriPrefix + path - rsPrefix = append(rsPrefix, v) - } - return rsPrefix -} - -// NeInfoByUDM 网元信息 -func NeInfoByUDM(neId string) (*dborm.NeInfo, error) { - neInfo, err := dborm.XormGetNeInfo("UDM", neId) - if err != nil { - log.Error("dborm.XormGetNeInfo is failed:", err) - return nil, err - } - if neInfo == nil || neInfo.Ip == "" { - return nil, fmt.Errorf("not ne_info or not IP") - } - return neInfo, nil -} - -// UDM 用户 -// -// PATH /udmUserManage -type UdmUserApi struct { - authUser service.ServiceUdmAuthUser - subUser service.ServiceUdmSubUser -} - -// UDM鉴权用户 -// -// GET /auths -func (s *UdmUserApi) UdmAuthUserList(w http.ResponseWriter, r *http.Request) { - querys := ctx.QueryMap(r) - querys["neId"] = "" - data := s.authUser.Page(querys) - ctx.JSON(w, 200, result.Ok(data)) -} - -// UDM鉴权用户-获取全部保存数据库 -// -// POST /authSave/{neId} -func (s *UdmUserApi) UdmAuthUserSave(w http.ResponseWriter, r *http.Request) { - neId := ctx.Param(r, "neId") - if neId == "" { - ctx.JSON(w, 400, result.CodeMsg(400, "parameter error")) - return - } - - neId = "" - data := s.authUser.Save(neId) - ctx.JSON(w, 200, result.OkData(data)) -} - -// UDM鉴权用户-信息 -// -// GET /authInfo/{neId}/{imsi} -func (s *UdmUserApi) UdmAuthUserInfo(w http.ResponseWriter, r *http.Request) { - neId := ctx.Param(r, "neId") - imsi := ctx.Param(r, "imsi") - if neId == "" || imsi == "" { - ctx.JSON(w, 400, result.CodeMsg(400, "parameter error")) - return - } - - neInfo, err := NeInfoByUDM(neId) - if err != nil { - ctx.JSON(w, 200, result.ErrMsg(err.Error())) - return - } - - msg := fmt.Sprintf("dsp authdat:imsi=%s", imsi) - - // 发送MML - data, err := mmlclient.MMLSendMsgToMap(neInfo.Ip, msg) - if err != nil { - ctx.JSON(w, 200, result.ErrMsg(err.Error())) - return - } - - // 查询数据库是否存在并存入 - neId = "" - var userInfo model.UdmAuthUser - list := s.authUser.List(model.UdmAuthUser{NeID: neId, Imsi: imsi}) - if len(list) > 0 { - userInfo = list[0] - // 返回查询的用户信息 - userInfo.Amf = data["amf"] - userInfo.AlgoIndex = data["algo"] - userInfo.Opc = data["opc"] - userInfo.Ki = data["ki"] - } else { - userInfo := model.UdmAuthUser{ - Imsi: imsi, - Amf: data["amf"], - AlgoIndex: data["algo"], - Opc: data["opc"], - Ki: data["ki"], - } - s.authUser.Insert(neId, userInfo) - } - ctx.JSON(w, 200, result.OkData(userInfo)) - -} - -// UDM鉴权用户-增加 -// -// POST /{neId} -func (s *UdmUserApi) UdmAuthUserAdd(w http.ResponseWriter, r *http.Request) { - neId := ctx.Param(r, "neId") - if neId == "" { - ctx.JSON(w, 400, result.CodeMsg(400, "parameter error")) - return - } - - var body model.UdmAuthUser - err := ctx.ShouldBindJSON(r, &body) - if err != nil || body.Imsi == "" { - ctx.JSON(w, 400, result.CodeMsg(400, "parameter error")) - return - } - - neInfo, err := NeInfoByUDM(neId) - if err != nil { - ctx.JSON(w, 200, result.ErrMsg(err.Error())) - return - } - - msg := fmt.Sprintf("add authdat:imsi=%s,ki=%s,amf=%s,algo=%s,opc=%s", body.Imsi, body.Ki, body.Amf, body.AlgoIndex, body.Opc) - - // 发送MML - data, err := mmlclient.MMLSendMsgToString(neInfo.Ip, msg) - if err != nil { - ctx.JSON(w, 200, result.ErrMsg(err.Error())) - return - } - - // 命令ok时 - if strings.Contains(data, "ok") { - neId = "" - s.authUser.Insert(neId, body) - } - ctx.JSON(w, 200, result.OkData(data)) -} - -// UDM鉴权用户-批量添加 -// -// POST /{neId}/{num} -func (s *UdmUserApi) UdmAuthUserAdds(w http.ResponseWriter, r *http.Request) { - neId := ctx.Param(r, "neId") - num := ctx.Param(r, "num") - if neId == "" || num == "" { - ctx.JSON(w, 400, result.CodeMsg(400, "parameter error")) - return - } - - var body model.UdmAuthUser - err := ctx.ShouldBindJSON(r, &body) - if err != nil || body.Imsi == "" { - ctx.JSON(w, 400, result.CodeMsg(400, "parameter error")) - return - } - - neInfo, err := NeInfoByUDM(neId) - if err != nil { - ctx.JSON(w, 200, result.ErrMsg(err.Error())) - return - } - - msg := fmt.Sprintf("bad authdat:start_imsi=%s,sub_num=%s,ki=%s,amf=%s,algo=%s,opc=%s", body.Imsi, num, body.Ki, body.Amf, body.AlgoIndex, body.Opc) - - // 发送MML - data, err := mmlclient.MMLSendMsgToString(neInfo.Ip, msg) - if err != nil { - ctx.JSON(w, 200, result.ErrMsg(err.Error())) - return - } - - // 命令ok时 - if strings.Contains(data, "ok") { - neId = "" - s.authUser.Inserts(neId, body, num) - } - ctx.JSON(w, 200, result.OkData(data)) -} - -// UDM鉴权用户-修改 -// -// PUT /{neId} -func (s *UdmUserApi) UdmAuthUserEdit(w http.ResponseWriter, r *http.Request) { - neId := ctx.Param(r, "neId") - if neId == "" { - ctx.JSON(w, 400, result.CodeMsg(400, "parameter error")) - return - } - - var body model.UdmAuthUser - err := ctx.ShouldBindJSON(r, &body) - if err != nil || body.Imsi == "" { - ctx.JSON(w, 400, result.CodeMsg(400, "parameter error")) - return - } - - neInfo, err := NeInfoByUDM(neId) - if err != nil { - ctx.JSON(w, 200, result.ErrMsg(err.Error())) - return - } - - msg := fmt.Sprintf("mod authdata:imsi=%s", body.Imsi) - // 修改的参数名称 - if body.Ki != "" { - msg += fmt.Sprintf(",ki=%s", body.Ki) - } - if body.Amf != "" { - msg += fmt.Sprintf(",amf=%s", body.Amf) - } - if body.AlgoIndex != "" { - msg += fmt.Sprintf(",algo=%s", body.AlgoIndex) - } - if body.Opc != "" { - msg += fmt.Sprintf(",opc=%s", body.Opc) - } - - // 发送MML - data, err := mmlclient.MMLSendMsgToString(neInfo.Ip, msg) - if err != nil { - ctx.JSON(w, 200, result.ErrMsg(err.Error())) - return - } - - // 命令ok时 - if strings.Contains(data, "ok") { - neId = "" - s.authUser.Update(neId, body) - } - ctx.JSON(w, 200, result.OkData(data)) -} - -// UDM鉴权用户-删除 -// -// DELETE /{neId}/{imsi} -func (s *UdmUserApi) UdmAuthUserRemove(w http.ResponseWriter, r *http.Request) { - neId := ctx.Param(r, "neId") - imsi := ctx.Param(r, "imsi") - if neId == "" || imsi == "" { - ctx.JSON(w, 400, result.CodeMsg(400, "parameter error")) - return - } - - neInfo, err := NeInfoByUDM(neId) - if err != nil { - ctx.JSON(w, 200, result.ErrMsg(err.Error())) - return - } - - msg := fmt.Sprintf("del authdat:imsi=%s", imsi) - - // 发送MML - data, err := mmlclient.MMLSendMsgToString(neInfo.Ip, msg) - if err != nil { - ctx.JSON(w, 200, result.ErrMsg(err.Error())) - return - } - - // 命令ok时 - if strings.Contains(data, "ok") { - neId = "" - s.authUser.Delete(neId, imsi) - } - ctx.JSON(w, 200, result.OkData(data)) -} - -// UDM鉴权用户-批量删除 -// -// DELETE /{neId}/{imsi}/{num} -func (s *UdmUserApi) UdmAuthUserRemoves(w http.ResponseWriter, r *http.Request) { - neId := ctx.Param(r, "neId") - imsi := ctx.Param(r, "imsi") - num := ctx.Param(r, "num") - if neId == "" || imsi == "" || num == "" { - ctx.JSON(w, 400, result.CodeMsg(400, "parameter error")) - return - } - - neInfo, err := NeInfoByUDM(neId) - if err != nil { - ctx.JSON(w, 200, result.ErrMsg(err.Error())) - return - } - - msg := fmt.Sprintf("bde authdat:start_imsi=%s,sub_num=%s", imsi, num) - - // 发送MML - data, err := mmlclient.MMLSendMsgToString(neInfo.Ip, msg) - if err != nil { - ctx.JSON(w, 200, result.ErrMsg(err.Error())) - return - } - - // 命令ok时 - if strings.Contains(data, "ok") { - neId = "" - s.authUser.Deletes(neId, imsi, num) - } - ctx.JSON(w, 200, result.OkData(data)) -} - -// UDM鉴权用户-导出 -// -// POST /authExport -func (s *UdmUserApi) UdmAuthUserExport(w http.ResponseWriter, r *http.Request) { - var body struct { - NeId string `json:"neId"` - Type string `json:"type"` - } - err := ctx.ShouldBindJSON(r, &body) - if err != nil || body.NeId == "" || body.Type == "" { - ctx.JSON(w, 400, result.CodeMsg(400, "parameter error")) - return - } - - if !(body.Type == "csv" || body.Type == "txt") { - ctx.JSON(w, 200, result.ErrMsg("Export file types support CSV and txt")) - return - } - - neId := "" - list := s.authUser.List(model.UdmAuthUser{NeID: neId}) - // 文件名 - fileName := fmt.Sprintf("OMC_AUTH_USER_EXPORT_%s_%d.%s", neId, time.Now().UnixMilli(), body.Type) - filePath := fmt.Sprintf("%s/upload/mml/%s", conf.Get("ne.omcdir"), fileName) - - if body.Type == "csv" { - // 转换数据 - data := [][]string{} - data = append(data, []string{"imsi", "ki", "algo", "amf", "opc"}) - for _, v := range list { - data = append(data, []string{v.Imsi, v.Ki, v.AlgoIndex, v.Amf, v.Opc}) - } - // 输出到文件 - err := file.WriterFileCSV(data, filePath) - if err != nil { - ctx.JSON(w, 200, result.ErrMsg(err.Error())) - return - } - } - - if body.Type == "txt" { - // 转换数据 - data := [][]string{} - for _, v := range list { - data = append(data, []string{v.Imsi, v.Ki, v.AlgoIndex, v.Amf, v.Opc}) - } - // 输出到文件 - err = file.WriterFileTXT(data, ",", filePath) - if err != nil { - ctx.JSON(w, 200, result.ErrMsg(err.Error())) - return - } - } - - ctx.FileAttachment(w, r, filePath, fileName) -} - -// UDM鉴权用户-导入 -// -// POST /authImport/{neId} -func (s *UdmUserApi) UdmAuthUserImport(w http.ResponseWriter, r *http.Request) { - neId := ctx.Param(r, "neId") - if neId == "" { - ctx.JSON(w, 400, result.CodeMsg(400, "parameter error")) - return - } - - // 获取文件名 - _, fileHeader, err := r.FormFile("file") - if err != nil { - ctx.JSON(w, 200, result.ErrMsg(err.Error())) - return - } - if !(strings.HasSuffix(fileHeader.Filename, ".csv") || strings.HasSuffix(fileHeader.Filename, ".txt")) { - ctx.JSON(w, 200, result.ErrMsg("Please upload files in. csv and. txt formats with content fields: imsi,ki,algo,amf,opc")) - return - } - - neInfo, err := NeInfoByUDM(neId) - if err != nil { - ctx.JSON(w, 200, result.ErrMsg(err.Error())) - return - } - - // 文件名 - fileName := fmt.Sprintf("OMC_AUTH_USER_IMPORT_%s_%d_%s", neId, time.Now().UnixMilli(), fileHeader.Filename) - localPath := fmt.Sprintf("%s/upload/mml/%s", conf.Get("ne.omcdir"), fileName) - nePath := conf.Get("mml.upload").(string) - // 输出保存文件 - err = ctx.SaveUploadedFile(r, localPath) - if err != nil { - ctx.JSON(w, 200, result.ErrMsg(err.Error())) - return - } - - // 复制到远程 - err = ssh.FileSCPLocalToNe(neInfo.Ip, localPath, nePath) - if err != nil { - ctx.JSON(w, 200, result.ErrMsg(err.Error())) - return - } - - msg := fmt.Sprintf("import authdat:path=%s", fmt.Sprintf("%s/%s", nePath, fileName)) - - // 发送MML - data, err := mmlclient.MMLSendMsgToString(neInfo.Ip, msg) - if err != nil { - ctx.JSON(w, 200, result.ErrMsg(err.Error())) - return - } - - // 命令ok时 - if strings.Contains(data, "ok") { - if strings.HasSuffix(fileHeader.Filename, ".csv") { - data := file.ReadFileCSV(localPath) - neId = "" - go s.authUser.InsertCSV(neId, data) - } - if strings.HasSuffix(fileHeader.Filename, ".txt") { - data := file.ReadFileTXT(",", localPath) - neId = "" - go s.authUser.InsertTxt(neId, data) - } - } - ctx.JSON(w, 200, result.OkMsg(data)) -} - -// UDM签约用户 -// -// GET /subs -func (s *UdmUserApi) UdmSubUserList(w http.ResponseWriter, r *http.Request) { - querys := ctx.QueryMap(r) - querys["neId"] = "" - data := s.subUser.Page(querys) - ctx.JSON(w, 200, result.Ok(data)) -} - -// UDM签约用户-获取全部保存数据库 -// -// POST /subSave/{neId} -func (s *UdmUserApi) UdmSubUserSave(w http.ResponseWriter, r *http.Request) { - neId := ctx.Param(r, "neId") - if neId == "" { - ctx.JSON(w, 400, result.CodeMsg(400, "parameter error")) - return - } - - neId = "" - data := s.subUser.Save(neId) - ctx.JSON(w, 200, result.OkData(data)) -} - -// UDM签约用户-信息 -// -// GET /subInfo/{neId}/{imsi} -func (s *UdmUserApi) UdmSubUserInfo(w http.ResponseWriter, r *http.Request) { - neId := ctx.Param(r, "neId") - imsi := ctx.Param(r, "imsi") - if neId == "" || imsi == "" { - ctx.JSON(w, 400, result.CodeMsg(400, "parameter error")) - return - } - - neInfo, err := NeInfoByUDM(neId) - if err != nil { - ctx.JSON(w, 200, result.ErrMsg(err.Error())) - return - } - - msg := fmt.Sprintf("dsp udmuser:imsi=%s", imsi) - - // 发送MML - data, err := mmlclient.MMLSendMsgToMap(neInfo.Ip, msg) - if err != nil { - ctx.JSON(w, 200, result.ErrMsg(err.Error())) - return - } - - // 解析返回的数据 - cnType, _ := strconv.ParseInt(data["CNType"][:4], 0, 64) - rat, _ := strconv.ParseInt(data["RAT"][:4], 0, 64) - msisdn := data["MSISDN"] - imsMsisdnLen := strings.Index(msisdn, ",") - if imsMsisdnLen != -1 { - msisdn = msisdn[:imsMsisdnLen] - } - userInfo := model.UdmSubUser{ - Imsi: imsi, - Msisdn: msisdn, - Ambr: data["AMBR"], - Arfb: data["AreaForbidden"], - Cn: fmt.Sprint(cnType), - SmData: data["SM-Data(snssai+dnn[1..n])"], - Sar: data["ServiceAreaRestriction"], - Nssai: data["NSSAI"], - SmfSel: data["Smf-Selection"], - Rat: fmt.Sprint(rat), - } - // 1,64,24,65,def_eps,1,2,010200000000,- - if v, ok := data["EPS-Data"]; ok { - userInfo.EpsDat = v - arr := strings.Split(v, ",") - userInfo.EpsFlag = arr[0] - userInfo.EpsOdb = arr[1] - userInfo.HplmnOdb = arr[2] - userInfo.Ard = arr[3] - userInfo.Epstpl = arr[4] - userInfo.ContextId = arr[5] - userInfo.ApnContext = arr[7] - userInfo.StaticIp = arr[8] - } - - // 查询数据库是否存在并存入更新 - neId = "" - list := s.subUser.List(model.UdmSubUser{NeID: neId, Imsi: imsi}) - if len(list) > 0 { - listItme := list[0] - userInfo.ID = listItme.ID - s.subUser.Update(neId, userInfo) - } else { - s.subUser.Insert(neId, userInfo) - } - ctx.JSON(w, 200, result.OkData(userInfo)) -} - -// UDM签约用户-增加 -// -// POST /{neId} -func (s *UdmUserApi) UdmSubUserAdd(w http.ResponseWriter, r *http.Request) { - neId := ctx.Param(r, "neId") - if neId == "" { - ctx.JSON(w, 400, result.CodeMsg(400, "parameter error")) - return - } - - var body model.UdmSubUser - err := ctx.ShouldBindJSON(r, &body) - if err != nil || body.Imsi == "" { - ctx.JSON(w, 400, result.CodeMsg(400, "parameter error")) - return - } - - neInfo, err := NeInfoByUDM(neId) - if err != nil { - ctx.JSON(w, 200, result.ErrMsg(err.Error())) - return - } - - msg := fmt.Sprintf("add udmuser:imsi=%s,msisdn=%s,ambr=%s,nssai=%s,arfb=%s,sar=%s,rat=%s,cn=%s,smf_sel=%s,sm_data=%s,eps_flag=%s,eps_odb=%s,hplmn_odb=%s,ard=%s,epstpl=%s,context_id=%s,apn_context=%s", - body.Imsi, body.Msisdn, body.Ambr, body.Nssai, body.Arfb, body.Sar, body.Rat, body.Cn, body.SmfSel, body.SmData, body.EpsFlag, body.EpsOdb, body.HplmnOdb, body.Ard, body.Epstpl, body.ContextId, body.ApnContext) - // static_ip指给4G UE分配的静态IP,没有可不带此字段名,批量添加IP会自动递增 - if body.StaticIp != "" { - msg += fmt.Sprintf(",static_ip=%s", body.StaticIp) - } - - // 发送MML - data, err := mmlclient.MMLSendMsgToString(neInfo.Ip, msg) - if err != nil { - ctx.JSON(w, 200, result.ErrMsg(err.Error())) - return - } - - // 命令ok时 - if strings.Contains(data, "ok") { - neId = "" - s.subUser.Insert(neId, body) - } - ctx.JSON(w, 200, result.OkData(data)) -} - -// UDM签约用户-批量添加 -// -// POST /{neId}/{num} -func (s *UdmUserApi) UdmSubUserAdds(w http.ResponseWriter, r *http.Request) { - neId := ctx.Param(r, "neId") - num := ctx.Param(r, "num") - if neId == "" || num == "" { - ctx.JSON(w, 400, result.CodeMsg(400, "parameter error")) - return - } - - var body model.UdmSubUser - err := ctx.ShouldBindJSON(r, &body) - if err != nil || body.Imsi == "" { - ctx.JSON(w, 400, result.CodeMsg(400, "parameter error")) - return - } - - neInfo, err := NeInfoByUDM(neId) - if err != nil { - ctx.JSON(w, 200, result.ErrMsg(err.Error())) - return - } - - msg := fmt.Sprintf("bad udmuser:start_imsi=%s,start_msisdn=%s,sub_num=%s,ambr=%s,nssai=%s,arfb=%s,sar=%s,rat=%s,cn=%s,smf_sel=%s,sm_data=%s,eps_flag=%s,eps_odb=%s,hplmn_odb=%s,ard=%s,epstpl=%s,context_id=%s,apn_context=%s", - body.Imsi, body.Msisdn, num, body.Ambr, body.Nssai, body.Arfb, body.Sar, body.Rat, body.Cn, body.SmfSel, body.SmData, body.EpsFlag, body.EpsOdb, body.HplmnOdb, body.Ard, body.Epstpl, body.ContextId, body.ApnContext) - // static_ip指给4G UE分配的静态IP,没有可不带此字段名,批量添加IP会自动递增 - if body.StaticIp != "" { - msg += fmt.Sprintf(",static_ip=%s", body.StaticIp) - } - - // 发送MML - data, err := mmlclient.MMLSendMsgToString(neInfo.Ip, msg) - if err != nil { - ctx.JSON(w, 200, result.ErrMsg(err.Error())) - return - } - - // 命令ok时 - if strings.Contains(data, "ok") { - neId = "" - s.subUser.Inserts(neId, body, num) - } - ctx.JSON(w, 200, result.OkData(data)) -} - -// UDM签约用户-批量添加4G用户 -// -// POST /sub4G/{neId} -func (s *UdmUserApi) UdmSubUserAdd4G(w http.ResponseWriter, r *http.Request) { - neId := ctx.Param(r, "neId") - if neId == "" { - ctx.JSON(w, 400, result.CodeMsg(400, "parameter error")) - return - } - - var body model.UdmSubUser - err := ctx.ShouldBindJSON(r, &body) - if err != nil || body.Imsi == "" || body.SubNum == "" { - ctx.JSON(w, 400, result.CodeMsg(400, "parameter error")) - return - } - - neInfo, err := NeInfoByUDM(neId) - if err != nil { - ctx.JSON(w, 200, result.ErrMsg(err.Error())) - return - } - - msg := fmt.Sprintf("bmd udmuser:start_imsi=%s,sub_num=%s,eps_flag=%s", body.Imsi, body.SubNum, body.EpsFlag) - - // 发送MML - data, err := mmlclient.MMLSendMsgToString(neInfo.Ip, msg) - if err != nil { - ctx.JSON(w, 200, result.ErrMsg(err.Error())) - return - } - - // 命令ok时 - if strings.Contains(data, "ok") { - neId = "" - s.subUser.Insert4G(neId, body) - } - ctx.JSON(w, 200, result.OkData(data)) -} - -// UDM签约用户-修改 -// -// PUT /{neId} -func (s *UdmUserApi) UdmSubUserEdit(w http.ResponseWriter, r *http.Request) { - neId := ctx.Param(r, "neId") - if neId == "" { - ctx.JSON(w, 400, result.CodeMsg(400, "parameter error")) - return - } - - var body model.UdmSubUser - err := ctx.ShouldBindJSON(r, &body) - if err != nil || body.Imsi == "" { - ctx.JSON(w, 400, result.CodeMsg(400, "parameter error")) - return - } - - neInfo, err := NeInfoByUDM(neId) - if err != nil { - ctx.JSON(w, 200, result.ErrMsg(err.Error())) - return - } - - msg := fmt.Sprintf("mod udmuser:imsi=%s", body.Imsi) - // 修改的参数名称 - if body.Msisdn != "" { - msg += fmt.Sprintf(",msisdn=%s", body.Msisdn) - } - if body.Ambr != "" { - msg += fmt.Sprintf(",ambr=%s", body.Ambr) - } - if body.Nssai != "" { - msg += fmt.Sprintf(",nssai=%s", body.Nssai) - } - if body.Arfb != "" { - msg += fmt.Sprintf(",arfb=%s", body.Arfb) - } - if body.Sar != "" { - msg += fmt.Sprintf(",sar=%s", body.Sar) - } - if body.Rat != "" { - msg += fmt.Sprintf(",rat=%s", body.Rat) - } - if body.Cn != "" { - msg += fmt.Sprintf(",cn=%s", body.Cn) - } - if body.SmfSel != "" { - msg += fmt.Sprintf(",smf_sel=%s", body.SmfSel) - } - if body.SmData != "" { - msg += fmt.Sprintf(",sm_data=%s", body.SmData) - } - if body.EpsDat != "" { - msg += fmt.Sprintf(",eps_dat=%s", body.EpsDat) - } - if body.EpsFlag != "" { - msg += fmt.Sprintf(",eps_flag=%s", body.EpsFlag) - } - if body.EpsOdb != "" { - msg += fmt.Sprintf(",eps_odb=%s", body.EpsOdb) - } - if body.HplmnOdb != "" { - msg += fmt.Sprintf(",hplmn_odb=%s", body.HplmnOdb) - } - if body.Epstpl != "" { - msg += fmt.Sprintf(",epstpl=%s", body.Epstpl) - } - if body.Ard != "" { - msg += fmt.Sprintf(",ard=%s", body.Ard) - } - if body.ContextId != "" { - msg += fmt.Sprintf(",context_id=%s", body.ContextId) - } - if body.ApnContext != "" { - msg += fmt.Sprintf(",apn_context=%s", body.ApnContext) - } - if body.StaticIp != "" { - msg += fmt.Sprintf(",static_ip=%s", body.StaticIp) - } - - // 发送MML - data, err := mmlclient.MMLSendMsgToString(neInfo.Ip, msg) - if err != nil { - ctx.JSON(w, 200, result.ErrMsg(err.Error())) - return - } - - // 命令ok时 - if strings.Contains(data, "ok") { - neId = "" - s.subUser.Update(neId, body) - } - ctx.JSON(w, 200, result.OkData(data)) -} - -// UDM签约用户-批量修改4G IP -// -// PUT /sub4gIP/{neId} -func (s *UdmUserApi) UdmSubUser4GIP(w http.ResponseWriter, r *http.Request) { - neId := ctx.Param(r, "neId") - if neId == "" { - ctx.JSON(w, 400, result.CodeMsg(400, "parameter error")) - return - } - - var body model.UdmSubUser - err := ctx.ShouldBindJSON(r, &body) - if err != nil || body.Imsi == "" || body.SubNum == "" || body.StaticIp == "" { - ctx.JSON(w, 400, result.CodeMsg(400, "parameter error")) - return - } - - neInfo, err := NeInfoByUDM(neId) - if err != nil { - ctx.JSON(w, 200, result.ErrMsg(err.Error())) - return - } - - msg := fmt.Sprintf("bmd udmuser:start_imsi=%s,sub_num=%s,static_ip=%s", body.Imsi, body.SubNum, body.StaticIp) - - // 发送MML - data, err := mmlclient.MMLSendMsgToString(neInfo.Ip, msg) - if err != nil { - ctx.JSON(w, 200, result.ErrMsg(err.Error())) - return - } - // 命令ok时 - if strings.Contains(data, "ok") { - neId = "" - s.subUser.Update4GIP(neId, body) - } - ctx.JSON(w, 200, result.OkData(data)) -} - -// UDM签约用户-批量修改sm-data -// -// PUT /subSmData/{neId} -func (s *UdmUserApi) UdmSubUserSmData(w http.ResponseWriter, r *http.Request) { - neId := ctx.Param(r, "neId") - if neId == "" { - ctx.JSON(w, 400, result.CodeMsg(400, "parameter error")) - return - } - - var body model.UdmSubUser - err := ctx.ShouldBindJSON(r, &body) - if err != nil || body.Imsi == "" || body.SubNum == "" || body.SmData == "" { - ctx.JSON(w, 400, result.CodeMsg(400, "parameter error")) - return - } - - neInfo, err := NeInfoByUDM(neId) - if err != nil { - ctx.JSON(w, 200, result.ErrMsg(err.Error())) - return - } - - // 3-000003&internet-10.10.1.1&ims-10.11.1.1 - msg := fmt.Sprintf("bmd udmuser:start_imsi=%s,sub_num=%s,sm_data=%s", body.Imsi, body.SubNum, body.SmData) - - // 发送MML - data, err := mmlclient.MMLSendMsgToString(neInfo.Ip, msg) - if err != nil { - ctx.JSON(w, 200, result.ErrMsg(err.Error())) - return - } - // 命令ok时 - if strings.Contains(data, "ok") { - neId = "" - s.subUser.UpdateSmData(neId, body) - } - ctx.JSON(w, 200, result.OkData(data)) -} - -// UDM签约用户-删除 -// -// DELETE /{neId}/{imsi} -func (s *UdmUserApi) UdmSubUserRemove(w http.ResponseWriter, r *http.Request) { - neId := ctx.Param(r, "neId") - imsi := ctx.Param(r, "imsi") - if neId == "" || imsi == "" { - ctx.JSON(w, 400, result.CodeMsg(400, "parameter error")) - return - } - - neInfo, err := NeInfoByUDM(neId) - if err != nil { - ctx.JSON(w, 200, result.ErrMsg(err.Error())) - return - } - - msg := fmt.Sprintf("del udmuser:imsi=%s", imsi) - - // 发送MML - data, err := mmlclient.MMLSendMsgToString(neInfo.Ip, msg) - if err != nil { - ctx.JSON(w, 200, result.ErrMsg(err.Error())) - return - } - - // 命令ok时 - if strings.Contains(data, "ok") { - neId = "" - s.subUser.Delete(neId, imsi) - } - ctx.JSON(w, 200, result.OkData(data)) -} - -// UDM签约用户-批量删除 -// -// DELETE /{neId}/{imsi}/{num} -func (s *UdmUserApi) UdmSubUserRemoves(w http.ResponseWriter, r *http.Request) { - neId := ctx.Param(r, "neId") - imsi := ctx.Param(r, "imsi") - num := ctx.Param(r, "num") - if neId == "" || imsi == "" || num == "" { - ctx.JSON(w, 400, result.CodeMsg(400, "parameter error")) - return - } - - neInfo, err := NeInfoByUDM(neId) - if err != nil { - ctx.JSON(w, 200, result.ErrMsg(err.Error())) - return - } - - msg := fmt.Sprintf("bde udmuser:start_imsi=%s,sub_num=%s", imsi, num) - - // 发送MML - data, err := mmlclient.MMLSendMsgToString(neInfo.Ip, msg) - if err != nil { - ctx.JSON(w, 200, result.ErrMsg(err.Error())) - return - } - - // 命令ok时 - if strings.Contains(data, "ok") { - neId = "" - s.subUser.Deletes(neId, imsi, num) - } - ctx.JSON(w, 200, result.OkData(data)) -} - -// UDM签约用户-导出 -// -// POST /subExport -func (s *UdmUserApi) UdmSubUserExport(w http.ResponseWriter, r *http.Request) { - var body struct { - NeId string `json:"neId"` - Type string `json:"type"` - } - err := ctx.ShouldBindJSON(r, &body) - if err != nil || body.NeId == "" || body.Type == "" { - ctx.JSON(w, 400, result.CodeMsg(400, "parameter error")) - return - } - - if !(body.Type == "csv" || body.Type == "txt") { - ctx.JSON(w, 200, result.ErrMsg("Export file type support csv、txt")) - return - } - - neId := "" - list := s.subUser.List(model.UdmSubUser{NeID: neId}) - // 文件名 - fileName := fmt.Sprintf("OMC_AUTH_USER_EXPORT_%s_%d.%s", neId, time.Now().UnixMilli(), body.Type) - filePath := fmt.Sprintf("%s/upload/mml/%s", conf.Get("ne.omcdir"), fileName) - - if body.Type == "csv" { - // 转换数据 - data := [][]string{} - data = append(data, []string{"imsi", "msisdn", "ambr", "nssai", "arfb", "sar", "rat", "cn", "smf_sel", "sm_dat", "eps_dat"}) - for _, v := range list { - epsDat := fmt.Sprintf("%s,%s,%s,%s,%s,%s,%s,%s", v.EpsFlag, v.EpsOdb, v.HplmnOdb, v.Ard, v.Epstpl, v.ContextId, v.ApnContext, v.StaticIp) - data = append(data, []string{v.Imsi, v.Msisdn, v.Ambr, v.Nssai, v.Arfb, v.Sar, v.Rat, v.Cn, v.SmfSel, v.SmData, epsDat}) - } - // 输出到文件 - err = file.WriterFileCSV(data, filePath) - if err != nil { - ctx.JSON(w, 200, result.ErrMsg(err.Error())) - return - } - } - - if body.Type == "txt" { - // 转换数据 - data := [][]string{} - for _, v := range list { - epsDat := fmt.Sprintf("%s,%s,%s,%s,%s,%s,%s,%s", v.EpsFlag, v.EpsOdb, v.HplmnOdb, v.Ard, v.Epstpl, v.ContextId, v.ApnContext, v.StaticIp) - data = append(data, []string{v.Imsi, v.Msisdn, v.Ambr, v.Nssai, v.Arfb, v.Sar, v.Rat, v.Cn, v.SmfSel, v.SmData, epsDat}) - } - // 输出到文件 - err = file.WriterFileTXT(data, ",", filePath) - if err != nil { - ctx.JSON(w, 200, result.ErrMsg(err.Error())) - return - } - } - - ctx.FileAttachment(w, r, filePath, fileName) -} - -// UDM签约用户-导入 -// -// POST /subImport/{neId} -func (s *UdmUserApi) UdmSubUserImport(w http.ResponseWriter, r *http.Request) { - neId := ctx.Param(r, "neId") - if neId == "" { - ctx.JSON(w, 400, result.CodeMsg(400, "parameter error")) - return - } - - // 获取文件名 - _, fileHeader, err := r.FormFile("file") - if err != nil { - ctx.JSON(w, 200, result.ErrMsg(err.Error())) - return - } - if !(strings.HasSuffix(fileHeader.Filename, ".csv") || strings.HasSuffix(fileHeader.Filename, ".txt")) { - ctx.JSON(w, 200, result.ErrMsg("Please upload files in. csv and. txt formats with content fields: imsi,msisdn,ambr,nssai,arfb,sar,rat,cn,smf_sel,sm_dat,eps_dat")) - return - } - - neInfo, err := NeInfoByUDM(neId) - if err != nil { - ctx.JSON(w, 200, result.ErrMsg(err.Error())) - return - } - - // 文件名 - fileName := fmt.Sprintf("OMC_SUB_USER_IMPORT_%s_%d_%s", neId, time.Now().UnixMilli(), fileHeader.Filename) - localPath := fmt.Sprintf("%s/upload/mml/%s", conf.Get("ne.omcdir"), fileName) - nePath := conf.Get("mml.upload").(string) - // 输出保存文件 - err = ctx.SaveUploadedFile(r, localPath) - if err != nil { - ctx.JSON(w, 200, result.ErrMsg(err.Error())) - return - } - - // 复制到远程 - err = ssh.FileSCPLocalToNe(neInfo.Ip, localPath, nePath) - if err != nil { - ctx.JSON(w, 200, result.ErrMsg(err.Error())) - return - } - - msg := fmt.Sprintf("import udmuser:path=%s", fmt.Sprintf("%s/%s", nePath, fileName)) - - // 发送MML - data, err := mmlclient.MMLSendMsgToString(neInfo.Ip, msg) - if err != nil { - ctx.JSON(w, 200, result.ErrMsg(err.Error())) - return - } - // 命令ok时 - if strings.Contains(data, "ok") { - if strings.HasSuffix(fileHeader.Filename, ".csv") { - data := file.ReadFileCSV(localPath) - neId = "" - go s.subUser.InsertCSV(neId, data) - } - if strings.HasSuffix(fileHeader.Filename, ".txt") { - data := file.ReadFileTXT(",", localPath) - neId = "" - go s.subUser.InsertTxt(neId, data) - } - } - ctx.JSON(w, 200, result.OkMsg(data)) -} diff --git a/features/udm_user/model/udm_auth_user.go b/features/udm_user/model/udm_auth_user.go deleted file mode 100644 index 520d346..0000000 --- a/features/udm_user/model/udm_auth_user.go +++ /dev/null @@ -1,13 +0,0 @@ -package model - -// UdmAuthUser UDM鉴权用户 -type UdmAuthUser struct { - ID string `json:"id" xorm:"pk 'id' autoincr"` - Imsi string `json:"imsi" xorm:"imsi"` // SIM卡号 - Amf string `json:"amf" xorm:"amf"` // ANF - Status string `json:"status" xorm:"status"` // 状态 - Ki string `json:"ki" xorm:"ki"` // ki - AlgoIndex string `json:"algoIndex" xorm:"algo_index"` // - Opc string `json:"opc" xorm:"opc"` - NeID string `json:"neId" xorm:"ne_id"` // UDM网元标识-子系统 -} diff --git a/features/udm_user/model/udm_sub_user.go b/features/udm_user/model/udm_sub_user.go deleted file mode 100644 index 466fce1..0000000 --- a/features/udm_user/model/udm_sub_user.go +++ /dev/null @@ -1,29 +0,0 @@ -package model - -// UdmSubUser UDM签约用户 -type UdmSubUser struct { - ID string `json:"id" xorm:"pk 'id' autoincr"` - Msisdn string `json:"msisdn" xorm:"msisdn"` // 相当手机号 - Imsi string `json:"imsi" xorm:"imsi"` // SIM卡号 - Ambr string `json:"ambr" xorm:"ambr"` - Nssai string `json:"nssai" xorm:"nssai"` - Rat string `json:"rat" xorm:"rat"` - Arfb string `json:"arfb" xorm:"arfb"` - Sar string `json:"sar" xorm:"sar"` - Cn string `json:"cn" xorm:"cn"` - SmData string `json:"smData" xorm:"sm_data"` - SmfSel string `json:"smfSel" xorm:"smf_sel"` - EpsDat string `json:"epsDat" xorm:"eps_dat"` - NeID string `json:"neId" xorm:"ne_id"` // UDM网元标识-子系统 - - EpsFlag string `json:"epsFlag" xorm:"eps_flag"` - EpsOdb string `json:"epsOdb" xorm:"eps_odb"` - HplmnOdb string `json:"hplmnOdb" xorm:"hplmn_odb"` - Ard string `json:"ard" xorm:"ard"` - Epstpl string `json:"epstpl" xorm:"epstpl"` - ContextId string `json:"contextId" xorm:"context_id"` - ApnContext string `json:"apnContext" xorm:"apn_context"` - StaticIp string `json:"staticIp" xorm:"static_ip"` - - SubNum string `json:"subNum,omitempty" xorm:"-"` // 批量数 -} diff --git a/features/udm_user/repo/repo_udm_auth_user.go b/features/udm_user/repo/repo_udm_auth_user.go deleted file mode 100644 index 9d9f68e..0000000 --- a/features/udm_user/repo/repo_udm_auth_user.go +++ /dev/null @@ -1,276 +0,0 @@ -package repo - -import ( - "strconv" - "strings" - - "nms_cxy/features/udm_user/model" - "nms_cxy/lib/core/datasource" - "nms_cxy/lib/core/utils/parse" - "nms_cxy/lib/log" -) - -// 实例化数据层 RepoUdmAuthUser 结构体 -var NewRepoUdmAuthUser = &RepoUdmAuthUser{ - selectSql: `select - id, imsi, amf, status, ki, algo_index, opc, ne_id - from u_auth_user`, - - resultMap: map[string]string{ - "id": "ID", - "imsi": "Imsi", - "amf": "Amf", - "status": "Status", - "ki": "Ki", - "algo_index": "AlgoIndex", - "opc": "Opc", - "ne_id": "NeID", - }, -} - -// RepoUdmAuthUser UDM鉴权用户 数据层处理 -type RepoUdmAuthUser struct { - // 查询视图对象SQL - selectSql string - // 结果字段与实体映射 - resultMap map[string]string -} - -// convertResultRows 将结果记录转实体结果组 -func (r *RepoUdmAuthUser) convertResultRows(rows []map[string]any) []model.UdmAuthUser { - arr := make([]model.UdmAuthUser, 0) - for _, row := range rows { - UdmUser := model.UdmAuthUser{} - for key, value := range row { - if keyMapper, ok := r.resultMap[key]; ok { - datasource.SetFieldValue(&UdmUser, keyMapper, value) - } - } - arr = append(arr, UdmUser) - } - return arr -} - -// SelectPage 根据条件分页查询 -func (r *RepoUdmAuthUser) SelectPage(query map[string]any) map[string]any { - // 查询条件拼接 - var conditions []string - var params []any - if v, ok := query["imsi"]; ok && v != "" { - conditions = append(conditions, "imsi like concat(concat('%', ?), '%')") - params = append(params, v) - } - if v, ok := query["neId"]; ok && v != "" { - conditions = append(conditions, "ne_id = ?") - params = append(params, v) - } - - // 构建查询条件语句 - whereSql := "" - if len(conditions) > 0 { - whereSql += " where " + strings.Join(conditions, " and ") - } - - result := map[string]any{ - "total": 0, - "rows": []model.UdmAuthUser{}, - } - - // 查询数量 长度为0直接返回 - totalSql := "select count(1) as 'total' from u_auth_user" - totalRows, err := datasource.RawDB("", totalSql+whereSql, params) - if err != nil { - log.Errorf("total err => %v", err) - return result - } - total := parse.Number(totalRows[0]["total"]) - if total == 0 { - return result - } else { - result["total"] = total - } - - // 分页 - pageNum, pageSize := datasource.PageNumSize(query["pageNum"], query["pageSize"]) - pageSql := " limit ?,? " - params = append(params, pageNum*pageSize) - params = append(params, pageSize) - - // 排序 - sortSql := "" - if v, ok := query["sortField"]; ok && v != "" { - if v == "imsi" { - sortSql += " order by imsi " - } - if o, ok := query["sortOrder"]; ok && o != nil && v != "" { - if o == "desc" { - sortSql += " desc " - } else { - sortSql += " asc " - } - } - } - - // 查询数据 - querySql := r.selectSql + whereSql + sortSql + pageSql - results, err := datasource.RawDB("", querySql, params) - if err != nil { - log.Errorf("query err => %v", err) - } - - // 转换实体 - result["rows"] = r.convertResultRows(results) - return result -} - -// SelectList 根据实体查询 -func (r *RepoUdmAuthUser) SelectList(auth model.UdmAuthUser) []model.UdmAuthUser { - // 查询条件拼接 - var conditions []string - var params []any - if auth.Imsi != "" { - conditions = append(conditions, "imsi = ?") - params = append(params, auth.Imsi) - } - if auth.NeID != "" { - conditions = append(conditions, "ne_id = ?") - params = append(params, auth.NeID) - } - - // 构建查询条件语句 - whereSql := "" - if len(conditions) > 0 { - whereSql += " where " + strings.Join(conditions, " and ") - } - - // 查询数据 - querySql := r.selectSql + whereSql + " order by imsi asc " - results, err := datasource.RawDB("", querySql, params) - if err != nil { - log.Errorf("query err => %v", err) - } - - // 转换实体 - return r.convertResultRows(results) -} - -// ClearAndInsert 清空ne_id后新增实体 -func (r *RepoUdmAuthUser) ClearAndInsert(neID string, authArr []model.UdmAuthUser) int64 { - var num int64 = 0 - - // 清空指定ne_id - _, err := datasource.ExecDB("", "TRUNCATE TABLE u_auth_user", nil) - // _, err := datasource.ExecDB("", "DELETE FROM u_auth_user WHERE ne_id = ?", []any{neID}) - if err != nil { - log.Errorf("TRUNCATE err => %v", err) - } - - n := len(authArr) - batchSize := 2000 - for i := 0; i < n; i += batchSize { - end := i + batchSize - if end > n { - end = n - } - batch := authArr[i:end] - - // 调用 InsertMulti 函数将批量数据插入数据库 - results, err := datasource.DefaultDB().Table("u_auth_user").InsertMulti(batch) - if err != nil { - log.Errorf("InsertMulti err => %v", err) - continue - } - num += results - } - return num -} - -// Insert 新增实体 -func (r *RepoUdmAuthUser) Insert(authUser model.UdmAuthUser) int64 { - results, err := datasource.DefaultDB().Table("u_auth_user").Insert(authUser) - if err != nil { - log.Errorf("Insert err => %v", err) - return results - } - return results -} - -// Insert 批量添加 -func (r *RepoUdmAuthUser) Inserts(authUsers []model.UdmAuthUser) int64 { - var num int64 - n := len(authUsers) - batchSize := 2000 - for i := 0; i < n; i += batchSize { - end := i + batchSize - if end > n { - end = n - } - batch := authUsers[i:end] - - // 调用 InsertMulti 函数将批量数据插入数据库 - results, err := datasource.DefaultDB().Table("u_auth_user").InsertMulti(batch) - if err != nil { - log.Errorf("Insert err => %v", err) - continue - } - num += results - } - return num -} - -// Update 修改更新 -func (r *RepoUdmAuthUser) Update(neID string, authUser model.UdmAuthUser) int64 { - // 查询先 - var user model.UdmAuthUser - has, err := datasource.DefaultDB().Table("u_auth_user").Where("imsi = ? and ne_id = ?", authUser.Imsi, neID).Get(&user) - if !has || err != nil { - return 0 - } - - if authUser.Ki != "" && authUser.Ki != user.Ki { - user.Ki = authUser.Ki - } - if authUser.Amf != "" && authUser.Amf != user.Amf { - user.Amf = authUser.Amf - } - if authUser.AlgoIndex != "" && authUser.AlgoIndex != user.AlgoIndex { - user.AlgoIndex = authUser.AlgoIndex - } - if authUser.Opc != "" && authUser.Opc != user.Opc { - user.Opc = authUser.Opc - } - - results, err := datasource.DefaultDB().Table("u_auth_user").Where("imsi = ? and ne_id = ?", user.Imsi, user.NeID).Update(user) - if err != nil { - return 0 - } - return results -} - -// Delete 删除实体 -func (r *RepoUdmAuthUser) Delete(neID, imsi string) int64 { - results, err := datasource.DefaultDB().Table("u_auth_user").Where("imsi = ? and ne_id = ?", imsi, neID).Delete() - if err != nil { - return results - } - return results -} - -// Delete 删除范围实体 -func (r *RepoUdmAuthUser) Deletes(neID, imsi, num string) int64 { - imsiV, err := strconv.Atoi(imsi) - if err != nil { - return 0 - } - - numV, err := strconv.Atoi(num) - if err != nil { - return 0 - } - - results, err := datasource.DefaultDB().Table("u_auth_user").Where("imsi >= ? and imsi < ? and ne_id = ?", imsiV, imsiV+numV, neID).Delete() - if err != nil { - return results - } - return results -} diff --git a/features/udm_user/repo/repo_udm_sub_user.go b/features/udm_user/repo/repo_udm_sub_user.go deleted file mode 100644 index 9317492..0000000 --- a/features/udm_user/repo/repo_udm_sub_user.go +++ /dev/null @@ -1,450 +0,0 @@ -package repo - -import ( - "fmt" - "strconv" - "strings" - - "nms_cxy/features/udm_user/model" - "nms_cxy/lib/core/datasource" - "nms_cxy/lib/core/utils/parse" - "nms_cxy/lib/log" -) - -// 实例化数据层 RepoUdmSubUser 结构体 -var NewRepoUdmSubUser = &RepoUdmSubUser{ - selectSql: `select - id, msisdn, imsi, ambr, nssai, rat, arfb, sar, cn, sm_data, smf_sel, eps_dat, ne_id, eps_flag, eps_odb, hplmn_odb, ard, epstpl, context_id, apn_context, static_ip - from u_sub_user`, - - resultMap: map[string]string{ - "id": "ID", - "msisdn": "Msisdn", - "imsi": "Imsi", - "ambr": "Ambr", - "nssai": "Nssai", - "rat": "Rat", - "arfb": "Arfb", - "sar": "Sar", - "cn": "Cn", - "sm_data": "SmData", - "smf_sel": "SmfSel", - "eps_dat": "EpsDat", - "ne_id": "NeID", - "eps_flag": "EpsFlag", - "eps_odb": "EpsOdb", - "hplmn_odb": "HplmnOdb", - "ard": "Ard", - "epstpl": "Epstpl", - "context_id": "ContextId", - "apn_context": "ApnContext", - "static_ip": "StaticIp", - }, -} - -// RepoUdmSubUser UDM签约用户 数据层处理 -type RepoUdmSubUser struct { - // 查询视图对象SQL - selectSql string - // 结果字段与实体映射 - resultMap map[string]string -} - -// convertResultRows 将结果记录转实体结果组 -func (r *RepoUdmSubUser) convertResultRows(rows []map[string]any) []model.UdmSubUser { - arr := make([]model.UdmSubUser, 0) - for _, row := range rows { - UdmUser := model.UdmSubUser{} - for key, value := range row { - if keyMapper, ok := r.resultMap[key]; ok { - datasource.SetFieldValue(&UdmUser, keyMapper, value) - } - } - arr = append(arr, UdmUser) - } - return arr -} - -// SelectPage 根据条件分页查询字典类型 -func (r *RepoUdmSubUser) SelectPage(query map[string]any) map[string]any { - // 查询条件拼接 - var conditions []string - var params []any - if v, ok := query["msisdn"]; ok && v != "" { - conditions = append(conditions, "msisdn like concat(concat('%', ?), '%')") - params = append(params, v) - } - if v, ok := query["imsi"]; ok && v != "" { - conditions = append(conditions, "imsi like concat(concat('%', ?), '%')") - params = append(params, v) - } - if v, ok := query["neId"]; ok && v != "" { - conditions = append(conditions, "ne_id = ?") - params = append(params, v) - } - - // 构建查询条件语句 - whereSql := "" - if len(conditions) > 0 { - whereSql += " where " + strings.Join(conditions, " and ") - } - - result := map[string]any{ - "total": 0, - "rows": []model.UdmAuthUser{}, - } - - // 查询数量 长度为0直接返回 - totalSql := "select count(1) as 'total' from u_sub_user" - totalRows, err := datasource.RawDB("", totalSql+whereSql, params) - if err != nil { - log.Errorf("total err => %v", err) - return result - } - total := parse.Number(totalRows[0]["total"]) - if total == 0 { - return result - } else { - result["total"] = total - } - - // 分页 - pageNum, pageSize := datasource.PageNumSize(query["pageNum"], query["pageSize"]) - pageSql := " limit ?,? " - params = append(params, pageNum*pageSize) - params = append(params, pageSize) - - // 排序 - sortSql := "" - if v, ok := query["sortField"]; ok && v != "" { - if v == "imsi" { - sortSql += " order by imsi " - } - if v == "msisdn" { - sortSql += " order by msisdn " - } - if o, ok := query["sortOrder"]; ok && o != nil && v != "" { - if o == "desc" { - sortSql += " desc " - } else { - sortSql += " asc " - } - } - } - - // 查询数据 - querySql := r.selectSql + whereSql + sortSql + pageSql - results, err := datasource.RawDB("", querySql, params) - if err != nil { - log.Errorf("query err => %v", err) - return result - } - - // 转换实体 - result["rows"] = r.convertResultRows(results) - return result -} - -// SelectList 根据实体查询 -func (r *RepoUdmSubUser) SelectList(auth model.UdmSubUser) []model.UdmSubUser { - // 查询条件拼接 - var conditions []string - var params []any - if auth.Imsi != "" { - conditions = append(conditions, "imsi = ?") - params = append(params, auth.Imsi) - } - if auth.NeID != "" { - conditions = append(conditions, "ne_id = ?") - params = append(params, auth.NeID) - } - - // 构建查询条件语句 - whereSql := "" - if len(conditions) > 0 { - whereSql += " where " + strings.Join(conditions, " and ") - } - - // 查询数据 - querySql := r.selectSql + whereSql + " order by imsi asc " - results, err := datasource.RawDB("", querySql, params) - if err != nil { - log.Errorf("query err => %v", err) - } - - // 转换实体 - return r.convertResultRows(results) -} - -// ClearAndInsert 清空ne_id后新增实体 -func (r *RepoUdmSubUser) ClearAndInsert(neID string, subArr []model.UdmSubUser) int64 { - var num int64 = 0 - - // 清空指定ne_id - _, err := datasource.ExecDB("", "TRUNCATE TABLE u_sub_user", nil) - // _, err := datasource.ExecDB("", "DELETE FROM u_sub_user WHERE ne_id = ?", []any{neID}) - if err != nil { - log.Errorf("TRUNCATE err => %v", err) - } - - n := len(subArr) - batchSize := 2000 - for i := 0; i < n; i += batchSize { - end := i + batchSize - if end > n { - end = n - } - batch := subArr[i:end] - - // 调用 InsertMulti 函数将批量数据插入数据库 - results, err := datasource.DefaultDB().Table("u_sub_user").InsertMulti(batch) - if err != nil { - log.Errorf("InsertMulti err => %v", err) - continue - } - num += results - } - - // for _, u := range subArr { - // u.NeID = neID - // results, err := datasource.DefaultDB().Table("u_sub_user").Insert(u) - // if err != nil { - // return num - // } - // num += results - // } - return num -} - -// Insert 新增实体 -func (r *RepoUdmSubUser) Insert(subUser model.UdmSubUser) int64 { - results, err := datasource.DefaultDB().Table("u_sub_user").Insert(subUser) - if err != nil { - log.Errorf("Insert err => %v", err) - return results - } - return results -} - -// Insert 批量添加 -func (r *RepoUdmSubUser) Inserts(subUser []model.UdmSubUser) int64 { - var num int64 - n := len(subUser) - batchSize := 2000 - for i := 0; i < n; i += batchSize { - end := i + batchSize - if end > n { - end = n - } - batch := subUser[i:end] - - // 调用 InsertMulti 函数将批量数据插入数据库 - results, err := datasource.DefaultDB().Table("u_sub_user").InsertMulti(batch) - if err != nil { - log.Errorf("Insert err => %v", err) - continue - } - num += results - } - return num -} - -// Insert4G 批量添加4G用户 -func (r *RepoUdmSubUser) Insert4G(neID string, subUser model.UdmSubUser) int64 { - var insertNum int64 - - imsiV, err := strconv.Atoi(subUser.Imsi) - if err != nil { - return 0 - } - numV, err := strconv.Atoi(subUser.SubNum) - if err != nil { - return 0 - } - - subUser.NeID = neID - for i := 0; i < numV; i++ { - subUser.Imsi = fmt.Sprint(imsiV + i) - - results, err := datasource.DefaultDB().Table("u_sub_user").Insert(subUser) - if err == nil { - log.Errorf("Insert err => %v", err) - insertNum += results - } - } - - return insertNum -} - -// Update 修改更新 -func (r *RepoUdmSubUser) Update(neID string, authUser model.UdmSubUser) int64 { - // 查询先 - var user model.UdmSubUser - has, err := datasource.DefaultDB().Table("u_sub_user").Where("imsi = ? and ne_id = ?", authUser.Imsi, neID).Get(&user) - if !has || err != nil { - return 0 - } - - if authUser.Msisdn != "" && authUser.Msisdn != user.Msisdn { - user.Msisdn = authUser.Msisdn - } - if authUser.Ambr != "" && authUser.Ambr != user.Ambr { - user.Ambr = authUser.Ambr - } - if authUser.Arfb != "" && authUser.Arfb != user.Arfb { - user.Arfb = authUser.Arfb - } - if authUser.Sar != "" && authUser.Sar != user.Sar { - user.Sar = authUser.Sar - } - if authUser.Rat != "" && authUser.Rat != user.Rat { - user.Rat = authUser.Rat - } - if authUser.Cn != "" && authUser.Cn != user.Cn { - user.Cn = authUser.Cn - } - if authUser.SmfSel != "" && authUser.SmfSel != user.SmfSel { - user.SmfSel = authUser.SmfSel - } - if authUser.SmData != "" && authUser.SmData != user.SmData { - user.SmData = authUser.SmData - } - if authUser.EpsDat != "" && authUser.EpsDat != user.EpsDat { - user.EpsDat = authUser.EpsDat - } - if authUser.EpsFlag != "" && authUser.EpsFlag != user.EpsFlag { - user.EpsFlag = authUser.EpsFlag - } - if authUser.EpsOdb != "" && authUser.EpsDat != user.EpsDat { - user.EpsOdb = authUser.EpsOdb - } - if authUser.HplmnOdb != "" && authUser.HplmnOdb != user.HplmnOdb { - user.HplmnOdb = authUser.HplmnOdb - } - if authUser.Epstpl != "" && authUser.Epstpl != user.Epstpl { - user.Epstpl = authUser.Epstpl - } - if authUser.Ard != "" && authUser.Ard != user.Ard { - user.Ard = authUser.Ard - } - if authUser.ContextId != "" && authUser.ContextId != user.ContextId { - user.ContextId = authUser.ContextId - } - if authUser.ApnContext != "" && authUser.ApnContext != user.ApnContext { - user.ApnContext = authUser.ApnContext - } - if authUser.StaticIp != "" && authUser.StaticIp != user.StaticIp { - user.StaticIp = authUser.StaticIp - } - - results, err := datasource.DefaultDB().Table("u_sub_user").Where("imsi = ? and ne_id = ?", user.Imsi, user.NeID).Update(user) - if err != nil { - log.Errorf("Update err => %v", err) - return 0 - } - return results -} - -// Update4GIP 批量修改4G IP -func (r *RepoUdmSubUser) Update4GIP(neID string, subUser model.UdmSubUser) int64 { - var insertNum int64 - - imsiV, err := strconv.Atoi(subUser.Imsi) - if err != nil || subUser.StaticIp == "" { - return insertNum - } - numV, err := strconv.Atoi(subUser.SubNum) - if err != nil { - return insertNum - } - - for i := 0; i < numV; i++ { - subUser.Imsi = fmt.Sprint(imsiV + i) - - // 查询先 - var user model.UdmSubUser - has, err := datasource.DefaultDB().Table("u_sub_user").Where("imsi = ? and ne_id = ?", subUser.Imsi, neID).Get(&user) - if has && err == nil { - // IP会自动递增 - parts := strings.Split(subUser.StaticIp, ".") - lastPart := parts[3] - lastNum, _ := strconv.Atoi(lastPart) - lastNum += i - newLastPart := strconv.Itoa(lastNum) - parts[3] = newLastPart - newIP := strings.Join(parts, ".") - user.StaticIp = newIP - // 更新 - results, err := datasource.DefaultDB().Table("u_sub_user").Update(user) - if err == nil { - log.Errorf("Update err => %v", err) - insertNum += results - } - } - } - return insertNum -} - -// UpdateSmData 批量修改sm-data -func (r *RepoUdmSubUser) UpdateSmData(neID string, subUser model.UdmSubUser) int64 { - var insertNum int64 - - imsiV, err := strconv.Atoi(subUser.Imsi) - if err != nil || subUser.StaticIp == "" { - return insertNum - } - numV, err := strconv.Atoi(subUser.SubNum) - if err != nil { - return insertNum - } - - for i := 0; i < numV; i++ { - subUser.Imsi = fmt.Sprint(imsiV + i) - - // 查询先 - var user model.UdmSubUser - has, err := datasource.DefaultDB().Table("u_sub_user").Where("imsi = ? and ne_id = ?", subUser.Imsi, neID).Get(&user) - if has && err == nil { - // IP会自动递增,需提前规划好DNN对应的IP;如dnn不需要绑定IP则不带此字段名 - // parts := strings.Split(subUser.SmData, "&") - user.SmData = subUser.SmData - // 更新 - results, err := datasource.DefaultDB().Table("u_sub_user").Update(user) - if err == nil { - log.Errorf("Update err => %v", err) - insertNum += results - } - } - } - return insertNum -} - -// Delete 删除实体 -func (r *RepoUdmSubUser) Delete(neID, imsi string) int64 { - results, err := datasource.DefaultDB().Table("u_sub_user").Where("imsi = ? and ne_id = ?", imsi, neID).Delete() - if err != nil { - log.Errorf("Delete err => %v", err) - return results - } - return results -} - -// Delete 删除范围实体 -func (r *RepoUdmSubUser) Deletes(neID, imsi, num string) int64 { - imsiV, err := strconv.Atoi(imsi) - if err != nil { - return 0 - } - - numV, err := strconv.Atoi(num) - if err != nil { - return 0 - } - - results, err := datasource.DefaultDB().Table("u_sub_user").Where("imsi >= ? and imsi < ? and ne_id = ?", imsiV, imsiV+numV, neID).Delete() - if err != nil { - log.Errorf("Delete err => %v", err) - return results - } - return results -} diff --git a/features/udm_user/service/service_redis_data.go b/features/udm_user/service/service_redis_data.go deleted file mode 100644 index addf6e0..0000000 --- a/features/udm_user/service/service_redis_data.go +++ /dev/null @@ -1,119 +0,0 @@ -package service - -import ( - "strings" - - "nms_cxy/features/udm_user/model" - "nms_cxy/src/framework/redis" -) - -// phoneImsiList 获取所有imsi -// func phoneImsiList() map[string]string { -// phoneAndImsiArr := make(map[string]string, 0) -// phoneKeys, err := redis.GetKeys("udmuser", "1*********") -// if err != nil { -// return phoneAndImsiArr -// } -// for _, phone := range phoneKeys { -// imsi, err := redis.Get("udmuser", phone) -// if err != nil { -// continue -// } -// phoneAndImsiArr[phone] = imsi -// } -// return phoneAndImsiArr -// } - -// redisUdmAuthUserList UDM鉴权用户 -func redisUdmAuthUserList() []model.UdmAuthUser { - user := []model.UdmAuthUser{} - ausfArr, err := redis.GetKeys("udmuser", "ausf:*") - if err != nil { - return user - } - for _, key := range ausfArr { - m, err := redis.GetHash("udmuser", key) - if err != nil { - continue - } - - // 跳过-号数据 - imsi := key[5:] - if strings.Contains(imsi, "-") { - continue - } - - status := "0" - if _, ok := m["auth_success"]; ok { - status = "1" - } - amf := "" - if v, ok := m["amf"]; ok { - amf = strings.Replace(v, "\r\n", "", 1) - } - a := model.UdmAuthUser{ - Imsi: imsi, - Amf: amf, - Status: status, - Ki: m["ki"], - AlgoIndex: m["algo"], - Opc: m["opc"], - } - user = append(user, a) - } - return user -} - -// redisUdmSubUserList UDM签约用户 -func redisUdmSubUserList() []model.UdmSubUser { - user := []model.UdmSubUser{} - udmsdArr, err := redis.GetKeys("udmuser", "udm-sd:*") - if err != nil { - return user - } - for _, key := range udmsdArr { - m, err := redis.GetHash("udmuser", key) - if err != nil { - continue - } - - a := model.UdmSubUser{ - Imsi: key[7:], - Msisdn: m["gpsi"], // 46003550072 strings.TrimPrefix(m["gpsi"], "86"), - SmfSel: m["smf-sel"], - SmData: m["sm-dat"], // 1-000001&cmnet&ims&3gnet - } - - // def_ambr,def_nssai,0,def_arfb,def_sar,3,1,12000,1,1000,0,1,- - if v, ok := m["am-dat"]; ok { - arr := strings.Split(v, ",") - a.Ambr = arr[0] - a.Nssai = arr[1] - a.Rat = arr[2] - a.Arfb = arr[3] - a.Sar = arr[4] - a.Cn = arr[5] - } - // 1,64,24,65,def_eps,1,2,010200000000,- - if v, ok := m["eps-dat"]; ok { - arr := strings.Split(v, ",") - // 跳过非常规数据 - if len(arr) > 9 { - continue - } - a.EpsDat = v - a.EpsFlag = arr[0] - a.EpsOdb = arr[1] - a.HplmnOdb = arr[2] - a.Ard = arr[3] - a.Epstpl = arr[4] - a.ContextId = arr[5] - a.ApnContext = arr[7] - // [6] 是不要的,导入和导出不用 - a.StaticIp = arr[8] - } - - user = append(user, a) - } - return user -} diff --git a/features/udm_user/service/service_udm_auth_user.go b/features/udm_user/service/service_udm_auth_user.go deleted file mode 100644 index 30daa0d..0000000 --- a/features/udm_user/service/service_udm_auth_user.go +++ /dev/null @@ -1,151 +0,0 @@ -package service - -import ( - "fmt" - "strconv" - - "nms_cxy/features/udm_user/model" - "nms_cxy/features/udm_user/repo" -) - -// 实例化服务层 ServiceUdmAuthUser 结构体 -var NewServiceUdmAuthUser = &ServiceUdmAuthUser{ - repoAuthUser: *repo.NewRepoUdmAuthUser, -} - -// ServiceUdmAuthUser UDM鉴权用户 服务层处理 -type ServiceUdmAuthUser struct { - repoAuthUser repo.RepoUdmAuthUser -} - -// Save UDM鉴权用户-获取全部保存数据库 -func (r *ServiceUdmAuthUser) Save(neID string) int64 { - var num int64 = 0 - authArr := redisUdmAuthUserList() - // 有数据才清空 - if len(authArr) == 0 { - return num - } - go r.repoAuthUser.ClearAndInsert(neID, authArr) - return int64(len(authArr)) -} - -// Page UDM签约用户-分页查询数据库 -func (r *ServiceUdmAuthUser) Page(query map[string]any) map[string]any { - return r.repoAuthUser.SelectPage(query) -} - -// List UDM签约用户-查询数据库 -func (r *ServiceUdmAuthUser) List(authUser model.UdmAuthUser) []model.UdmAuthUser { - return r.repoAuthUser.SelectList(authUser) -} - -// Insert UDM鉴权用户-新增单个 -// imsi长度15,ki长度32,opc长度0或者32 -func (r *ServiceUdmAuthUser) Insert(neID string, authUser model.UdmAuthUser) int64 { - authUser.NeID = neID - authUser.Status = "0" - return r.repoAuthUser.Insert(authUser) -} - -// Insert UDM鉴权用户-批量添加 -func (r *ServiceUdmAuthUser) Inserts(neID string, authUser model.UdmAuthUser, num string) int64 { - var arr []model.UdmAuthUser - - imsiVlen := len(authUser.Imsi) - imsiV, err := strconv.Atoi(authUser.Imsi) - if err != nil { - return 0 - } - - numV, err := strconv.Atoi(num) - if err != nil { - return 0 - } - - authUser.NeID = neID - authUser.Status = "0" - for i := 0; i < numV; i++ { - imsi := fmt.Sprint(imsiV + i) - if len(imsi) < imsiVlen { - imsi = fmt.Sprintf("%0*s", imsiVlen, imsi) - } - authUser.Imsi = imsi - arr = append(arr, authUser) - } - - return r.repoAuthUser.Inserts(arr) -} - -// InsertCSV UDM鉴权用户-批量添加 -func (r *ServiceUdmAuthUser) InsertCSV(neID string, data []map[string]string) int64 { - var arr []model.UdmAuthUser - for _, v := range data { - var authUser model.UdmAuthUser - authUser.NeID = neID - authUser.Status = "0" - if s, ok := v["imsi"]; ok { - authUser.Imsi = s - } - if s, ok := v["ki"]; ok { - authUser.Ki = s - } - if s, ok := v["algo"]; ok { - authUser.AlgoIndex = s - } - if s, ok := v["amf"]; ok { - authUser.Amf = s - } - if s, ok := v["opc"]; ok { - authUser.Opc = s - } - - if authUser.Imsi == "" { - continue - } - arr = append(arr, authUser) - } - return r.repoAuthUser.Inserts(arr) -} - -// InsertTxt UDM鉴权用户-批量添加 -func (r *ServiceUdmAuthUser) InsertTxt(neID string, data [][]string) int64 { - var arr []model.UdmAuthUser - for _, v := range data { - if len(v) < 4 { - continue - } - var authUser model.UdmAuthUser - authUser.NeID = neID - authUser.Status = "0" - authUser.Imsi = v[0] - authUser.Ki = v[1] - authUser.AlgoIndex = v[2] - authUser.Amf = v[3] - if len(v) == 5 { - authUser.Opc = v[4] - } - - if authUser.Imsi == "" { - continue - } - arr = append(arr, authUser) - } - - return r.repoAuthUser.Inserts(arr) -} - -// Insert UDM鉴权用户-修改更新 -func (r *ServiceUdmAuthUser) Update(neID string, authUser model.UdmAuthUser) int64 { - return r.repoAuthUser.Update(neID, authUser) -} - -// Insert UDM鉴权用户-删除单个 -func (r *ServiceUdmAuthUser) Delete(neID, imsi string) int64 { - return r.repoAuthUser.Delete(neID, imsi) -} - -// Insert UDM鉴权用户-删除范围 -func (r *ServiceUdmAuthUser) Deletes(neID, imsi, num string) int64 { - return r.repoAuthUser.Deletes(neID, imsi, num) -} diff --git a/features/udm_user/service/service_udm_sub_user.go b/features/udm_user/service/service_udm_sub_user.go deleted file mode 100644 index 205bdc9..0000000 --- a/features/udm_user/service/service_udm_sub_user.go +++ /dev/null @@ -1,231 +0,0 @@ -package service - -import ( - "fmt" - "strconv" - "strings" - - "nms_cxy/features/udm_user/model" - "nms_cxy/features/udm_user/repo" -) - -// 实例化服务层 ServiceUdmSubUser 结构体 -var NewServiceUdmSubUser = &ServiceUdmSubUser{ - repoSunUser: *repo.NewRepoUdmSubUser, -} - -// ServiceUdmSubUser UDM签约用户 服务层处理 -type ServiceUdmSubUser struct { - repoSunUser repo.RepoUdmSubUser -} - -// Save UDM签约用户-获取全部保存数据库 -func (r *ServiceUdmSubUser) Save(neID string) int64 { - var num int64 = 0 - subArr := redisUdmSubUserList() - // 有数据才清空 - if len(subArr) == 0 { - return num - } - go r.repoSunUser.ClearAndInsert(neID, subArr) - return int64(len(subArr)) -} - -// Page UDM签约用户-分页查询数据库 -func (r *ServiceUdmSubUser) Page(query map[string]any) map[string]any { - return r.repoSunUser.SelectPage(query) -} - -// List UDM签约用户-查询数据库 -func (r *ServiceUdmSubUser) List(subUser model.UdmSubUser) []model.UdmSubUser { - return r.repoSunUser.SelectList(subUser) -} - -// Insert UDM签约用户-新增单个 -// imsi长度15,ki长度32,opc长度0或者32 -func (r *ServiceUdmSubUser) Insert(neID string, subUser model.UdmSubUser) int64 { - subUser.NeID = neID - return r.repoSunUser.Insert(subUser) -} - -// Insert UDM签约用户-批量添加 -func (r *ServiceUdmSubUser) Inserts(neID string, subUser model.UdmSubUser, num string) int64 { - var arr []model.UdmSubUser - - imsiVlen := len(subUser.Imsi) - imsiV, err := strconv.Atoi(subUser.Imsi) - if err != nil { - return 0 - } - msisdnVlen := len(subUser.Msisdn) - msisdnV, err := strconv.Atoi(subUser.Msisdn) - if err != nil { - return 0 - } - - numV, err := strconv.Atoi(num) - if err != nil { - return 0 - } - - subUser.NeID = neID - for i := 0; i < numV; i++ { - msisdn := fmt.Sprint(msisdnV + i) - if len(msisdn) < msisdnVlen { - msisdn = fmt.Sprintf("%0*s", msisdnVlen, msisdn) - } - subUser.Msisdn = msisdn - - imsi := fmt.Sprint(imsiV + i) - if len(imsi) < imsiVlen { - imsi = fmt.Sprintf("%0*s", imsiVlen, imsi) - } - subUser.Imsi = imsi - - // IP会自动递增 - if len(subUser.StaticIp) > 5 { - parts := strings.Split(subUser.StaticIp, ".") - lastPart := parts[3] - lastNum, _ := strconv.Atoi(lastPart) - lastNum += i - newLastPart := strconv.Itoa(lastNum) - parts[3] = newLastPart - newIP := strings.Join(parts, ".") - subUser.StaticIp = newIP - } - - subUser.EpsDat = fmt.Sprintf("%s,%s,%s,%s,%s,%s,2,%s,%s", subUser.EpsFlag, subUser.EpsOdb, subUser.HplmnOdb, subUser.Ard, subUser.Epstpl, subUser.ContextId, subUser.ApnContext, subUser.StaticIp) - - arr = append(arr, subUser) - } - - return r.repoSunUser.Inserts(arr) -} - -// InsertCSV UDM签约用户-批量添加 -func (r *ServiceUdmSubUser) InsertCSV(neID string, data []map[string]string) int64 { - var arr []model.UdmSubUser - for _, v := range data { - var subUser model.UdmSubUser - subUser.NeID = neID - if s, ok := v["imsi"]; ok { - subUser.Imsi = s - } - if s, ok := v["msisdn"]; ok { - subUser.Msisdn = s - } - if s, ok := v["ambr"]; ok { - subUser.Ambr = s - } - if s, ok := v["nssai"]; ok { - subUser.Nssai = s - } - if s, ok := v["arfb"]; ok { - subUser.Arfb = s - } - if s, ok := v["sar"]; ok { - subUser.Sar = s - } - if s, ok := v["rat"]; ok { - subUser.Rat = s - } - if s, ok := v["cn"]; ok { - subUser.Cn = s - } - if s, ok := v["smf_sel"]; ok { - subUser.SmfSel = s - } - if s, ok := v["sm_dat"]; ok { - subUser.SmData = s - } - if s, ok := v["eps_dat"]; ok { - subUser.EpsDat = s - arr := strings.Split(s, ",") - if len(arr) == 8 { - subUser.EpsFlag = arr[0] - subUser.EpsOdb = arr[1] - subUser.HplmnOdb = arr[2] - subUser.Ard = arr[3] - subUser.Epstpl = arr[4] - subUser.ContextId = arr[5] - subUser.ApnContext = arr[6] - subUser.StaticIp = arr[7] - } - } - - if subUser.Imsi == "" { - continue - } - arr = append(arr, subUser) - } - return r.repoSunUser.Inserts(arr) -} - -// InsertTxt UDM签约用户-批量添加 -func (r *ServiceUdmSubUser) InsertTxt(neID string, data [][]string) int64 { - var arr []model.UdmSubUser - for _, v := range data { - if len(v) < 10 { - continue - } - var subUser model.UdmSubUser - subUser.NeID = neID - subUser.Imsi = v[0] - subUser.Msisdn = v[1] - subUser.Ambr = v[2] - subUser.Nssai = v[3] - subUser.Arfb = v[4] - subUser.Sar = v[5] - subUser.Rat = v[6] - subUser.Cn = v[7] - subUser.SmfSel = v[8] - subUser.SmData = v[9] - if len(v) > 17 { - subUser.EpsFlag = v[10] - subUser.EpsOdb = v[11] - subUser.HplmnOdb = v[12] - subUser.Ard = v[13] - subUser.Epstpl = v[14] - subUser.ContextId = v[15] - subUser.ApnContext = v[16] - subUser.StaticIp = v[17] - subUser.EpsDat = strings.Join(v[10:], ",") - } - - if subUser.Imsi == "" { - continue - } - arr = append(arr, subUser) - } - return r.repoSunUser.Inserts(arr) -} - -// Insert UDM签约用户-批量添加4G用户 -func (r *ServiceUdmSubUser) Insert4G(neID string, subUser model.UdmSubUser) int64 { - return r.repoSunUser.Insert4G(neID, subUser) -} - -// Insert UDM签约用户-修改更新 -func (r *ServiceUdmSubUser) Update(neID string, subUser model.UdmSubUser) int64 { - return r.repoSunUser.Update(neID, subUser) -} - -// Update4GIP UDM签约用户-批量修改4G IP -func (r *ServiceUdmSubUser) Update4GIP(neID string, subUser model.UdmSubUser) int64 { - return r.repoSunUser.Update4GIP(neID, subUser) -} - -// Update4GIP UDM签约用户-批量修改sm-data -func (r *ServiceUdmSubUser) UpdateSmData(neID string, subUser model.UdmSubUser) int64 { - return r.repoSunUser.UpdateSmData(neID, subUser) -} - -// Insert UDM签约用户-删除单个 -func (r *ServiceUdmSubUser) Delete(neID, imsi string) int64 { - return r.repoSunUser.Delete(neID, imsi) -} - -// Insert UDM签约用户-删除范围 -func (r *ServiceUdmSubUser) Deletes(neID, imsi, num string) int64 { - return r.repoSunUser.Deletes(neID, imsi, num) -} diff --git a/features/ue/ue.go b/features/ue/ue.go index 04a7221..608ae7e 100644 --- a/features/ue/ue.go +++ b/features/ue/ue.go @@ -8,12 +8,14 @@ import ( "strings" "time" + "nms_cxy/lib/core/ctx" "nms_cxy/lib/dborm" "nms_cxy/lib/global" "nms_cxy/lib/log" "nms_cxy/lib/services" "nms_cxy/omc/config" tokenConst "nms_cxy/src/framework/constants/token" + neService "nms_cxy/src/modules/network_element/service" "github.com/go-resty/resty/v2" "github.com/gorilla/mux" @@ -47,6 +49,7 @@ type SmfUEInfo struct { UpfN3IP string `json:"upfN3IP"` RanN3IP string `json:"ranN3IP"` Activetime string `json:"activeTime"` + UpState string `json:"upState"` } `json:"pduSessionInfo"` } @@ -241,66 +244,38 @@ func GetSubscriptionsFromNSSF(w http.ResponseWriter, r *http.Request) { // Get UEInfo from NF/NFs func GetUEInfoFromNF(w http.ResponseWriter, r *http.Request) { - log.Info("GetUEInfoFromNF processing... ") + log.Debug("GetUEInfoFromNF processing... ") - vars := mux.Vars(r) - neType := vars["elementTypeValue"] - if neType == "" { - services.ResponseNotFound404UriNotExist(w, r) - return - } - //neTypeLower := strings.ToLower(neType) - var neId string - neIds := services.GetParamsArrByName("neId", r) - if len(neIds) == 1 { - neId = neIds[0] - } else { + neId := ctx.GetQuery(r, "neId") + neType := ctx.GetParam(r, "elementTypeValue") + if neType == "" || neId == "" { + log.Error("elementTypeValue/neId is empty") services.ResponseNotFound404UriNotExist(w, r) return } - // token, err := services.CheckFrontValidRequest(w, r) - // if err != nil { - // log.Error("Request error:", err) - // return - // } - // log.Debug("token:", token) + neInfo := neService.NewNeInfoImpl.SelectNeInfoByNeTypeAndNeID(neType, neId) - neInfo, err := dborm.XormGetNeInfo(neType, neId) - if err != nil { - log.Error("Failed to XormGetNeInfo:", err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } else if neInfo == nil { - err := global.ErrCMNotFoundTargetNE - log.Error(global.ErrCMNotFoundTargetNE) - services.ResponseInternalServerError500ProcessError(w, err) - return + var response services.MapResponse + if neInfo.NeId == neId && neInfo.NeId != "" { + requestURI2NF := fmt.Sprintf("http://%s:%v%s", neInfo.IP, neInfo.Port, r.RequestURI) + log.Debug("requestURI2NF:", requestURI2NF) + resp, err := client.R(). + EnableTrace(). + SetHeaders(map[string]string{"User-Agent": config.GetDefaultUserAgent()}). + SetHeaders(map[string]string{"Content-Type": "application/json;charset=UTF-8"}). + Get(requestURI2NF) + if err != nil { + log.Error("Failed to Get from NF:", err) + services.ResponseInternalServerError500ProcessError(w, err) + return + } else { + _ = json.Unmarshal(resp.Body(), &response) + } + log.Debug("response:", response) } - log.Trace("neInfo:", neInfo) - hostUri := fmt.Sprintf("http://%s:%v", neInfo.Ip, neInfo.Port) - requestURI2NF := fmt.Sprintf("%s%s", hostUri, r.RequestURI) - - log.Debug("requestURI2NF:", requestURI2NF) - - resp, err := client.R(). - EnableTrace(). - SetHeaders(map[string]string{tokenConst.HEADER_KEY: r.Header.Get(tokenConst.HEADER_KEY)}). - // SetHeaders(map[string]string{"accessToken": token}). - SetHeaders(map[string]string{"User-Agent": config.GetDefaultUserAgent()}). - SetHeaders(map[string]string{"Content-Type": "application/json;charset=UTF-8"}). - Get(requestURI2NF) - if err != nil { - log.Error("Get system state from NF is failed:", err) - services.ResponseInternalServerError500ProcessError(w, err) - return - } else { - var response services.MapResponse - _ = json.Unmarshal(resp.Body(), &response) - services.ResponseWithJson(w, resp.StatusCode(), response) - return - } + services.ResponseWithJson(w, http.StatusOK, response) } // POST User Info from NF/NFs diff --git a/go.mod b/go.mod index 07c18d6..eacacf5 100644 --- a/go.mod +++ b/go.mod @@ -17,11 +17,13 @@ require ( github.com/gosnmp/gosnmp v1.35.0 github.com/jasonlvhit/gocron v0.0.1 github.com/lestrrat/go-file-rotatelogs v0.0.0-20180223000712-d3151e2a480f + github.com/linxGnu/gosmpp v0.2.0 github.com/matoous/go-nanoid/v2 v2.0.0 github.com/metaleap/go-xsd v0.0.0-20180330193350-61f7638f502f github.com/mojocn/base64Captcha v1.3.5 github.com/mssola/user_agent v0.6.0 github.com/patrickmn/go-cache v2.1.0+incompatible + github.com/prometheus-community/pro-bing v0.4.0 github.com/redis/go-redis/v9 v9.1.0 github.com/reiver/go-telnet v0.0.0-20180421082511-9ff0b2ab096e github.com/robfig/cron/v3 v3.0.1 @@ -32,8 +34,8 @@ require ( github.com/xuri/excelize/v2 v2.7.1 github.com/xuri/xgen v0.0.0-20230702070049-db840e1a4605 github.com/ziutek/telnet v0.0.0-20180329124119-c3b780dc415b - golang.org/x/crypto v0.21.0 - golang.org/x/term v0.18.0 + golang.org/x/crypto v0.24.0 + golang.org/x/term v0.21.0 gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df gopkg.in/yaml.v3 v3.0.1 gorm.io/driver/mysql v1.5.1 @@ -42,7 +44,7 @@ require ( ) require ( - github.com/chzyer/readline v1.5.1 // indirect + github.com/beorn7/perks v1.0.1 // indirect github.com/creack/pty v1.1.9 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/dustin/go-humanize v1.0.1 // indirect @@ -50,8 +52,7 @@ require ( github.com/eapache/go-xerial-snappy v0.0.0-20230731223053-c322873962e3 // indirect github.com/eapache/queue v1.1.0 // indirect github.com/go-admin-team/go-admin-core v1.3.12-0.20221121065133-27b7dbe27a8f // indirect - github.com/go-gsm/charset v1.0.0 // indirect - github.com/go-gsm/ucp v0.0.1 // indirect + github.com/go-ini/ini v1.67.0 // indirect github.com/hashicorp/errwrap v1.0.0 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/hashicorp/go-uuid v1.0.3 // indirect @@ -60,21 +61,20 @@ require ( github.com/jcmturner/gofork v1.7.6 // indirect github.com/jcmturner/gokrb5/v8 v8.4.4 // indirect github.com/jcmturner/rpc/v2 v2.0.3 // indirect - github.com/klauspost/compress v1.17.7 // indirect - github.com/linxGnu/gosmpp v0.2.0 // indirect + github.com/klauspost/compress v1.17.9 // indirect + github.com/kr/fs v0.1.0 // indirect github.com/minio/md5-simd v1.1.2 // indirect - github.com/minio/minio-go/v7 v7.0.69 // indirect - github.com/minio/sha256-simd v1.0.1 // indirect github.com/pierrec/lz4/v4 v4.1.21 // indirect - github.com/prometheus-community/pro-bing v0.4.0 // indirect + github.com/prometheus/client_model v0.5.0 // indirect + github.com/prometheus/common v0.48.0 // indirect + github.com/prometheus/procfs v0.12.0 // indirect github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect github.com/rs/xid v1.5.0 // indirect - golang.org/x/sync v0.6.0 // indirect - golang.org/x/time v0.1.0 // indirect + golang.org/x/sync v0.7.0 // indirect ) require ( - github.com/IBM/sarama v1.43.0 + github.com/IBM/sarama v1.43.2 github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible // indirect github.com/bsm/redislock v0.8.2 // indirect github.com/bytedance/go-tagexpr/v2 v2.7.12 // indirect @@ -83,6 +83,7 @@ require ( github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/chanxuehong/rand v0.0.0-20201110082127-2f19a1bdd973 // indirect github.com/chanxuehong/wechat v0.0.0-20201110083048-0180211b69fd // indirect + github.com/chenjiandongx/ginprom v0.0.0-20210617023641-6c809602c38a github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.3 // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect @@ -100,7 +101,7 @@ require ( github.com/go-playground/validator/v10 v10.14.0 // indirect github.com/go-redis/redis/v8 v8.11.5 // indirect github.com/go-redis/redis/v9 v9.0.0-rc.1 // indirect - github.com/goccy/go-json v0.10.2 // indirect + github.com/goccy/go-json v0.10.3 github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect github.com/golang/protobuf v1.5.3 // indirect github.com/golang/snappy v0.0.4 // indirect @@ -114,7 +115,7 @@ require ( github.com/jinzhu/now v1.1.5 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect - github.com/klauspost/cpuid/v2 v2.2.6 // indirect + github.com/klauspost/cpuid/v2 v2.2.8 // indirect github.com/leodido/go-urn v1.2.4 // indirect github.com/lestrrat/go-envload v0.0.0-20180220120943-6ed08b54a570 // indirect github.com/lestrrat/go-strftime v0.0.0-20180220042222-ba3bf9c1d042 // indirect @@ -125,6 +126,7 @@ require ( github.com/mattn/goveralls v0.0.2 // indirect github.com/metaleap/go-util v0.0.0-20180330192724-a09253046f73 // indirect github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b // indirect + github.com/minio/minio-go/v7 v7.0.73 github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect @@ -133,7 +135,9 @@ require ( github.com/nyaruka/phonenumbers v1.0.55 // indirect github.com/pelletier/go-toml/v2 v2.0.8 // indirect github.com/pkg/errors v0.9.1 // indirect + github.com/pkg/sftp v1.13.6 github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect + github.com/prometheus/client_golang v1.19.1 github.com/reiver/go-oi v1.0.0 // indirect github.com/richardlehane/mscfb v1.0.4 // indirect github.com/richardlehane/msoleps v1.0.3 // indirect @@ -156,14 +160,13 @@ require ( github.com/yusufpapurcu/wmi v1.2.3 // indirect golang.org/x/arch v0.3.0 // indirect golang.org/x/image v0.5.0 // indirect - golang.org/x/net v0.22.0 - golang.org/x/sys v0.18.0 // indirect - golang.org/x/text v0.14.0 - golang.org/x/tools v0.16.1 // indirect - google.golang.org/protobuf v1.30.0 // indirect + golang.org/x/net v0.26.0 + golang.org/x/sys v0.21.0 // indirect + golang.org/x/text v0.16.0 + golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect + google.golang.org/protobuf v1.33.0 // indirect gopkg.in/AlecAivazis/survey.v1 v1.8.5 // indirect gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect - gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/kyokomi/emoji.v1 v1.5.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect diff --git a/go.sum b/go.sum index 7ab14b0..f8a6e5e 100644 --- a/go.sum +++ b/go.sum @@ -41,8 +41,8 @@ gitea.com/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a/go.mod h1:EXuID2Zs0p gitee.com/travelliu/dm v1.8.11192/go.mod h1:DHTzyhCrM843x9VdKVbZ+GKXGRbKM2sJ4LxihRxShkE= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/IBM/sarama v1.43.0 h1:YFFDn8mMI2QL0wOrG0J2sFoVIAFl7hS9JQi2YZsXtJc= -github.com/IBM/sarama v1.43.0/go.mod h1:zlE6HEbC/SMQ9mhEYaF7nNLYOUyrs0obySKCckWP9BM= +github.com/IBM/sarama v1.43.2 h1:HABeEqRUh32z8yzY2hGB/j8mHSzC/HA9zlEjqFNCzSw= +github.com/IBM/sarama v1.43.2/go.mod h1:Kyo4WkF24Z+1nz7xeVUFWIuKVV8RS3wM8mkvPKMdXFQ= github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible h1:1G1pk05UrOh0NlF1oeaaix1x8XzrfjIDK47TY0Zehcw= github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= @@ -67,6 +67,7 @@ github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/bsm/ginkgo/v2 v2.9.5 h1:rtVBYPs3+TC5iLUVOis1B9tjLTup7Cj5IfzosKtvTJ0= @@ -94,16 +95,14 @@ github.com/chanxuehong/rand v0.0.0-20201110082127-2f19a1bdd973/go.mod h1:9+sJ9zv github.com/chanxuehong/util v0.0.0-20200304121633-ca8141845b13/go.mod h1:XEYt99iTxMqkv+gW85JX/DdUINHUe43Sbe5AtqSaDAQ= github.com/chanxuehong/wechat v0.0.0-20201110083048-0180211b69fd h1:TM3wjEWel4U31J72dlhnwCBqPC0+FA0Ejm2NCbn5a5U= github.com/chanxuehong/wechat v0.0.0-20201110083048-0180211b69fd/go.mod h1:/dvhOIRCjjiZu6NV0QTTiMcc5XwoORbxfDSsRY2IfaM= +github.com/chenjiandongx/ginprom v0.0.0-20210617023641-6c809602c38a h1:yTfhjWYoPomJkHVArtNHpo36FuOa6Kc2ZjTLvyyQ5Lg= +github.com/chenjiandongx/ginprom v0.0.0-20210617023641-6c809602c38a/go.mod h1:lINNCb1ZH3c0uL/9ApaQ8muR4QILsi0STj8Ojt8ZmwU= github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams= github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= -github.com/chzyer/logex v1.2.1/go.mod h1:JLbx6lG2kDbNRFnfkgvh4eRJRPX1QCoOIWomwysCBrQ= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= -github.com/chzyer/readline v1.5.1 h1:upd/6fQk4src78LMRzh5vItIt361/o4uq553V8B5sGI= -github.com/chzyer/readline v1.5.1/go.mod h1:Eh+b79XXUwfKfcPLepksvw2tcLE/Ct21YObkaSkeBlk= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= -github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38GC8= github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= @@ -186,10 +185,8 @@ github.com/go-forks/fsnotify v1.4.7/go.mod h1:AU8mot+GznW5+B4jRJHxKg/2EeO+jMORGR github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-gsm/charset v1.0.0 h1:6k6LOKHtxgCPXE15X0unRewjOksyhmHBIp6x7qLQ6Ls= -github.com/go-gsm/charset v1.0.0/go.mod h1:sC8+2VpAM2sZDlxv11MxWIZiuf8MipOgM/hCYsRQRps= -github.com/go-gsm/ucp v0.0.1 h1:vM5ly5iRNGMGGiVx4K3+puF9AhpwkC76BkiV9LFv0bw= -github.com/go-gsm/ucp v0.0.1/go.mod h1:58/PrXWFcmaQyZ5p/Dp2YiCnhlVx0HdKXFGmqiVO/mI= +github.com/go-ini/ini v1.67.0 h1:z6ZrTEZqSWOTyH2FlglNbNgARyHG8oLW9gMELqKr06A= +github.com/go-ini/ini v1.67.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o= @@ -223,6 +220,8 @@ github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg78 github.com/goccy/go-json v0.8.1/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= +github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA= +github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= @@ -285,8 +284,9 @@ github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= @@ -305,7 +305,6 @@ github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLe github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -457,20 +456,22 @@ github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:C github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.17.7 h1:ehO88t2UGzQK66LMdE8tibEd1ErmzZjNEqWkjLAKQQg= -github.com/klauspost/compress v1.17.7/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= +github.com/klauspost/compress v1.17.8 h1:YcnTYrq7MikUT7k0Yb5eceMmALQPYBW/Xltxn0NAMnU= +github.com/klauspost/compress v1.17.8/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= +github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= +github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= github.com/klauspost/cpuid/v2 v2.0.1/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk= github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= -github.com/klauspost/cpuid/v2 v2.2.6 h1:ndNyv040zDGIDh8thGkXYjnFtiN02M1PVVF+JE/48xc= -github.com/klauspost/cpuid/v2 v2.2.6/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= +github.com/klauspost/cpuid/v2 v2.2.8 h1:+StwCXwm9PdpiEkPyzBXIy+M9KUb4ODm0Zarf1kS5BM= +github.com/klauspost/cpuid/v2 v2.2.8/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/fs v0.1.0 h1:Jskdu9ieNAYnjxsi0LbQp1ulIKZV1LAFgK1tWhpZgl8= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= @@ -537,10 +538,8 @@ github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyex github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/minio/md5-simd v1.1.2 h1:Gdi1DZK69+ZVMoNHRXJyNcxrMA4dSxoYHZSQbirFg34= github.com/minio/md5-simd v1.1.2/go.mod h1:MzdKDxYpY2BT9XQFocsiZf/NKVtR7nkE4RoEpN+20RM= -github.com/minio/minio-go/v7 v7.0.69 h1:l8AnsQFyY1xiwa/DaQskY4NXSLA2yrGsW5iD9nRPVS0= -github.com/minio/minio-go/v7 v7.0.69/go.mod h1:XAvOPJQ5Xlzk5o3o/ArO2NMbhSGkimC+bpW/ngRKDmQ= -github.com/minio/sha256-simd v1.0.1 h1:6kaan5IFmwTNynnKKpDHe6FWHohJOHhCPchzK49dzMM= -github.com/minio/sha256-simd v1.0.1/go.mod h1:Pz6AKMiUdngCLpeTL/RJY1M9rUuPMYujV5xJjtbRSN8= +github.com/minio/minio-go/v7 v7.0.73 h1:qr2vi96Qm7kZ4v7LLebjte+MQh621fFWnv93p12htEo= +github.com/minio/minio-go/v7 v7.0.73/go.mod h1:qydcVzV8Hqtj1VtEocfxbmVFa2siu6HGa+LDEPogjD8= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= @@ -626,6 +625,8 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA= github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= +github.com/pkg/sftp v1.13.6 h1:JFZT4XbOU7l77xGSpOdW+pwIMqP044IyjXX6FGyEKFo= +github.com/pkg/sftp v1.13.6/go.mod h1:tz1ryNURKu77RL+GuCzmoJYxQczL3wLNNpPWagdg4Qk= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= @@ -637,18 +638,26 @@ github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXP github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og= +github.com/prometheus/client_golang v1.19.1 h1:wZWJDwK+NameRJuPGDhlnFgx8e8HN3XHQeLaYJFJBOE= +github.com/prometheus/client_golang v1.19.1/go.mod h1:mP78NwGzrVks5S2H6ab8+ZZGJLZUq1hoULYBAYBw1Ho= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw= +github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI= github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA= +github.com/prometheus/common v0.48.0 h1:QO8U2CdOzSn1BBsmXJXduaaW+dY/5QLjfB8svtSzKKE= +github.com/prometheus/common v0.48.0/go.mod h1:0/KsvlIEfPQCQ5I2iNSAWKPZziNCvRs5EC6ILDTlAPc= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= +github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 h1:N/ElC8H3+5XpJzTSTfLsJV/mx9Q9g7kxmchpfZyxgzM= github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= @@ -669,8 +678,8 @@ github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= -github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= +github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= github.com/rs/xid v1.5.0 h1:mKX4bl4iPYJtEIxp6CYiUuLQ/8DYMoz0PUdtGgMFRVc= github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= @@ -825,12 +834,15 @@ golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE= -golang.org/x/crypto v0.16.0 h1:mMMrFzRSCF0GvB7Ne27XVtVAaXLrPmgPC7/v0tkwHaY= -golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= -golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= -golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= +golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo= +golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= +golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30= +golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= +golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI= +golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -875,7 +887,6 @@ golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181102091132-c10e9556a7bc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -916,13 +927,16 @@ golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT golang.org/x/net v0.0.0-20211029224645-99673261e6eb/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= -golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c= -golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= -golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc= -golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= +golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4= +golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= +golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w= +golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8= +golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ= +golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -946,6 +960,8 @@ golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= +golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180606202747-9527bec2660b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1009,29 +1025,31 @@ golang.org/x/sys v0.0.0-20210902050250-f475640dd07b/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= -golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= -golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y= +golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws= +golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY= -golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4= -golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= -golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8= -golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= +golang.org/x/term v0.17.0 h1:mkTF7LCd6WGJNL3K1Ad7kwxNfYAW6a8a8QqtMblp/4U= +golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= +golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk= +golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1040,16 +1058,17 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= +golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.1.0 h1:xYY+Bajn2a7VBmTM5GikTmnK8ZuX8YgnQCqZpbBNtmA= -golang.org/x/time v0.1.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -1112,6 +1131,7 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.16.1 h1:TLyB3WofjdOEepBHAU20JdNC1Zbg87elYofWYAY5oZA= golang.org/x/tools v0.16.1/go.mod h1:kYVVN6I1mBNoB1OX+noeBjbRk4IUEPa7JJ+TJMEooJ0= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -1216,8 +1236,8 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= -google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= +google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/AlecAivazis/survey.v1 v1.8.5 h1:QoEEmn/d5BbuPIL2qvXwzJdttFFhRQFkaq+tEKb7SMI= gopkg.in/AlecAivazis/survey.v1 v1.8.5/go.mod h1:iBNOmqKz/NUbZx3bA+4hAGLRC7fSK7tgtVDT4tB22XA= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= diff --git a/lib/core/account/account.go b/lib/core/account/account.go deleted file mode 100644 index 98c0df3..0000000 --- a/lib/core/account/account.go +++ /dev/null @@ -1,54 +0,0 @@ -package account - -import ( - "fmt" - "strconv" - "time" - - sysMenuService "nms_cxy/features/sys_menu/service" - sysRoleService "nms_cxy/features/sys_role/service" - "nms_cxy/lib/core/cache" - "nms_cxy/lib/core/vo" - "nms_cxy/lib/dborm" - srcConfig "nms_cxy/src/framework/config" -) - -// 登录缓存用户信息 -func CacheLoginUser(user *dborm.User) { - // 过期时间 - expiresStr, err := dborm.XormGetConfigValue("Security", "sessionExpires") - if err != nil { - expiresStr = "18000" - } - expiresValue, _ := strconv.Atoi(expiresStr) - expireTime := time.Duration(expiresValue) * time.Second - - nowTime := time.Now().UnixMilli() - - // 登录用户 - loginUser := vo.LoginUser{ - UserID: fmt.Sprint(user.Id), - UserName: user.Name, - ExpireTime: nowTime + expireTime.Milliseconds(), - LoginTime: nowTime, - User: *user, - } - - // 是否管理员 - if srcConfig.IsAdmin(loginUser.UserID) { - loginUser.Permissions = []string{"*:*:*"} - } else { - // 获取权限标识 - loginUser.Permissions = sysMenuService.NewRepoSysMenu.SelectMenuPermsByUserId(loginUser.UserID) - // 获取角色信息 - loginUser.User.Roles = sysRoleService.NewRepoSysRole.SelectRoleListByUserId(loginUser.UserID) - } - - // 缓存时间 - cache.SetLocalTTL(user.AccountId, loginUser, time.Duration(expireTime)) -} - -// 清除缓存用户信息 -func ClearLoginUser(accountId string) { - cache.DeleteLocalTTL(accountId) -} diff --git a/lib/core/constants/cachekey/cachekey.go b/lib/core/constants/cachekey/cachekey.go deleted file mode 100644 index 0e69445..0000000 --- a/lib/core/constants/cachekey/cachekey.go +++ /dev/null @@ -1,24 +0,0 @@ -package cachekey - -// 缓存的key常量 - -// 登录用户 -const LOGIN_TOKEN_KEY = "login_tokens:" - -// 验证码 -const CAPTCHA_CODE_KEY = "captcha_codes:" - -// 参数管理 -const SYS_CONFIG_KEY = "sys_config:" - -// 字典管理 -const SYS_DICT_KEY = "sys_dict:" - -// 防重提交 -const REPEAT_SUBMIT_KEY = "repeat_submit:" - -// 限流 -const RATE_LIMIT_KEY = "rate_limit:" - -// 登录账户密码错误次数 -const PWD_ERR_CNT_KEY = "pwd_err_cnt:" diff --git a/lib/core/utils/ctx/ctx.go b/lib/core/ctx/ctx.go similarity index 74% rename from lib/core/utils/ctx/ctx.go rename to lib/core/ctx/ctx.go index 53e74b7..2d0c914 100644 --- a/lib/core/utils/ctx/ctx.go +++ b/lib/core/ctx/ctx.go @@ -10,16 +10,16 @@ import ( "path/filepath" "strings" - "nms_cxy/lib/core/vo" - commonConstants "nms_cxy/src/framework/constants/common" - tokenConst "nms_cxy/src/framework/constants/token" + "nms_cxy/src/framework/constants/token" + tokenUtils "nms_cxy/src/framework/utils/token" + "nms_cxy/src/framework/vo" "github.com/gorilla/mux" "golang.org/x/text/language" ) -// Param 地址栏参数{id} -func Param(r *http.Request, key string) string { +// GetParam 地址栏参数{id} +func GetParam(r *http.Request, key string) string { vars := mux.Vars(r) v, ok := vars[key] if ok { @@ -48,7 +48,7 @@ func QueryMap(r *http.Request) map[string]any { return queryParams } -// ShouldBindQuery 查询参数读取json请求结构团体 +// ShouldBindQuery 查询参数读取json请求结构团体 &xxx func ShouldBindQuery(r *http.Request, args any) error { queryParams := QueryMap(r) body, err := json.Marshal(queryParams) @@ -58,7 +58,7 @@ func ShouldBindQuery(r *http.Request, args any) error { return json.Unmarshal(body, args) } -// 读取json请求结构团体 +// ShouldBindJSON 读取json请求结构团体 &xxx func ShouldBindJSON(r *http.Request, args any) error { body, err := io.ReadAll(io.LimitReader(r.Body, 1<<20)) // 设置较大的长度,例如 1<<20 (1MB) if err != nil { @@ -123,12 +123,26 @@ func SaveUploadedFile(r *http.Request, dst string) error { // Authorization 解析请求头 func Authorization(r *http.Request) string { - authHeader := r.Header.Get(tokenConst.HEADER_KEY) + // Query请求查询 + if authQuery := r.URL.Query().Get(token.ACCESS_TOKEN); authQuery != "" { + return authQuery + } + // Header请求头 + if authHeader := r.Header.Get(token.ACCESS_TOKEN); authHeader != "" { + return authHeader + } + + // Query请求查询 + if authQuery := r.URL.Query().Get(token.RESPONSE_FIELD); authQuery != "" { + return authQuery + } + // Header请求头 + authHeader := r.Header.Get(token.HEADER_KEY) if authHeader == "" { return "" } // 拆分 Authorization 请求头,提取 JWT 令牌部分 - arr := strings.Split(authHeader, tokenConst.HEADER_PREFIX) + arr := strings.Split(authHeader, token.HEADER_PREFIX) if len(arr) == 2 && arr[1] == "" { return "" } @@ -165,12 +179,24 @@ type ContextKey string // LoginUser 登录用户信息需要Authorize中间件 func LoginUser(r *http.Request) (vo.LoginUser, error) { - // 上下文 - v := r.Context().Value(ContextKey(commonConstants.CTX_LOGIN_USER)) - if v != nil { - return v.(vo.LoginUser), nil + // 获取请求头标识信息 + tokenStr := Authorization(r) + if tokenStr == "" { + return vo.LoginUser{}, fmt.Errorf("not token info") } - return vo.LoginUser{}, fmt.Errorf("No user information") + // 验证令牌 + claims, err := tokenUtils.Verify(tokenStr) + if err != nil { + return vo.LoginUser{}, fmt.Errorf("token verify fail") + } + + // 获取缓存的用户信息 + loginUser := tokenUtils.LoginUser(claims) + if loginUser.UserID == "" { + return vo.LoginUser{}, fmt.Errorf("not user info") + } + + return loginUser, nil } // LoginUserToUserID 登录用户信息-用户ID @@ -188,5 +214,5 @@ func LoginUserToUserName(r *http.Request) string { if err != nil { return "" } - return loginUser.UserName + return loginUser.User.UserName } diff --git a/lib/core/datasource/datasource.go b/lib/core/datasource/datasource.go deleted file mode 100644 index 7146df3..0000000 --- a/lib/core/datasource/datasource.go +++ /dev/null @@ -1,50 +0,0 @@ -package datasource - -import ( - "database/sql" - "regexp" - - "nms_cxy/lib/dborm" - - "xorm.io/xorm" -) - -// 获取默认数据源 -func DefaultDB() *xorm.Engine { - return dborm.DbClient.XEngine -} - -// RawDB 原生查询语句 -func RawDB(source string, sql string, parameters []any) ([]map[string]any, error) { - // 数据源 - db := DefaultDB() - - // 使用正则表达式替换连续的空白字符为单个空格 - fmtSql := regexp.MustCompile(`\s+`).ReplaceAllString(sql, " ") - - // log.Infof("sql=> %v", fmtSql) - // log.Infof("parameters=> %v", parameters) - - // 查询结果 - var rows []map[string]any - err := db.SQL(fmtSql, parameters...).Find(&rows) - if err != nil { - return nil, err - } - return rows, nil -} - -// ExecDB 原生执行语句 -func ExecDB(source string, sql string, parameters []any) (sql.Result, error) { - // 数据源 - db := DefaultDB() - - // 使用正则表达式替换连续的空白字符为单个空格 - fmtSql := regexp.MustCompile(`\s+`).ReplaceAllString(sql, " ") - // 执行结果 - res, err := db.Exec(append([]any{fmtSql}, parameters...)...) - if err != nil { - return nil, err - } - return res, err -} diff --git a/lib/core/datasource/repo.go b/lib/core/datasource/repo.go deleted file mode 100644 index 7b81a4e..0000000 --- a/lib/core/datasource/repo.go +++ /dev/null @@ -1,126 +0,0 @@ -package datasource - -import ( - "fmt" - "reflect" - "strconv" - "strings" -) - -// PageNumSize 分页页码记录数 -func PageNumSize(pageNum, pageSize any) (int, int) { - // 记录起始索引 - pageNumStr := fmt.Sprintf("%v", pageNum) - num := 1 - if v, err := strconv.Atoi(pageNumStr); err == nil && v > 0 { - num = v - } - - // 显示记录数 - pageSizeStr := fmt.Sprintf("%v", pageSize) - size := 10 - if v, err := strconv.Atoi(pageSizeStr); err == nil && v > 0 { - size = v - } - return num - 1, size -} - -// SetFieldValue 判断结构体内是否存在指定字段并设置值 -func SetFieldValue(obj any, fieldName string, value any) { - // 获取结构体的反射值 - userValue := reflect.ValueOf(obj) - - // 获取字段的反射值 - fieldValue := userValue.Elem().FieldByName(fieldName) - - // 检查字段是否存在 - if fieldValue.IsValid() && fieldValue.CanSet() { - // 获取字段的类型 - fieldType := fieldValue.Type() - - // 转换传入的值类型为字段类型 - switch fieldType.Kind() { - case reflect.String: - if value == nil { - fieldValue.SetString("") - } else { - fieldValue.SetString(fmt.Sprintf("%v", value)) - } - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - intValue, err := strconv.ParseInt(fmt.Sprintf("%v", value), 10, 64) - if err != nil { - intValue = 0 - } - fieldValue.SetInt(intValue) - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: - uintValue, err := strconv.ParseUint(fmt.Sprintf("%v", value), 10, 64) - if err != nil { - uintValue = 0 - } - fieldValue.SetUint(uintValue) - case reflect.Float32, reflect.Float64: - floatValue, err := strconv.ParseFloat(fmt.Sprintf("%v", value), 64) - if err != nil { - floatValue = 0 - } - fieldValue.SetFloat(floatValue) - default: - // 设置字段的值 - fieldValue.Set(reflect.ValueOf(value).Convert(fieldValue.Type())) - } - } -} - -// ConvertIdsSlice 将 []string 转换为 []any -func ConvertIdsSlice(ids []string) []any { - // 将 []string 转换为 []any - arr := make([]any, len(ids)) - for i, v := range ids { - arr[i] = v - } - return arr -} - -// 查询-参数值的占位符 -func KeyPlaceholderByQuery(sum int) string { - placeholders := make([]string, sum) - for i := 0; i < sum; i++ { - placeholders[i] = "?" - } - return strings.Join(placeholders, ",") -} - -// 插入-参数映射键值占位符 keys, placeholder, values -func KeyPlaceholderValueByInsert(params map[string]any) ([]string, string, []any) { - // 参数映射的键 - keys := make([]string, len(params)) - // 参数映射的值 - values := make([]any, len(params)) - sum := 0 - for k, v := range params { - keys[sum] = k - values[sum] = v - sum++ - } - // 参数值的占位符 - placeholders := make([]string, sum) - for i := 0; i < sum; i++ { - placeholders[i] = "?" - } - return keys, strings.Join(placeholders, ","), values -} - -// 更新-参数映射键值占位符 keys, values -func KeyValueByUpdate(params map[string]any) ([]string, []any) { - // 参数映射的键 - keys := make([]string, len(params)) - // 参数映射的值 - values := make([]any, len(params)) - sum := 0 - for k, v := range params { - keys[sum] = k + "=?" - values[sum] = v - sum++ - } - return keys, values -} diff --git a/lib/core/mml_client/mml_client.go b/lib/core/mml_client/mml_client.go deleted file mode 100644 index 1513f3c..0000000 --- a/lib/core/mml_client/mml_client.go +++ /dev/null @@ -1,87 +0,0 @@ -package mmlclient - -import ( - "bufio" - "fmt" - "io" - "net" - "time" - - "nms_cxy/lib/core/conf" -) - -// 定义MMLClient结构体 -type MMLClient struct { - awaitTime time.Duration // 等待时间 - conn net.Conn - reader *bufio.Reader - size int // 包含字符 -} - -// 封装NewMMLClient函数,用于创建MMLClient实例 -// 网元UDM的IP地址 "198.51.100.1" -func NewMMLClient(ip string) (*MMLClient, error) { - // 创建TCP连接 - portMML := conf.Get("mml.port").(int) - hostMML := fmt.Sprintf("%s:%d", ip, portMML) - conn, err := net.Dial("tcp", hostMML) - if err != nil { - return nil, err - } - - // 进行登录 - usernameMML := conf.Get("mml.user").(string) - passwordMML := conf.Get("mml.password").(string) - fmt.Fprintln(conn, usernameMML) - fmt.Fprintln(conn, passwordMML) - - // 发送后等待 - awaitTime := time.Duration(300) * time.Millisecond - time.Sleep(awaitTime) - - // 读取内容 - buf := make([]byte, 1024*1024*1) - n, err := conn.Read(buf) - if err != nil { - return nil, err - } - - // 创建MMLClient实例 - client := &MMLClient{ - conn: conn, - reader: bufio.NewReader(conn), - awaitTime: awaitTime, - size: n, - } - - return client, nil -} - -// 封装Send函数,用于向TCP连接发送数据 -func (c *MMLClient) Send(msg string) error { - _, err := fmt.Fprintln(c.conn, msg) - if err != nil { - return err - } - time.Sleep(c.awaitTime) - return nil -} - -// 封装Receive函数,用于从TCP连接中接收数据 -func (c *MMLClient) Receive() (string, error) { - buf := make([]byte, 1024*1024*1) - n, err := c.reader.Read(buf) - if err != nil { - if err == io.EOF { - return "", fmt.Errorf("server closed the connection") - } - return "", err - } - c.size += n - return string(buf[0:n]), nil -} - -// 封装Close函数,用于关闭TCP连接 -func (c *MMLClient) Close() error { - return c.conn.Close() -} diff --git a/lib/core/mml_client/send.go b/lib/core/mml_client/send.go deleted file mode 100644 index 943772c..0000000 --- a/lib/core/mml_client/send.go +++ /dev/null @@ -1,105 +0,0 @@ -package mmlclient - -import ( - "fmt" - "strings" -) - -// 发送MML原始消息 -// ip 网元IP地址 -// msg 指令 -func MMLSendMsg(ip, msg string) (string, error) { - // 创建MMLClient实例 - client, err := NewMMLClient(ip) - if err != nil { - return "", fmt.Errorf("failed to create MMLClient instance: %v", err) - } - defer client.Close() - - // 发送数据 - err = client.Send(msg) - if err != nil { - return "", fmt.Errorf("sending data failed: %v", err) - } - - // 接收数据 - data, err := client.Receive() - if err != nil { - return "", fmt.Errorf("failed to receive data: %v", err) - } - - return data, nil -} - -// 发送MML -// ip 网元IP地址 -// msg 指令 -func MMLSendMsgToString(ip, msg string) (string, error) { - // 发送获取数据 - str, err := MMLSendMsg(ip, msg) - if err != nil { - return "", err - } - - str = strings.ToLower(str) - - // 截断 - index := strings.Index(str, "\n") - if index != -1 { - str = str[:index] - } - - // 命令成功 - if strings.Contains(str, "ok") || strings.Contains(str, "success") { - return str, nil - } - - return "", fmt.Errorf(str) -} - -// 发送MML -// ip 网元IP地址 -// msg 指令 -func MMLSendMsgToMap(ip, msg string) (map[string]string, error) { - // 发送获取数据 - str, err := MMLSendMsg(ip, msg) - if err != nil { - return nil, err - } - - // 无数据 - if strings.HasPrefix(str, "No Auth Data") { - return nil, fmt.Errorf("no auth data") - } - - // 初始化一个map用于存储拆分后的键值对 - m := make(map[string]string) - - var items []string - if strings.Contains(str, "\r\n") { - // 按照分隔符"\r\n"进行拆分 - items = strings.Split(str, "\r\n") - } else if strings.Contains(str, "\n") { - // 按照分隔符"\n"进行拆分 - items = strings.Split(str, "\n") - } - - // 遍历拆分后的结果 - for _, item := range items { - var pair []string - - if strings.Contains(item, "=") { - // 按照分隔符"="进行拆分键值对 - pair = strings.SplitN(item, "=", 2) - } else if strings.Contains(item, ":") { - // 按照分隔符":"进行拆分键值对 - pair = strings.SplitN(item, ":", 2) - } - - if len(pair) == 2 { - // 将键值对存入map中 - m[pair[0]] = pair[1] - } - } - return m, err -} diff --git a/lib/core/utils/date/date.go b/lib/core/utils/date/date.go deleted file mode 100644 index 51a0c0a..0000000 --- a/lib/core/utils/date/date.go +++ /dev/null @@ -1,70 +0,0 @@ -package date - -import ( - "fmt" - "time" - - "nms_cxy/lib/log" -) - -const ( - // 年 列如:2022 - YYYY = "2006" - // 年-月 列如:2022-12 - YYYY_MM = "2006-01" - // 年-月-日 列如:2022-12-30 - YYYY_MM_DD = "2006-01-02" - // 年月日时分秒 列如:20221230010159 - YYYYMMDDHHMMSS = "20060102150405" - // 年-月-日 时:分:秒 列如:2022-12-30 01:01:59 - YYYY_MM_DD_HH_MM_SS = "2006-01-02 15:04:05" -) - -// 格式时间字符串 -// -// dateStr 时间字符串 -// -// formatStr 时间格式 默认YYYY-MM-DD HH:mm:ss -func ParseStrToDate(dateStr, formatStr string) time.Time { - t, err := time.Parse(formatStr, dateStr) - if err != nil { - log.Infof("utils ParseStrToDate err %v", err) - return time.Time{} - } - return t -} - -// 格式时间 -// -// date 可转的Date对象 -// -// formatStr 时间格式 默认YYYY-MM-DD HH:mm:ss -func ParseDateToStr(date any, formatStr string) string { - t, ok := date.(time.Time) - if !ok { - switch v := date.(type) { - case int64: - if v == 0 { - return "" - } - t = time.UnixMilli(v) - case string: - parsedTime, err := time.Parse(formatStr, v) - if err != nil { - fmt.Printf("utils ParseDateToStr err %v \n", err) - return "" - } - t = parsedTime - default: - return "" - } - } - return t.Format(formatStr) -} - -// 格式时间成日期路径 -// -// 年/月 列如:2022/12 -func ParseDatePath(date time.Time) string { - return date.Format("2006/01") -} diff --git a/lib/core/utils/parse/parse.go b/lib/core/utils/parse/parse.go deleted file mode 100644 index ed2fd5d..0000000 --- a/lib/core/utils/parse/parse.go +++ /dev/null @@ -1,139 +0,0 @@ -package parse - -import ( - "fmt" - "reflect" - "regexp" - "strconv" - "strings" - "time" - - "github.com/robfig/cron/v3" -) - -// Number 解析数值型 -func Number(str any) int64 { - switch str := str.(type) { - case string: - if str == "" { - return 0 - } - num, err := strconv.ParseInt(str, 10, 64) - if err != nil { - return 0 - } - return num - case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64: - return reflect.ValueOf(str).Int() - case float32, float64: - return int64(reflect.ValueOf(str).Float()) - default: - return 0 - } -} - -// Boolean 解析布尔型 -func Boolean(str any) bool { - switch str := str.(type) { - case string: - if str == "" || str == "false" || str == "0" { - return false - } - // 尝试将字符串解析为数字 - if num, err := strconv.ParseFloat(str, 64); err == nil { - return num != 0 - } - return true - case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64: - num := reflect.ValueOf(str).Int() - return num != 0 - case float32, float64: - num := reflect.ValueOf(str).Float() - return num != 0 - default: - return false - } -} - -// FirstUpper 首字母转大写 -// -// 字符串 abc_123!@# 结果 Abc_123 -func FirstUpper(str string) string { - if len(str) == 0 { - return str - } - reg := regexp.MustCompile(`[^_\w]+`) - str = reg.ReplaceAllString(str, "") - return strings.ToUpper(str[:1]) + str[1:] -} - -// Bit 比特位为单位 -func Bit(bit float64) string { - var GB, MB, KB string - - if bit > float64(1<<30) { - GB = fmt.Sprintf("%0.2f", bit/(1<<30)) - } - - if bit > float64(1<<20) && bit < (1<<30) { - MB = fmt.Sprintf("%.2f", bit/(1<<20)) - } - - if bit > float64(1<<10) && bit < (1<<20) { - KB = fmt.Sprintf("%.2f", bit/(1<<10)) - } - - if GB != "" { - return GB + "GB" - } else if MB != "" { - return MB + "MB" - } else if KB != "" { - return KB + "KB" - } else { - return fmt.Sprintf("%vB", bit) - } -} - -// CronExpression 解析 Cron 表达式,返回下一次执行的时间戳(毫秒) -// -// 【*/5 * * * * ?】 6个参数 -func CronExpression(expression string) int64 { - specParser := cron.NewParser(cron.Second | cron.Minute | cron.Hour | cron.Dom | cron.Month | cron.Dow | cron.Descriptor) - schedule, err := specParser.Parse(expression) - if err != nil { - fmt.Println(err) - return 0 - } - return schedule.Next(time.Now()).UnixMilli() -} - -// SafeContent 内容值进行安全掩码 -func SafeContent(value string) string { - if len(value) < 3 { - return strings.Repeat("*", len(value)) - } else if len(value) < 6 { - return string(value[0]) + strings.Repeat("*", len(value)-1) - } else if len(value) < 10 { - return string(value[0]) + strings.Repeat("*", len(value)-2) + string(value[len(value)-1]) - } else if len(value) < 15 { - return value[:2] + strings.Repeat("*", len(value)-4) + value[len(value)-2:] - } else { - return value[:3] + strings.Repeat("*", len(value)-6) + value[len(value)-3:] - } -} - -// RemoveDuplicates 数组内字符串去重 -func RemoveDuplicates(ids []string) []string { - uniqueIDs := make(map[string]bool) - uniqueIDSlice := make([]string, 0) - - for _, id := range ids { - _, ok := uniqueIDs[id] - if !ok && id != "" { - uniqueIDs[id] = true - uniqueIDSlice = append(uniqueIDSlice, id) - } - } - - return uniqueIDSlice -} diff --git a/lib/core/utils/regular/regular.go b/lib/core/utils/regular/regular.go deleted file mode 100644 index e4b9cc6..0000000 --- a/lib/core/utils/regular/regular.go +++ /dev/null @@ -1,54 +0,0 @@ -package regular - -import ( - "regexp" -) - -// Replace 正则替换 -func Replace(originStr, pattern, repStr string) string { - regex := regexp.MustCompile(pattern) - return regex.ReplaceAllString(originStr, repStr) -} - -// 判断是否为有效用户名格式 -// -// 用户名不能以数字开头,可包含大写小写字母,数字,且不少于5位 -func ValidUsername(username string) bool { - if username == "" { - return false - } - pattern := `^[a-zA-Z][a-z0-9A-Z]{5,}` - match, err := regexp.MatchString(pattern, username) - if err != nil { - return false - } - return match -} - -// 判断是否为有效手机号格式,1开头的11位手机号 -func ValidMobile(mobile string) bool { - if mobile == "" { - return false - } - pattern := `^1[3|4|5|6|7|8|9][0-9]\d{8}$` - match, err := regexp.MatchString(pattern, mobile) - if err != nil { - return false - } - return match -} - -// 判断是否为http(s)://开头 -// -// link 网络链接 -func ValidHttp(link string) bool { - if link == "" { - return false - } - pattern := `^http(s)?:\/\/+` - match, err := regexp.MatchString(pattern, link) - if err != nil { - return false - } - return match -} diff --git a/lib/core/utils/scan/scan.go b/lib/core/utils/scan/scan.go deleted file mode 100644 index 6313763..0000000 --- a/lib/core/utils/scan/scan.go +++ /dev/null @@ -1,31 +0,0 @@ -package scan - -import ( - "net" - "strconv" -) - -func ScanPort(port int) bool { - ln, err := net.Listen("tcp", ":"+strconv.Itoa(port)) - if err != nil { - return true - } - defer ln.Close() - return false -} - -func ScanUDPPort(port int) bool { - ln, err := net.ListenUDP("udp", &net.UDPAddr{IP: net.IPv4(127, 0, 0, 1), Port: port}) - if err != nil { - return true - } - defer ln.Close() - return false -} - -func ScanPortWithProto(port int, proto string) bool { - if proto == "udp" { - return ScanUDPPort(port) - } - return ScanPort(port) -} diff --git a/lib/core/vo/login_user.go b/lib/core/vo/login_user.go index cb32bcc..4f4ae73 100644 --- a/lib/core/vo/login_user.go +++ b/lib/core/vo/login_user.go @@ -23,6 +23,4 @@ type LoginUser struct { // User 用户信息 User dborm.User `json:"user"` - - Session dborm.Session `json:"-"` } diff --git a/lib/core/vo/router.go b/lib/core/vo/router.go deleted file mode 100644 index a3cc408..0000000 --- a/lib/core/vo/router.go +++ /dev/null @@ -1,17 +0,0 @@ -package vo - -// Router 路由信息对象 -type Router struct { - // 路由名字 英文首字母大写 - Name string `json:"name"` - // 路由地址 - Path string `json:"path"` - // 其他元素 - Meta RouterMeta `json:"meta"` - // 组件地址 - Component string `json:"component"` - // 重定向地址 - Redirect string `json:"redirect"` - // 子路由 - Children []Router `json:"children,omitempty"` -} diff --git a/lib/core/vo/router_meta.go b/lib/core/vo/router_meta.go deleted file mode 100644 index b3447e0..0000000 --- a/lib/core/vo/router_meta.go +++ /dev/null @@ -1,17 +0,0 @@ -package vo - -// RouterMeta 路由元信息对象 -type RouterMeta struct { - // 设置该菜单在侧边栏和面包屑中展示的名字 - Title string `json:"title"` - // 设置该菜单的图标 - Icon string `json:"icon"` - // 设置为true,则不会被 缓存 - Cache bool `json:"cache"` - // 内链地址(http(s)://开头), 打开目标位置 '_blank' | '_self' | '' - Target string `json:"target"` - // 在菜单中隐藏子节点 - HideChildInMenu bool `json:"hideChildInMenu"` - // 在菜单中隐藏自己和子节点 - HideInMenu bool `json:"hideInMenu"` -} diff --git a/lib/core/vo/treeselect.go b/lib/core/vo/treeselect.go deleted file mode 100644 index a732e58..0000000 --- a/lib/core/vo/treeselect.go +++ /dev/null @@ -1,36 +0,0 @@ -package vo - -// import sysmenu "nms_cxy/features/sys_menu" - -// TreeSelect 树结构实体类 -type TreeSelect struct { - // ID 节点ID - ID string `json:"id"` - - // Label 节点名称 - Label string `json:"label"` - - // Title 节点名称旧版本layui - Title string `json:"title"` - - // Children 子节点 - Children []TreeSelect `json:"children"` -} - -// // SysMenuTreeSelect 使用给定的 SysMenu 对象解析为 TreeSelect 对象 -// func SysMenuTreeSelect(sysMenu sysmenu.SysMenu) TreeSelect { -// t := TreeSelect{} -// t.ID = sysMenu.MenuID -// t.Label = sysMenu.MenuName - -// if len(sysMenu.Children) > 0 { -// for _, menu := range sysMenu.Children { -// child := SysMenuTreeSelect(menu) -// t.Children = append(t.Children, child) -// } -// } else { -// t.Children = []TreeSelect{} -// } - -// return t -// } diff --git a/lib/dborm/dborm.go b/lib/dborm/dborm.go index 3fd1490..aba81eb 100644 --- a/lib/dborm/dborm.go +++ b/lib/dborm/dborm.go @@ -10,9 +10,9 @@ import ( "strings" - "nms_cxy/features/sys_role/model" "nms_cxy/lib/log" "nms_cxy/lib/oauth" + "nms_cxy/src/modules/system/model" _ "github.com/go-sql-driver/mysql" "xorm.io/xorm" @@ -45,9 +45,9 @@ type DatabaseClient struct { var DbClient DatabaseClient -func InitDbClient(dbType, dbUser, dbPassword, dbHost, dbPort, dbName string) error { - DbClient.dbUrl = fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8mb4&collation=utf8mb4_general_ci&parseTime=true&loc=Local", - dbUser, dbPassword, dbHost, dbPort, dbName) +func InitDbClient(dbType, dbUser, dbPassword, dbHost, dbPort, dbName, dbParam string) error { + DbClient.dbUrl = fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?%s", + dbUser, dbPassword, dbHost, dbPort, dbName, dbParam) DbClient.dbType = dbType DbClient.dbConnMaxLifetime = 0 DbClient.dbMaxIdleConns = 0 @@ -55,8 +55,7 @@ func InitDbClient(dbType, dbUser, dbPassword, dbHost, dbPort, dbName string) err if log.GetLevel() == log.LOG_TRACE { DbClient.IsShowSQL = true } - log.Debugf("dbType:%s dbUrl:%s:******@tcp(%s:%s)/%s??charset=utf8mb4&collation=utf8mb4_general_ci&parseTime=true&loc=Local", - dbType, dbUser, dbHost, dbPort, dbName) + log.Debugf("dbType:%s dbUrl:%s:", dbType, DbClient.dbUrl) var err error DbClient.XEngine, err = xorm.NewEngine(DbClient.dbType, DbClient.dbUrl) @@ -67,9 +66,12 @@ func InitDbClient(dbType, dbUser, dbPassword, dbHost, dbPort, dbName string) err DbClient.XEngine.SetConnMaxLifetime(DbClient.dbConnMaxLifetime) DbClient.XEngine.SetMaxIdleConns(DbClient.dbMaxIdleConns) DbClient.XEngine.SetMaxOpenConns(DbClient.dbMaxOpenConns) + DbClient.XEngine.DatabaseTZ = time.Local // 必须 + DbClient.XEngine.TZLocation = time.Local // 必须 if DbClient.IsShowSQL { DbClient.XEngine.ShowSQL(true) } + xEngine = DbClient.XEngine return nil @@ -180,20 +182,20 @@ func InsertDataWithJson(insertData interface{}) (int64, error) { } type NeInfo struct { - Id int `json:"id" xorm:"pk 'id' autoincr"` - NeType string `json:"neType" xorm:"ne_type"` - NeId string `json:"neId" xorm:"ne_id"` // neUID/rmUID 网元唯一标识 - RmUID string `json:"rmUid" xorm:"rm_uid"` // neUID/rmUID网元UID - NeName string `json:"neName" xorm:"ne_name"` // NeName/UserLabel 网元名称/网元设备友好名称 - Ip string `json:"ip" xorm:"ip"` - Port string `json:"port" xorm:"port"` - PvFlag string `json:"pvFlag" xorm:"pv_flag"` // 网元虚实性标识 VNF/PNF: 虚拟/物理 - NeAddress string `json:"neAddress" xorm:"ne_address"` // 只对PNF - Province string `json:"province" xorm:"province"` // 网元所在省份 - VendorName string `json:"vendorName" xorm:"vendor_name"` // 厂商名称 - Dn string `json:"dn" xorm:"dn"` // 网络标识 - Status int `json:"status" xorm:"status"` - UpdateTime string `json:"-" xorm:"-"` + Id int `json:"id" xorm:"pk 'id' autoincr"` + NeType string `json:"neType" xorm:"ne_type"` + NeId string `json:"neId" xorm:"ne_id"` // neUID/rmUID 网元唯一标识 + RmUID string `json:"rmUid" xorm:"rm_uid"` // neUID/rmUID网元UID + NeName string `json:"neName" xorm:"ne_name"` // NeName/UserLabel 网元名称/网元设备友好名称 + Ip string `json:"ip" xorm:"ip"` + Port string `json:"port" xorm:"port"` + PvFlag string `json:"pvFlag" xorm:"pv_flag"` // 网元虚实性标识 VNF/PNF: 虚拟/物理 + NeAddress string `json:"neAddress" xorm:"ne_address"` // 只对PNF + Province string `json:"province" xorm:"province"` // 网元所在省份 + VendorName string `json:"vendorName" xorm:"vendor_name"` // 厂商名称 + Dn string `json:"dn" xorm:"dn"` // 网络标识 + Status int `json:"status" xorm:"status"` + UpdateTime time.Time `json:"updateTime" xorm:"<-"` } func XormGetMySQLVersion() (string, error) { @@ -1400,11 +1402,11 @@ type MeasureThreshold struct { type NeSoftware struct { Id int `json:"id" xorm:"pk 'id' autoincr"` NeType string `json:"neType" xorm:"ne_type"` - FileName string `json:"neName" xorm:"file_name"` - Path string `json:"path"` - Version string `json:"version"` - Md5Sum string `json:"md5Sum" xorm:"md5_sum"` - Comment string `json:"comment"` + FileName string `json:"fileName" xorm:"name"` + Path string `json:"path" xorm:"path"` + Version string `json:"version" ` + Md5Sum string `json:"md5Sum" xorm:"-"` + Comment string `json:"comment" xorm:"description"` // Status string `json:"status"` UpdateTime string `json:"createTime" xorm:"-" ` } @@ -1413,13 +1415,13 @@ type NeVersion struct { Id int `json:"id" xorm:"pk 'id' autoincr"` NeType string `json:"neType" xorm:"ne_type"` NeId string `json:"neId" xorm:"ne_id"` - Version string `json:"version"` - FilePath string `json:"filePath" xorm:"file_path"` + Version string `json:"version" ` + FilePath string `json:"filePath" xorm:"path"` NewVersion string `json:"newVersion" xorm:"new_version"` - NewFile string `json:"newFile" xorm:"new_file"` + NewFile string `json:"newFile" xorm:"new_path"` PreVersion string `json:"preVersion" xorm:"pre_version"` - PreFile string `json:"preFile" xorm:"pre_file"` - Status string `json:"status"` + PreFile string `json:"preFile" xorm:"pre_path"` + Status string `json:"status" xorm:"status"` UpdateTime string `json:"createTime" xorm:"-" ` } @@ -1451,6 +1453,15 @@ func XormDeleteDataByWhere(where, table string) (int64, error) { return affected, nil } +func XormDeleteDataByWhereNoSession(where, table string) (int64, error) { + affected, err := DbClient.XEngine.Table(table).Where(where).Delete() + if err != nil { + log.Error("Failed to Delete:", err) + return 0, err + } + return affected, nil +} + func XormDeleteDataById(id int, table string) (int64, error) { log.Debug("XormDeleteDataByWhere processing... ") @@ -1632,9 +1643,10 @@ type AlarmForwardLog struct { AlarmTitle string `json:"alarmTitle" xorm:"alarm_title"` AlarmSeq int `json:"alarmSeq" xorm:"alarm_seq"` EventTime string `json:"eventTime" xorm:"event_time"` + Interface string `json:"interface" xorm:"interface"` ToUser string `json:"toUser" xorm:"to_user"` OperResult string `json:"operResult" xorm:"oper_result"` - LogTime string `json:"-" xorm:"-"` + LogTime string `json:"logTime" xorm:"<-"` } func XormInsertAlarmForwardLog(logData *AlarmForwardLog) (int64, error) { @@ -1669,7 +1681,7 @@ func XormInsertSystemLog(logData *SystemLog) (int64, error) { return affected, err } -type permission struct { +type Permission struct { ID int `json:"-" xorm:"pk 'id' autoincr"` PermissionName string `json:"permissionName"` Method string `json:"method"` @@ -1696,25 +1708,26 @@ func IsPermissionAllowed(token, method, module, dbname, tbname, pack string) (bo type NeLicense struct { NeType string `json:"neType" xorm:"ne_type"` NeID string `json:"neID" xorm:"ne_id"` - SerialNo string `json:"serialNo" xorm:"serial_no"` - Capcity int `json:"capcity" xorm:"capcity"` - Used int `json:"used" xorm:"used"` - FeatureEnabled string `json:"featureEnabled" xorm:"feature_enabled"` - ExpirationDate string `json:"expirationDate" xorm:"expiration_date"` + SerialNo string `json:"serialNo" xorm:"serial_num"` + Capcity int `json:"capcity" xorm:"-"` + Used int `json:"used" xorm:"-"` + FeatureEnabled string `json:"featureEnabled" xorm:"-"` + ExpirationDate string `json:"expirationDate" xorm:"expiry_date"` Status string `json:"status" xorm:"status"` - Path string `json:"path" xorm:"path"` - FileName string `json:"file_name" xorm:"file_name"` - Comment string `json:"comment" xorm:"comment"` + Path string `json:"path" xorm:"license_path"` + FileName string `json:"file_name" xorm:"-"` + Comment string `json:"comment" xorm:"remark"` CreatedAt string `json:"createdAt" xorm:"-"` UpdatedAt string `json:"updatedAt" xorm:"-"` DeletedAt string `json:"deletedAt" xorm:"-"` } func XormAdjustmentNeLicense(neType, neID string, value int) (int64, error) { + return 1, nil //neLicense := NeLicense{NeType: neType, NeID: neID, Capability: value} // session.LogoutTime.Valid = true // session.LogoutTime.Time = time.Now() - res, err := xEngine.Exec("update ne_license set capcity=capcity+? where IFNULL(ne_type, '')=? and IFNULL(ne_id, '')=?", value, neType, neID) + // res, err := xEngine.Exec("update ne_license set capcity=capcity+? where IFNULL(ne_type, '')=? and IFNULL(ne_id, '')=?", value, neType, neID) // defer xSession.Close() //affected, err := xSession.Table("ne_license").Where("ne_type=? and ne_id=?", neType, neID).Update(&neLicense) @@ -1722,25 +1735,26 @@ func XormAdjustmentNeLicense(neType, neID string, value int) (int64, error) { // //affected, err := xSession.Table("ne_license").SQL("ne_tye=? and ne_id=?", neType, neID).Update(session) // err := xSession.SQL("update ne_license set capability=capability+? where ne_type=? and ne_id=?", value, neType, neID) //xSession.Commit() - affected, err := res.RowsAffected() - return affected, err + // affected, err := res.RowsAffected() + // return affected, err } func XormUpdateNeLicense(neType, neID string, capcity int) (int64, error) { - var err error - var res sql.Result - if neType != "" && neID != "" { - res, err = xEngine.Exec("update ne_license set capcity=? where ne_type=? and ne_id=?", capcity, neType, neID) - } else if neType != "" && neID == "" { - res, err = xEngine.Exec("update ne_license set capcity=? where ne_type=?", capcity, neType) - } else if neType == "" && neID != "" { - res, err = xEngine.Exec("update ne_license set capcity=? where ne_id=?", capcity, neID) - } else { - res, err = xEngine.Exec("update ne_license set capcity=?", capcity) - } + return 1, nil + // var err error + // var res sql.Result + // if neType != "" && neID != "" { + // res, err = xEngine.Exec("update ne_license set capcity=? where ne_type=? and ne_id=?", capcity, neType, neID) + // } else if neType != "" && neID == "" { + // res, err = xEngine.Exec("update ne_license set capcity=? where ne_type=?", capcity, neType) + // } else if neType == "" && neID != "" { + // res, err = xEngine.Exec("update ne_license set capcity=? where ne_id=?", capcity, neID) + // } else { + // res, err = xEngine.Exec("update ne_license set capcity=?", capcity) + // } - affected, err := res.RowsAffected() - return affected, err + // affected, err := res.RowsAffected() + // return affected, err } type NorthboundCm struct { @@ -1765,21 +1779,21 @@ func XormGetNorthboundCm(neType string, cmResults *[]NorthboundCm) error { log.Info("XormGetNorthboundCm processing... ") cmResult := new(NorthboundCm) - rows, err := xEngine.Table("northbound_cm"). + rows, err := xEngine.Table("nbi_cm"). Distinct("object_type"). Where("`ne_type` = ?", neType). Desc("timestamp"). Cols("*"). Rows(cmResult) if err != nil { - log.Error("Failed to get table northbound_cm:", err) + log.Error("Failed to get table nbi_cm:", err) return err } defer rows.Close() for rows.Next() { err := rows.Scan(cmResult) if err != nil { - log.Error("Failed to get table northbound_cm:", err) + log.Error("Failed to get table nbi_cm:", err) return err } *cmResults = append(*cmResults, *cmResult) @@ -1791,14 +1805,14 @@ func XormGetNorthboundCmLatestObject(neType, neID, objectType string) (*Northbou log.Info("XormGetNorthboundCmLatestObject processing... ") cmResult := new(NorthboundCm) - _, err := xEngine.Table("northbound_cm"). + _, err := xEngine.Table("nbi_cm"). Where("`ne_type`=? and `ne_id`=? and `object_type`=?", neType, neID, objectType). Desc("timestamp"). Cols("*"). Limit(1). Get(cmResult) if err != nil { - log.Error("Failed to get table northbound_cm:", err) + log.Error("Failed to get table nbi_cm:", err) return nil, err } diff --git a/lib/global/kits.go b/lib/global/kits.go index 593f18c..22091f0 100644 --- a/lib/global/kits.go +++ b/lib/global/kits.go @@ -696,3 +696,33 @@ func IsRpmOrDebPackage(filePath string) int { return fileType } + +func RecurseStructToMap(obj any) map[string]any { + out := make(map[string]any) + v := reflect.ValueOf(obj) + if v.Kind() == reflect.Ptr { + v = v.Elem() + } + + // 递归函数,用于处理嵌套结构体 + var recurse func(reflect.Value) any + recurse = func(value reflect.Value) any { + if value.Kind() == reflect.Struct { + nestedOut := make(map[string]any) + for i := 0; i < value.NumField(); i++ { + nestedOut[value.Type().Field(i).Name] = recurse(value.Field(i)) + } + return nestedOut + } else if value.Kind() == reflect.Ptr { + return recurse(value.Elem()) + } + return value.Interface() + } + + t := v.Type() + for i := 0; i < v.NumField(); i++ { + f := v.Field(i) + out[t.Field(i).Name] = recurse(f) + } + return out +} diff --git a/lib/midware/arrow_ip_addr.go b/lib/midware/arrow_ip_addr.go deleted file mode 100644 index 2e538ba..0000000 --- a/lib/midware/arrow_ip_addr.go +++ /dev/null @@ -1,77 +0,0 @@ -package midware - -import ( - "encoding/json" - "net/http" - "strings" - "time" - - "nms_cxy/lib/dborm" - "nms_cxy/lib/services" -) - -// 登录策略限制登录时间和访问ip范围 -func ArrowIPAddr(next http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - ipAddr := strings.Split(r.RemoteAddr, ":")[0] - - // 读取配置信息 登录策略设置 - result, err := dborm.XormGetConfig("Security", "loginSecurity") - if err != nil { - next.ServeHTTP(w, r) - return - } - data := make(map[string]any) - err = json.Unmarshal([]byte(result["value_json"].(string)), &data) - if err != nil { - next.ServeHTTP(w, r) - return - } - - // 开关 - switchStr := data["switch"].(string) - if switchStr == "0" { - next.ServeHTTP(w, r) - return - } - - ipRange := data["ipRange"].(string) - logintimeRange := data["logintime_range"].(string) - - // 检查ip - ips := strings.Split(ipRange, "/") - hasIP := false - for _, ip := range ips { - if ipAddr == ip { - hasIP = true - } - } - if !hasIP { - services.ResponseErrorWithJson(w, 502, "网关登录策略-IP限制: "+ipAddr) - return - } - - // 检查开放时间 - logintimeRangeArr := strings.Split(logintimeRange, " - ") - - // 加载中国时区 - loc, _ := time.LoadLocation("Asia/Shanghai") - // 获取当前时间 - currentTime := time.Now().In(loc) - - // 获取当前日期 - currentDate := time.Date(currentTime.Year(), currentTime.Month(), currentTime.Day(), 0, 0, 0, 0, currentTime.Location()) - ymd := currentDate.Format("2006-01-02") - - // 定义开始时间和结束时间 - startTime, _ := time.ParseInLocation("2006-01-02 15:04:05", ymd+" "+logintimeRangeArr[0], loc) - endTime, _ := time.ParseInLocation("2006-01-02 15:04:05", ymd+" "+logintimeRangeArr[1], loc) - - // 判断当前时间是否在范围内 - if currentTime.After(startTime) && currentTime.Before(endTime) { - next.ServeHTTP(w, r) - } else { - services.ResponseErrorWithJson(w, 502, "网关登录策略-不在开放时间范围内") - } - }) -} diff --git a/lib/midware/authorize.go b/lib/midware/authorize.go deleted file mode 100644 index d76dd02..0000000 --- a/lib/midware/authorize.go +++ /dev/null @@ -1,228 +0,0 @@ -package midware - -import ( - "context" - "fmt" - "net/http" - - "nms_cxy/lib/core/cache" - "nms_cxy/lib/core/utils/ctx" - "nms_cxy/lib/core/vo" - "nms_cxy/lib/core/vo/result" - "nms_cxy/lib/dborm" - commonConstants "nms_cxy/src/framework/constants/common" - tokenUtils "nms_cxy/src/framework/utils/token" -) - -// Authorize 用户身份授权认证校验 -// -// 只需含有其中角色 "hasRoles": {"xxx"}, -// -// 只需含有其中权限 "hasPerms": {"xxx"}, -// -// 同时匹配其中角色 "matchRoles": {"xxx"}, -// -// 同时匹配其中权限 "matchPerms": {"xxx"}, -func Authorize(options map[string][]string) func(http.Handler) http.Handler { - return func(next http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - // 获取请求头标识信息 - tokenStr := ctx.Authorization(r) - // 获取请求头标识信息-旧头 - accessToken := r.Header.Get("AccessToken") - if tokenStr == "" && accessToken != "" { - // 验证令牌 == 这里直接查数据库session - if !dborm.XormExistValidToken(accessToken, 0) { - ctx.JSON(w, 401, result.CodeMsg(401, "Invalid identity authorization valid error")) - return - } - se, err := dborm.XormUpdateSessionShakeTime(accessToken) - if err != nil { - ctx.JSON(w, 401, result.CodeMsg(401, "Invalid identity authorization shake error")) - return - } - - // 获取缓存的用户信息 - data, ok := cache.GetLocalTTL(se.AccountId) - if data == nil || !ok { - ctx.JSON(w, 401, result.CodeMsg(401, "Invalid identity authorization info error")) - return - } - loginUser := data.(vo.LoginUser) - - // 登录用户角色权限校验 - if options != nil { - var roles []string - for _, item := range loginUser.User.Roles { - roles = append(roles, item.RoleKey) - } - perms := loginUser.Permissions - verifyOk := verifyRolePermission(roles, perms, options) - if !verifyOk { - msg := fmt.Sprintf("Unauthorized access %s %s", r.Method, r.RequestURI) - ctx.JSON(w, 403, result.CodeMsg(403, msg)) - return - } - } - - // 在请求的 Context 中存储数据 - rContext := r.Context() - rContext = context.WithValue(rContext, ctx.ContextKey(commonConstants.CTX_LOGIN_USER), loginUser) - // 继续处理请求 - next.ServeHTTP(w, r.WithContext(rContext)) - return - } - - // 获取请求头标识信息 - if tokenStr == "" { - ctx.JSON(w, 401, result.CodeMsg(401, "Invalid identity authorization token error")) - return - } - - // 验证令牌 - claims, err := tokenUtils.Verify(tokenStr) - if err != nil { - ctx.JSON(w, 401, result.CodeMsg(401, "Invalid identity authorization valid error")) - return - } - - // 获取缓存的用户信息 - loginUser := tokenUtils.LoginUser(claims) - if loginUser.UserID == "" { - ctx.JSON(w, 401, result.CodeMsg(401, "Invalid identity authorization shake error")) - return - } - - // 检查刷新有效期后存入上下文 - tokenUtils.RefreshIn(&loginUser) - - // 登录用户角色权限校验 - if options != nil { - var roles []string - for _, item := range loginUser.User.Roles { - roles = append(roles, item.RoleKey) - } - perms := loginUser.Permissions - verifyOk := verifyRolePermission(roles, perms, options) - if !verifyOk { - msg := fmt.Sprintf("Unauthorized access %s %s", r.Method, r.RequestURI) - ctx.JSON(w, 403, result.CodeMsg(403, msg)) - return - } - } - - // 在请求的 Context 中存储数据 - rContext := r.Context() - rContext = context.WithValue(rContext, ctx.ContextKey(commonConstants.CTX_LOGIN_USER), loginUser) - // 继续处理请求 - next.ServeHTTP(w, r.WithContext(rContext)) - }) - } -} - -// verifyRolePermission 校验角色权限是否满足 -// -// roles 角色字符数组 -// -// perms 权限字符数组 -// -// options 参数 -func verifyRolePermission(roles, perms []string, options map[string][]string) bool { - // 直接放行 管理员角色或任意权限 - if contains(roles, "admin") || contains(perms, "*:*:*") { - return true - } - opts := make([]bool, 4) - - // 只需含有其中角色 - hasRole := false - if arr, ok := options["hasRoles"]; ok && len(arr) > 0 { - hasRole = some(roles, arr) - opts[0] = true - } - - // 只需含有其中权限 - hasPerms := false - if arr, ok := options["hasPerms"]; ok && len(arr) > 0 { - hasPerms = some(perms, arr) - opts[1] = true - } - - // 同时匹配其中角色 - matchRoles := false - if arr, ok := options["matchRoles"]; ok && len(arr) > 0 { - matchRoles = every(roles, arr) - opts[2] = true - } - - // 同时匹配其中权限 - matchPerms := false - if arr, ok := options["matchPerms"]; ok && len(arr) > 0 { - matchPerms = every(perms, arr) - opts[3] = true - } - - // 同时判断 含有其中 - if opts[0] && opts[1] { - return hasRole || hasPerms - } - // 同时判断 匹配其中 - if opts[2] && opts[3] { - return matchRoles && matchPerms - } - // 同时判断 含有其中且匹配其中 - if opts[0] && opts[3] { - return hasRole && matchPerms - } - if opts[1] && opts[2] { - return hasPerms && matchRoles - } - - return hasRole || hasPerms || matchRoles || matchPerms -} - -// contains 检查字符串数组中是否包含指定的字符串 -func contains(arr []string, target string) bool { - for _, str := range arr { - if str == target { - return true - } - } - return false -} - -// some 检查字符串数组中含有其中一项 -func some(origin []string, target []string) bool { - has := false - for _, t := range target { - for _, o := range origin { - if t == o { - has = true - break - } - } - if has { - break - } - } - return has -} - -// every 检查字符串数组中同时包含所有项 -func every(origin []string, target []string) bool { - match := true - for _, t := range target { - found := false - for _, o := range origin { - if t == o { - found = true - break - } - } - if !found { - match = false - break - } - } - return match -} diff --git a/lib/midware/cors.go b/lib/midware/cors.go deleted file mode 100644 index b0a73ad..0000000 --- a/lib/midware/cors.go +++ /dev/null @@ -1,66 +0,0 @@ -package midware - -import ( - "net/http" - "strings" -) - -// Cors 跨域 -func Cors(next http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - // 设置Vary头部 - w.Header().Set("Vary", "Origin") - w.Header().Set("Keep-Alive", "timeout=5") - - requestOrigin := r.Header.Get("Origin") - if requestOrigin == "" { - next.ServeHTTP(w, r) - return - } - - w.Header().Set("Access-Control-Allow-Origin", "*") - - w.Header().Set("Access-Control-Allow-Credentials", "true") - - // OPTIONS - if r.Method == "OPTIONS" { - requestMethod := r.Header.Get("Access-Control-Request-Method") - if requestMethod == "" { - next.ServeHTTP(w, r) - return - } - - // 响应最大时间值 - w.Header().Set("Access-Control-Max-Age", "31536000") - - // 允许方法 - allowMethods := []string{ - "OPTIONS", - "HEAD", - "GET", - "POST", - "PUT", - "DELETE", - "PATCH", - } - w.Header().Set("Access-Control-Allow-Methods", strings.Join(allowMethods, ",")) - - // 允许请求头 - allowHeaders := []string{ - "Accesstoken", - "Content-Type", - "operationtype", - } - w.Header().Set("Access-Control-Allow-Headers", strings.Join(allowHeaders, ",")) - - w.WriteHeader(204) - return - } - - // 暴露请求头 - exposeHeaders := []string{"X-RepeatSubmit-Rest", "AccessToken"} - w.Header().Set("Access-Control-Expose-Headers", strings.Join(exposeHeaders, ",")) - - next.ServeHTTP(w, r) - }) -} diff --git a/lib/midware/mml_log.go b/lib/midware/mml_log.go index f3c7614..2bb8c28 100644 --- a/lib/midware/mml_log.go +++ b/lib/midware/mml_log.go @@ -9,11 +9,10 @@ import ( "strings" "time" - "nms_cxy/lib/core/datasource" - "nms_cxy/lib/core/utils/ctx" - "nms_cxy/lib/core/utils/date" - "nms_cxy/lib/dborm" + "nms_cxy/lib/core/ctx" "nms_cxy/lib/log" + "nms_cxy/src/framework/datasource" + "nms_cxy/src/framework/utils/date" ) // LogMML mml操作日志搜集 @@ -37,7 +36,7 @@ func LogMML(next http.Handler) http.Handler { // 收尾存入数据库的参数 mmlCmd := bodyArgs["mml"].([]any)[0] ipAddr := strings.Split(r.RemoteAddr, ":")[0] - neType := ctx.Param(r, "elementTypeValue") + neType := ctx.GetParam(r, "elementTypeValue") neId := ctx.GetQuery(r, "ne_id") timeStr := date.ParseDateToStr(time.Now(), date.YYYY_MM_DD_HH_MM_SS) @@ -50,19 +49,12 @@ func LogMML(next http.Handler) http.Handler { resultStr := fmt.Sprintf(`{"status":"%s","size":"%s","content-type":"%s"}`, status, size, contentType) // 用户名 - username := "-" - accessToken := r.Header.Get("AccessToken") - if accessToken != "" { - // 验证令牌 == 这里直接查数据库session - se, _ := dborm.XormUpdateSessionShakeTime(accessToken) - username = se.AccountId - } - + username := ctx.LoginUserToUserName(r) // 执行插入 sql := "insert into mml_log (user,ip,ne_type,ne_id,mml,result,log_time)values(?,?,?,?,?,?,?)" _, sqlerr := datasource.ExecDB("", sql, []any{username, ipAddr, neType, neId, mmlCmd, resultStr, timeStr}) if sqlerr != nil { - log.Errorf("insert row : %v", err.Error()) + log.Errorf("insert row : %v", sqlerr.Error()) } }) } diff --git a/lib/midware/operate_log.go b/lib/midware/operate_log.go index 8cfedf5..f780b24 100644 --- a/lib/midware/operate_log.go +++ b/lib/midware/operate_log.go @@ -11,11 +11,11 @@ import ( "strings" "time" - "nms_cxy/lib/core/utils/parse" - "nms_cxy/lib/dborm" + "nms_cxy/lib/core/ctx" "nms_cxy/src/framework/constants/common" "nms_cxy/src/framework/middleware/collectlogs" "nms_cxy/src/framework/utils/ip2region" + "nms_cxy/src/framework/utils/parse" "nms_cxy/src/modules/system/model" "nms_cxy/src/modules/system/service" ) @@ -47,13 +47,7 @@ func LogOperate(options collectlogs.Options) func(http.Handler) http.Handler { funcName = funcName[lastDotIndex+1:] // 用户名 - username := "-" - accessToken := r.Header.Get("AccessToken") - if accessToken != "" { - // 验证令牌 == 这里直接查数据库session - se, _ := dborm.XormUpdateSessionShakeTime(accessToken) - username = se.AccountId - } + username := ctx.LoginUserToUserName(r) // 解析ip地址 ip := strings.Split(r.RemoteAddr, ":")[0] diff --git a/lib/routes/routes.go b/lib/routes/routes.go index 7500ffe..83e938f 100644 --- a/lib/routes/routes.go +++ b/lib/routes/routes.go @@ -9,25 +9,16 @@ import ( "nms_cxy/features/cdr" "nms_cxy/features/cm" "nms_cxy/features/dbrest" + "nms_cxy/features/event" "nms_cxy/features/file" "nms_cxy/features/fm" "nms_cxy/features/lm" "nms_cxy/features/mml" - "nms_cxy/features/monitor/monitor" - "nms_cxy/features/monitor/psnet" - "nms_cxy/features/nbi" "nms_cxy/features/pm" "nms_cxy/features/security" "nms_cxy/features/sm" "nms_cxy/features/state" - sysconfig "nms_cxy/features/sys_config" - sysdictdata "nms_cxy/features/sys_dict_data" - sysdicttype "nms_cxy/features/sys_dict_type" - sysmenu "nms_cxy/features/sys_menu" - sysrole "nms_cxy/features/sys_role" - sysuser "nms_cxy/features/sys_user" "nms_cxy/features/trace" - udmuser "nms_cxy/features/udm_user" "nms_cxy/features/ue" "nms_cxy/lib/midware" "nms_cxy/lib/services" @@ -174,16 +165,16 @@ func init() { Register("POST", mml.UriMML, mml.PostMMLToNF, midware.LogMML) Register("POST", mml.UriMMLDiscard, mml.PostMMLToNF, nil) Register("POST", mml.UriOmMmlExt, mml.PostMMLToOMC, midware.LogMML) - Register("POST", mml.CustomUriMML, mml.PostMMLToNF, midware.LogMML) - Register("POST", mml.CustomUriOmMmlExt, mml.PostMMLToOMC, midware.LogMML) + Register("POST", mml.CustomUriMML, mml.PostMMLToNF, nil) + Register("POST", mml.CustomUriOmMmlExt, mml.PostMMLToOMC, nil) // post mml2 (standard upf port=5002) Register("POST", mml.UriMML2, mml.PostMML2ToNF, midware.LogMML) - Register("POST", mml.CustomUriMML2, mml.PostMML2ToNF, midware.LogMML) + Register("POST", mml.CustomUriMML2, mml.PostMML2ToNF, nil) // Northbound Get NRM - Register("GET", nbi.GetNRMUri, nbi.NBIGetNRMFromNF, nil) + // Register("GET", nbi.GetNRMUri, nbi.NBIGetNRMFromNF, nil) - Register("GET", nbi.CustomGetNRMUri, nbi.NBIGetNRMFromNF, nil) + // Register("GET", nbi.CustomGetNRMUri, nbi.NBIGetNRMFromNF, nil) // Import/Export NF CM Register("GET", cm.NeCmUri, cm.ExportCmFromNF, nil) @@ -233,16 +224,6 @@ func init() { Register("PUT", trace.CustomUriTraceTask, trace.PutTraceTaskToNF, nil) Register("DELETE", trace.CustomUriTraceTask, trace.DeleteTraceTaskToNF, nil) - // 网元发送执行 pcap抓包任务 - Register("POST", trace.UriTcpdumpTask, trace.TcpdumpNeTask, midware.LogOperate(collectlogs.OptionNew("Packet Capturing Task", collectlogs.BUSINESS_TYPE_INSERT))) - Register("POST", trace.CustomUriTcpdumpTask, trace.TcpdumpNeTask, midware.LogOperate(collectlogs.OptionNew("Packet Capturing Task", collectlogs.BUSINESS_TYPE_INSERT))) - // 网元发送执行 抓包下载pcap文件 - Register("POST", trace.UriTcpdumpPcapDownload, trace.TcpdumpPcapDownload, midware.LogOperate(collectlogs.OptionNew("Packet Capturing Task", collectlogs.BUSINESS_TYPE_EXPORT))) - Register("POST", trace.CustomUriTcpdumpPcapDownload, trace.TcpdumpPcapDownload, midware.LogOperate(collectlogs.OptionNew("Packet Capturing Task", collectlogs.BUSINESS_TYPE_EXPORT))) - // 网元发送执行UPF pcap抓包 - Register("POST", trace.UriTcpdumpNeUPFTask, trace.TcpdumpNeUPFTask, midware.LogOperate(collectlogs.OptionNew("Packet Capturing Task", collectlogs.BUSINESS_TYPE_INSERT))) - Register("POST", trace.CustomUriTcpdumpNeUPFTask, trace.TcpdumpNeUPFTask, midware.LogOperate(collectlogs.OptionNew("Packet Capturing Task", collectlogs.BUSINESS_TYPE_INSERT))) - // file management Register("POST", file.UriFile, file.UploadFile, midware.LogOperate(collectlogs.OptionNew("File", collectlogs.BUSINESS_TYPE_INSERT))) Register("GET", file.UriFile, file.DownloadFile, midware.LogOperate(collectlogs.OptionNew("File", collectlogs.BUSINESS_TYPE_OTHER))) @@ -280,9 +261,7 @@ func init() { Register("DELETE", ue.CustomUriPCFUserM, ue.DeletePCFUserInfo, nil) //PCF User file Register("GET", ue.UriPCFUserFileExport, ue.GetUEInfoFileExportNF, nil) - Register("GET", ue.CustomUriPCFUserFileExport, ue.GetUEInfoFromNF, nil) Register("PUT", ue.UriPCFUserFileImport, ue.PutPCFUserInfo, nil) - Register("PUT", ue.CustomUriPCFUserFileImport, ue.PutPCFUserInfo, nil) // UE Number Register("GET", ue.UriUENum, ue.GetUENumFromNF, nil) @@ -300,23 +279,20 @@ func init() { Register("GET", ue.UriNSSFSubscriptions, ue.GetSubscriptionsFromNSSF, nil) Register("GET", ue.CustomUriNSSFSubscriptions, ue.GetSubscriptionsFromNSSF, nil) - Register("POST", cdr.UriCDREvent, cdr.PostCDREventFromNF, nil) - Register("POST", cdr.CustomUriCDREvent, cdr.PostCDREventFromNF, nil) + // ims cdr event + Register("POST", cdr.UriIMSCDREvent, cdr.PostCDREventFromIMS, nil) + Register("POST", cdr.CustomUriIMSCDREvent, cdr.PostCDREventFromIMS, nil) - // UE event + // smf cdr event + Register("POST", cdr.UriSMFCDREvent, cdr.PostCDREventFromSMF, nil) + Register("POST", cdr.CustomUriSMFCDREvent, cdr.PostCDREventFromSMF, nil) + + // UE event 上报的UE事件 + Register("POST", event.UriUEEvent, event.PostUEEvent, nil) + + // UE event AMF上报的UE事件, 无前缀给到Gin处理 //Register("POST", event.UriUEEvent, event.PostUEEventFromAMF, nil) - // 进程网络 - Register("GET", psnet.UriWs, psnet.ProcessWs, nil) - Register("POST", psnet.UriStop, psnet.StopProcess, nil) - Register("POST", psnet.UriPing, psnet.Ping, nil) - - // 主机CPU内存监控 - Register("POST", monitor.UriLoad, monitor.LoadMonitor, nil) - Register("GET", monitor.UriNetOpt, monitor.Netoptions, nil) - Register("GET", monitor.UriIPAddr, monitor.IPAddr, nil) - Register("GET", monitor.UriIoOpt, monitor.Iooptions, nil) - // 文件资源 Register("GET", file.UriDiskList, file.DiskList, nil) Register("POST", file.UriListFiles, file.ListFiles, nil) @@ -337,56 +313,6 @@ func init() { Register("POST", lm.ExtBackupDataUri, lm.ExtDatabaseBackupData, nil) Register("POST", lm.CustomExtBackupDataUri, lm.ExtDatabaseBackupData, nil) - // 系统登录 - Register("POST", security.UriLogin, security.LoginOMC, nil) - Register("POST", security.CustomUriLogin, security.LoginOMC, nil) - - // 获取验证码 - Register("GET", security.UriCaptchaImage, security.CaptchaImage, nil) - Register("GET", security.CustomUriCaptchaImage, security.CaptchaImage, nil) - - // 登录用户信息 - Register("GET", security.UriUserInfo, security.UserInfo, midware.Authorize(nil)) - Register("GET", security.CustomUriUserInfo, security.UserInfo, midware.Authorize(nil)) - - // 登录用户路由信息 - Register("GET", security.UriRouters, security.Routers, midware.Authorize(nil)) - Register("GET", security.CustomUriRouters, security.Routers, midware.Authorize(nil)) - - // 参数配置信息接口添加到路由 - for _, v := range sysconfig.Routers() { - Register(v.Method, v.Pattern, v.Handler, v.Middleware) - } - - // 字典类型信息接口添加到路由 - for _, v := range sysdicttype.Routers() { - Register(v.Method, v.Pattern, v.Handler, v.Middleware) - } - - // 字典类型对应的字典数据信息接口添加到路由 - for _, v := range sysdictdata.Routers() { - Register(v.Method, v.Pattern, v.Handler, v.Middleware) - } - - // 菜单接口添加到路由 - for _, v := range sysmenu.Routers() { - Register(v.Method, v.Pattern, v.Handler, v.Middleware) - } - - // 角色接口添加到路由 - for _, v := range sysrole.Routers() { - Register(v.Method, v.Pattern, v.Handler, v.Middleware) - } - - // 用户接口添加到路由 - for _, v := range sysuser.Routers() { - Register(v.Method, v.Pattern, v.Handler, v.Middleware) - } - - // UDM 用户信息接口添加到路由 - for _, v := range udmuser.Routers() { - Register(v.Method, v.Pattern, v.Handler, v.Middleware) - } } // To resolv rest POST/PUT/DELETE/PATCH cross domain diff --git a/lib/wsinfo/client.go b/lib/wsinfo/client.go deleted file mode 100644 index 36201cd..0000000 --- a/lib/wsinfo/client.go +++ /dev/null @@ -1,45 +0,0 @@ -package wsinfo - -import ( - "github.com/gorilla/websocket" -) - -type Client struct { - ID string - Socket *websocket.Conn - Msg chan []byte -} - -func NewWsClient(ID string, socket *websocket.Conn) *Client { - return &Client{ - ID: ID, - Socket: socket, - Msg: make(chan []byte, 100), - } -} - -func (c *Client) Read() { - defer func() { - close(c.Msg) - }() - for { - _, message, err := c.Socket.ReadMessage() - if err != nil { - return - } - ProcessData(c, message) - } -} - -func (c *Client) Write() { - defer func() { - c.Socket.Close() - }() - for { - message, ok := <-c.Msg - if !ok { - return - } - _ = c.Socket.WriteMessage(websocket.TextMessage, message) - } -} diff --git a/lib/wsinfo/process_data.go b/lib/wsinfo/process_data.go deleted file mode 100644 index 4bc4a01..0000000 --- a/lib/wsinfo/process_data.go +++ /dev/null @@ -1,383 +0,0 @@ -package wsinfo - -import ( - "encoding/json" - "fmt" - "sort" - "strings" - "sync" - "time" - - "nms_cxy/lib/log" - - "github.com/shirou/gopsutil/v3/host" - "github.com/shirou/gopsutil/v3/net" - "github.com/shirou/gopsutil/v3/process" -) - -type WsInput struct { - Type string `json:"type"` - DownloadProgress - PsProcessConfig - SSHSessionConfig - NetConfig -} - -type DownloadProgress struct { - Keys []string `json:"keys"` -} - -type PsProcessConfig struct { - Pid int32 `json:"pid"` - Name string `json:"name"` - Username string `json:"username"` -} - -type SSHSessionConfig struct { - LoginUser string `json:"loginUser"` - LoginIP string `json:"loginIP"` -} - -type NetConfig struct { - Port uint32 `json:"port"` - ProcessName string `json:"processName"` - ProcessID int32 `json:"processID"` -} - -type PsProcessData struct { - PID int32 `json:"PID"` - Name string `json:"name"` - PPID int32 `json:"PPID"` - Username string `json:"username"` - Status string `json:"status"` - StartTime string `json:"startTime"` - NumThreads int32 `json:"numThreads"` - NumConnections int `json:"numConnections"` - CpuPercent string `json:"cpuPercent"` - - DiskRead string `json:"diskRead"` - DiskWrite string `json:"diskWrite"` - CmdLine string `json:"cmdLine"` - - Rss string `json:"rss"` - VMS string `json:"vms"` - HWM string `json:"hwm"` - Data string `json:"data"` - Stack string `json:"stack"` - Locked string `json:"locked"` - Swap string `json:"swap"` - - CpuValue float64 `json:"cpuValue"` - RssValue uint64 `json:"rssValue"` - - Envs []string `json:"envs"` - - OpenFiles []process.OpenFilesStat `json:"openFiles"` - Connects []processConnect `json:"connects"` -} - -type processConnect struct { - Type string `json:"type"` - Status string `json:"status"` - Laddr net.Addr `json:"localaddr"` - Raddr net.Addr `json:"remoteaddr"` - PID int32 `json:"PID"` - Name string `json:"name"` -} - -type ProcessConnects []processConnect - -func (p ProcessConnects) Len() int { - return len(p) -} - -func (p ProcessConnects) Less(i, j int) bool { - return p[i].PID < p[j].PID -} - -func (p ProcessConnects) Swap(i, j int) { - p[i], p[j] = p[j], p[i] -} - -type sshSession struct { - Username string `json:"username"` - PID int32 `json:"PID"` - Terminal string `json:"terminal"` - Host string `json:"host"` - LoginTime string `json:"loginTime"` -} - -func ProcessData(c *Client, inputMsg []byte) { - wsInput := &WsInput{} - err := json.Unmarshal(inputMsg, wsInput) - if err != nil { - log.Errorf("unmarshal wsInput error,err %s", err.Error()) - return - } - switch wsInput.Type { - case "ps": - res, err := getProcessData(wsInput.PsProcessConfig) - if err != nil { - return - } - c.Msg <- res - case "ssh": - res, err := getSSHSessions(wsInput.SSHSessionConfig) - if err != nil { - return - } - c.Msg <- res - case "net": - res, err := getNetConnections(wsInput.NetConfig) - if err != nil { - return - } - c.Msg <- res - } - -} - -type Process struct { - Total uint64 `json:"total"` - Written uint64 `json:"written"` - Percent float64 `json:"percent"` - Name string `json:"name"` -} - -const ( - b = uint64(1) - kb = 1024 * b - mb = 1024 * kb - gb = 1024 * mb -) - -func formatBytes(bytes uint64) string { - switch { - case bytes < kb: - return fmt.Sprintf("%dB", bytes) - case bytes < mb: - return fmt.Sprintf("%.2fKB", float64(bytes)/float64(kb)) - case bytes < gb: - return fmt.Sprintf("%.2fMB", float64(bytes)/float64(mb)) - default: - return fmt.Sprintf("%.2fGB", float64(bytes)/float64(gb)) - } -} - -func getProcessData(processConfig PsProcessConfig) (res []byte, err error) { - var processes []*process.Process - processes, err = process.Processes() - if err != nil { - return - } - - var ( - result []PsProcessData - resultMutex sync.Mutex - wg sync.WaitGroup - numWorkers = 4 - ) - - handleData := func(proc *process.Process) { - procData := PsProcessData{ - PID: proc.Pid, - } - if processConfig.Pid > 0 && processConfig.Pid != proc.Pid { - return - } - if procName, err := proc.Name(); err == nil { - procData.Name = procName - } else { - procData.Name = "" - } - if processConfig.Name != "" && !strings.Contains(procData.Name, processConfig.Name) { - return - } - if username, err := proc.Username(); err == nil { - procData.Username = username - } - if processConfig.Username != "" && !strings.Contains(procData.Username, processConfig.Username) { - return - } - procData.PPID, _ = proc.Ppid() - statusArray, _ := proc.Status() - if len(statusArray) > 0 { - procData.Status = strings.Join(statusArray, ",") - } - createTime, procErr := proc.CreateTime() - if procErr == nil { - t := time.Unix(createTime/1000, 0) - procData.StartTime = t.Format("2006-1-2 15:04:05") - } - procData.NumThreads, _ = proc.NumThreads() - connections, procErr := proc.Connections() - if procErr == nil { - procData.NumConnections = len(connections) - for _, conn := range connections { - if conn.Laddr.IP != "" || conn.Raddr.IP != "" { - procData.Connects = append(procData.Connects, processConnect{ - Status: conn.Status, - Laddr: conn.Laddr, - Raddr: conn.Raddr, - }) - } - } - } - procData.CpuValue, _ = proc.CPUPercent() - procData.CpuPercent = fmt.Sprintf("%.2f", procData.CpuValue) + "%" - menInfo, procErr := proc.MemoryInfo() - if procErr == nil { - procData.Rss = formatBytes(menInfo.RSS) - procData.RssValue = menInfo.RSS - procData.Data = formatBytes(menInfo.Data) - procData.VMS = formatBytes(menInfo.VMS) - procData.HWM = formatBytes(menInfo.HWM) - procData.Stack = formatBytes(menInfo.Stack) - procData.Locked = formatBytes(menInfo.Locked) - procData.Swap = formatBytes(menInfo.Swap) - } else { - procData.Rss = "--" - procData.Data = "--" - procData.VMS = "--" - procData.HWM = "--" - procData.Stack = "--" - procData.Locked = "--" - procData.Swap = "--" - - procData.RssValue = 0 - } - ioStat, procErr := proc.IOCounters() - if procErr == nil { - procData.DiskWrite = formatBytes(ioStat.WriteBytes) - procData.DiskRead = formatBytes(ioStat.ReadBytes) - } else { - procData.DiskWrite = "--" - procData.DiskRead = "--" - } - procData.CmdLine, _ = proc.Cmdline() - procData.OpenFiles, _ = proc.OpenFiles() - procData.Envs, _ = proc.Environ() - - resultMutex.Lock() - result = append(result, procData) - resultMutex.Unlock() - } - - chunkSize := (len(processes) + numWorkers - 1) / numWorkers - for i := 0; i < numWorkers; i++ { - wg.Add(1) - start := i * chunkSize - end := (i + 1) * chunkSize - if end > len(processes) { - end = len(processes) - } - - go func(start, end int) { - defer wg.Done() - for j := start; j < end; j++ { - handleData(processes[j]) - } - }(start, end) - } - - wg.Wait() - - sort.Slice(result, func(i, j int) bool { - return result[i].PID < result[j].PID - }) - res, err = json.Marshal(result) - return -} - -func getSSHSessions(config SSHSessionConfig) (res []byte, err error) { - var ( - result []sshSession - users []host.UserStat - processes []*process.Process - ) - processes, err = process.Processes() - if err != nil { - return - } - users, err = host.Users() - if err != nil { - return - } - for _, proc := range processes { - name, _ := proc.Name() - if name != "sshd" || proc.Pid == 0 { - continue - } - connections, _ := proc.Connections() - for _, conn := range connections { - for _, user := range users { - if user.Host == "" { - continue - } - if conn.Raddr.IP == user.Host { - if config.LoginUser != "" && !strings.Contains(user.User, config.LoginUser) { - continue - } - if config.LoginIP != "" && !strings.Contains(user.Host, config.LoginIP) { - continue - } - if terminal, err := proc.Cmdline(); err == nil { - if strings.Contains(terminal, user.Terminal) { - session := sshSession{ - Username: user.User, - Host: user.Host, - Terminal: user.Terminal, - PID: proc.Pid, - } - t := time.Unix(int64(user.Started), 0) - session.LoginTime = t.Format("2006-1-2 15:04:05") - result = append(result, session) - } - } - } - } - } - } - res, err = json.Marshal(result) - return -} - -var netTypes = [...]string{"tcp", "udp"} - -func getNetConnections(config NetConfig) (res []byte, err error) { - var ( - result []processConnect - proc *process.Process - ) - for _, netType := range netTypes { - connections, _ := net.Connections(netType) - if err == nil { - for _, conn := range connections { - if config.ProcessID > 0 && config.ProcessID != conn.Pid { - continue - } - proc, err = process.NewProcess(conn.Pid) - if err == nil { - name, _ := proc.Name() - if name != "" && config.ProcessName != "" && !strings.Contains(name, config.ProcessName) { - continue - } - if config.Port > 0 && config.Port != conn.Laddr.Port && config.Port != conn.Raddr.Port { - continue - } - result = append(result, processConnect{ - Type: netType, - Status: conn.Status, - Laddr: conn.Laddr, - Raddr: conn.Raddr, - PID: conn.Pid, - Name: name, - }) - } - - } - } - } - res, err = json.Marshal(result) - return -} diff --git a/omc/config/config.go b/omc/config/config.go index 63e5f6b..e3cd20d 100644 --- a/omc/config/config.go +++ b/omc/config/config.go @@ -2,24 +2,15 @@ package config import ( "fmt" - "nms_cxy/lib/global" - "nms_cxy/lib/log" "os" "strings" + "nms_cxy/lib/global" + "nms_cxy/lib/log" + "gopkg.in/yaml.v3" ) -type DbConfig struct { - Type string `yaml:"type"` - User string `yaml:"user"` - Password string `yaml:"password"` - Host string `yaml:"host"` - Port string `yaml:"port"` - Name string `yaml:"name"` - Backup string `yaml:"backup"` -} - // Yaml struct of config type YamlConfig struct { Logger struct { @@ -29,16 +20,23 @@ type YamlConfig struct { Count int `yaml:"count"` } `yaml:"logger"` - Rest []struct { - IPv4 string `yaml:"ipv4"` - IPv6 string `yaml:"ipv6"` - Port uint16 `yaml:"port"` - Scheme string `yaml:"scheme"` - ClientAuthType int `yaml:"clientAuthType"` - CaFile string `yaml:"caFile"` - CertFile string `yaml:"certFile"` - KeyFile string `yaml:"keyFile"` - } `yaml:"rest"` + Pprof struct { + Enabled bool `yaml:"enabled"` + Addr string `yaml:"addr"` + } `yaml:"pprof"` + + // Rest []struct { + // IPv4 string `yaml:"ipv4"` + // IPv6 string `yaml:"ipv6"` + // Port uint16 `yaml:"port"` + // Scheme string `yaml:"scheme"` + // ClientAuthType int `yaml:"clientAuthType"` + // CaFile string `yaml:"caFile"` + // CertFile string `yaml:"certFile"` + // KeyFile string `yaml:"keyFile"` + // } `yaml:"rest"` + + Rest []RestParam WebServer struct { Enabled bool `yaml:"enabled"` @@ -83,39 +81,9 @@ type YamlConfig struct { CmdTimeout int `yaml:"cmdTimeout"` } `yaml:"omc"` - Alarm struct { - ForwardAlarm bool `yaml:"forwardAlarm"` - Email struct { - Smtp string `yaml:"smtp"` - Port uint16 `yaml:"port"` - User string `yaml:"user"` - Password string `yaml:"password"` - TlsSkipVerify bool `yaml:"tlsSkipVerify"` - } `yaml:"email"` - SMS struct { - ApiURL string `yaml:"apiURL"` - AccessKeyID string `yaml:"AccessKeyID"` - AccessKeySecret string `yaml:"accessKeySecret"` - SignName string `yaml:"signName"` - TemplateCode string `yaml:"templateCode"` - } `yaml:"sms"` - SMSC struct { - Addr string `yaml:"addr"` - UserName string `yaml:"userName"` - Password string `yaml:"password"` - } `yaml:"smsc"` - } `yaml:"alarm"` + Alarm AlarmConfig `yaml:"alarm"` - MML struct { - Port int `yaml:"port"` - Port2 int `yaml:"port2"` - Sleep int64 `yaml:"sleep"` - DeadLine int64 `yaml:"deadLine"` - User string `yaml:"user"` - Password string `ymal:"password"` - MmlHome string `yaml:"mmlHome"` - Upload string `yaml:"upload"` - } `yaml:"mml"` + MML MMLParam `yaml:"mml"` NE struct { Addr string `yaml:"addr"` @@ -156,6 +124,67 @@ type YamlConfig struct { } `yaml:"testConfig"` } +type RestParam struct { + IPv4 string `yaml:"ipv4"` + IPv6 string `yaml:"ipv6"` + Port uint16 `yaml:"port"` + Scheme string `yaml:"scheme,omitempty" default:"http"` + ClientAuthType int `yaml:"clientAuthType"` + CaFile string `yaml:"caFile"` + CertFile string `yaml:"certFile"` + KeyFile string `yaml:"keyFile"` +} + +type DbConfig struct { + Type string `yaml:"type"` + User string `yaml:"user"` + Password string `yaml:"password"` + Host string `yaml:"host"` + Port string `yaml:"port"` + Name string `yaml:"name"` + ConnParam string `yaml:"connParam,omitempty"` + Backup string `yaml:"backup"` +} + +type AlarmConfig struct { + SplitEventAlarm bool `yaml:"splitEventAlarm"` + ForwardAlarm bool `yaml:"forwardAlarm"` + SMProxy string `yaml:"smProxy"` + Email struct { + Smtp string `yaml:"smtp"` + Port uint16 `yaml:"port"` + User string `yaml:"user"` + Password string `yaml:"password"` + TlsSkipVerify bool `yaml:"tlsSkipVerify"` + } `yaml:"email"` + SMS struct { + ApiURL string `yaml:"apiURL"` + AccessKeyID string `yaml:"AccessKeyID"` + AccessKeySecret string `yaml:"accessKeySecret"` + SignName string `yaml:"signName"` + TemplateCode string `yaml:"templateCode"` + } `yaml:"sms"` + SMSC struct { + Addr string `yaml:"addr"` + SystemID string `yaml:"systemID"` + Password string `yaml:"password"` + SystemType string `yaml:"systemType"` + } `yaml:"smsc"` +} + +type MMLParam struct { + Port int `yaml:"port"` + Port2 int `yaml:"port2"` + Sleep int64 `yaml:"sleep"` + DeadLine int64 `yaml:"deadLine"` + SizeRow int16 `yaml:"sizeRow"` + SizeCol int16 `yaml:"sizeCol"` + BufferSize int `yaml:"bufferSize"` + User string `yaml:"user"` + Password string `ymal:"password"` + MmlHome string `yaml:"mmlHome"` +} + type TestDatas struct { UDM struct { CapUsed uint32 `yaml:"capUsed"` @@ -187,7 +216,25 @@ type TestDataMap struct { NeTestDatas []map[string]NeTestData } -var yamlConfig YamlConfig +var yamlConfig YamlConfig = NewYamlConfig() + +// set default value for yaml config +func NewYamlConfig() YamlConfig { + return YamlConfig{ + Database: DbConfig{ + Type: "mysql", + ConnParam: "charset=utf8mb4&collation=utf8mb4_general_ci&parseTime=True&interpolateParams=True", + }, + MML: MMLParam{ + SizeRow: 200, + SizeCol: 120, + BufferSize: 65535, + }, + Alarm: AlarmConfig{ + SplitEventAlarm: true, + }, + } +} func ReadConfig(configFile string) { yamlFile, err := os.ReadFile(configFile) @@ -323,10 +370,27 @@ func ReadTestConfigYaml(pfile string) (ret error) { } func GetDefaultUserAgent() string { - return "OMC/" + global.Version + return "OMC-restagent/" + global.Version } -// const defaultConfigFile = "./etc/omc.yaml" +func GetOMCHostUrl() string { + var omcip string = "127.0.0.1" + var rest RestParam = yamlConfig.Rest[0] + var port uint16 = rest.Port + if rest.IPv4 != "0.0.0.0" && rest.IPv4 != "" { + omcip = rest.IPv4 + } else if rest.IPv6 != "::" && rest.IPv6 != "" { + omcip = "[" + rest.IPv6 + "]" + } + var scheme string = "http" + if rest.Scheme != "" { + scheme = rest.Scheme + } + + return fmt.Sprintf("%s://%s:%d", scheme, omcip, port) +} + +// const defaultConfigFile = "./etc/restconf.yaml" // func init() { // cfile := flag.String("c", defaultConfigFile, "config file") @@ -337,7 +401,7 @@ func GetDefaultUserAgent() string { // //global.GoVer = "go version go1.15.7 linux/arm64" // flag.Parse() // if *pv { -// fmt.Printf("OMC version: %s\n%s\n%s\n\n", global.Version, global.BuildTime, global.GoVer) +// fmt.Printf("OMC restagent version: %s\n%s\n%s\n\n", global.Version, global.BuildTime, global.GoVer) // os.Exit(0) // } // if *ph { diff --git a/omc/etc/omc.yaml b/omc/etc/omc.yaml index dc1bfd0..6b1f88a 100644 --- a/omc/etc/omc.yaml +++ b/omc/etc/omc.yaml @@ -2,30 +2,35 @@ # level: /trace/debug/info/warn/error/fatal, default: debug # duration: rotation time with xx hours, example: 1/12/24 hours # count: rotation count of log, default is 30 rotation +# pprof: false(default)/true to disable/enable pprof logger: - file: d:/local.git/nms_cxy/omc/log/omc.log + file: ./etc/omc/log/omc.log level: trace duration: 24 count: 2 +pprof: + enabled: true + addr: :36060 + # rest agent listen ipv4/v6 and port, support multiple routines # ip: 0.0.0.0 or ::0, support IPv4/v6 -# clientAuthType: 0:NoClientCert (default), 1:RequestClientCert, 2:RequireAnyClientCert, +# clientAuthType: 0:NoClientCert (default), 1:RequestClientCert, 2:RequireAnyClientCert, # 3:VerifyClientCertIfGiven, 4:RequireAndVerifyClientCerts rest: - ipv4: 0.0.0.0 - ipv6: + ipv6: port: 33040 webServer: enabled: false - rootDir: d:/local.git/fe.ems.vue3/dist - listen: + rootDir: ./etc/omc/dist + listen: - addr: :80 schema: http - addr: :443 scheme: https - clientAuthType: 0 + clientAuthType: 0 caFile: ./etc/certs/omc-ca.crt certFile: ./etc/certs/omc-server.crt keyFile: ./etc/certs/omc-server.key @@ -34,10 +39,11 @@ database: type: mysql user: root password: "root@1234" - host: "192.168.5.59" + host: "192.168.8.58" port: 3306 - name: omc_db_nms_cxy - backup: d:/local.git/be.ems/omc/database + name: "omc_db_nms_cxy" + connParam: charset=utf8mb4&collation=utf8mb4_general_ci&parseTime=True&interpolateParams=True + backup: ./etc/omc/database # Redis 缓存数据,数据源声明全小写 redis: @@ -45,42 +51,44 @@ redis: # OMC系统使用库 default: port: 6379 # Redis port - host: "192.168.5.59" # Redis host + host: "192.168.8.58" # Redis host password: "redis@1234" db: 10 # Redis db_num # UDM网元用户库 udmuser: - port: 6379 # Redis port - host: "192.168.13.140" - password: "" + port: 36379 # Redis port + host: "192.168.8.58" + password: "helloearth" db: 0 # Redis db_num # 多个数据源时可以用这个指定默认的数据源 defaultDataSourceName: "default" # sleep: time delay for after write buffer (millisecond) -# deadLine: timeout for io read and write (second) +# deadLine: timeout for io read and write (second) mml: port: 4100 port2: 5002 sleep: 200 deadLine: 10 + sizeRow: 600 + sizeCol: 128 + bufferSize: 65535 user: admin password: admin mmlHome: ./mmlhome - upload: /home/agtuser # NE config ne: - user: agtuser + user: omcuser etcdir: /usr/local/etc bindir: /usr/local/bin omcdir: /usr/local/omc scpdir: /tmp licensedir: /usr/local/etc/{neType}/license - # backup etc list of IMS,no space - etcListIMS: "{*.yaml,mmtel,vars.cfg}" - etcListDefault: "{*.yaml,*.conf,*.cfg}" - # true/false to overwrite config file when dpkg ne software + # backup etc list of IMS,no space + etcListIMS: '{*.yaml,mmtel,vars.cfg}' + etcListDefault: '{*.yaml,*.conf,*.cfg}' + # true/false to overwrite config file when dpkg ne software dpkgOverwrite: false # dpkg timeout (second) dpkgTimeout: 180 @@ -100,24 +108,25 @@ omc: checksign: false rootDir: ./ binDir: ./bin - backup: ./backup - upload: ./upload - frontUpload: d:/local.git/fe.ems/upload - frontTraceDir: d:/local.git/fe.ems/trace - software: ./software - license: ./license + backup: ./etc/omc/backup + upload: ./etc/omc/upload + frontUpload: ./etc/omc/upload + frontTraceDir: ./etc/omc/trace + software: ./etc/omc/software + license: ./etc/omc/license gtpUri: gtp:192.168.2.219:2152 checkContentType: false testMode: false rbacMode: true - runDir: + runDir: cmdTimeout: 120 # Alarm module setting # Forward interface: # email/sms +# smProxy: sms(Short Message Service)/smsc(SMS Centre) alarm: - forwardAlarm: true + forwardAlarm: false email: smtp: mail.agrandtech.com port: 25 @@ -125,17 +134,19 @@ alarm: password: "1000smtp@omc!" # TLS skip verify: true/false tlsSkipVerify: true + smProxy: smsc sms: - apiURL: http://smsc.xxx.com.cn/ + apiURL: http://smsc.xxx.com/ accessKeyID: xxxx accessKeySecret: xxxx signName: xxx SMSC templateCode: 1000 smsc: - addr: "192.168.14.211:2775" - userName: OMC - password: "123456" - + addr: "192.168.13.114:2775" + systemID: "omc" + password: "omc123" + systemType: "UTRAN" + #User authorized information # crypt: mysql/md5/bcrypt # token: true/false to check accessToken @@ -150,7 +161,7 @@ auth: publicKey: ./etc/certs/omc_pub.key privateKey: ./etc/certs/omc_pri.key -# Parameter for limit number +# Parameter for limit number # rmuid_maxnum: the max number of rmUID, default: 50 # alarmid_maxnum: the max number of AlarmID, default: 50 # pmid_maxnum: the max number of pmID, default: 50 diff --git a/omc/etc/restconf-t.yaml b/omc/etc/restconf-t.yaml deleted file mode 100644 index 0d69e8c..0000000 --- a/omc/etc/restconf-t.yaml +++ /dev/null @@ -1,134 +0,0 @@ -# file: log file name -# level: /trace/debug/info/warn/error/fatal, default: debug -# duration: rotation time with xx hours, example: 1/12/24 hours -# count: rotation count of log, default is 30 rotation -logger: - file: d:/local.git/nms_cxy/omc/log/omc-t.log - level: trace - duration: 24 - count: 2 - -# rest agent listen ipv4/v6 and port, support multiple routines -# ip: 0.0.0.0 or ::0, support IPv4/v6 -rest: - - ipv4: 0.0.0.0 - ipv6: - port: 33030 - - ipv4: 0.0.0.0 - ipv6: - port: 36060 - -database: - type: mysql - user: root - password: 1000omc@kp! - host: 127.0.0.1 - port: 33066 - name: omc_db - backup: d:/local.git/nms_cxy/omc/database - -# Redis 缓存数据,数据源声明全小写 -redis: - dataSource: - # OMC系统使用库 - default: - port: 6379 # Redis port - host: "192.168.2.166" # Redis host - password: "" - db: 10 # Redis db_num - # UDM网元用户库 - udmuser: - port: 6379 # Redis port - host: "192.168.2.166" - password: "" - db: 0 # Redis db_num - # 多个数据源时可以用这个指定默认的数据源 - defaultDataSourceName: "default" - -mml: - port: 4100 - sleep: 200 - user: admin - password: admin - mmlHome: ./mmlhome - -ne: - user: root - etcdir: /usr/local/etc - bindir: /usr/local/bin - omcdir: /usr/local/omc - scpdir: /tmp - licensedir: /usr/local/etc/{neType}/license - -# chk2ne: true/false, if put OmcNeConfig parameters to NE -omc: - uriPrefix: "/omc/rest" - neType: OMC - neId: 001 - rmUID: 4400HX101 - neName: OMC - province: GD - vendor: "" - dn: 4600 - chk2ne: false - sn: 13750650 - checksign: false - backup: ./backup - upload: ./upload - frontUpload: d:/local.git/fe.ems/upload - frontTraceDir: d:/local.git/fe.ems/trace - software: ./software - license: ./license - gtpUri: gtp:192.168.2.119:2152 - checkContentType: false - testMode: false - rbacMode: true - runDir: - -# Alarm module setting -# Forward interface: -# email/sms -alarm: - forwardAlarm: true - email: - smtp: smtp@xxx.com.cn - port: 25 - user: smtpuser - password: smtpuser@omc - sms: - apiURL: http://smsc.xxx.com.cn/ - accessKeyID: xxxx - accessKeySecret: xxxx - signName: xxx SMSC - templateCode: 1000 - -#User authorized information -# crypt: mysql/md5/bcrypt -# token: true/false to check accessToken -# expires for session, unit: second -# Support single/multiple session of user -auth: - crypt: bcrypt - token: true - expires: 1800 - session: multiple - publicKey: ./etc/certs/omc_pub.key - privateKey: ./etc/certs/omc_pri.key - -# Parameter for limit number -# rmuid_maxnum: the max number of rmUID, default: 50 -# alarmid_maxnum: the max number of AlarmID, default: 50 -# pmid_maxnum: the max number of pmID, default: 50 -# subid_maxnum: the max number of subscription ID, default: 20 -# uri_maxlen: the max length of uri, default: 8192 -# rmuid_regexp: regexp pattern of rmUID -params: - rmuidmaxnum: 50 - alarmidmaxnum: 50 - pmidmaxnum: 50 - subidmaxnum: 20 - urimaxlen: 2100000 - rmuidregexp: "[0-9]{4}[A-Z]{2}[A-Z]{2}[0-9A-Z]{1}[0-9A-Z]{3}[0-9A-Z]{1,16}" -testConfig: - enabled: true - file: ./etc/testconfig.yaml \ No newline at end of file diff --git a/omc/makefile b/omc/makefile index 82da4a2..8202729 100644 --- a/omc/makefile +++ b/omc/makefile @@ -1,18 +1,18 @@ # Makefile for rest agent project PROJECT = OMC -VERSION = 2.2403.3 +VERSION = 2.2407.1 LIBDIR = nms_cxy/lib BINNAME = omc .PHONY: build $(BINNAME) build $(BINNAME): - go build -o $(BINNAME) -v -ldflags "-X '$(LIBDIR)/global.Version=$(VERSION)' \ + go build -o $(BINNAME) -v -ldflags "-s -w -X '$(LIBDIR)/global.Version=$(VERSION)' \ -X '$(LIBDIR)/global.BuildTime=`date`' \ -X '$(LIBDIR)/global.GoVer=`go version`'" -run: $(BINNAME) - ./$(BINNAME) +run: $(BINNAME) + ./$(BINNAME) clean: rm ./$(BINNAME) diff --git a/omc/omc.go b/omc/omc.go index b708d4e..bfec1b5 100644 --- a/omc/omc.go +++ b/omc/omc.go @@ -9,10 +9,13 @@ import ( "strconv" "strings" + _ "net/http/pprof" + "nms_cxy/features/dbrest" "nms_cxy/features/event" "nms_cxy/features/fm" "nms_cxy/features/lm" + "nms_cxy/features/mml" "nms_cxy/features/pm" "nms_cxy/lib/dborm" "nms_cxy/lib/global" @@ -21,7 +24,6 @@ import ( "nms_cxy/omc/config" "nms_cxy/src" "nms_cxy/src/framework/middleware" - libSession "nms_cxy/src/lib_features/session" "github.com/gin-gonic/gin" "golang.org/x/net/http2" @@ -138,61 +140,69 @@ func HttpListenWebServer(addr string) { } func main() { + // src 配置中心初始加载 src.ConfigurationInit() app := src.AppEngine() conf := config.GetYamlConfig() - log.InitLogger(conf.Logger.File, conf.Logger.Duration, conf.Logger.Count, "omc", config.GetLogLevel()) - fmt.Printf("OMC version: %s\n", global.Version) + if conf.Pprof.Enabled { + // 启用pprof HTTP服务 + go func() { + fmt.Println(http.ListenAndServe(conf.Pprof.Addr, nil)) + }() + } + + log.InitLogger(conf.Logger.File, conf.Logger.Duration, conf.Logger.Count, "omc:", config.GetLogLevel()) + fmt.Printf("OMC restagent version: %s\n", global.Version) log.Infof("========================= OMC startup =========================") - log.Infof("OMC version: %s %s %s", global.Version, global.BuildTime, global.GoVer) + log.Infof("OMC restagent version: %s %s %s", global.Version, global.BuildTime, global.GoVer) err := dborm.InitDbClient(conf.Database.Type, conf.Database.User, conf.Database.Password, - conf.Database.Host, conf.Database.Port, conf.Database.Name) + conf.Database.Host, conf.Database.Port, conf.Database.Name, conf.Database.ConnParam) if err != nil { fmt.Println("dborm.initDbClient err:", err) os.Exit(4) } err = fm.InitDbClient(conf.Database.Type, conf.Database.User, conf.Database.Password, - conf.Database.Host, conf.Database.Port, conf.Database.Name) + conf.Database.Host, conf.Database.Port, conf.Database.Name, conf.Database.ConnParam) if err != nil { fmt.Println("dborm.initDbClient err:", err) os.Exit(4) } err = pm.InitDbClient(conf.Database.Type, conf.Database.User, conf.Database.Password, - conf.Database.Host, conf.Database.Port, conf.Database.Name) + conf.Database.Host, conf.Database.Port, conf.Database.Name, conf.Database.ConnParam) if err != nil { fmt.Println("dborm.initDbClient err:", err) os.Exit(4) } err = dbrest.InitDbClient(conf.Database.Type, conf.Database.User, conf.Database.Password, - conf.Database.Host, conf.Database.Port, conf.Database.Name) + conf.Database.Host, conf.Database.Port, conf.Database.Name, conf.Database.ConnParam) if err != nil { fmt.Println("dbrest.initDbClient err:", err) os.Exit(4) } err = lm.InitDbClient(conf.Database.Type, conf.Database.User, conf.Database.Password, - conf.Database.Host, conf.Database.Port, conf.Database.Name) + conf.Database.Host, conf.Database.Port, conf.Database.Name, conf.Database.ConnParam) if err != nil { fmt.Println("lm.initDbClient err:", err) os.Exit(4) } + mml.InitMML() + // 将 mux.Router 注册到 gin.Engine // 默认路由组 defaultUriGroup := app.Group(config.DefaultUriPrefix) defaultUriGroup.Use(middleware.PreAuthorize(nil)) - defaultUriGroup.Use(libSession.SessionHeader()) defaultUriGroup.Any("/*any", gin.WrapH(routes.NewRouter())) // 可配置前缀路由组 uriGroup := app.Group(config.UriPrefix) - uriGroup.Use(libSession.SessionHeader()) uriGroup.Any("/*any", gin.WrapH(routes.NewRouter())) // AMF上报的UE事件, 无前缀,暂时特殊处理 - app.POST(event.UriUEEvent, event.PostUEEventFromAMF) + app.POST(event.UriUEEventAMF, event.PostUEEventFromAMF) for _, rest := range conf.Rest { // ipv4 goroutines diff --git a/src/app.go b/src/app.go index 50d896c..a43f1a8 100644 --- a/src/app.go +++ b/src/app.go @@ -8,18 +8,20 @@ import ( "nms_cxy/src/framework/errorcatch" "nms_cxy/src/framework/middleware" "nms_cxy/src/framework/middleware/security" + "nms_cxy/src/framework/utils/machine" "nms_cxy/src/modules/chart" "nms_cxy/src/modules/common" "nms_cxy/src/modules/crontask" "nms_cxy/src/modules/monitor" networkdata "nms_cxy/src/modules/network_data" networkelement "nms_cxy/src/modules/network_element" - nmscxy "nms_cxy/src/modules/nms_cxy" "nms_cxy/src/modules/system" "nms_cxy/src/modules/trace" "nms_cxy/src/modules/ws" + "github.com/chenjiandongx/ginprom" "github.com/gin-gonic/gin" + "github.com/prometheus/client_golang/prometheus/promhttp" ) //go:embed assets/* @@ -29,6 +31,13 @@ var assetsDir embed.FS func AppEngine() *gin.Engine { app := initAppEngine() + // TODO 不建议在主分支中加入 + // 性能分析监控 + if promEnabled := config.Get("pprof.enabled"); promEnabled != nil && promEnabled.(bool) { + app.Use(ginprom.PromMiddleware(nil)) + app.GET("/metrics", ginprom.PromHandler(promhttp.Handler())) + } + // 初始全局默认 initDefeat(app) @@ -38,6 +47,9 @@ func AppEngine() *gin.Engine { // 设置程序内全局资源访问 config.SetAssetsDirFS(assetsDir) + // 首次安装启动记录 + machine.Launch() + // 读取服务配置 app.ForwardedByClientIP = config.Get("server.proxy").(bool) return app @@ -109,7 +121,7 @@ func initDefeat(app *gin.Engine) { app.NoRoute(func(c *gin.Context) { c.JSON(404, gin.H{ "code": 404, - "msg": fmt.Sprintf("%s Not Found", c.Request.RequestURI), + "msg": fmt.Sprintf("Not Found %s", c.Request.RequestURI), }) }) } @@ -124,8 +136,6 @@ func initModulesRoute(app *gin.Engine) { networkelement.Setup(app) // 网元数据模块 networkdata.Setup(app) - // 北向模块 - 中国星网 - nmscxy.Setup(app) // 跟踪模块 trace.Setup(app) // 图表模块 diff --git a/src/framework/config/config.go b/src/framework/config/config.go index bdc31a4..66468f4 100644 --- a/src/framework/config/config.go +++ b/src/framework/config/config.go @@ -27,9 +27,9 @@ func InitConfig() { func initFlag() { // --env prod pflag.String("env", "prod", "Specify Run Environment Configuration local or prod") - // --c /etc/omc.yaml - // -c /etc/omc.yaml - pConfig := pflag.StringP("config", "c", "./etc/omc.yaml", "Specify Configuration File") + // --c /etc/restconf.yaml + // -c /etc/restconf.yaml + pConfig := pflag.StringP("config", "c", "./etc/restconf.yaml", "Specify Configuration File") // --version // -V pVersion := pflag.BoolP("version", "V", false, "Output program version") diff --git a/src/framework/config/config/config.default.yaml b/src/framework/config/config/config.default.yaml index 4878ffa..ee39665 100644 --- a/src/framework/config/config/config.default.yaml +++ b/src/framework/config/config/config.default.yaml @@ -1,7 +1,7 @@ # 项目信息 framework: name: "CN EMS" - version: "2.2403.3" + version: "2.2407.1" # 应用服务配置 server: @@ -15,7 +15,7 @@ logger: fileDir: "/var/log" fileName: "omc.log" level: 2 # 日志记录的等级 0:silent<1:info<2:warn<3:error - maxDay: 180 # 日志会保留 180 天 + maxDay: 7 # 日志会保留 180 天 maxSize: 10 # 调整按 10MB 大小的切割 # 静态文件配置, 相对项目根路径或填绝对路径 @@ -68,6 +68,8 @@ upload: # 软件包 - ".deb" - ".rpm" + # 验证文件 + - ".ini" # cors 跨域 cors: diff --git a/src/framework/constants/admin/admin.go b/src/framework/constants/admin/admin.go index 7ac32c5..1c158a8 100644 --- a/src/framework/constants/admin/admin.go +++ b/src/framework/constants/admin/admin.go @@ -1,12 +1,12 @@ package admin -// 管理员常量信息 +// 系统管理员常量信息 -// 管理员-系统指定角色ID +// 系统管理员-系统指定角色ID const ROLE_ID = "1" -// 管理员-系统指定角色KEY -const ROLE_KEY = "admin" +// 系统管理员-系统指定角色KEY +const ROLE_KEY = "system" -// 管理员-系统指定权限 +// 系统管理员-系统指定权限 const PERMISSION = "*:*:*" diff --git a/src/framework/constants/common/common.go b/src/framework/constants/common/common.go index 3786104..08e0bcb 100644 --- a/src/framework/constants/common/common.go +++ b/src/framework/constants/common/common.go @@ -19,3 +19,6 @@ const STATUS_NO = "0" // 上下文信息-登录用户 const CTX_LOGIN_USER = "loginuser" + +// 启动-引导系统初始 +const LAUNCH_BOOTLOADER = "bootloader" diff --git a/src/framework/constants/uploadsubpath/uploadsubpath.go b/src/framework/constants/uploadsubpath/uploadsubpath.go index c58e87f..b4c181f 100644 --- a/src/framework/constants/uploadsubpath/uploadsubpath.go +++ b/src/framework/constants/uploadsubpath/uploadsubpath.go @@ -26,6 +26,9 @@ const ( // 软件包 SOFTWARE = "software" + + // 授权文件 + LICENSE = "license" ) // 子路径类型映射 @@ -38,4 +41,5 @@ var UploadSubpath = map[string]string{ DOWNLOAD: "下载", CHUNK: "切片", SOFTWARE: "软件包", + LICENSE: "授权文件", } diff --git a/src/framework/logger/writer.go b/src/framework/logger/writer.go index 3209686..d535f64 100644 --- a/src/framework/logger/writer.go +++ b/src/framework/logger/writer.go @@ -34,7 +34,7 @@ const ( // NewLogger 实例日志器对象 func NewLogger(env, fileDir, fileName string, level, maxDay, maxSize int) (*Logger, error) { logFilePath := filepath.Join(fileDir, fileName) - if err := os.MkdirAll(filepath.Dir(logFilePath), 0750); err != nil { + if err := os.MkdirAll(filepath.Dir(logFilePath), 0775); err != nil { return nil, fmt.Errorf("failed to mkdir logger dir: %v", err) } fileHandle, err := os.OpenFile(logFilePath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666) diff --git a/src/framework/middleware/collectlogs/operate_log.go b/src/framework/middleware/collectlogs/operate_log.go index 955dce7..3331181 100644 --- a/src/framework/middleware/collectlogs/operate_log.go +++ b/src/framework/middleware/collectlogs/operate_log.go @@ -8,6 +8,7 @@ import ( "time" "nms_cxy/src/framework/constants/common" + tokenConstants "nms_cxy/src/framework/constants/token" "nms_cxy/src/framework/i18n" "nms_cxy/src/framework/utils/ctx" "nms_cxy/src/framework/utils/parse" @@ -178,6 +179,8 @@ var maskProperties []string = []string{ "oldPassword", "newPassword", "confirmPassword", + tokenConstants.RESPONSE_FIELD, + tokenConstants.ACCESS_TOKEN, } // processSensitiveFields 处理敏感属性字段 diff --git a/src/framework/middleware/pre_authorize.go b/src/framework/middleware/pre_authorize.go index e91ca96..34741ff 100644 --- a/src/framework/middleware/pre_authorize.go +++ b/src/framework/middleware/pre_authorize.go @@ -20,6 +20,7 @@ var URL_WHITE_LIST = []string{ "/systemState", "/omcNeConfig", "/cdrEvent", + "/ueEvent", "/upload-ue", "/oauth/token", } diff --git a/src/framework/utils/crypto/aes.go b/src/framework/utils/crypto/aes.go index 4db36ac..290eb71 100644 --- a/src/framework/utils/crypto/aes.go +++ b/src/framework/utils/crypto/aes.go @@ -10,21 +10,17 @@ import ( "io" ) -// aesKey 字符串AES加解密密钥 -const aesKey = "AGT66VfY4SMaiT97" - // StringEncryptByAES 字符串AES加密 func StringEncryptByAES(text string) (string, error) { if len(text) == 0 { return "", nil } - pass := []byte(text) - xpass, err := aesEncryptWithSalt([]byte(aesKey), pass) - if err == nil { - pass64 := base64.StdEncoding.EncodeToString(xpass) - return pass64, err + xpass, err := aesEncryptWithSalt([]byte(text)) + if err != nil { + return "", err } - return "", err + pass64 := base64.StdEncoding.EncodeToString(xpass) + return pass64, nil } // StringDecryptByAES 字符串AES解密 @@ -36,53 +32,70 @@ func StringDecryptByAES(text string) (string, error) { if err != nil { return "", err } - var tpass []byte - tpass, err = aesDecryptWithSalt([]byte(aesKey), bytesPass) - if err == nil { - result := string(tpass[:]) - return result, err + + tpass, err := aesDecryptWithSalt(bytesPass) + if err != nil { + return "", err } - return "", err + return string(tpass), nil } -// aesEncryptWithSalt AES加密 -func aesEncryptWithSalt(key, plaintext []byte) ([]byte, error) { - blockSize := aes.BlockSize - padding := blockSize - len(plaintext)%blockSize - padtext := bytes.Repeat([]byte{byte(padding)}, padding) - plaintext = append(plaintext, padtext...) +// aesKey 字符串AES加解密密钥 +const aesKey = "AGT66VfY4SMaiT97a7df0aef1704d5c5" - block, err := aes.NewCipher(key) +// const aesKey = "AGT66VfY4SMaiT97" +// aesEncryptWithSalt AES加密 +func aesEncryptWithSalt(plaintext []byte) ([]byte, error) { + block, err := aes.NewCipher([]byte(aesKey)) if err != nil { return nil, err } + blockSize := aes.BlockSize + + padding := blockSize - (len(plaintext) % blockSize) + padtext := bytes.Repeat([]byte{byte(padding)}, padding) + plaintext = append(plaintext, padtext...) + ciphertext := make([]byte, blockSize+len(plaintext)) - iv := ciphertext[0:blockSize] + iv := ciphertext[:blockSize] if _, err := io.ReadFull(rand.Reader, iv); err != nil { return nil, err } - cbc := cipher.NewCBCEncrypter(block, iv) - cbc.CryptBlocks(ciphertext[blockSize:], plaintext) + + mode := cipher.NewCBCEncrypter(block, iv) + mode.CryptBlocks(ciphertext[blockSize:], plaintext) + return ciphertext, nil } // aesDecryptWithSalt AES解密 -func aesDecryptWithSalt(key, ciphertext []byte) ([]byte, error) { +func aesDecryptWithSalt(ciphertext []byte) ([]byte, error) { blockSize := aes.BlockSize - var block cipher.Block - block, err := aes.NewCipher(key) + if len(ciphertext) < blockSize { + return nil, fmt.Errorf("ciphertext too short") + } + + iv := ciphertext[:blockSize] + ciphertext = ciphertext[blockSize:] + + block, err := aes.NewCipher([]byte(aesKey)) if err != nil { return nil, err } - if len(ciphertext) < blockSize { - return nil, fmt.Errorf("iciphertext too short") + + if len(ciphertext)%blockSize != 0 { + return nil, fmt.Errorf("ciphertext is not a multiple of the block size") } - iv := ciphertext[:blockSize] - ciphertext = ciphertext[blockSize:] - cbc := cipher.NewCBCDecrypter(block, iv) - cbc.CryptBlocks(ciphertext, ciphertext) - length := len(ciphertext) - unpadding := int(ciphertext[len(ciphertext)-1]) - ciphertext = ciphertext[:(length - unpadding)] + + mode := cipher.NewCBCDecrypter(block, iv) + mode.CryptBlocks(ciphertext, ciphertext) + + // 去除填充 + padding := int(ciphertext[len(ciphertext)-1]) + if padding > blockSize || padding == 0 { + return nil, fmt.Errorf("invalid padding") + } + ciphertext = ciphertext[:len(ciphertext)-padding] + return ciphertext, nil } diff --git a/src/framework/utils/ctx/ctx.go b/src/framework/utils/ctx/ctx.go index 1b2864c..551a854 100644 --- a/src/framework/utils/ctx/ctx.go +++ b/src/framework/utils/ctx/ctx.go @@ -85,8 +85,8 @@ func Authorization(c *gin.Context) string { return "" } // 拆分 Authorization 请求头,提取 JWT 令牌部分 - arr := strings.Split(authHeader, token.HEADER_PREFIX) - if len(arr) == 2 && arr[1] == "" { + arr := strings.SplitN(authHeader, token.HEADER_PREFIX, 2) + if len(arr) < 2 { return "" } return arr[1] @@ -213,6 +213,11 @@ func LoginUserToDataScopeSQL(c *gin.Context, deptAlias string, userAlias string) conditions = append(conditions, sql) } + if roledatascope.DEPT == dataScope { + sql := fmt.Sprintf(`%s.dept_id = '%s'`, deptAlias, userInfo.DeptID) + conditions = append(conditions, sql) + } + if roledatascope.DEPT_AND_CHILD == dataScope { sql := fmt.Sprintf(`%s.dept_id IN ( SELECT dept_id FROM sys_dept WHERE dept_id = '%s' or find_in_set('%s' , ancestors ) )`, deptAlias, userInfo.DeptID, userInfo.DeptID) conditions = append(conditions, sql) @@ -221,7 +226,7 @@ func LoginUserToDataScopeSQL(c *gin.Context, deptAlias string, userAlias string) if roledatascope.SELF == dataScope { // 数据权限为仅本人且没有userAlias别名不查询任何数据 if userAlias == "" { - sql := fmt.Sprintf(`%s.dept_id = '0'`, deptAlias) + sql := fmt.Sprintf(`%s.parent_id = '0'`, deptAlias) conditions = append(conditions, sql) } else { sql := fmt.Sprintf(`%s.user_id = '%s'`, userAlias, userInfo.UserID) diff --git a/src/framework/utils/date/date.go b/src/framework/utils/date/date.go index 00c1f33..f726a83 100644 --- a/src/framework/utils/date/date.go +++ b/src/framework/utils/date/date.go @@ -17,6 +17,8 @@ const ( YYYYMMDDHHMMSS = "20060102150405" // 年-月-日 时:分:秒 列如:2022-12-30 01:01:59 YYYY_MM_DD_HH_MM_SS = "2006-01-02 15:04:05" + // 年-月-日T时:分:秒Z时区 列如:2022-12-30T01:01:59+08:00 + YYYY_MM_DDTHH_MM_SSZ = time.RFC3339 ) // 格式时间字符串 @@ -46,7 +48,14 @@ func ParseDateToStr(date any, formatStr string) string { if v == 0 { return "" } - t = time.UnixMilli(v) + if v > 9999999999 { + t = time.UnixMilli(v) + } else if v > 999999999 { + t = time.Unix(v, 0) + } else { + logger.Infof("utils ParseDateToStr err %v", "Invalid timestamp") + return "" + } case string: parsedTime, err := time.Parse(formatStr, v) if err != nil { diff --git a/src/framework/utils/file/csv.go b/src/framework/utils/file/csv.go index 38091d2..c4f0f6d 100644 --- a/src/framework/utils/file/csv.go +++ b/src/framework/utils/file/csv.go @@ -20,7 +20,7 @@ func WriterFileCSV(data [][]string, filePath string) error { dirPath := filepath.Dir(filePath) // 确保文件夹路径存在 - err := os.MkdirAll(dirPath, os.ModePerm) + err := os.MkdirAll(dirPath, 0775) if err != nil { logger.Errorf("MkdirAll dir %v", err) } diff --git a/src/framework/utils/file/excel.go b/src/framework/utils/file/excel.go index c1cf77d..4b72d83 100644 --- a/src/framework/utils/file/excel.go +++ b/src/framework/utils/file/excel.go @@ -142,7 +142,7 @@ func WriteSheet(headerCells map[string]string, dataCells []map[string]any, fileN saveFilePath := filepath.Join(dir, filePath, fileName) // 创建文件目录 - if err := os.MkdirAll(filepath.Dir(saveFilePath), 0750); err != nil { + if err := os.MkdirAll(filepath.Dir(saveFilePath), 0775); err != nil { return "", fmt.Errorf("failed to create save file %v", err) } diff --git a/src/framework/utils/file/file.go b/src/framework/utils/file/file.go index 679ccac..b8cb5b2 100644 --- a/src/framework/utils/file/file.go +++ b/src/framework/utils/file/file.go @@ -60,9 +60,12 @@ func uploadWhiteList() []string { // fileName 原始文件名称含后缀,如:logo.png func generateFileName(fileName string) string { fileExt := filepath.Ext(fileName) - // 替换掉后缀和特殊字符保留文件名 + // 去除后缀 newFileName := regular.Replace(fileName, fileExt, "") - newFileName = regular.Replace(newFileName, `[<>:"\\|?*]+`, "") + // 去除非法字符 + newFileName = regular.Replace(newFileName, `[\\/:*?"<>|]`, "") + // 去除空格 + newFileName = regular.Replace(newFileName, `\s`, "_") newFileName = strings.TrimSpace(newFileName) return fmt.Sprintf("%s_%s%s", newFileName, generate.Code(6), fileExt) } @@ -174,13 +177,13 @@ func ReadUploadFileStream(filePath, headerRange string) (map[string]any, error) "range": "", "chunkSize": 0, "fileSize": 0, - "data": nil, + "data": []byte{}, } // 文件大小 fileSize := getFileSize(fileAsbPath) if fileSize <= 0 { - return result, nil + return result, fmt.Errorf("file does not exist") } result["fileSize"] = fileSize @@ -309,12 +312,12 @@ func CopyUploadFile(filePath, dst string) error { } defer src.Close() - if err := os.MkdirAll(filepath.Dir(dst), 0750); err != nil { + if err := os.MkdirAll(filepath.Dir(dst), 0775); err != nil { return err } // 如果目标文件已经存在,先将目标文件重命名 - if _, err := os.Stat(dst); err == nil { + if info, err := os.Stat(dst); err == nil && !info.IsDir() { ext := filepath.Ext(dst) name := dst[0 : len(dst)-len(ext)] newName := fmt.Sprintf("%s-%s%s", name, time.Now().Format("20060102_150405"), ext) diff --git a/src/framework/utils/file/json.go b/src/framework/utils/file/json.go index 43bbd2b..6b31a67 100644 --- a/src/framework/utils/file/json.go +++ b/src/framework/utils/file/json.go @@ -16,7 +16,7 @@ func WriterFileJSON(data any, filePath string) error { dirPath := filepath.Dir(filePath) // 确保文件夹路径存在 - err := os.MkdirAll(dirPath, os.ModePerm) + err := os.MkdirAll(dirPath, 0775) if err != nil { logger.Errorf("CreateFile MkdirAll %v", err) } @@ -46,7 +46,7 @@ func WriterFileJSONLine(data []any, filePath string) error { dirPath := filepath.Dir(filePath) // 确保文件夹路径存在 - err := os.MkdirAll(dirPath, os.ModePerm) + err := os.MkdirAll(dirPath, 0775) if err != nil { logger.Errorf("CreateFile MkdirAll %v", err) } diff --git a/src/framework/utils/file/txt.go b/src/framework/utils/file/txt.go index 0df9495..010a804 100644 --- a/src/framework/utils/file/txt.go +++ b/src/framework/utils/file/txt.go @@ -22,7 +22,7 @@ func WriterFileTXT(data [][]string, sep string, filePath string) error { dirPath := filepath.Dir(filePath) // 确保文件夹路径存在 - err := os.MkdirAll(dirPath, os.ModePerm) + err := os.MkdirAll(dirPath, 0775) if err != nil { logger.Errorf("CreateFile MkdirAll %v", err) } diff --git a/src/framework/utils/file/utils.go b/src/framework/utils/file/utils.go index 24ad059..93270c1 100644 --- a/src/framework/utils/file/utils.go +++ b/src/framework/utils/file/utils.go @@ -26,7 +26,7 @@ func transferToNewFile(file *multipart.FileHeader, dst string) error { } defer src.Close() - if err = os.MkdirAll(filepath.Dir(dst), 0750); err != nil { + if err = os.MkdirAll(filepath.Dir(dst), 0775); err != nil { return err } @@ -66,7 +66,7 @@ func mergeToNewFile(dirPath string, writePath string, fileName string) error { // 写入到新路径文件 newFilePath := filepath.Join(writePath, fileName) - if err = os.MkdirAll(filepath.Dir(newFilePath), 0750); err != nil { + if err = os.MkdirAll(filepath.Dir(newFilePath), 0775); err != nil { return err } diff --git a/src/framework/utils/machine/launch.go b/src/framework/utils/machine/launch.go new file mode 100644 index 0000000..e882bd7 --- /dev/null +++ b/src/framework/utils/machine/launch.go @@ -0,0 +1,178 @@ +package machine + +import ( + "encoding/json" + "fmt" + "hash/fnv" + "os" + "runtime" + "time" + + "nms_cxy/src/framework/constants/common" + "nms_cxy/src/framework/logger" + "nms_cxy/src/framework/utils/cmd" + "nms_cxy/src/framework/utils/crypto" + "nms_cxy/src/framework/utils/parse" +) + +// 机器的唯一标识符 +var Code string + +// 初始信息 +var LaunchInfo map[string]any + +// codeGenerate 生成机器的唯一标识符 +func codeGenerate() string { + var machineID string + + // 获取主机名 + hostname, err := os.Hostname() + if err != nil { + panic(err) + } + machineID += hostname + + // 获取 CPU 信息 + numCPU := runtime.NumCPU() + machineID += fmt.Sprintf("%d", numCPU) + + // 获取操作系统信息 + osInfo := runtime.GOOS + machineID += osInfo + + // 使用哈希函数生成机器码 + h := fnv.New32a() + h.Write([]byte(machineID)) + machineCode := h.Sum32() + + return fmt.Sprintf("%x", machineCode) +} + +// 网管本地路径 +func filePath() string { + filePath := "/usr/local/etc/omc/machine.ini" + if runtime.GOOS == "windows" { + filePath = fmt.Sprintf("C:%s", filePath) + } + return filePath +} + +// codeFileRead 读取机器保留的信息 +func codeFileRead() (map[string]any, error) { + var mapData map[string]any + // 读取文件内容 + bytes, err := os.ReadFile(filePath()) + if err != nil { + logger.Warnf("CodeFileRead ReadFile => %s", err.Error()) + return mapData, fmt.Errorf("not file") + } + content := string(bytes) + // 解密 + contentDe, err := crypto.StringDecryptByAES(content) + if err != nil { + logger.Errorf("CodeFileRead decrypt: %v", err.Error()) + return mapData, fmt.Errorf("decrypt fail") + } + // 序列化Map + mapData, err = parse.ConvertConfigToMap("json", string(contentDe)) + if err != nil { + logger.Warnf("CodeFileRead ConvertConfigToMap => %s", err.Error()) + return mapData, fmt.Errorf("content error") + } + return mapData, nil +} + +// codeFileWrite 写入机器保留的信息 +func codeFileWrite(data map[string]any) error { + jsonByte, _ := json.Marshal(data) + // 加密 + contentEn, err := crypto.StringEncryptByAES(string(jsonByte)) + if err != nil { + logger.Errorf("insert encrypt: %v", err.Error()) + return fmt.Errorf("encrypt fail") + } + return parse.ConvertConfigToFile("txt", filePath(), contentEn) +} + +// Launch 记录首次安装启动初始信息 +func Launch() { + Code = codeGenerate() + // 检查文件是否存在 + if _, err := os.Stat(filePath()); err != nil { + LaunchInfo = map[string]any{ + "code": Code, // 机器码 + "useTime": time.Now().UnixMilli(), // 首次使用时间 + + common.LAUNCH_BOOTLOADER: true, // 启动引导 + common.LAUNCH_BOOTLOADER + "Time": 0, // 引导完成时间 + } + codeFileWrite(LaunchInfo) + } else { + // 读取记录文件 + data, err := codeFileRead() + if err != nil { + // 文件异常就重新生成 + os.Remove(filePath()) + Launch() + return + } + LaunchInfo = data + } +} + +// SetLaunchInfo 新增额外的初始信息 +func SetLaunchInfo(info map[string]any) error { + if info == nil { + return fmt.Errorf("not info") + } + + // 固定值禁止变更 + constKeys := []string{"code", "useTime"} + for k, v := range info { + constKey := false + for _, ck := range constKeys { + if ck == k { + constKey = true + break + } + } + if constKey { + continue + } else { + LaunchInfo[k] = v + } + } + return codeFileWrite(LaunchInfo) +} + +// Bootloader 启动引导标记 +func Bootloader(flag bool) error { + return SetLaunchInfo(map[string]any{ + common.LAUNCH_BOOTLOADER: flag, // 启动引导 true开 false关 + common.LAUNCH_BOOTLOADER + "Time": time.Now().UnixMilli(), // 引导完成时间 + }) +} + +// Reset 引导数据重置 +func Reset() error { + // 重置数据库 + if runtime.GOOS == "windows" { + // return fmt.Errorf("not support window") + } else { + // 重置数据库 + if _, err := cmd.Execf("sudo /usr/local/omc/bin/setomc.sh -m install"); err != nil { + return err + } + // 重启服务 + if _, err := cmd.Execf("nohup sh -c \"sleep 1s && %s\" > /dev/null 2>&1 &", "sudo systemctl restart restagent"); err != nil { + return err + } + } + + // 重置引导标记 + if err := Bootloader(true); err != nil { + return err + } + + return nil +} diff --git a/src/framework/utils/parse/parse.go b/src/framework/utils/parse/parse.go index ff8145c..67fb831 100644 --- a/src/framework/utils/parse/parse.go +++ b/src/framework/utils/parse/parse.go @@ -1,8 +1,11 @@ package parse import ( + "encoding/json" "fmt" "image/color" + "os" + "path/filepath" "reflect" "regexp" "strconv" @@ -10,6 +13,7 @@ import ( "time" "github.com/robfig/cron/v3" + "gopkg.in/yaml.v3" ) // Number 解析数值型 @@ -51,6 +55,8 @@ func Boolean(str any) bool { case float32, float64: num := reflect.ValueOf(str).Float() return num != 0 + case bool: + return str default: return false } @@ -165,3 +171,83 @@ func Color(colorStr string) *color.RGBA { A: 255, // 不透明 } } + +// ConvertIPMask 转换IP网络地址掩码 24->"255.255.255.0" 20->"255.255.240.0" +func ConvertIPMask(bits int64) string { + if bits < 0 || bits > 32 { + return "255.255.255.255" + } + + // 构建一个32位的uint32类型掩码,指定前bits位为1,其余为0 + mask := uint32((1<>24), + fmt.Sprintf("%d", (mask>>16)&255), + fmt.Sprintf("%d", (mask>>8)&255), + fmt.Sprintf("%d", mask&255), + } + + // 将分组用点号连接起来形成掩码字符串 + return strings.Join(groups, ".") +} + +// ConvertConfigToMap 将配置内容转换为Map结构数据 +// +// configType 类型支持:txt json yaml yml +func ConvertConfigToMap(configType, content string) (map[string]any, error) { + // 类型支持:viper.SupportedExts + // config := viper.New() + // config.SetConfigType(configType) + // err := config.ReadConfig(bytes.NewBuffer([]byte(content))) + // return config.AllSettings(), err + + var configMap map[string]interface{} + var err error + if configType == "" || configType == "txt" { + configMap = map[string]interface{}{ + "txt": content, + } + } + if configType == "yaml" || configType == "yml" { + err = yaml.Unmarshal([]byte(content), &configMap) + } + if configType == "json" { + err = json.Unmarshal([]byte(content), &configMap) + } + return configMap, err +} + +// ConvertConfigToFile 将数据写入到指定文件内 +// +// configType 类型支持:txt json yaml yml +func ConvertConfigToFile(configType, filePath string, data any) error { + // viper.SupportedExts + // config := viper.New() + // config.SetConfigType(configType) + // for key, value := range mapData { + // config.Set(key, value) + // } + // return config.WriteConfigAs(filePath) + + var dataByte []byte + var err error + if configType == "" || configType == "txt" { + dataByte = []byte(data.(string)) + } + if configType == "yaml" || configType == "yml" { + dataByte, err = yaml.Marshal(data) + } + if configType == "json" { + dataByte, err = json.Marshal(data) + } + if err != nil { + return err + } + + if err := os.MkdirAll(filepath.Dir(filePath), 0775); err != nil { + return err + } + return os.WriteFile(filePath, dataByte, 0644) +} diff --git a/src/framework/utils/regular/regular.go b/src/framework/utils/regular/regular.go index 9feebc3..3eeb31c 100644 --- a/src/framework/utils/regular/regular.go +++ b/src/framework/utils/regular/regular.go @@ -48,7 +48,7 @@ func ValidMobile(mobile string) bool { if mobile == "" { return false } - pattern := `^1[3|4|5|6|7|8|9][0-9]\d{8}$` + pattern := `^.{3,}$` // `^1[3|4|5|6|7|8|9][0-9]\d{8}$` match, err := regexp.MatchString(pattern, mobile) if err != nil { return false diff --git a/src/framework/utils/repo/repo.go b/src/framework/utils/repo/repo.go index ecf61f2..7924ddb 100644 --- a/src/framework/utils/repo/repo.go +++ b/src/framework/utils/repo/repo.go @@ -20,7 +20,7 @@ func PageNumSize(pageNum, pageSize any) (int64, int64) { // 显示记录数 size := parse.Number(pageSize) - if size < 0 { + if size < 1 { size = 10 } return num - 1, size @@ -66,12 +66,12 @@ func SetFieldValue(obj any, fieldName string, value any) { } fieldValue.SetFloat(floatValue) case reflect.Struct: - fmt.Printf("%s 时间解析 %s %v \n", fieldName, fieldValue.Type(), value) + fmt.Printf("%s time resolution %s %v \n", fieldName, fieldValue.Type(), value) if fieldValue.Type() == reflect.TypeOf(time.Time{}) && value != nil { // 解析 value 并转换为 time.Time 类型 parsedTime, err := time.Parse("2006-01-02 15:04:05 +0800 CST", fmt.Sprintf("%v", value)) if err != nil { - fmt.Println("时间解析出错:", err) + fmt.Println("Time resolution error:", err) } else { // 设置字段的值 fieldValue.Set(reflect.ValueOf(parsedTime)) diff --git a/src/framework/utils/ssh/files.go b/src/framework/utils/ssh/files.go index 0bf4556..39822e1 100644 --- a/src/framework/utils/ssh/files.go +++ b/src/framework/utils/ssh/files.go @@ -4,7 +4,6 @@ import ( "fmt" "strings" - "nms_cxy/src/framework/config" "nms_cxy/src/framework/logger" "nms_cxy/src/framework/utils/cmd" "nms_cxy/src/framework/utils/parse" @@ -23,35 +22,31 @@ type FileListRow struct { } // 文件列表 -// neIp 网元IP空字符串为本地 // search 文件名后模糊* // // return 目录大小,行记录,异常 -func FileList(path, neIp, search string) (string, []FileListRow, error) { +func FileList(sshClient *ConnSSH, path, search string) (string, []FileListRow, error) { totalSize := "" var rows []FileListRow rowStr := "" // 发送命令 - searchStr := "" + searchStr := "*" if search != "" { - searchStr = search + "*" + searchStr = search + searchStr } - pathStr := fmt.Sprintf("cd %s \n", path) - cmdStr := fmt.Sprintf("ls -lht --time-style=+%%s %s \n", searchStr) + cmdStr := fmt.Sprintf("cd %s && ls -lthd --time-style=+%%s %s", path, searchStr) - // 是否远程读取 - if neIp != "" { - usernameNe := config.Get("ne.user").(string) // 网元统一用户 - sshHost := fmt.Sprintf("%s@%s", usernameNe, neIp) - resultStr, err := cmd.ExecWithCheck("ssh", sshHost, pathStr, cmdStr) + // 是否远程客户端读取 + if sshClient == nil { + resultStr, err := cmd.Execf(cmdStr) if err != nil { logger.Errorf("Ne FileList Path: %s, Search: %s, Error:%s", path, search, err.Error()) return totalSize, rows, err } rowStr = resultStr } else { - resultStr, err := cmd.Execf(pathStr, cmdStr) + resultStr, err := sshClient.RunCMD(cmdStr) if err != nil { logger.Errorf("Ne FileList Path: %s, Search: %s, Error:%s", path, search, err.Error()) return totalSize, rows, err diff --git a/src/framework/utils/ssh/scp.go b/src/framework/utils/ssh/scp.go deleted file mode 100644 index 639c028..0000000 --- a/src/framework/utils/ssh/scp.go +++ /dev/null @@ -1,44 +0,0 @@ -package ssh - -import ( - "fmt" - "os" - "os/exec" - "path/filepath" - - "nms_cxy/src/framework/config" - "nms_cxy/src/framework/logger" -) - -// 网元NE 文件复制到远程文件 -func FileSCPLocalToNe(neIp, localPath, nePath string) error { - usernameNe := config.Get("ne.user").(string) - // scp /path/to/local/file.txt user@remote-server:/path/to/remote/directory/ - neDir := fmt.Sprintf("%s@%s:%s", usernameNe, neIp, nePath) - cmd := exec.Command("scp", "-r", localPath, neDir) - _, err := cmd.CombinedOutput() - if err != nil { - logger.Errorf("FileSCPLocalToNe %s", err.Error()) - return err - } - return nil -} - -// 网元NE 远程文件复制到本地文件 -func FileSCPNeToLocal(neIp, nePath, localPath string) error { - // 确保文件夹路径存在 - if err := os.MkdirAll(filepath.Dir(localPath), 0750); err != nil { - logger.Errorf("FileSCPNeToLocal MkdirAll err %v", err) - return err - } - usernameNe := config.Get("ne.user").(string) - // scp user@remote-server:/path/to/remote/directory/ /path/to/local/file.txt - neDir := fmt.Sprintf("%s@%s:%s", usernameNe, neIp, nePath) - cmd := exec.Command("scp", "-r", neDir, localPath) - _, err := cmd.CombinedOutput() - if err != nil { - logger.Errorf("FileSCPNeToLocal %s", err.Error()) - return err - } - return nil -} diff --git a/src/framework/utils/ssh/sftp.go b/src/framework/utils/ssh/sftp.go new file mode 100644 index 0000000..72712b6 --- /dev/null +++ b/src/framework/utils/ssh/sftp.go @@ -0,0 +1,203 @@ +package ssh + +import ( + "io" + "os" + "path/filepath" + + "nms_cxy/src/framework/logger" + + gosftp "github.com/pkg/sftp" +) + +// SSHClientSFTP SSH客户端SFTP对象 +type SSHClientSFTP struct { + Client *gosftp.Client +} + +// Close 关闭会话 +func (s *SSHClientSFTP) Close() { + if s.Client != nil { + s.Client.Close() + } +} + +// CopyDirRemoteToLocal 复制目录-远程到本地 +func (s *SSHClientSFTP) CopyDirRemoteToLocal(remoteDir, localDir string) error { + // 列出远程目录中的文件和子目录 + remoteFiles, err := s.Client.ReadDir(remoteDir) + if err != nil { + logger.Errorf("CopyDirRemoteToLocal failed to reading remote directory %s: => %s", remoteDir, err.Error()) + return err + } + + // 创建本地目录 + err = os.MkdirAll(localDir, 0775) + if err != nil { + logger.Errorf("CopyDirRemoteToLocal failed to creating local directory %s: => %s", localDir, err.Error()) + return err + } + + // 遍历远程文件和子目录并复制到本地 + for _, remoteFile := range remoteFiles { + remotePath := filepath.Join(remoteDir, remoteFile.Name()) + localPath := filepath.Join(localDir, remoteFile.Name()) + + if remoteFile.IsDir() { + // 如果是子目录,则递归复制子目录 + err = s.CopyDirRemoteToLocal(remotePath, localPath) + if err != nil { + logger.Errorf("CopyDirRemoteToLocal failed to copying remote directory %s: => %s", remotePath, err.Error()) + continue + } + } else { + // 如果是文件,则复制文件内容 + remoteFile, err := s.Client.Open(remotePath) + if err != nil { + logger.Errorf("CopyDirRemoteToLocal failed to opening remote file %s: => %s", remotePath, err.Error()) + continue + } + defer remoteFile.Close() + + localFile, err := os.Create(localPath) + if err != nil { + logger.Errorf("CopyDirRemoteToLocal failed to creating local file %s: => %s", localPath, err.Error()) + continue + } + defer localFile.Close() + + _, err = io.Copy(localFile, remoteFile) + if err != nil { + logger.Errorf("CopyDirRemoteToLocal failed to copying file contents from %s to %s: => %s", remotePath, localPath, err.Error()) + continue + } + } + } + return nil +} + +// CopyDirRemoteToLocal 复制目录-本地到远程 +func (s *SSHClientSFTP) CopyDirLocalToRemote(localDir, remoteDir string) error { + // 创建远程目录 + err := s.Client.MkdirAll(remoteDir) + if err != nil { + logger.Errorf("CopyDirLocalToRemote failed to creating remote directory %s: => %s", remoteDir, err.Error()) + return err + } + + // 遍历本地目录中的文件和子目录并复制到远程 + err = filepath.Walk(localDir, func(localPath string, info os.FileInfo, err error) error { + if err != nil { + return err + } + + // 生成远程路径 + remotePath := filepath.Join(remoteDir, localPath[len(localDir):]) + + if info.IsDir() { + // 如果是子目录,则创建远程目录 + err := s.Client.MkdirAll(remotePath) + if err != nil { + logger.Errorf("CopyDirLocalToRemote failed to creating remote directory %s: => %s", remotePath, err.Error()) + return nil + } + } else { + // 如果是文件,则复制文件内容 + localFile, err := os.Open(localPath) + if err != nil { + logger.Errorf("CopyDirLocalToRemote failed to opening local file %s: => %s", localPath, err.Error()) + return nil + } + defer localFile.Close() + + remoteFile, err := s.Client.Create(remotePath) + if err != nil { + logger.Errorf("CopyDirLocalToRemote failed to creating remote file %s: => %s", remotePath, err.Error()) + return nil + } + defer remoteFile.Close() + + _, err = io.Copy(remoteFile, localFile) + if err != nil { + logger.Errorf("CopyDirLocalToRemote failed to copying file contents from %s to %s: => %s", localPath, remotePath, err.Error()) + return nil + } + } + + return nil + }) + if err != nil { + logger.Errorf("CopyDirLocalToRemote failed to walking local directory: => %s", err.Error()) + return err + } + return nil +} + +// CopyDirRemoteToLocal 复制文件-远程到本地 +func (s *SSHClientSFTP) CopyFileRemoteToLocal(remotePath, localPath string) error { + // 打开远程文件 + remoteFile, err := s.Client.Open(remotePath) + if err != nil { + logger.Errorf("CopyFileRemoteToLocal failed to opening remote file: => %s", err.Error()) + return err + } + defer remoteFile.Close() + + if err := os.MkdirAll(filepath.Dir(localPath), 0775); err != nil { + return err + } + + // 如果目标文件已经存在,先将目标文件重命名 + // if info, err := os.Stat(localPath); err == nil && !info.IsDir() { + // ext := filepath.Ext(localPath) + // name := localPath[0 : len(localPath)-len(ext)] + // newName := fmt.Sprintf("%s-%s%s", name, time.Now().Format("20060102_150405"), ext) + // err := os.Rename(localPath, newName) + // if err != nil { + // return err + // } + // } + + // 创建本地文件 + localFile, err := os.Create(localPath) + if err != nil { + logger.Errorf("CopyFileRemoteToLocal failed to creating local file: => %s", err.Error()) + return err + } + defer localFile.Close() + + // 复制文件内容 + _, err = io.Copy(localFile, remoteFile) + if err != nil { + logger.Errorf("CopyFileRemoteToLocal failed to copying contents: => %s", err.Error()) + return err + } + return nil +} + +// CopyDirRemoteToLocal 复制文件-本地到远程 +func (s *SSHClientSFTP) CopyFileLocalToRemote(localPath, remotePath string) error { + // 打开本地文件 + localFile, err := os.Open(localPath) + if err != nil { + logger.Errorf("CopyFileLocalToRemote failed to opening local file: => %s", err.Error()) + return err + } + defer localFile.Close() + + // 创建远程文件 + remoteFile, err := s.Client.Create(remotePath) + if err != nil { + logger.Errorf("CopyFileLocalToRemote failed to creating remote file: => %s", err.Error()) + return err + } + defer remoteFile.Close() + + // 复制文件内容 + _, err = io.Copy(remoteFile, localFile) + if err != nil { + logger.Errorf("CopyFileLocalToRemote failed to copying contents: => %s", err.Error()) + return err + } + return nil +} diff --git a/src/framework/utils/ssh/ssh.go b/src/framework/utils/ssh/ssh.go index e1e8a41..b5e0226 100644 --- a/src/framework/utils/ssh/ssh.go +++ b/src/framework/utils/ssh/ssh.go @@ -1,17 +1,16 @@ package ssh import ( - "bytes" "fmt" - "io" "os" "os/user" "strings" - "sync" "time" "nms_cxy/src/framework/logger" + "nms_cxy/src/framework/utils/cmd" + gosftp "github.com/pkg/sftp" gossh "golang.org/x/crypto/ssh" ) @@ -87,33 +86,6 @@ func (c *ConnSSH) Close() { } } -// NewClientByLocalPrivate 创建SSH客户端-本地私钥(~/.ssh/id_rsa)直连 -// -// ssh.ConnSSH{ -// User: "user", -// Addr: "192.168.x.x", -// Port: body.Port, -// } -func (c *ConnSSH) NewClientByLocalPrivate() (*ConnSSH, error) { - c.Port = 22 - c.AuthMode = "1" - usr, err := user.Current() - if err != nil { - logger.Errorf("NewClientByLocal get current user => %s", err.Error()) - return nil, err - } - - // 读取用户默认的私钥文件 - keyPath := fmt.Sprintf("%s/.ssh/id_rsa", usr.HomeDir) - key, err := os.ReadFile(keyPath) - if err != nil { - logger.Errorf("NewClientByLocal [%s] read private key => %s", usr.Username, err.Error()) - return nil, err - } - c.PrivateKey = string(key) - return c.NewClient() -} - // RunCMD 执行单次命令 func (c *ConnSSH) RunCMD(cmd string) (string, error) { if c.Client == nil { @@ -135,7 +107,7 @@ func (c *ConnSSH) RunCMD(cmd string) (string, error) { return c.LastResult, err } -// NewClient 创建SSH客户端会话对象 +// NewClientSession 创建SSH客户端会话对象 func (c *ConnSSH) NewClientSession(cols, rows int) (*SSHClientSession, error) { sshSession, err := c.Client.NewSession() if err != nil { @@ -172,75 +144,84 @@ func (c *ConnSSH) NewClientSession(cols, rows int) (*SSHClientSession, error) { }, nil } -// SSHClientSession SSH客户端会话对象 -type SSHClientSession struct { - Stdin io.WriteCloser - Stdout *singleWriter - Session *gossh.Session +// NewClientSFTP 创建SSH客户端SFTP对象 +func (c *ConnSSH) NewClientSFTP() (*SSHClientSFTP, error) { + sftpClient, err := gosftp.NewClient(c.Client) + if err != nil { + logger.Errorf("NewClientSFTP failed to create sftp: => %s", err.Error()) + return nil, err + } + + return &SSHClientSFTP{ + Client: sftpClient, + }, nil } -// Close 关闭会话 -func (s *SSHClientSession) Close() { - if s.Stdin != nil { - s.Stdin.Close() - } - if s.Stdout != nil { - s.Stdout = nil - } - if s.Session != nil { - s.Session.Close() +// NewClientByLocalPrivate 创建SSH客户端-本地私钥(~/.ssh/id_rsa)直连 +// +// ssh.ConnSSH{ +// User: "user", +// Addr: "192.168.x.x", +// Port: body.Port, +// } +func (c *ConnSSH) NewClientByLocalPrivate() (*ConnSSH, error) { + c.Port = 22 + c.AuthMode = "1" + privateKey, err := c.CurrentUserRsaKey(false) + if err != nil { + return nil, err } + c.PrivateKey = privateKey + return c.NewClient() } -// Write 写入命令 回车(\n)才会执行 -func (s *SSHClientSession) Write(cmd string) (int, error) { - if s.Stdin == nil { - return 0, fmt.Errorf("ssh client session is nil to content write failed") - } - return s.Stdin.Write([]byte(cmd)) -} - -// Read 读取结果 等待一会才有结果 -func (s *SSHClientSession) Read() []byte { - if s.Stdout == nil { - return []byte{} - } - // time.Sleep(300 * time.Millisecond) - bs := s.Stdout.Bytes() - if len(bs) > 0 { - s.Stdout.Reset() - return bs - } - return []byte{} -} - -// CombinedOutput 发送命令带结果返回 -func (s *SSHClientSession) CombinedOutput(cmd string) (string, error) { - n, err := s.Write(cmd) - if n == 0 || err != nil { +// CurrentUserRsaKey 当前用户OMC使用的RSA私钥 +// 默认读取私钥 +// ssh-keygen -t rsa -P "" -f ~/.ssh/id_rsa +// ssh-keygen -y -f ~/.ssh/id_rsa > ~/.ssh/id_rsa.pub +func (c *ConnSSH) CurrentUserRsaKey(publicKey bool) (string, error) { + usr, err := user.Current() + if err != nil { + logger.Errorf("CurrentUserRsaKey get => %s", err.Error()) return "", err } - return string(s.Read()), nil + + // 是否存在私钥并创建 + keyPath := fmt.Sprintf("%s/.ssh/id_rsa", usr.HomeDir) + if _, err := os.Stat(keyPath); err != nil { + if _, err := cmd.ExecWithCheck("ssh-keygen", "-t", "rsa", "-P", "", "-f", keyPath); err != nil { + logger.Errorf("CurrentUserPrivateKey ssh-keygen [%s] rsa => %s", usr.Username, err.Error()) + } + } + + // 读取用户默认的文件 + if publicKey { + keyPath = keyPath + ".pub" + } + key, err := os.ReadFile(keyPath) + if err != nil { + logger.Errorf("CurrentUserRsaKey [%s] read => %s", usr.Username, err.Error()) + return "", fmt.Errorf("read file %s fail", keyPath) + } + return string(key), nil } -// singleWriter SSH客户端会话消息 -type singleWriter struct { - b bytes.Buffer - mu sync.Mutex -} - -func (w *singleWriter) Write(p []byte) (int, error) { - w.mu.Lock() - defer w.mu.Unlock() - return w.b.Write(p) -} -func (w *singleWriter) Bytes() []byte { - w.mu.Lock() - defer w.mu.Unlock() - return w.b.Bytes() -} -func (w *singleWriter) Reset() { - w.mu.Lock() - defer w.mu.Unlock() - w.b.Reset() +// SendToAuthorizedKeys 发送当前用户私钥到远程服务器进行授权密钥 +func (c *ConnSSH) SendToAuthorizedKeys() error { + publicKey, err := c.CurrentUserRsaKey(true) + if err != nil { + return err + } + authorizedKeysEntry := fmt.Sprintln(strings.TrimSpace(publicKey)) + cmdStrArr := []string{ + fmt.Sprintf("sudo mkdir -p /home/%s/.ssh && sudo chown %s:%s /home/%s/.ssh && sudo chmod 700 /home/%s/.ssh", c.User, c.User, c.User, c.User, c.User), + fmt.Sprintf("sudo touch /home/%s/.ssh/authorized_keys && sudo chown %s:%s /home/%s/.ssh/authorized_keys && sudo chmod 600 /home/%s/.ssh/authorized_keys", c.User, c.User, c.User, c.User, c.User), + fmt.Sprintf("echo '%s' | sudo tee -a /home/%s/.ssh/authorized_keys", authorizedKeysEntry, c.User), + } + _, err = c.RunCMD(strings.Join(cmdStrArr, " && ")) + if err != nil { + logger.Errorf("SendAuthorizedKeys echo err %s", err.Error()) + return err + } + return nil } diff --git a/src/framework/utils/ssh/ssh_session.go b/src/framework/utils/ssh/ssh_session.go new file mode 100644 index 0000000..1244ac2 --- /dev/null +++ b/src/framework/utils/ssh/ssh_session.go @@ -0,0 +1,73 @@ +package ssh + +import ( + "bytes" + "fmt" + "io" + "sync" + + gossh "golang.org/x/crypto/ssh" +) + +// SSHClientSession SSH客户端会话对象 +type SSHClientSession struct { + Stdin io.WriteCloser + Stdout *singleWriter + Session *gossh.Session +} + +// Close 关闭会话 +func (s *SSHClientSession) Close() { + if s.Stdin != nil { + s.Stdin.Close() + } + if s.Stdout != nil { + s.Stdout = nil + } + if s.Session != nil { + s.Session.Close() + } +} + +// Write 写入命令 回车(\n)才会执行 +func (s *SSHClientSession) Write(cmd string) (int, error) { + if s.Stdin == nil { + return 0, fmt.Errorf("ssh client session is nil to content write failed") + } + return s.Stdin.Write([]byte(cmd)) +} + +// Read 读取结果 +func (s *SSHClientSession) Read() []byte { + if s.Stdout == nil { + return []byte{} + } + bs := s.Stdout.Bytes() + if len(bs) > 0 { + s.Stdout.Reset() + return bs + } + return []byte{} +} + +// singleWriter SSH客户端会话消息 +type singleWriter struct { + b bytes.Buffer + mu sync.Mutex +} + +func (w *singleWriter) Write(p []byte) (int, error) { + w.mu.Lock() + defer w.mu.Unlock() + return w.b.Write(p) +} +func (w *singleWriter) Bytes() []byte { + w.mu.Lock() + defer w.mu.Unlock() + return w.b.Bytes() +} +func (w *singleWriter) Reset() { + w.mu.Lock() + defer w.mu.Unlock() + w.b.Reset() +} diff --git a/src/framework/utils/telnet/parse.go b/src/framework/utils/telnet/parse.go new file mode 100644 index 0000000..31e46bc --- /dev/null +++ b/src/framework/utils/telnet/parse.go @@ -0,0 +1,77 @@ +package telnet + +import ( + "fmt" + "strings" +) + +// ConvertToStr 转换为string +func ConvertToStr(telnetClient *ConnTelnet, cmd string) (string, error) { + output, err := telnetClient.RunCMD(cmd) + if err != nil { + return "", err + } + str := strings.ToLower(output) + + // 截断 + index := strings.Index(str, "\n") + if index != -1 { + str = str[:index] + } + + // 命令成功 + if strings.Contains(str, "ok") || strings.Contains(str, "success") { + return str, nil + } + + return "", fmt.Errorf(str) +} + +// ConvertToMap 转换为map +func ConvertToMap(telnetClient *ConnTelnet, cmd string) (map[string]string, error) { + output, err := telnetClient.RunCMD(cmd) + if err != nil { + return nil, err + } + + // 无数据 + if strings.HasPrefix(output, "No ") { + // 截断 + index := strings.Index(output, "\n") + if index != -1 { + output = output[:index] + } + return nil, fmt.Errorf(output) + } + + // 初始化一个map用于存储拆分后的键值对 + m := make(map[string]string) + + var items []string + if strings.Contains(output, "\r\n") { + // 按照分隔符"\r\n"进行拆分 + items = strings.Split(output, "\r\n") + } else if strings.Contains(output, "\n") { + // 按照分隔符"\n"进行拆分 + items = strings.Split(output, "\n") + } + + // 遍历拆分后的结果 + for _, item := range items { + var pair []string + + if strings.Contains(item, "=") { + // 按照分隔符"="进行拆分键值对 + pair = strings.SplitN(item, "=", 2) + } else if strings.Contains(item, ":") { + // 按照分隔符":"进行拆分键值对 + pair = strings.SplitN(item, ":", 2) + } + + if len(pair) == 2 { + // 将键值对存入map中 + m[pair[0]] = pair[1] + } + } + return m, err +} diff --git a/src/framework/utils/telnet/telnet.go b/src/framework/utils/telnet/telnet.go index 651ede9..bcafd08 100644 --- a/src/framework/utils/telnet/telnet.go +++ b/src/framework/utils/telnet/telnet.go @@ -51,6 +51,12 @@ func (c *ConnTelnet) NewClient() (*ConnTelnet, error) { // fmt.Fprintln(client, c.Password) c.Client = &client + + // 调整窗口大小 (120 列 x 128 行) + requestPty(c.Client, 120, 128) + + // 排空连接登录的信息 + c.RunCMD("") return c, nil } @@ -67,50 +73,32 @@ func (c *ConnTelnet) RunCMD(cmd string) (string, error) { return "", fmt.Errorf("telnet client not connected") } conn := *c.Client - var buf bytes.Buffer - tmp := make([]byte, 1024) - - // 排空连接登录的信息 - for { - // 设置读取超时时间为100毫秒 - conn.SetReadDeadline(time.Now().Add(100 * time.Millisecond)) - n, err := conn.Read(tmp) - if err != nil { - // 判断是否是超时错误 - if netErr, ok := err.(net.Error); ok && netErr.Timeout() { - break - } - break - } - if n == 0 { - break - } - buf.Write(tmp[:n]) - } - buf.Reset() // 写入命令 - _, err := conn.Write([]byte(cmd)) - if err != nil { - return "", err + if cmd != "" { + if _, err := conn.Write([]byte(cmd)); err != nil { + return "", err + } } - // 读取本次响应命令消息 + var buf bytes.Buffer + tmp := make([]byte, 1024) for { - // 设置读取超时时间为1000毫秒 - conn.SetReadDeadline(time.Now().Add(1000 * time.Millisecond)) + // 读取命令消息 n, err := conn.Read(tmp) - if err != nil { - // 判断是否是超时错误 - if netErr, ok := err.(net.Error); ok && netErr.Timeout() { - break - } + if n == 0 || err != nil { + tmp = nil break } - if n == 0 { + + tmpStr := string(tmp[:n]) + buf.WriteString(tmpStr) + + // 是否有终止符 + if strings.HasSuffix(tmpStr, ">") || strings.HasSuffix(tmpStr, "> ") || strings.HasSuffix(tmpStr, "# ") { + tmp = nil break } - buf.Write(tmp[:n]) } defer buf.Reset() @@ -119,100 +107,24 @@ func (c *ConnTelnet) RunCMD(cmd string) (string, error) { } // NewClient 创建Telnet客户端会话对象 -func (c *ConnTelnet) NewClientSession() (*TelnetClientSession, error) { +func (c *ConnTelnet) NewClientSession(cols, rows int) (*TelnetClientSession, error) { if c.Client == nil { return nil, fmt.Errorf("telnet client not connected") } - conn := *c.Client - - var buf bytes.Buffer - tmp := make([]byte, 1024) - // 排空连接登录的信息 - for { - // 设置读取超时时间为5毫秒 - conn.SetReadDeadline(time.Now().Add(5 * time.Millisecond)) - n, err := conn.Read(tmp) - if err != nil { - // 判断是否是超时错误 - if netErr, ok := err.(net.Error); ok && netErr.Timeout() { - break - } - break - } - if n == 0 { - break - } - buf.Write(tmp[:n]) - } - buf.Reset() - + requestPty(c.Client, cols, rows) return &TelnetClientSession{ - Client: conn, + Client: *c.Client, }, nil } -// TelnetClientSession Telnet客户端会话对象 -type TelnetClientSession struct { - Client net.Conn -} - -// Close 关闭会话 -func (s *TelnetClientSession) Close() { - if s.Client != nil { - s.Client.Close() - } -} - -// Write 写入命令 不带回车(\n)也会执行根据客户端情况 -func (s *TelnetClientSession) Write(cmd string) (int, error) { - if s.Client == nil { - return 0, fmt.Errorf("client is nil to content write failed") - } - return s.Client.Write([]byte(cmd)) -} - -// Read 读取结果 等待一会才有结果 -func (s *TelnetClientSession) Read() []byte { - if s.Client == nil { - return []byte{} - } - - buf := make([]byte, 1024) - // 设置读取超时时间为100毫秒 - s.Client.SetReadDeadline(time.Now().Add(100 * time.Millisecond)) - _, err := s.Client.Read(buf) - if err != nil { - return []byte{} - } - return buf -} - -// CombinedOutput 发送命令带结果返回 -func (s *TelnetClientSession) CombinedOutput(cmd string) (string, error) { - n, err := s.Write(cmd) - if n == 0 || err != nil { - return "", err - } - - var buf bytes.Buffer - tmp := make([]byte, 1024) - for { - // 设置读取超时时间为1000毫秒 - s.Client.SetReadDeadline(time.Now().Add(1000 * time.Millisecond)) - n, err := s.Client.Read(tmp) - if err != nil { - // 判断是否是超时错误 - if netErr, ok := err.(net.Error); ok && netErr.Timeout() { - break - } - break - } - if n == 0 { - break - } - buf.Write(tmp[:n]) - } - defer buf.Reset() - - return buf.String(), nil +// requestPty 调整终端窗口大小 +func requestPty(client *net.Conn, cols, rows int) error { + if client == nil { + return fmt.Errorf("telnet client not connected") + } + conn := *client + // 需要确保接收方理解并正确处理发送窗口大小设置命令 + conn.Write([]byte{255, 251, 31}) + conn.Write([]byte{255, 250, 31, byte(cols >> 8), byte(cols & 0xFF), byte(rows >> 8), byte(rows & 0xFF), 255, 240}) + return nil } diff --git a/src/framework/utils/telnet/telnet_session.go b/src/framework/utils/telnet/telnet_session.go new file mode 100644 index 0000000..9289eeb --- /dev/null +++ b/src/framework/utils/telnet/telnet_session.go @@ -0,0 +1,74 @@ +package telnet + +import ( + "bytes" + "fmt" + "net" + "time" +) + +// TelnetClientSession Telnet客户端会话对象 +type TelnetClientSession struct { + Client net.Conn +} + +// Close 关闭会话 +func (s *TelnetClientSession) Close() { + if s.Client != nil { + s.Client.Close() + } +} + +// Write 写入命令 不带回车(\n)也会执行根据客户端情况 +func (s *TelnetClientSession) Write(cmd string) (int, error) { + if s.Client == nil { + return 0, fmt.Errorf("client is nil to content write failed") + } + return s.Client.Write([]byte(cmd)) +} + +// Read 读取结果 等待一会才有结果 +func (s *TelnetClientSession) Read() []byte { + if s.Client == nil { + return []byte{} + } + + buf := make([]byte, 1024) + // 设置读取超时时间为100毫秒 + s.Client.SetReadDeadline(time.Now().Add(100 * time.Millisecond)) + _, err := s.Client.Read(buf) + if err != nil { + return []byte{} + } + return buf +} + +// CombinedOutput 发送命令带结果返回 +func (s *TelnetClientSession) CombinedOutput(cmd string) (string, error) { + n, err := s.Write(cmd) + if n == 0 || err != nil { + return "", err + } + + var buf bytes.Buffer + tmp := make([]byte, 1024) + for { + // 设置读取超时时间为1000毫秒 + s.Client.SetReadDeadline(time.Now().Add(1000 * time.Millisecond)) + n, err := s.Client.Read(tmp) + if err != nil { + // 判断是否是超时错误 + if netErr, ok := err.(net.Error); ok && netErr.Timeout() { + break + } + break + } + if n == 0 { + break + } + buf.Write(tmp[:n]) + } + defer buf.Reset() + + return buf.String(), nil +} diff --git a/src/framework/utils/token/token.go b/src/framework/utils/token/token.go index 6df979a..642b36c 100644 --- a/src/framework/utils/token/token.go +++ b/src/framework/utils/token/token.go @@ -11,6 +11,7 @@ import ( "nms_cxy/src/framework/logger" redisCahe "nms_cxy/src/framework/redis" "nms_cxy/src/framework/utils/generate" + "nms_cxy/src/framework/utils/machine" "nms_cxy/src/framework/vo" jwt "github.com/golang-jwt/jwt/v5" @@ -74,7 +75,7 @@ func Create(loginUser *vo.LoginUser, ilobArgs ...string) string { // 生成令牌设置密钥 secret := config.Get("jwt.secret").(string) - tokenStr, err := jwtToken.SignedString([]byte(secret)) + tokenStr, err := jwtToken.SignedString([]byte(machine.Code + "@" + secret)) if err != nil { logger.Infof("jwt sign err : %v", err) return "" @@ -118,7 +119,7 @@ func Verify(tokenString string) (jwt.MapClaims, error) { // 判断加密算法是预期的加密算法 if _, ok := token.Method.(*jwt.SigningMethodHMAC); ok { secret := config.Get("jwt.secret").(string) - return []byte(secret), nil + return []byte(machine.Code + "@" + secret), nil } return nil, jwt.ErrSignatureInvalid }) diff --git a/src/lib_features/account/account.go b/src/lib_features/account/account.go deleted file mode 100644 index 7059086..0000000 --- a/src/lib_features/account/account.go +++ /dev/null @@ -1,39 +0,0 @@ -package libfeatures - -import ( - "time" - - "nms_cxy/lib/dborm" - "nms_cxy/lib/oauth" - libConfig "nms_cxy/omc/config" - "nms_cxy/src/framework/logger" - "nms_cxy/src/framework/redis" -) - -// SessionToken 设置登录会话-兼容旧登录方式 -func SessionToken(username, sourceAddr string) bool { - // token, _ := redis.Get("", "session_token") - // if token != "" { - // se, err := dborm.XormUpdateSessionShakeTime(token) - // if se.AccountId != username || err != nil { - // // 过期时间单位秒 配置1800是半小时 - // expireTime := time.Duration(int64(libConfig.GetExpiresFromConfig())) * time.Second - // redis.SetByExpire("", "session_token", token, expireTime) - // return true - // } - // } - // 不管原先的登录情况,直接插入写入覆盖redis中session - // - token := oauth.GenRandToken("omc") // Generate new token to session ID - affected, err := dborm.XormInsertSession(username, sourceAddr, token, libConfig.GetExpiresFromConfig(), libConfig.GetYamlConfig().Auth.Session) - if err != nil { - logger.Errorf("SessionToken XormInsertSession err %v", err) - } - if affected >= 1 { - // 过期时间单位秒 配置1800是半小时 - expireTime := time.Duration(int64(libConfig.GetExpiresFromConfig())) * time.Second - redis.SetByExpire("", "session_token", token, expireTime) - return true - } - return false -} diff --git a/src/lib_features/config/config.go b/src/lib_features/config/config.go index c0dd41b..c446902 100644 --- a/src/lib_features/config/config.go +++ b/src/lib_features/config/config.go @@ -12,7 +12,7 @@ import ( // BuildInfo 程序-V查看编译版本号信息 func BuildInfo() string { - return fmt.Sprintf("OMC version: %s\n%s\n%s\n\n", libGlobal.Version, libGlobal.BuildTime, libGlobal.GoVer) + return fmt.Sprintf("OMC Version: %s\n%s\n%s\n\n", libGlobal.Version, libGlobal.BuildTime, libGlobal.GoVer) } // ConfigRead 指定配置文件读取 diff --git a/src/lib_features/readme.md b/src/lib_features/readme.md index 6f43371..57a250c 100644 --- a/src/lib_features/readme.md +++ b/src/lib_features/readme.md @@ -1,5 +1,4 @@ # 外层 lib 和 features 粘合层 -- config.go 配置合并: omc.yaml 文件内容,主要是数据库配置 -- account.go 登录会话生成 token -- session.go 中间件方式设置请求头 token 值 +- config.go 配置合并: restagent.yaml 文件内容,主要是数据库配置 + diff --git a/src/lib_features/session/session.go b/src/lib_features/session/session.go deleted file mode 100644 index 1e36c8a..0000000 --- a/src/lib_features/session/session.go +++ /dev/null @@ -1,29 +0,0 @@ -package session - -import ( - "time" - - libConfig "nms_cxy/omc/config" - "nms_cxy/src/framework/redis" - - "github.com/gin-gonic/gin" -) - -// SessionHeader 旧登录方式token头 -func SessionHeader() gin.HandlerFunc { - return func(c *gin.Context) { - // 读取登录生成的会话token - token, _ := redis.Get("", "session_token") - if token != "" { - // 过期时间单位秒 配置1800是半小时 - expireTime := time.Duration(int64(libConfig.GetExpiresFromConfig())) * time.Second - redis.SetByExpire("", "session_token", token, expireTime) - c.Request.Header.Set("Accesstoken", token) - } - - // Accesstoken: omc-ce4d0a86-8515-ad51-3249-4913c95f8e34 - // 调用下一个处理程序 - c.Next() - - } -} diff --git a/src/modules/common/common.go b/src/modules/common/common.go index 1e9c1bc..35c7a1e 100644 --- a/src/modules/common/common.go +++ b/src/modules/common/common.go @@ -25,6 +25,14 @@ func Setup(router *gin.Engine) { // 系统可暴露的配置信息 indexGroup.GET("/sys-conf", controller.NewCommont.SysConfig) + // 系统引导初始化 + guideGroup := router.Group("/bootloader") + { + guideGroup.POST("", controller.NewBootloader.Start) + guideGroup.PUT("", middleware.PreAuthorize(nil), controller.NewBootloader.Done) + guideGroup.DELETE("", middleware.PreAuthorize(nil), controller.NewBootloader.Reset) + guideGroup.PUT("/account", middleware.PreAuthorize(nil), controller.NewBootloader.Account) + } // 验证码操作处理 indexGroup.GET("/captchaImage", diff --git a/src/modules/common/controller/account.go b/src/modules/common/controller/account.go index cb4a538..39333f4 100644 --- a/src/modules/common/controller/account.go +++ b/src/modules/common/controller/account.go @@ -9,7 +9,6 @@ import ( tokenUtils "nms_cxy/src/framework/utils/token" "nms_cxy/src/framework/vo" "nms_cxy/src/framework/vo/result" - libAccount "nms_cxy/src/lib_features/account" commonModel "nms_cxy/src/modules/common/model" commonService "nms_cxy/src/modules/common/service" systemService "nms_cxy/src/modules/system/service" @@ -84,9 +83,6 @@ func (s *AccountController) Login(c *gin.Context) { ) } - // 设置登录会话-兼容旧登录方式 - libAccount.SessionToken(loginBody.Username, ipaddr) - c.JSON(200, result.OkData(map[string]any{ tokenConstants.RESPONSE_FIELD: tokenStr, })) diff --git a/src/modules/common/controller/bootloader.go b/src/modules/common/controller/bootloader.go new file mode 100644 index 0000000..0e6c46f --- /dev/null +++ b/src/modules/common/controller/bootloader.go @@ -0,0 +1,182 @@ +package controller + +import ( + adminConstants "nms_cxy/src/framework/constants/admin" + "nms_cxy/src/framework/constants/common" + tokenConstants "nms_cxy/src/framework/constants/token" + "nms_cxy/src/framework/i18n" + "nms_cxy/src/framework/utils/ctx" + "nms_cxy/src/framework/utils/machine" + "nms_cxy/src/framework/utils/regular" + tokenUtils "nms_cxy/src/framework/utils/token" + "nms_cxy/src/framework/vo" + "nms_cxy/src/framework/vo/result" + commonService "nms_cxy/src/modules/common/service" + systemService "nms_cxy/src/modules/system/service" + + "github.com/gin-gonic/gin" +) + +// 实例化控制层 BootloaderController 结构体 +var NewBootloader = &BootloaderController{ + accountService: commonService.NewAccountImpl, + sysUserService: systemService.NewSysUserImpl, +} + +// 系统引导初始化 +// +// PATH /bootloader +type BootloaderController struct { + // 账号身份操作服务 + accountService commonService.IAccount + // 用户信息服务 + sysUserService systemService.ISysUser +} + +// 首次引导开始 +// +// POST / +func (s *BootloaderController) Start(c *gin.Context) { + // 是否完成引导 + launchInfo := machine.LaunchInfo + if launchInfo == nil { + c.JSON(200, result.Err(nil)) + return + } + if v, ok := launchInfo[common.LAUNCH_BOOTLOADER]; ok && !v.(bool) { + c.JSON(200, result.ErrMsg("bootloader done")) + return + } + + // 查询用户登录账号 + sysUser := s.sysUserService.SelectUserById("1") + if sysUser.UserID != "1" { + c.JSON(200, result.ErrMsg("not found user data")) + return + } + + // 登录用户信息 + loginUser := vo.LoginUser{ + UserID: sysUser.UserID, + DeptID: sysUser.DeptID, + User: sysUser, + Permissions: []string{adminConstants.PERMISSION}, + } + + // 当前请求信息 + ipaddr, location := ctx.IPAddrLocation(c) + os, browser := ctx.UaOsBrowser(c) + + // 生成令牌,创建系统访问记录 + tokenStr := tokenUtils.Create(&loginUser, ipaddr, location, os, browser) + if tokenStr == "" { + c.JSON(200, result.Err(nil)) + return + } else { + s.accountService.UpdateLoginDateAndIP(&loginUser) + } + + c.JSON(200, result.OkData(map[string]any{ + tokenConstants.RESPONSE_FIELD: tokenStr, + })) +} + +// 首次引导完成 +// +// PUT / +func (s *BootloaderController) Done(c *gin.Context) { + // 是否完成引导 + launchInfo := machine.LaunchInfo + if launchInfo == nil { + c.JSON(200, result.Err(nil)) + return + } + if v, ok := launchInfo[common.LAUNCH_BOOTLOADER]; ok && !v.(bool) { + c.JSON(200, result.ErrMsg("bootloader done")) + return + } + + // 标记引导完成 + if err := machine.Bootloader(false); err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return + } + + // 清除授权信息 + tokenUtils.Remove(ctx.Authorization(c)) + c.JSON(200, result.Ok(nil)) +} + +// 引导系统数据重置 +// +// DELETE / +func (s *BootloaderController) Reset(c *gin.Context) { + // 是否完成引导 + launchInfo := machine.LaunchInfo + if launchInfo == nil { + c.JSON(200, result.Err(nil)) + return + } + if v, ok := launchInfo[common.LAUNCH_BOOTLOADER]; ok && v.(bool) { + c.JSON(200, result.ErrMsg("bootloader not done")) + return + } + + if err := machine.Reset(); err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return + } + + // 清除授权信息 + tokenUtils.Remove(ctx.Authorization(c)) + c.JSON(200, result.Ok(nil)) +} + +// 账号变更 +// +// PUT /account +func (s *BootloaderController) Account(c *gin.Context) { + language := ctx.AcceptLanguage(c) + var body struct { + UserName string `json:"username" binding:"required"` + Password string `json:"password" binding:"required"` + } + if err := c.ShouldBindJSON(&body); err != nil { + c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) + return + } + + if !regular.ValidPassword(body.Password) { + // 登录密码至少包含大小写字母、数字、特殊符号,且不少于6位 + c.JSON(200, result.ErrMsg(i18n.TKey(language, "user.errPasswd"))) + return + } + + // 是否完成引导 + launchInfo := machine.LaunchInfo + if launchInfo == nil { + c.JSON(200, result.Err(nil)) + return + } + if v, ok := launchInfo[common.LAUNCH_BOOTLOADER]; ok && !v.(bool) { + c.JSON(200, result.ErrMsg("bootloader done")) + return + } + + // 查询用户登录账号 + sysUser := s.sysUserService.SelectUserById("2") + if sysUser.UserID != "2" { + c.JSON(200, result.ErrMsg("not found user data")) + return + } + sysUser.UserName = body.UserName + sysUser.NickName = body.UserName + sysUser.Password = body.Password + sysUser.UpdateBy = ctx.LoginUserToUserName(c) + rows := s.sysUserService.UpdateUser(sysUser) + if rows > 0 { + c.JSON(200, result.Ok(nil)) + return + } + c.JSON(200, result.Err(nil)) +} diff --git a/src/modules/common/controller/file.go b/src/modules/common/controller/file.go index 597c055..e0434a4 100644 --- a/src/modules/common/controller/file.go +++ b/src/modules/common/controller/file.go @@ -43,13 +43,6 @@ func (s *FileController) Download(c *gin.Context) { return } routerPath := string(decodedBytes) - // 地址文件名截取 - fileName := routerPath[strings.LastIndex(routerPath, "/")+1:] - - // 响应头 - c.Writer.Header().Set("Content-Disposition", `attachment; filename="`+url.QueryEscape(fileName)+`"`) - c.Writer.Header().Set("Accept-Ranges", "bytes") - c.Writer.Header().Set("Content-Type", "application/octet-stream") // 断点续传 headerRange := c.GetHeader("Range") @@ -58,6 +51,12 @@ func (s *FileController) Download(c *gin.Context) { c.JSON(200, result.ErrMsg(err.Error())) return } + + // 响应头 + c.Writer.Header().Set("Content-Disposition", `attachment; filename="`+url.QueryEscape(filepath.Base(routerPath))+`"`) + c.Writer.Header().Set("Accept-Ranges", "bytes") + c.Writer.Header().Set("Content-Type", "application/octet-stream") + if headerRange != "" { c.Writer.Header().Set("Content-Range", fmt.Sprint(resultMap["range"])) c.Writer.Header().Set("Content-Length", fmt.Sprint(resultMap["chunkSize"])) @@ -65,7 +64,6 @@ func (s *FileController) Download(c *gin.Context) { } else { c.Writer.Header().Set("Content-Length", fmt.Sprint(resultMap["fileSize"])) c.Status(200) - } c.Writer.Write(resultMap["data"].([]byte)) } @@ -222,7 +220,7 @@ func (s *CommontController) TransferStaticFile(c *gin.Context) { delPrefix := strings.Replace(body.StaticPath, static["prefix"].(string), "", 1) staticPath := strings.Replace(delPrefix, "{language}", lang, 1) - newFile := fmt.Sprintf("%s%s", dir, staticPath) + newFile := filepath.ToSlash(fmt.Sprintf("%s%s", dir, staticPath)) err = file.CopyUploadFile(body.UploadPath, newFile) if err != nil { diff --git a/src/modules/common/service/commont.impl.go b/src/modules/common/service/commont.impl.go index 42affd5..34b7191 100644 --- a/src/modules/common/service/commont.impl.go +++ b/src/modules/common/service/commont.impl.go @@ -5,6 +5,8 @@ import ( "nms_cxy/lib/global" "nms_cxy/src/framework/config" + "nms_cxy/src/framework/constants/common" + "nms_cxy/src/framework/utils/machine" systemService "nms_cxy/src/modules/system/service" ) @@ -29,6 +31,17 @@ func (s *CommontImpl) SystemConfigInfo() map[string]string { infoMap["version"] = global.Version infoMap["buildTime"] = global.BuildTime infoMap["goVer"] = global.GoVer + // 系统首次使用标记 + launchInfo := machine.LaunchInfo + if launchInfo != nil { + if v, ok := launchInfo[common.LAUNCH_BOOTLOADER]; ok { + infoMap[common.LAUNCH_BOOTLOADER] = fmt.Sprint(v) + } else { + infoMap[common.LAUNCH_BOOTLOADER] = "true" + } + } else { + infoMap[common.LAUNCH_BOOTLOADER] = "true" + } // 序列号 infoMap["serialNum"] = fmt.Sprint(config.Get("omc.sn")) // 获取LOGO类型 diff --git a/src/modules/crontask/processor/deleteExpiredRecord/deleteExpiredRecord.go b/src/modules/crontask/processor/deleteExpiredRecord/deleteExpiredRecord.go index 67cd919..fd83e2b 100644 --- a/src/modules/crontask/processor/deleteExpiredRecord/deleteExpiredRecord.go +++ b/src/modules/crontask/processor/deleteExpiredRecord/deleteExpiredRecord.go @@ -25,8 +25,9 @@ type BarProcessor struct { type BarParams struct { Duration int `json:"duration"` TableName string `json:"tableName"` - ColName string `json:"colName"` // column name of time string - Extras string `json:"extras"` // extras condition for where + ColName string `json:"colName"` // column name of time string + Extras string `json:"extras"` // extras condition for where + SessFlag bool `json:"sessFlag"` // session flag, true: session model, false: no session } func (s *BarProcessor) Execute(data any) (any, error) { @@ -74,10 +75,19 @@ func (s *BarProcessor) Execute(data any) (any, error) { where = fmt.Sprintf("NOW()>ADDDATE(`%s`,interval %d day) and %s", params.ColName, params.Duration, params.Extras) } - affected, err := dborm.XormDeleteDataByWhere(where, params.TableName) - if err != nil { - // panic(fmt.Sprintf("Failed to XormDeleteDataByWhere:%v", err)) - return nil, err + var affected int64 = 0 + if params.SessFlag { + affected, err = dborm.XormDeleteDataByWhere(where, params.TableName) + if err != nil { + // panic(fmt.Sprintf("Failed to XormDeleteDataByWhere:%v", err)) + return nil, err + } + } else { + affected, err = dborm.XormDeleteDataByWhereNoSession(where, params.TableName) + if err != nil { + // panic(fmt.Sprintf("Failed to XormDeleteDataByWhere:%v", err)) + return nil, err + } } // 返回结果,用于记录执行结果 diff --git a/src/modules/crontask/processor/genNeStateAlarm/genNeStateAlarm.go b/src/modules/crontask/processor/genNeStateAlarm/genNeStateAlarm.go index cd8f9f4..e853a30 100644 --- a/src/modules/crontask/processor/genNeStateAlarm/genNeStateAlarm.go +++ b/src/modules/crontask/processor/genNeStateAlarm/genNeStateAlarm.go @@ -113,7 +113,8 @@ func (s *BarProcessor) Execute(data any) (any, error) { for _, ne := range nes { //log.Debug("ne:", ne) - sql := fmt.Sprintf("select * from ne_state where ne_type = '%s' and ne_id = '%s' order by timestamp desc limit 1", ne.NeType, ne.NeId) + sql := fmt.Sprintf("select * from ne_state where ne_type='%s' and ne_id='%s' order by `timestamp` desc limit 1", ne.NeType, ne.NeId) + log.Debug("SQL:", sql) neState, err := dborm.XormGetDataBySQL(sql) if err != nil { log.Error("Failed to get ne_state:", err) @@ -121,7 +122,7 @@ func (s *BarProcessor) Execute(data any) (any, error) { } if len(*neState) == 0 { log.Warn("Not found record in ne_state:") - continue + //continue } //log.Debug("neState:", *neState) @@ -150,7 +151,7 @@ func (s *BarProcessor) Execute(data any) (any, error) { var timestamp string if len(*neState) == 0 { log.Infof("Not found ne_state neType:%s, neId:%s", ne.NeType, ne.NeId) - timestamp = ne.UpdateTime + timestamp = ne.UpdateTime.Format(time.DateTime) } else { timestamp = (*neState)[0]["timestamp"] } @@ -202,11 +203,13 @@ func (s *BarProcessor) Execute(data any) (any, error) { var response *resty.Response requestURI := fmt.Sprintf("/api/rest/faultManagement/v1/elementType/%s/objectType/alarms", ne.NeType) - restHost := fmt.Sprintf("http://127.0.0.1:%d", config.GetYamlConfig().Rest[0].Port) + //restHost := fmt.Sprintf("http://127.0.0.1:%d", config.GetYamlConfig().Rest[0].Port) + restHost := config.GetOMCHostUrl() requestURL := fmt.Sprintf("%s%s", restHost, requestURI) log.Debug("requestURL: POST ", requestURL) response, err = client.R(). EnableTrace(). + //SetHeaders(map[string]string{tokenConst.HEADER_KEY: r.Header.Get(tokenConst.HEADER_KEY)}). SetHeaders(map[string]string{"User-Agent": config.GetDefaultUserAgent()}). SetHeaders(map[string]string{"Content-Type": "application/json;charset=UTF-8"}). SetBody(body). @@ -269,7 +272,8 @@ func (s *BarProcessor) Execute(data any) (any, error) { var response *resty.Response requestURI := fmt.Sprintf("/api/rest/faultManagement/v1/elementType/%s/objectType/alarms", ne.NeType) - restHost := fmt.Sprintf("http://127.0.0.1:%d", config.GetYamlConfig().Rest[0].Port) + //restHost := fmt.Sprintf("http://127.0.0.1:%d", config.GetYamlConfig().Rest[0].Port) + restHost := config.GetOMCHostUrl() requestURL := fmt.Sprintf("%s%s", restHost, requestURI) log.Debug("requestURL: POST ", requestURL) response, err = client.R(). diff --git a/src/modules/crontask/processor/getStateFromNE/getStateFromNE.go b/src/modules/crontask/processor/getStateFromNE/getStateFromNE.go index 0d0786d..5525c07 100644 --- a/src/modules/crontask/processor/getStateFromNE/getStateFromNE.go +++ b/src/modules/crontask/processor/getStateFromNE/getStateFromNE.go @@ -117,17 +117,20 @@ func (s *BarProcessor) Execute(data any) (any, error) { log.Trace("response body:", string(response.Body())) state := new(SystemState) _ = json.Unmarshal(response.Body(), &state) - var dateStr *string = nil - if state.ExpiryDate != "" && state.ExpiryDate != "-" { - dateStr = &state.ExpiryDate - } + // var dateStr *string = nil + // if state.ExpiryDate != "" && state.ExpiryDate != "-" { + // dateStr = &state.ExpiryDate + // } neState := new(dborm.NeState) neState.NeType = ne.NeType neState.NeId = ne.NeId neState.Version = state.Version neState.Capability = state.Capability neState.SerialNum = state.SerialNum - neState.ExpiryDate = *dateStr + // if dateStr != nil { + // neState.ExpiryDate = *dateStr + // } + neState.ExpiryDate = state.ExpiryDate cu, _ := json.Marshal(state.CpuUsage) neState.CpuUsage = string(cu) mu, _ := json.Marshal(state.MemUsage) diff --git a/src/modules/monitor/controller/sys_job.go b/src/modules/monitor/controller/sys_job.go index f8eaf11..4643a0b 100644 --- a/src/modules/monitor/controller/sys_job.go +++ b/src/modules/monitor/controller/sys_job.go @@ -40,12 +40,17 @@ type SysJobController struct { // // GET /list func (s *SysJobController) List(c *gin.Context) { - querys := ctx.QueryMap(c) - data := s.sysJobService.SelectJobPage(querys) - - rows := data["rows"].([]model.SysJob) - // 闭包函数处理多语言 language := ctx.AcceptLanguage(c) + querys := ctx.QueryMap(c) + // 多语言值转key查询 + if v, ok := querys["jobName"]; ok && v != "" { + querys["jobName"] = i18n.TFindKeyPrefix(language, "job", v.(string)) + } + + data := s.sysJobService.SelectJobPage(querys) + rows := data["rows"].([]model.SysJob) + + // 闭包函数处理多语言 converI18n := func(language string, arr *[]model.SysJob) { for i := range *arr { (*arr)[i].JobName = i18n.TKey(language, (*arr)[i].JobName) @@ -314,14 +319,21 @@ func (s *SysJobController) ResetQueueJob(c *gin.Context) { func (s *SysJobController) Export(c *gin.Context) { language := ctx.AcceptLanguage(c) // 查询结果,根据查询条件结果,单页最大值限制 - querys := ctx.BodyJSONMap(c) - data := s.sysJobService.SelectJobPage(querys) - if data["total"].(int64) == 0 { + // querys := ctx.BodyJSONMap(c) + // data := s.sysJobService.SelectJobPage(querys) + // if data["total"].(int64) == 0 { + // // 导出数据记录为空 + // c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.exportEmpty"))) + // return + // } + // rows := data["rows"].([]model.SysJob) + + rows := s.sysJobService.SelectJobList(model.SysJob{}) + if len(rows) <= 0 { // 导出数据记录为空 c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.exportEmpty"))) return } - rows := data["rows"].([]model.SysJob) // 闭包函数处理多语言 converI18n := func(language string, arr *[]model.SysJob) { @@ -340,10 +352,10 @@ func (s *SysJobController) Export(c *gin.Context) { "B1": i18n.TKey(language, "job.export.jobName"), "C1": i18n.TKey(language, "job.export.jobGroupName"), "D1": i18n.TKey(language, "job.export.invokeTarget"), - "E1": i18n.TKey(language, "job.export.targetParams"), - "F1": i18n.TKey(language, "job.export.cronExpression"), - "G1": i18n.TKey(language, "job.export.status"), - "H1": i18n.TKey(language, "job.export.remark"), + "E1": i18n.TKey(language, "job.export.cronExpression"), + "F1": i18n.TKey(language, "job.export.status"), + "G1": i18n.TKey(language, "job.export.remark"), + // "E1": i18n.TKey(language, "job.export.targetParams"), } // 读取任务组名字典数据 dictSysJobGroup := s.sysDictDataService.SelectDictDataByType("sys_job_group") @@ -370,10 +382,10 @@ func (s *SysJobController) Export(c *gin.Context) { "B" + idx: row.JobName, "C" + idx: sysJobGroup, "D" + idx: row.InvokeTarget, - "E" + idx: row.TargetParams, - "F" + idx: row.CronExpression, - "G" + idx: statusValue, - "H" + idx: row.Remark, + "E" + idx: row.CronExpression, + "F" + idx: statusValue, + "G" + idx: row.Remark, + // "E" + idx: row.TargetParams, }) } diff --git a/src/modules/monitor/controller/sys_job_log.go b/src/modules/monitor/controller/sys_job_log.go index 6e89e0e..082a602 100644 --- a/src/modules/monitor/controller/sys_job_log.go +++ b/src/modules/monitor/controller/sys_job_log.go @@ -39,6 +39,7 @@ type SysJobLogController struct { // // GET /list func (s *SysJobLogController) List(c *gin.Context) { + language := ctx.AcceptLanguage(c) // 查询参数转换map querys := ctx.QueryMap(c) // 任务ID优先级更高 @@ -47,11 +48,15 @@ func (s *SysJobLogController) List(c *gin.Context) { querys["jobName"] = jobInfo.JobName querys["jobGroup"] = jobInfo.JobGroup } - data := s.sysJobLogService.SelectJobLogPage(querys) + // 多语言值转key查询 + if v, ok := querys["jobName"]; ok && v != "" { + querys["jobName"] = i18n.TFindKeyPrefix(language, "job", v.(string)) + } + data := s.sysJobLogService.SelectJobLogPage(querys) rows := data["rows"].([]model.SysJobLog) + // 闭包函数处理多语言 - language := ctx.AcceptLanguage(c) converI18n := func(language string, arr *[]model.SysJobLog) { for i := range *arr { (*arr)[i].JobName = i18n.TKey(language, (*arr)[i].JobName) @@ -124,17 +129,24 @@ func (s *SysJobLogController) Clean(c *gin.Context) { // // POST /export func (s *SysJobLogController) Export(c *gin.Context) { + language := ctx.AcceptLanguage(c) // 查询结果,根据查询条件结果,单页最大值限制 - querys := ctx.BodyJSONMap(c) - data := s.sysJobLogService.SelectJobLogPage(querys) - if data["total"].(int64) == 0 { - c.JSON(200, result.ErrMsg("Export data record is empty")) + // querys := ctx.BodyJSONMap(c) + // data := s.sysJobLogService.SelectJobLogPage(querys) + // if data["total"].(int64) == 0 { + // c.JSON(200, result.ErrMsg("Export data record is empty")) + // return + // } + // rows := data["rows"].([]model.SysJobLog) + + rows := s.sysJobLogService.SelectJobLogList(model.SysJobLog{}) + if len(rows) <= 0 { + // 导出数据记录为空 + c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.exportEmpty"))) return } - rows := data["rows"].([]model.SysJobLog) // 闭包函数处理多语言 - language := ctx.AcceptLanguage(c) converI18n := func(language string, arr *[]model.SysJobLog) { for i := range *arr { (*arr)[i].JobName = i18n.TKey(language, (*arr)[i].JobName) @@ -150,10 +162,11 @@ func (s *SysJobLogController) Export(c *gin.Context) { "B1": i18n.TKey(language, "job.export.jobName"), "C1": i18n.TKey(language, "job.export.jobGroupName"), "D1": i18n.TKey(language, "job.export.invokeTarget"), - "E1": i18n.TKey(language, "job.export.targetParams"), - "F1": i18n.TKey(language, "job.export.jobID"), - "G1": i18n.TKey(language, "job.export.jobLogStatus"), - "H1": i18n.TKey(language, "job.export.jobLogTime"), + // "E1": i18n.TKey(language, "job.export.targetParams"), + // "F1": i18n.TKey(language, "job.export.jobID"), + "E1": i18n.TKey(language, "job.export.jobLogStatus"), + "F1": i18n.TKey(language, "job.export.jobLogTime"), + "G1": i18n.TKey(language, "log.operate.export.costTime"), } // 读取任务组名字典数据 dictSysJobGroup := s.sysDictDataService.SelectDictDataByType("sys_job_group") @@ -179,10 +192,11 @@ func (s *SysJobLogController) Export(c *gin.Context) { "B" + idx: row.JobName, "C" + idx: sysJobGroup, "D" + idx: row.InvokeTarget, - "E" + idx: row.TargetParams, - "F" + idx: row.JobMsg, - "G" + idx: statusValue, - "H" + idx: date.ParseDateToStr(row.CreateTime, date.YYYY_MM_DD_HH_MM_SS), + // "E" + idx: row.TargetParams, + // "F" + idx: row.JobMsg, + "E" + idx: statusValue, + "F" + idx: date.ParseDateToStr(row.CreateTime, date.YYYY_MM_DD_HH_MM_SS), + "G" + idx: row.CostTime, }) } diff --git a/src/modules/monitor/repository/sys_job_log.impl.go b/src/modules/monitor/repository/sys_job_log.impl.go index 1e54c88..7cf2b5c 100644 --- a/src/modules/monitor/repository/sys_job_log.impl.go +++ b/src/modules/monitor/repository/sys_job_log.impl.go @@ -6,7 +6,6 @@ import ( "nms_cxy/src/framework/datasource" "nms_cxy/src/framework/logger" - "nms_cxy/src/framework/utils/date" "nms_cxy/src/framework/utils/parse" "nms_cxy/src/framework/utils/repo" "nms_cxy/src/modules/monitor/model" @@ -80,8 +79,7 @@ func (r *SysJobLogImpl) SelectJobLogPage(query map[string]any) map[string]any { } if ok && beginTime != "" { conditions = append(conditions, "create_time >= ?") - beginDate := date.ParseStrToDate(beginTime.(string), date.YYYY_MM_DD) - params = append(params, beginDate.UnixMilli()) + params = append(params, parse.Number(beginTime.(string))) } endTime, ok := query["endTime"] if !ok { @@ -89,8 +87,7 @@ func (r *SysJobLogImpl) SelectJobLogPage(query map[string]any) map[string]any { } if ok && endTime != "" { conditions = append(conditions, "create_time <= ?") - endDate := date.ParseStrToDate(endTime.(string), date.YYYY_MM_DD) - params = append(params, endDate.UnixMilli()) + params = append(params, parse.Number(endTime.(string))) } // 构建查询条件语句 diff --git a/src/modules/network_data/controller/alarm.go b/src/modules/network_data/controller/all_alarm.go similarity index 100% rename from src/modules/network_data/controller/alarm.go rename to src/modules/network_data/controller/all_alarm.go diff --git a/src/modules/network_data/controller/perf_kpi.go b/src/modules/network_data/controller/all_kpi.go similarity index 98% rename from src/modules/network_data/controller/perf_kpi.go rename to src/modules/network_data/controller/all_kpi.go index 33eb9ab..32ec48b 100644 --- a/src/modules/network_data/controller/perf_kpi.go +++ b/src/modules/network_data/controller/all_kpi.go @@ -1,9 +1,9 @@ package controller import ( - "nms_cxy/lib/core/utils/date" "nms_cxy/src/framework/i18n" "nms_cxy/src/framework/utils/ctx" + "nms_cxy/src/framework/utils/date" "nms_cxy/src/framework/vo/result" "nms_cxy/src/modules/network_data/model" neDataService "nms_cxy/src/modules/network_data/service" diff --git a/src/modules/network_data/controller/amf.go b/src/modules/network_data/controller/amf.go index f019d1d..b95c824 100644 --- a/src/modules/network_data/controller/amf.go +++ b/src/modules/network_data/controller/amf.go @@ -1,23 +1,31 @@ package controller import ( + "encoding/json" + "fmt" + "strconv" "strings" + "time" "nms_cxy/src/framework/i18n" + "nms_cxy/src/framework/logger" "nms_cxy/src/framework/utils/ctx" + "nms_cxy/src/framework/utils/file" "nms_cxy/src/framework/utils/parse" "nms_cxy/src/framework/vo/result" "nms_cxy/src/modules/network_data/model" neDataService "nms_cxy/src/modules/network_data/service" neService "nms_cxy/src/modules/network_element/service" + sysService "nms_cxy/src/modules/system/service" "github.com/gin-gonic/gin" + "github.com/gin-gonic/gin/binding" ) // 实例化控制层 AMFController 结构体 var NewAMFController = &AMFController{ neInfoService: neService.NewNeInfoImpl, - ueEventService: neDataService.NewUEEventImpl, + ueEventService: neDataService.NewUEEventAMFImpl, } // 网元AMF @@ -26,8 +34,8 @@ var NewAMFController = &AMFController{ type AMFController struct { // 网元信息服务 neInfoService neService.INeInfo - // CDR会话事件服务 - ueEventService neDataService.IUEEvent + // UE会话事件服务 + ueEventService neDataService.IUEEventAMF } // UE会话列表 @@ -35,19 +43,19 @@ type AMFController struct { // GET /ue/list func (s *AMFController) UEList(c *gin.Context) { language := ctx.AcceptLanguage(c) - var querys model.UEEventQuery + var querys model.UEEventAMFQuery if err := c.ShouldBindQuery(&querys); err != nil { c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) return } // 查询网元获取IP - neInfo := s.neInfoService.SelectNeInfoByNeTypeAndNeID(querys.NeType, querys.NeID) - if neInfo.NeId != querys.NeID || neInfo.IP == "" { - c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.noNEInfo"))) - return - } - querys.RmUID = neInfo.RmUID + // neInfo := s.neInfoService.SelectNeInfoByNeTypeAndNeID(querys.NeType, querys.NeID) + // if neInfo.NeId != querys.NeID || neInfo.IP == "" { + // c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.noNEInfo"))) + // return + // } + // querys.RmUID = neInfo.RmUID // 查询数据 data := s.ueEventService.SelectPage(querys) @@ -79,3 +87,125 @@ func (s *AMFController) UERemove(c *gin.Context) { msg := i18n.TTemplate(language, "app.common.deleteSuccess", map[string]any{"num": rows}) c.JSON(200, result.OkMsg(msg)) } + +// UE会话列表导出 +// +// POST /ue/export +func (s *AMFController) UEExport(c *gin.Context) { + language := ctx.AcceptLanguage(c) + // 查询结果,根据查询条件结果,单页最大值限制 + var querys model.UEEventAMFQuery + if err := c.ShouldBindBodyWith(&querys, binding.JSON); err != nil { + c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) + return + } + // 限制导出数据集 + if querys.PageSize > 10000 { + querys.PageSize = 10000 + } + data := s.ueEventService.SelectPage(querys) + if parse.Number(data["total"]) == 0 { + // 导出数据记录为空 + c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.exportEmpty"))) + return + } + rows := data["rows"].([]model.UEEventAMF) + + // 导出文件名称 + fileName := fmt.Sprintf("amf_ue_event_export_%d_%d.xlsx", len(rows), time.Now().UnixMilli()) + // 第一行表头标题 + headerCells := map[string]string{ + "A1": "ID", + "B1": "IMSI", + "C1": "Event Type", + "D1": "Result", + "E1": "Time", + } + // 读取字典数据 UE 事件类型 + dictUEEventType := sysService.NewSysDictDataImpl.SelectDictDataByType("ue_event_type") + // 读取字典数据 UE 事件认证代码类型 + dictUEAauthCode := sysService.NewSysDictDataImpl.SelectDictDataByType("ue_auth_code") + // 读取字典数据 UE 事件CM状态 + dictUEEventCmState := sysService.NewSysDictDataImpl.SelectDictDataByType("ue_event_cm_state") + // 从第二行开始的数据 + dataCells := make([]map[string]any, 0) + for i, row := range rows { + idx := strconv.Itoa(i + 2) + // 解析 JSON 字符串为 map + var eventJSON map[string]interface{} + err := json.Unmarshal([]byte(row.EventJSONStr), &eventJSON) + if err != nil { + logger.Warnf("UEExport Error parsing JSON: %s", err.Error()) + continue + } + + // 取IMSI + imsi := "" + if v, ok := eventJSON["imsi"]; ok && v != nil { + imsi = v.(string) + } + // 取类型 + eventType := "" + for _, v := range dictUEEventType { + if row.EventType == v.DictValue { + eventType = i18n.TKey(language, v.DictLabel) + break + } + } + // 取结果 + eventResult := "" + // 取时间 + timeStr := "" + if row.EventType == "auth-result" { + if v, ok := eventJSON["authTime"]; ok && v != nil { + timeStr = v.(string) + } + if v, ok := eventJSON["authCode"]; ok && v != nil { + eventResult = v.(string) + for _, v := range dictUEAauthCode { + if eventResult == v.DictValue { + eventResult = i18n.TKey(language, v.DictLabel) + break + } + } + } + } + if row.EventType == "detach" { + if v, ok := eventJSON["detachTime"]; ok && v != nil { + timeStr = v.(string) + } + eventResult = "Success" + } + if row.EventType == "cm-state" { + if v, ok := eventJSON["changeTime"]; ok && v != nil { + timeStr = v.(string) + } + if v, ok := eventJSON["status"]; ok && v != nil { + eventResult = v.(string) + for _, v := range dictUEEventCmState { + if eventResult == v.DictValue { + eventResult = i18n.TKey(language, v.DictLabel) + break + } + } + } + } + + dataCells = append(dataCells, map[string]any{ + "A" + idx: row.ID, + "B" + idx: imsi, + "C" + idx: eventType, + "D" + idx: eventResult, + "E" + idx: timeStr, + }) + } + + // 导出数据表格 + saveFilePath, err := file.WriteSheet(headerCells, dataCells, fileName, "") + if err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return + } + + c.FileAttachment(saveFilePath, fileName) +} diff --git a/src/modules/network_data/controller/ims.go b/src/modules/network_data/controller/ims.go index 079164d..7e0a96e 100644 --- a/src/modules/network_data/controller/ims.go +++ b/src/modules/network_data/controller/ims.go @@ -1,23 +1,32 @@ package controller import ( + "encoding/json" + "fmt" + "strconv" "strings" + "time" "nms_cxy/src/framework/i18n" + "nms_cxy/src/framework/logger" "nms_cxy/src/framework/utils/ctx" + "nms_cxy/src/framework/utils/date" + "nms_cxy/src/framework/utils/file" "nms_cxy/src/framework/utils/parse" "nms_cxy/src/framework/vo/result" "nms_cxy/src/modules/network_data/model" neDataService "nms_cxy/src/modules/network_data/service" neService "nms_cxy/src/modules/network_element/service" + sysService "nms_cxy/src/modules/system/service" "github.com/gin-gonic/gin" + "github.com/gin-gonic/gin/binding" ) // 实例化控制层 IMSController 结构体 var NewIMSController = &IMSController{ neInfoService: neService.NewNeInfoImpl, - cdrEventService: neDataService.NewCDREventImpl, + cdrEventService: neDataService.NewCDREventIMSImpl, } // 网元IMS @@ -27,7 +36,7 @@ type IMSController struct { // 网元信息服务 neInfoService neService.INeInfo // CDR会话事件服务 - cdrEventService neDataService.ICDREvent + cdrEventService neDataService.ICDREventIMS } // CDR会话列表 @@ -35,19 +44,19 @@ type IMSController struct { // GET /cdr/list func (s *IMSController) CDRList(c *gin.Context) { language := ctx.AcceptLanguage(c) - var querys model.CDREventQuery + var querys model.CDREventIMSQuery if err := c.ShouldBindQuery(&querys); err != nil { c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) return } // 查询网元获取IP - neInfo := s.neInfoService.SelectNeInfoByNeTypeAndNeID(querys.NeType, querys.NeID) - if neInfo.NeId != querys.NeID || neInfo.IP == "" { - c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.noNEInfo"))) - return - } - querys.RmUID = neInfo.RmUID + // neInfo := s.neInfoService.SelectNeInfoByNeTypeAndNeID(querys.NeType, querys.NeID) + // if neInfo.NeId != querys.NeID || neInfo.IP == "" { + // c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.noNEInfo"))) + // return + // } + // querys.RmUID = neInfo.RmUID // 查询数据 data := s.cdrEventService.SelectPage(querys) @@ -79,3 +88,126 @@ func (s *IMSController) CDRRemove(c *gin.Context) { msg := i18n.TTemplate(language, "app.common.deleteSuccess", map[string]any{"num": rows}) c.JSON(200, result.OkMsg(msg)) } + +// CDR会话列表导出 +// +// POST /cdr/export +func (s *IMSController) CDRExport(c *gin.Context) { + language := ctx.AcceptLanguage(c) + // 查询结果,根据查询条件结果,单页最大值限制 + var querys model.CDREventIMSQuery + if err := c.ShouldBindBodyWith(&querys, binding.JSON); err != nil { + c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) + return + } + // 限制导出数据集 + if querys.PageSize > 10000 { + querys.PageSize = 10000 + } + data := s.cdrEventService.SelectPage(querys) + if parse.Number(data["total"]) == 0 { + // 导出数据记录为空 + c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.exportEmpty"))) + return + } + rows := data["rows"].([]model.CDREventIMS) + + // 导出文件名称 + fileName := fmt.Sprintf("ims_cdr_event_export_%d_%d.xlsx", len(rows), time.Now().UnixMilli()) + // 第一行表头标题 + headerCells := map[string]string{ + "A1": "ID", + "B1": "Record Behavior", + "C1": "Type", + "D1": "Called", + "E1": "Caller", + "F1": "Duration", + "G1": "Result", + "H1": "Time", + } + // 读取字典数据 CDR SIP响应代码类别类型 + dictCDRSipCode := sysService.NewSysDictDataImpl.SelectDictDataByType("cdr_sip_code") + // 读取字典数据 CDR 呼叫类型 + dictCDRCallType := sysService.NewSysDictDataImpl.SelectDictDataByType("cdr_call_type") + // 从第二行开始的数据 + dataCells := make([]map[string]any, 0) + for i, row := range rows { + idx := strconv.Itoa(i + 2) + // 解析 JSON 字符串为 map + var cdrJSON map[string]interface{} + err := json.Unmarshal([]byte(row.CDRJSONStr), &cdrJSON) + if err != nil { + logger.Warnf("CDRExport Error parsing JSON: %s", err.Error()) + continue + } + // 记录类型 + recordType := "" + if v, ok := cdrJSON["recordType"]; ok && v != nil { + recordType = v.(string) + } + // 被叫 + called := "" + if v, ok := cdrJSON["calledParty"]; ok && v != nil { + called = v.(string) + } + // 主叫 + caller := "" + if v, ok := cdrJSON["callerParty"]; ok && v != nil { + caller = v.(string) + } + // 呼叫类型 + callType := "sms" + callTypeLable := "SMS" + if v, ok := cdrJSON["callType"]; ok && v != nil { + callType = v.(string) + for _, v := range dictCDRCallType { + if callType == v.DictValue { + callTypeLable = i18n.TKey(language, v.DictLabel) + break + } + } + } + // 时长 + duration := "-" + if v, ok := cdrJSON["callDuration"]; ok && v != nil && callType != "sms" { + duration = fmt.Sprint(parse.Number(v)) + } + // 呼叫结果 非短信都有code作为结果 sms短信都ok + callResult := "Success" + if v, ok := cdrJSON["cause"]; ok && v != nil && callType != "sms" { + cause := fmt.Sprint(v) + for _, v := range dictCDRSipCode { + if cause == v.DictValue { + callResult = i18n.TKey(language, v.DictLabel) + break + } + } + } + // 取时间 + timeStr := "" + if v, ok := cdrJSON["releaseTime"]; ok && v != nil { + releaseTime := parse.Number(v) + timeStr = date.ParseDateToStr(releaseTime, date.YYYY_MM_DDTHH_MM_SSZ) + } + + dataCells = append(dataCells, map[string]any{ + "A" + idx: row.ID, + "B" + idx: recordType, + "C" + idx: callTypeLable, + "D" + idx: called, + "E" + idx: caller, + "F" + idx: duration, + "G" + idx: callResult, + "H" + idx: timeStr, + }) + } + + // 导出数据表格 + saveFilePath, err := file.WriteSheet(headerCells, dataCells, fileName, "") + if err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return + } + + c.FileAttachment(saveFilePath, fileName) +} diff --git a/src/modules/network_data/controller/mme.go b/src/modules/network_data/controller/mme.go new file mode 100644 index 0000000..8911f46 --- /dev/null +++ b/src/modules/network_data/controller/mme.go @@ -0,0 +1,201 @@ +package controller + +import ( + "encoding/json" + "fmt" + "strconv" + "strings" + "time" + + "nms_cxy/src/framework/i18n" + "nms_cxy/src/framework/logger" + "nms_cxy/src/framework/utils/ctx" + "nms_cxy/src/framework/utils/date" + "nms_cxy/src/framework/utils/file" + "nms_cxy/src/framework/utils/parse" + "nms_cxy/src/framework/vo/result" + "nms_cxy/src/modules/network_data/model" + neDataService "nms_cxy/src/modules/network_data/service" + neService "nms_cxy/src/modules/network_element/service" + sysService "nms_cxy/src/modules/system/service" + + "github.com/gin-gonic/gin" + "github.com/gin-gonic/gin/binding" +) + +// 实例化控制层 MMEController 结构体 +var NewMMEController = &MMEController{ + neInfoService: neService.NewNeInfoImpl, + ueEventService: neDataService.NewUEEventMMEImpl, +} + +// 网元MME +// +// PATH /mme +type MMEController struct { + // 网元信息服务 + neInfoService neService.INeInfo + // UE会话事件服务 + ueEventService neDataService.IUEEventMME +} + +// UE会话列表 +// +// GET /ue/list +func (s *MMEController) UEList(c *gin.Context) { + language := ctx.AcceptLanguage(c) + var querys model.UEEventMMEQuery + if err := c.ShouldBindQuery(&querys); err != nil { + c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) + return + } + + // 查询网元获取IP + // neInfo := s.neInfoService.SelectNeInfoByNeTypeAndNeID(querys.NeType, querys.NeID) + // if neInfo.NeId != querys.NeID || neInfo.IP == "" { + // c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.noNEInfo"))) + // return + // } + // querys.RmUID = neInfo.RmUID + + // 查询数据 + data := s.ueEventService.SelectPage(querys) + c.JSON(200, result.Ok(data)) +} + +// UE会话删除 +// +// DELETE /ue/:ueIds +func (s *MMEController) UERemove(c *gin.Context) { + language := ctx.AcceptLanguage(c) + ueIds := c.Param("ueIds") + if ueIds == "" { + c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) + return + } + // 处理字符转id数组后去重 + ids := strings.Split(ueIds, ",") + uniqueIDs := parse.RemoveDuplicates(ids) + if len(uniqueIDs) <= 0 { + c.JSON(200, result.Err(nil)) + return + } + rows, err := s.ueEventService.DeleteByIds(uniqueIDs) + if err != nil { + c.JSON(200, result.ErrMsg(i18n.TKey(language, err.Error()))) + return + } + msg := i18n.TTemplate(language, "app.common.deleteSuccess", map[string]any{"num": rows}) + c.JSON(200, result.OkMsg(msg)) +} + +// UE会话列表导出 +// +// POST /ue/export +func (s *MMEController) UEExport(c *gin.Context) { + language := ctx.AcceptLanguage(c) + // 查询结果,根据查询条件结果,单页最大值限制 + var querys model.UEEventMMEQuery + if err := c.ShouldBindBodyWith(&querys, binding.JSON); err != nil { + c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) + return + } + // 限制导出数据集 + if querys.PageSize > 10000 { + querys.PageSize = 10000 + } + data := s.ueEventService.SelectPage(querys) + if parse.Number(data["total"]) == 0 { + // 导出数据记录为空 + c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.exportEmpty"))) + return + } + rows := data["rows"].([]model.UEEventMME) + + // 导出文件名称 + fileName := fmt.Sprintf("mme_ue_event_export_%d_%d.xlsx", len(rows), time.Now().UnixMilli()) + // 第一行表头标题 + headerCells := map[string]string{ + "A1": "ID", + "B1": "IMSI", + "C1": "Event Type", + "D1": "Result", + "E1": "Time", + } + // 读取字典数据 UE 事件类型 + dictUEEventType := sysService.NewSysDictDataImpl.SelectDictDataByType("ue_event_type") + // 读取字典数据 UE 事件认证代码类型 + dictUEAauthCode := sysService.NewSysDictDataImpl.SelectDictDataByType("ue_auth_code") + // 读取字典数据 UE 事件CM状态 + dictUEEventCmState := sysService.NewSysDictDataImpl.SelectDictDataByType("ue_event_cm_state") + // 从第二行开始的数据 + dataCells := make([]map[string]any, 0) + for i, row := range rows { + idx := strconv.Itoa(i + 2) + // 解析 JSON 字符串为 map + var eventJSON map[string]interface{} + err := json.Unmarshal([]byte(row.EventJSONStr), &eventJSON) + if err != nil { + logger.Warnf("UEExport Error parsing JSON: %s", err.Error()) + continue + } + + // 取IMSI + imsi := "" + if v, ok := eventJSON["imsi"]; ok && v != nil { + imsi = v.(string) + } + // 取类型 + eventType := row.EventType + for _, v := range dictUEEventType { + if row.EventType == v.DictValue { + eventType = i18n.TKey(language, v.DictLabel) + break + } + } + // 取结果 + eventResult := "" + if v, ok := eventJSON["result"]; ok && v != nil { + eventResult = v.(string) + if row.EventType == "auth-result" { + for _, v := range dictUEAauthCode { + if eventResult == v.DictValue { + eventResult = i18n.TKey(language, v.DictLabel) + break + } + } + } + if row.EventType == "cm-state" { + for _, v := range dictUEEventCmState { + if eventResult == v.DictValue { + eventResult = i18n.TKey(language, v.DictLabel) + break + } + } + } + } + // 取时间 + timeStr := "" + if v, ok := eventJSON["timestamp"]; ok && v != nil { + rowTime := parse.Number(v) + timeStr = date.ParseDateToStr(rowTime, date.YYYY_MM_DDTHH_MM_SSZ) + } + + dataCells = append(dataCells, map[string]any{ + "A" + idx: row.ID, + "B" + idx: imsi, + "C" + idx: eventType, + "D" + idx: eventResult, + "E" + idx: timeStr, + }) + } + + // 导出数据表格 + saveFilePath, err := file.WriteSheet(headerCells, dataCells, fileName, "") + if err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return + } + + c.FileAttachment(saveFilePath, fileName) +} diff --git a/src/modules/network_data/controller/smf.go b/src/modules/network_data/controller/smf.go new file mode 100644 index 0000000..04d9156 --- /dev/null +++ b/src/modules/network_data/controller/smf.go @@ -0,0 +1,259 @@ +package controller + +import ( + "encoding/json" + "fmt" + "strconv" + "strings" + "time" + + "nms_cxy/src/framework/i18n" + "nms_cxy/src/framework/logger" + "nms_cxy/src/framework/utils/ctx" + "nms_cxy/src/framework/utils/file" + "nms_cxy/src/framework/utils/parse" + "nms_cxy/src/framework/vo/result" + "nms_cxy/src/modules/network_data/model" + neDataService "nms_cxy/src/modules/network_data/service" + neService "nms_cxy/src/modules/network_element/service" + + "github.com/gin-gonic/gin" + "github.com/gin-gonic/gin/binding" +) + +// 实例化控制层 SMFController 结构体 +var NewSMFController = &SMFController{ + neInfoService: neService.NewNeInfoImpl, + cdrEventService: neDataService.NewCDREventSMFImpl, +} + +// 网元SMF +// +// PATH /smf +type SMFController struct { + // 网元信息服务 + neInfoService neService.INeInfo + // CDR会话事件服务 + cdrEventService neDataService.ICDREventSMF +} + +// CDR会话列表 +// +// GET /cdr/list +func (s *SMFController) CDRList(c *gin.Context) { + language := ctx.AcceptLanguage(c) + var querys model.CDREventSMFQuery + if err := c.ShouldBindQuery(&querys); err != nil { + c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) + return + } + + // 查询网元获取IP + // neInfo := s.neInfoService.SelectNeInfoByNeTypeAndNeID(querys.NeType, querys.NeID) + // if neInfo.NeId != querys.NeID || neInfo.IP == "" { + // c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.noNEInfo"))) + // return + // } + // querys.RmUID = neInfo.RmUID + + // 查询数据 + data := s.cdrEventService.SelectPage(querys) + c.JSON(200, result.Ok(data)) +} + +// CDR会话删除 +// +// DELETE /cdr/:cdrIds +func (s *SMFController) CDRRemove(c *gin.Context) { + language := ctx.AcceptLanguage(c) + cdrIds := c.Param("cdrIds") + if cdrIds == "" { + c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) + return + } + // 处理字符转id数组后去重 + ids := strings.Split(cdrIds, ",") + uniqueIDs := parse.RemoveDuplicates(ids) + if len(uniqueIDs) <= 0 { + c.JSON(200, result.Err(nil)) + return + } + rows, err := s.cdrEventService.DeleteByIds(uniqueIDs) + if err != nil { + c.JSON(200, result.ErrMsg(i18n.TKey(language, err.Error()))) + return + } + msg := i18n.TTemplate(language, "app.common.deleteSuccess", map[string]any{"num": rows}) + c.JSON(200, result.OkMsg(msg)) +} + +// CDR会话列表导出 +// +// POST /cdr/export +func (s *SMFController) CDRExport(c *gin.Context) { + language := ctx.AcceptLanguage(c) + // 查询结果,根据查询条件结果,单页最大值限制 + var querys model.CDREventSMFQuery + if err := c.ShouldBindBodyWith(&querys, binding.JSON); err != nil { + c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) + return + } + // 限制导出数据集 + if querys.PageSize > 10000 { + querys.PageSize = 10000 + } + data := s.cdrEventService.SelectPage(querys) + if parse.Number(data["total"]) == 0 { + // 导出数据记录为空 + c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.exportEmpty"))) + return + } + rows := data["rows"].([]model.CDREventSMF) + + // 导出文件名称 + fileName := fmt.Sprintf("smf_cdr_event_export_%d_%d.xlsx", len(rows), time.Now().UnixMilli()) + // 第一行表头标题 + headerCells := map[string]string{ + "A1": "ID", + "B1": "Charging ID", + "C1": "Subscriber ID Data", + "D1": "Subscriber ID Type", + "E1": "Data Volume Uplink", + "F1": "Data Volume Downlink", + "G1": "Data Total Volume", + "H1": "Duration", + "I1": "Invocation Time", + "J1": "PDU Session Charging Information", + } + // 从第二行开始的数据 + dataCells := make([]map[string]any, 0) + for i, row := range rows { + idx := strconv.Itoa(i + 2) + // 解析 JSON 字符串为 map + var cdrJSON map[string]interface{} + err := json.Unmarshal([]byte(row.CDRJSONStr), &cdrJSON) + if err != nil { + logger.Warnf("CDRExport Error parsing JSON: %s", err.Error()) + continue + } + // 计费ID + chargingID := "" + if v, ok := cdrJSON["chargingID"]; ok && v != nil { + chargingID = fmt.Sprint(parse.Number(v)) + } + // 订阅 ID 类型 + subscriptionIDType := "-" + // 订阅 ID 数据 + subscriptionIDData := "-" + if v, ok := cdrJSON["subscriberIdentifier"]; ok && v != nil { + if sub, subOk := v.(map[string]any); subOk && sub != nil { + subscriptionIDType = sub["subscriptionIDType"].(string) + subscriptionIDData = sub["subscriptionIDData"].(string) + } + } + // 数据量上行链路 + dataVolumeUplink := []string{} + // 数据量下行链路 + dataVolumeDownlink := []string{} + // 数据总量 + dataTotalVolume := []string{} + if v, ok := cdrJSON["listOfMultipleUnitUsage"]; ok && v != nil { + usageList := v.([]any) + if len(usageList) > 0 { + for _, used := range usageList { + usedUnit := used.(map[string]any) + usedUnitList := usedUnit["usedUnitContainer"].([]any) + if len(usedUnitList) > 0 { + for _, data := range usedUnitList { + udata := data.(map[string]any) + if dup, dupOk := udata["dataVolumeUplink"]; dupOk { + dataVolumeUplink = append(dataVolumeUplink, fmt.Sprint(parse.Number(dup))) + } + if ddown, ddownOk := udata["dataVolumeDownlink"]; ddownOk { + dataVolumeDownlink = append(dataVolumeDownlink, fmt.Sprint(parse.Number(ddown))) + } + if dt, dtOk := udata["dataTotalVolume"]; dtOk { + dataTotalVolume = append(dataTotalVolume, fmt.Sprint(parse.Number(dt))) + } + } + } + } + } + } + // 时长 + duration := "-" + if v, ok := cdrJSON["duration"]; ok && v != nil { + duration = fmt.Sprint(parse.Number(v)) + } + // 调用时间 + invocationTimestamp := "" + if v, ok := cdrJSON["invocationTimestamp"]; ok && v != nil { + invocationTimestamp = v.(string) + } + // 记录打开时间 + pduSessionChargingInformation := "" + if v, ok := cdrJSON["pDUSessionChargingInformation"]; ok && v != nil { + pduInfo := v.(map[string]any) + + User_Identifier := "" + if v, ok := pduInfo["userIdentifier"]; ok && v != nil { + User_Identifier = v.(string) + } + SSC_Mode := "" + if v, ok := pduInfo["sSCMode"]; ok && v != nil { + SSC_Mode = v.(string) + } + RAT_Type := "" + if v, ok := pduInfo["rATType"]; ok && v != nil { + RAT_Type = v.(string) + } + DNN_ID := "" + if v, ok := pduInfo["dNNID"]; ok && v != nil { + DNN_ID = v.(string) + } + PDU_Type := "" + if v, ok := pduInfo["pDUType"]; ok && v != nil { + PDU_Type = v.(string) + } + PDU_IPv4 := "" + PDU_IPv6 := "" + if v, ok := pduInfo["pDUAddress"]; ok && v != nil { + pDUAddress := v.(map[string]any) + if addr, ok := pDUAddress["pDUIPv4Address"]; ok && addr != nil { + PDU_IPv4 = addr.(string) + } + if addr, ok := pDUAddress["pDUIPv6AddresswithPrefix"]; ok && addr != nil { + PDU_IPv6 = addr.(string) + } + } + + pduSessionChargingInformation = fmt.Sprintf(`User Identifier: %s +SSC Mode: %s RAT Type: %s DNN ID: %s +PDU Type: %s +PDU IPv4 Address: %s +PDU IPv6 Addres Swith Prefix: %s`, User_Identifier, SSC_Mode, RAT_Type, DNN_ID, PDU_Type, PDU_IPv4, PDU_IPv6) + } + + dataCells = append(dataCells, map[string]any{ + "A" + idx: row.ID, + "B" + idx: chargingID, + "C" + idx: subscriptionIDData, + "D" + idx: subscriptionIDType, + "E" + idx: strings.Join(dataVolumeUplink, ","), + "F" + idx: strings.Join(dataVolumeDownlink, ","), + "G" + idx: strings.Join(dataTotalVolume, ","), + "H" + idx: duration, + "I" + idx: invocationTimestamp, + "J" + idx: pduSessionChargingInformation, + }) + } + + // 导出数据表格 + saveFilePath, err := file.WriteSheet(headerCells, dataCells, fileName, "") + if err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return + } + + c.FileAttachment(saveFilePath, fileName) +} diff --git a/src/modules/network_element/controller/udm_auth.go b/src/modules/network_data/controller/udm_auth.go similarity index 60% rename from src/modules/network_element/controller/udm_auth.go rename to src/modules/network_data/controller/udm_auth.go index 10d5272..099ba5f 100644 --- a/src/modules/network_element/controller/udm_auth.go +++ b/src/modules/network_data/controller/udm_auth.go @@ -2,18 +2,19 @@ package controller import ( "fmt" + "path/filepath" "strings" "time" - mmlclient "nms_cxy/lib/core/mml_client" "nms_cxy/src/framework/constants/uploadsubpath" "nms_cxy/src/framework/i18n" "nms_cxy/src/framework/utils/ctx" "nms_cxy/src/framework/utils/file" "nms_cxy/src/framework/utils/parse" - "nms_cxy/src/framework/utils/ssh" + "nms_cxy/src/framework/utils/telnet" "nms_cxy/src/framework/vo/result" - "nms_cxy/src/modules/network_element/model" + "nms_cxy/src/modules/network_data/model" + neDataService "nms_cxy/src/modules/network_data/service" neService "nms_cxy/src/modules/network_element/service" "github.com/gin-gonic/gin" @@ -22,21 +23,21 @@ import ( // 实例化控制层 UDMAuthController 结构体 var NewUDMAuth = &UDMAuthController{ - udmAuthService: neService.NewUDMAuthImpl, + udmAuthService: neDataService.NewUDMAuthImpl, neInfoService: neService.NewNeInfoImpl, } -// UDM鉴权用户请求 +// UDM鉴权用户 // // PATH /udm/auth type UDMAuthController struct { // UDM鉴权信息服务 - udmAuthService neService.IUDMAuth + udmAuthService neDataService.IUDMAuth // 网元信息服务 neInfoService neService.INeInfo } -// UDM鉴权用户-获取全部保存数据库 +// UDM鉴权用户重载数据 // // POST /resetData/:neId func (s *UDMAuthController) ResetData(c *gin.Context) { @@ -48,21 +49,21 @@ func (s *UDMAuthController) ResetData(c *gin.Context) { } neId = "" - data := s.udmAuthService.Save(neId) + data := s.udmAuthService.ResetData(neId) c.JSON(200, result.OkData(data)) } -// UDM鉴权用户 +// UDM鉴权用户列表 // // GET /list func (s *UDMAuthController) List(c *gin.Context) { querys := ctx.QueryMap(c) querys["neId"] = "" - data := s.udmAuthService.Page(querys) + data := s.udmAuthService.SelectPage(querys) c.JSON(200, result.Ok(data)) } -// UDM鉴权用户-信息 +// UDM鉴权用户信息 // // GET /:neId/:imsi func (s *UDMAuthController) Info(c *gin.Context) { @@ -81,10 +82,16 @@ func (s *UDMAuthController) Info(c *gin.Context) { return } - msg := fmt.Sprintf("dsp authdat:imsi=%s", imsi) + telnetClient, err := s.neInfoService.NeRunTelnetClient("UDM", neId, 1) + if err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return + } + defer telnetClient.Close() // 发送MML - data, err := mmlclient.MMLSendMsgToMap(neInfo.IP, msg) + cmd := fmt.Sprintf("dsp authdat:imsi=%s", imsi) + data, err := telnet.ConvertToMap(telnetClient, cmd) if err != nil { c.JSON(200, result.ErrMsg(err.Error())) return @@ -95,31 +102,31 @@ func (s *UDMAuthController) Info(c *gin.Context) { return } - // 查询数据库是否存在并存入 neId = "" - var userInfo model.UDMAuth - list := s.udmAuthService.List(model.UDMAuth{NeID: neId, Imsi: imsi}) - if len(list) > 0 { - userInfo = list[0] - // 返回查询的用户信息 - userInfo.Amf = data["amf"] - userInfo.AlgoIndex = data["algo"] - userInfo.Opc = data["opc"] - userInfo.Ki = data["ki"] - } else { - userInfo := model.UDMAuth{ - Imsi: imsi, - Amf: data["amf"], - AlgoIndex: data["algo"], - Opc: data["opc"], - Ki: data["ki"], - } - s.udmAuthService.Insert(neId, userInfo) + u := model.UDMAuth{ + IMSI: imsi, + Amf: data["amf"], + Status: "1", + Ki: data["ki"], + AlgoIndex: data["algo"], + Opc: data["opc"], + NeId: neId, } - c.JSON(200, result.OkData(userInfo)) + + // 查询imsi存在赋予id用于更新 + list := s.udmAuthService.SelectList(u) + if len(list) > 0 { + item := list[0] + if item.ID != "" { + u.ID = item.ID + } + } + go s.udmAuthService.Insert(neId, u) + + c.JSON(200, result.OkData(u)) } -// UDM鉴权用户-增加 +// UDM鉴权用户新增 // // POST /:neId func (s *UDMAuthController) Add(c *gin.Context) { @@ -132,7 +139,7 @@ func (s *UDMAuthController) Add(c *gin.Context) { var body model.UDMAuth err := c.ShouldBindBodyWith(&body, binding.JSON) - if err != nil || body.Imsi == "" { + if err != nil || body.IMSI == "" { c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) return } @@ -144,10 +151,16 @@ func (s *UDMAuthController) Add(c *gin.Context) { return } - msg := fmt.Sprintf("add authdat:imsi=%s,ki=%s,amf=%s,algo=%s,opc=%s", body.Imsi, body.Ki, body.Amf, body.AlgoIndex, body.Opc) + telnetClient, err := s.neInfoService.NeRunTelnetClient("UDM", neId, 1) + if err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return + } + defer telnetClient.Close() // 发送MML - data, err := mmlclient.MMLSendMsgToString(neInfo.IP, msg) + cmd := fmt.Sprintf("add authdat:imsi=%s,ki=%s,amf=%s,algo=%s,opc=%s", body.IMSI, body.Ki, body.Amf, body.AlgoIndex, body.Opc) + data, err := telnet.ConvertToStr(telnetClient, cmd) if err != nil { c.JSON(200, result.ErrMsg(err.Error())) return @@ -156,12 +169,12 @@ func (s *UDMAuthController) Add(c *gin.Context) { // 命令ok时 if strings.Contains(data, "ok") { neId = "" - s.udmAuthService.Insert(neId, body) + go s.udmAuthService.Insert(neId, body) } c.JSON(200, result.OkData(data)) } -// UDM鉴权用户-批量添加 +// UDM鉴权用户批量新增 // // POST /:neId/:num func (s *UDMAuthController) Adds(c *gin.Context) { @@ -175,7 +188,7 @@ func (s *UDMAuthController) Adds(c *gin.Context) { var body model.UDMAuth err := c.ShouldBindBodyWith(&body, binding.JSON) - if err != nil || body.Imsi == "" { + if err != nil || body.IMSI == "" { c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) return } @@ -187,10 +200,16 @@ func (s *UDMAuthController) Adds(c *gin.Context) { return } - msg := fmt.Sprintf("baa authdat:start_imsi=%s,sub_num=%s,ki=%s,amf=%s,algo=%s,opc=%s", body.Imsi, num, body.Ki, body.Amf, body.AlgoIndex, body.Opc) + telnetClient, err := s.neInfoService.NeRunTelnetClient("UDM", neId, 1) + if err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return + } + defer telnetClient.Close() // 发送MML - data, err := mmlclient.MMLSendMsgToString(neInfo.IP, msg) + cmd := fmt.Sprintf("baa authdat:start_imsi=%s,sub_num=%s,ki=%s,amf=%s,algo=%s,opc=%s", body.IMSI, num, body.Ki, body.Amf, body.AlgoIndex, body.Opc) + data, err := telnet.ConvertToStr(telnetClient, cmd) if err != nil { c.JSON(200, result.ErrMsg(err.Error())) return @@ -199,12 +218,12 @@ func (s *UDMAuthController) Adds(c *gin.Context) { // 命令ok时 if strings.Contains(data, "ok") { neId = "" - s.udmAuthService.Inserts(neId, body, num) + go s.udmAuthService.LoadData(neId, body.IMSI, num) } c.JSON(200, result.OkData(data)) } -// UDM鉴权用户-修改 +// UDM鉴权用户修改 // // PUT /:neId func (s *UDMAuthController) Edit(c *gin.Context) { @@ -217,7 +236,7 @@ func (s *UDMAuthController) Edit(c *gin.Context) { var body model.UDMAuth err := c.ShouldBindBodyWith(&body, binding.JSON) - if err != nil || body.Imsi == "" { + if err != nil || body.IMSI == "" { c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) return } @@ -229,23 +248,29 @@ func (s *UDMAuthController) Edit(c *gin.Context) { return } - msg := fmt.Sprintf("mod authdata:imsi=%s", body.Imsi) - // 修改的参数名称 - if body.Ki != "" { - msg += fmt.Sprintf(",ki=%s", body.Ki) - } - if body.Amf != "" { - msg += fmt.Sprintf(",amf=%s", body.Amf) - } - if body.AlgoIndex != "" { - msg += fmt.Sprintf(",algo=%s", body.AlgoIndex) - } - if body.Opc != "" { - msg += fmt.Sprintf(",opc=%s", body.Opc) + telnetClient, err := s.neInfoService.NeRunTelnetClient("UDM", neId, 1) + if err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return } + defer telnetClient.Close() // 发送MML - data, err := mmlclient.MMLSendMsgToString(neInfo.IP, msg) + cmd := fmt.Sprintf("mod authdata:imsi=%s", body.IMSI) + // 修改的参数名称 + if body.Ki != "" { + cmd += fmt.Sprintf(",ki=%s", body.Ki) + } + if body.Amf != "" { + cmd += fmt.Sprintf(",amf=%s", body.Amf) + } + if body.AlgoIndex != "" { + cmd += fmt.Sprintf(",algo=%s", body.AlgoIndex) + } + if body.Opc != "" { + cmd += fmt.Sprintf(",opc=%s", body.Opc) + } + data, err := telnet.ConvertToStr(telnetClient, cmd) if err != nil { c.JSON(200, result.ErrMsg(err.Error())) return @@ -254,12 +279,12 @@ func (s *UDMAuthController) Edit(c *gin.Context) { // 命令ok时 if strings.Contains(data, "ok") { neId = "" - s.udmAuthService.Update(neId, body) + go s.udmAuthService.Insert(neId, body) } c.JSON(200, result.OkData(data)) } -// UDM鉴权用户-删除 +// UDM鉴权用户删除 // // DELETE /:neId/:imsi func (s *UDMAuthController) Remove(c *gin.Context) { @@ -286,27 +311,34 @@ func (s *UDMAuthController) Remove(c *gin.Context) { return } + telnetClient, err := s.neInfoService.NeRunTelnetClient("UDM", neId, 1) + if err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return + } + defer telnetClient.Close() + resultData := map[string]string{} for _, imsi := range uniqueIDs { - msg := fmt.Sprintf("del authdat:imsi=%s", imsi) - // 发送MML - data, err := mmlclient.MMLSendMsgToString(neInfo.IP, msg) + cmd := fmt.Sprintf("del authdat:imsi=%s", imsi) + data, err := telnet.ConvertToStr(telnetClient, cmd) if err != nil { resultData[imsi] = err.Error() + continue } // 命令ok时 if strings.Contains(data, "ok") { neId = "" - s.udmAuthService.Delete(neId, imsi) - resultData[imsi] = data + go s.udmAuthService.Delete(neId, imsi) } + resultData[imsi] = data } c.JSON(200, result.OkData(resultData)) } -// UDM鉴权用户-批量删除 +// UDM鉴权用户批量删除 // // DELETE /:neId/:imsi/:num func (s *UDMAuthController) Removes(c *gin.Context) { @@ -326,10 +358,16 @@ func (s *UDMAuthController) Removes(c *gin.Context) { return } - msg := fmt.Sprintf("bde authdat:start_imsi=%s,sub_num=%s", imsi, num) + telnetClient, err := s.neInfoService.NeRunTelnetClient("UDM", neId, 1) + if err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return + } + defer telnetClient.Close() // 发送MML - data, err := mmlclient.MMLSendMsgToString(neInfo.IP, msg) + cmd := fmt.Sprintf("bde authdat:start_imsi=%s,sub_num=%s", imsi, num) + data, err := telnet.ConvertToStr(telnetClient, cmd) if err != nil { c.JSON(200, result.ErrMsg(err.Error())) return @@ -338,12 +376,12 @@ func (s *UDMAuthController) Removes(c *gin.Context) { // 命令ok时 if strings.Contains(data, "ok") { neId = "" - s.udmAuthService.Deletes(neId, imsi, num) + go s.udmAuthService.LoadData(neId, imsi, num) } c.JSON(200, result.OkData(data)) } -// UDM鉴权用户-导出 +// UDM鉴权用户导出 // // POST /export func (s *UDMAuthController) Export(c *gin.Context) { @@ -359,14 +397,14 @@ func (s *UDMAuthController) Export(c *gin.Context) { } if !(body.Type == "csv" || body.Type == "txt") { - c.JSON(200, result.ErrMsg(i18n.TKey(language, "ne.udm.errImportUserAuthFileFormat"))) + c.JSON(200, result.ErrMsg(i18n.TKey(language, "ne.udm.errExportType"))) return } neId := "" - list := s.udmAuthService.List(model.UDMAuth{NeID: neId}) + list := s.udmAuthService.SelectList(model.UDMAuth{NeId: neId}) // 文件名 - fileName := fmt.Sprintf("OMC_AUTH_USER_EXPORT_%s_%d.%s", neId, time.Now().UnixMilli(), body.Type) + fileName := fmt.Sprintf("udm_auth_user_export_%s_%d.%s", neId, time.Now().UnixMilli(), body.Type) filePath := fmt.Sprintf("%s/%s", file.ParseUploadFileDir(uploadsubpath.EXPORT), fileName) if body.Type == "csv" { @@ -374,7 +412,7 @@ func (s *UDMAuthController) Export(c *gin.Context) { data := [][]string{} data = append(data, []string{"imsi", "ki", "algo", "amf", "opc"}) for _, v := range list { - data = append(data, []string{v.Imsi, v.Ki, v.AlgoIndex, v.Amf, v.Opc}) + data = append(data, []string{v.IMSI, v.Ki, v.AlgoIndex, v.Amf, v.Opc}) } // 输出到文件 err := file.WriterFileCSV(data, filePath) @@ -388,7 +426,7 @@ func (s *UDMAuthController) Export(c *gin.Context) { // 转换数据 data := [][]string{} for _, v := range list { - data = append(data, []string{v.Imsi, v.Ki, v.AlgoIndex, v.Amf, v.Opc}) + data = append(data, []string{v.IMSI, v.Ki, v.AlgoIndex, v.Amf, v.Opc}) } // 输出到文件 err = file.WriterFileTXT(data, ",", filePath) @@ -401,55 +439,68 @@ func (s *UDMAuthController) Export(c *gin.Context) { c.FileAttachment(filePath, fileName) } -// UDM鉴权用户-导入 +// UDM鉴权用户导入 // // POST /import func (s *UDMAuthController) Import(c *gin.Context) { language := ctx.AcceptLanguage(c) - neId := c.PostForm("neId") - if neId == "" { + var body struct { + NeId string `json:"neId" binding:"required"` + UploadPath string `json:"uploadPath" binding:"required"` + } + if err := c.ShouldBindBodyWith(&body, binding.JSON); err != nil { c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) return } - formFile, err := c.FormFile("file") - if err != nil { - c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) - return - } - // 获取文件名 - if !(strings.HasSuffix(formFile.Filename, ".csv") || strings.HasSuffix(formFile.Filename, ".txt")) { + + // 判断文件名 + if !(strings.HasSuffix(body.UploadPath, ".csv") || strings.HasSuffix(body.UploadPath, ".txt")) { c.JSON(200, result.ErrMsg(i18n.TKey(language, "ne.udm.errImportUserAuthFileFormat"))) return } - // 上传文件转存 - upFilePath, err := file.TransferUploadFile(formFile, uploadsubpath.IMPORT, nil) - if err != nil { - c.JSON(200, result.ErrMsg(err.Error())) - return - } // 查询网元获取IP - neInfo := s.neInfoService.SelectNeInfoByNeTypeAndNeID("UDM", neId) - if neInfo.NeId != neId || neInfo.IP == "" { + neInfo := s.neInfoService.SelectNeInfoByNeTypeAndNeID("UDM", body.NeId) + if neInfo.NeId != body.NeId || neInfo.IP == "" { c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.noNEInfo"))) return } - // 本地文件 - localPath := file.ParseUploadFilePath(upFilePath) - nePath := "/tmp" //config.Get("mml.upload").(string) - // 复制到远程 - err = ssh.FileSCPLocalToNe(neInfo.IP, localPath, nePath) + // 网元主机的SSH客户端 + sshClient, err := s.neInfoService.NeRunSSHClient(neInfo.NeType, neInfo.NeId) if err != nil { c.JSON(200, result.ErrMsg(err.Error())) return } + defer sshClient.Close() + // 网元主机的SSH客户端进行文件传输 + sftpClient, err := sshClient.NewClientSFTP() + if err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return + } + defer sftpClient.Close() - fileName := localPath[strings.LastIndex(localPath, "/")+1:] - msg := fmt.Sprintf("import authdat:path=%s", fmt.Sprintf("%s/%s", nePath, fileName)) + // 本地文件 + localFilePath := file.ParseUploadFilePath(body.UploadPath) + neFilePath := fmt.Sprintf("/tmp/%s", filepath.Base(localFilePath)) + // 复制到远程 + if err = sftpClient.CopyFileLocalToRemote(localFilePath, neFilePath); err != nil { + c.JSON(200, result.ErrMsg("error uploading file")) + return + } + + // 网元主机的Telnet客户端 + telnetClient, err := s.neInfoService.NeRunTelnetClient(neInfo.NeType, neInfo.NeId, 1) + if err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return + } + defer telnetClient.Close() // 发送MML - data, err := mmlclient.MMLSendMsgToString(neInfo.IP, msg) + cmd := fmt.Sprintf("import authdat:path=%s", neFilePath) + data, err := telnet.ConvertToStr(telnetClient, cmd) if err != nil { c.JSON(200, result.ErrMsg(err.Error())) return @@ -457,15 +508,15 @@ func (s *UDMAuthController) Import(c *gin.Context) { // 命令ok时 if strings.Contains(data, "ok") { - if strings.HasSuffix(fileName, ".csv") { - data := file.ReadFileCSV(localPath) - neId = "" - go s.udmAuthService.InsertCSV(neId, data) + if strings.HasSuffix(body.UploadPath, ".csv") { + data := file.ReadFileCSV(localFilePath) + neId := "" + go s.udmAuthService.InsertData(neId, "csv", data) } - if strings.HasSuffix(fileName, ".txt") { - data := file.ReadFileTXT(",", localPath) - neId = "" - go s.udmAuthService.InsertTxt(neId, data) + if strings.HasSuffix(body.UploadPath, ".txt") { + data := file.ReadFileTXT(",", localFilePath) + neId := "" + go s.udmAuthService.InsertData(neId, "txt", data) } } c.JSON(200, result.OkMsg(data)) diff --git a/src/modules/network_element/controller/udm_sub.go b/src/modules/network_data/controller/udm_sub.go similarity index 62% rename from src/modules/network_element/controller/udm_sub.go rename to src/modules/network_data/controller/udm_sub.go index e38e84f..8c955d3 100644 --- a/src/modules/network_element/controller/udm_sub.go +++ b/src/modules/network_data/controller/udm_sub.go @@ -2,19 +2,20 @@ package controller import ( "fmt" + "path/filepath" "strconv" "strings" "time" - mmlclient "nms_cxy/lib/core/mml_client" "nms_cxy/src/framework/constants/uploadsubpath" "nms_cxy/src/framework/i18n" "nms_cxy/src/framework/utils/ctx" "nms_cxy/src/framework/utils/file" "nms_cxy/src/framework/utils/parse" - "nms_cxy/src/framework/utils/ssh" + "nms_cxy/src/framework/utils/telnet" "nms_cxy/src/framework/vo/result" - "nms_cxy/src/modules/network_element/model" + "nms_cxy/src/modules/network_data/model" + neDataService "nms_cxy/src/modules/network_data/service" neService "nms_cxy/src/modules/network_element/service" "github.com/gin-gonic/gin" @@ -23,21 +24,21 @@ import ( // 实例化控制层 UDMSubController 结构体 var NewUDMSub = &UDMSubController{ - udmSubService: neService.NewUDMSubImpl, + udmSubService: neDataService.NewUDMSubImpl, neInfoService: neService.NewNeInfoImpl, } -// UDM签约用户请求 +// UDM签约用户 // // PATH /udm/sub type UDMSubController struct { - // UDM鉴权信息服务 - udmSubService neService.IUDMSub + // UDM签约信息服务 + udmSubService neDataService.IUDMSub // 网元信息服务 neInfoService neService.INeInfo } -// UDM签约用户-获取全部保存数据库 +// UDM签约用户重载数据 // // POST /resetData/:neId func (s *UDMSubController) ResetData(c *gin.Context) { @@ -49,21 +50,21 @@ func (s *UDMSubController) ResetData(c *gin.Context) { } neId = "" - data := s.udmSubService.Save(neId) + data := s.udmSubService.ResetData(neId) c.JSON(200, result.OkData(data)) } -// UDM签约用户 +// UDM签约用户列表 // // GET /list func (s *UDMSubController) List(c *gin.Context) { querys := ctx.QueryMap(c) querys["neId"] = "" - data := s.udmSubService.Page(querys) + data := s.udmSubService.SelectPage(querys) c.JSON(200, result.Ok(data)) } -// UDM签约用户-信息 +// UDM签约用户信息 // // GET /:neId/:imsi func (s *UDMSubController) Info(c *gin.Context) { @@ -82,10 +83,16 @@ func (s *UDMSubController) Info(c *gin.Context) { return } - msg := fmt.Sprintf("dsp udmuser:imsi=%s", imsi) + telnetClient, err := s.neInfoService.NeRunTelnetClient("UDM", neId, 1) + if err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return + } + defer telnetClient.Close() // 发送MML - data, err := mmlclient.MMLSendMsgToMap(neInfo.IP, msg) + cmd := fmt.Sprintf("dsp udmuser:imsi=%s", imsi) + data, err := telnet.ConvertToMap(telnetClient, cmd) if err != nil { c.JSON(200, result.ErrMsg(err.Error())) return @@ -104,8 +111,9 @@ func (s *UDMSubController) Info(c *gin.Context) { if imsMsisdnLen != -1 { msisdn = msisdn[:imsMsisdnLen] } - userInfo := model.UDMSub{ - Imsi: imsi, + neId = "" + u := model.UDMSub{ + IMSI: imsi, Msisdn: msisdn, Ambr: data["AMBR"], Arfb: data["AreaForbidden"], @@ -115,35 +123,37 @@ func (s *UDMSubController) Info(c *gin.Context) { Nssai: data["NSSAI"], SmfSel: data["Smf-Selection"], Rat: fmt.Sprint(rat), + NeId: neId, } // 1,64,24,65,def_eps,1,2,010200000000,- if v, ok := data["EPS-Data"]; ok { - userInfo.EpsDat = v + u.EpsDat = v arr := strings.Split(v, ",") - userInfo.EpsFlag = arr[0] - userInfo.EpsOdb = arr[1] - userInfo.HplmnOdb = arr[2] - userInfo.Ard = arr[3] - userInfo.Epstpl = arr[4] - userInfo.ContextId = arr[5] - userInfo.ApnContext = arr[7] - userInfo.StaticIp = arr[8] + u.EpsFlag = arr[0] + u.EpsOdb = arr[1] + u.HplmnOdb = arr[2] + u.Ard = arr[3] + u.Epstpl = arr[4] + u.ContextId = arr[5] + u.ApnContext = arr[7] + // [6] 是不要的,导入和导出不用 + u.StaticIp = arr[8] } - // 查询数据库是否存在并存入更新 - neId = "" - list := s.udmSubService.List(model.UDMSub{NeID: neId, Imsi: imsi}) + // 查询imsi存在赋予id用于更新 + list := s.udmSubService.SelectList(u) if len(list) > 0 { - listItme := list[0] - userInfo.ID = listItme.ID - s.udmSubService.Update(neId, userInfo) - } else { - s.udmSubService.Insert(neId, userInfo) + item := list[0] + if item.ID != "" { + u.ID = item.ID + } } - c.JSON(200, result.OkData(userInfo)) + go s.udmSubService.Insert(neId, u) + + c.JSON(200, result.OkData(u)) } -// UDM签约用户-增加 +// UDM签约用户新增 // // POST /:neId func (s *UDMSubController) Add(c *gin.Context) { @@ -156,7 +166,7 @@ func (s *UDMSubController) Add(c *gin.Context) { var body model.UDMSub err := c.ShouldBindBodyWith(&body, binding.JSON) - if err != nil || body.Imsi == "" { + if err != nil || body.IMSI == "" { c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) return } @@ -168,15 +178,21 @@ func (s *UDMSubController) Add(c *gin.Context) { return } - msg := fmt.Sprintf("add udmuser:imsi=%s,msisdn=%s,ambr=%s,nssai=%s,arfb=%s,sar=%s,rat=%s,cn=%s,smf_sel=%s,sm_data=%s,eps_flag=%s,eps_odb=%s,hplmn_odb=%s,ard=%s,epstpl=%s,context_id=%s,apn_context=%s", - body.Imsi, body.Msisdn, body.Ambr, body.Nssai, body.Arfb, body.Sar, body.Rat, body.Cn, body.SmfSel, body.SmData, body.EpsFlag, body.EpsOdb, body.HplmnOdb, body.Ard, body.Epstpl, body.ContextId, body.ApnContext) - // static_ip指给4G UE分配的静态IP,没有可不带此字段名,批量添加IP会自动递增 - if body.StaticIp != "" { - msg += fmt.Sprintf(",static_ip=%s", body.StaticIp) + telnetClient, err := s.neInfoService.NeRunTelnetClient("UDM", neId, 1) + if err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return } + defer telnetClient.Close() // 发送MML - data, err := mmlclient.MMLSendMsgToString(neInfo.IP, msg) + cmd := fmt.Sprintf("add udmuser:imsi=%s,msisdn=%s,ambr=%s,nssai=%s,arfb=%s,sar=%s,rat=%s,cn=%s,smf_sel=%s,sm_data=%s,eps_flag=%s,eps_odb=%s,hplmn_odb=%s,ard=%s,epstpl=%s,context_id=%s,apn_context=%s", + body.IMSI, body.Msisdn, body.Ambr, body.Nssai, body.Arfb, body.Sar, body.Rat, body.Cn, body.SmfSel, body.SmData, body.EpsFlag, body.EpsOdb, body.HplmnOdb, body.Ard, body.Epstpl, body.ContextId, body.ApnContext) + // static_ip指给4G UE分配的静态IP,没有可不带此字段名,批量添加IP会自动递增 + if body.StaticIp != "" { + cmd += fmt.Sprintf(",static_ip=%s", body.StaticIp) + } + data, err := telnet.ConvertToStr(telnetClient, cmd) if err != nil { c.JSON(200, result.ErrMsg(err.Error())) return @@ -185,12 +201,12 @@ func (s *UDMSubController) Add(c *gin.Context) { // 命令ok时 if strings.Contains(data, "ok") { neId = "" - s.udmSubService.Insert(neId, body) + go s.udmSubService.Insert(neId, body) } c.JSON(200, result.OkData(data)) } -// UDM签约用户-批量添加 +// UDM签约用户批量新增 // // POST /:neId/:num func (s *UDMSubController) Adds(c *gin.Context) { @@ -204,7 +220,7 @@ func (s *UDMSubController) Adds(c *gin.Context) { var body model.UDMSub err := c.ShouldBindBodyWith(&body, binding.JSON) - if err != nil || body.Imsi == "" { + if err != nil || body.IMSI == "" { c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) return } @@ -216,15 +232,21 @@ func (s *UDMSubController) Adds(c *gin.Context) { return } - msg := fmt.Sprintf("baa udmuser:start_imsi=%s,start_msisdn=%s,sub_num=%s,ambr=%s,nssai=%s,arfb=%s,sar=%s,rat=%s,cn=%s,smf_sel=%s,sm_data=%s,eps_flag=%s,eps_odb=%s,hplmn_odb=%s,ard=%s,epstpl=%s,context_id=%s,apn_context=%s", - body.Imsi, body.Msisdn, num, body.Ambr, body.Nssai, body.Arfb, body.Sar, body.Rat, body.Cn, body.SmfSel, body.SmData, body.EpsFlag, body.EpsOdb, body.HplmnOdb, body.Ard, body.Epstpl, body.ContextId, body.ApnContext) - // static_ip指给4G UE分配的静态IP,没有可不带此字段名,批量添加IP会自动递增 - if body.StaticIp != "" { - msg += fmt.Sprintf(",static_ip=%s", body.StaticIp) + telnetClient, err := s.neInfoService.NeRunTelnetClient("UDM", neId, 1) + if err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return } + defer telnetClient.Close() // 发送MML - data, err := mmlclient.MMLSendMsgToString(neInfo.IP, msg) + cmd := fmt.Sprintf("baa udmuser:start_imsi=%s,start_msisdn=%s,sub_num=%s,ambr=%s,nssai=%s,arfb=%s,sar=%s,rat=%s,cn=%s,smf_sel=%s,sm_data=%s,eps_flag=%s,eps_odb=%s,hplmn_odb=%s,ard=%s,epstpl=%s,context_id=%s,apn_context=%s", + body.IMSI, body.Msisdn, num, body.Ambr, body.Nssai, body.Arfb, body.Sar, body.Rat, body.Cn, body.SmfSel, body.SmData, body.EpsFlag, body.EpsOdb, body.HplmnOdb, body.Ard, body.Epstpl, body.ContextId, body.ApnContext) + // static_ip指给4G UE分配的静态IP,没有可不带此字段名,批量添加IP会自动递增 + if body.StaticIp != "" { + cmd += fmt.Sprintf(",static_ip=%s", body.StaticIp) + } + data, err := telnet.ConvertToStr(telnetClient, cmd) if err != nil { c.JSON(200, result.ErrMsg(err.Error())) return @@ -233,12 +255,12 @@ func (s *UDMSubController) Adds(c *gin.Context) { // 命令ok时 if strings.Contains(data, "ok") { neId = "" - s.udmSubService.Inserts(neId, body, num) + go s.udmSubService.LoadData(neId, body.IMSI, num) } c.JSON(200, result.OkData(data)) } -// UDM签约用户-修改 +// UDM签约用户修改 // // PUT /:neId func (s *UDMSubController) Edit(c *gin.Context) { @@ -251,7 +273,7 @@ func (s *UDMSubController) Edit(c *gin.Context) { var body model.UDMSub err := c.ShouldBindBodyWith(&body, binding.JSON) - if err != nil || body.Imsi == "" { + if err != nil || body.IMSI == "" { c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) return } @@ -263,65 +285,71 @@ func (s *UDMSubController) Edit(c *gin.Context) { return } - msg := fmt.Sprintf("mod udmuser:imsi=%s", body.Imsi) - // 修改的参数名称 - if body.Msisdn != "" { - msg += fmt.Sprintf(",msisdn=%s", body.Msisdn) - } - if body.Ambr != "" { - msg += fmt.Sprintf(",ambr=%s", body.Ambr) - } - if body.Nssai != "" { - msg += fmt.Sprintf(",nssai=%s", body.Nssai) - } - if body.Arfb != "" { - msg += fmt.Sprintf(",arfb=%s", body.Arfb) - } - if body.Sar != "" { - msg += fmt.Sprintf(",sar=%s", body.Sar) - } - if body.Rat != "" { - msg += fmt.Sprintf(",rat=%s", body.Rat) - } - if body.Cn != "" { - msg += fmt.Sprintf(",cn=%s", body.Cn) - } - if body.SmfSel != "" { - msg += fmt.Sprintf(",smf_sel=%s", body.SmfSel) - } - if body.SmData != "" { - msg += fmt.Sprintf(",sm_data=%s", body.SmData) - } - if body.EpsDat != "" { - msg += fmt.Sprintf(",eps_dat=%s", body.EpsDat) - } - if body.EpsFlag != "" { - msg += fmt.Sprintf(",eps_flag=%s", body.EpsFlag) - } - if body.EpsOdb != "" { - msg += fmt.Sprintf(",eps_odb=%s", body.EpsOdb) - } - if body.HplmnOdb != "" { - msg += fmt.Sprintf(",hplmn_odb=%s", body.HplmnOdb) - } - if body.Epstpl != "" { - msg += fmt.Sprintf(",epstpl=%s", body.Epstpl) - } - if body.Ard != "" { - msg += fmt.Sprintf(",ard=%s", body.Ard) - } - if body.ContextId != "" { - msg += fmt.Sprintf(",context_id=%s", body.ContextId) - } - if body.ApnContext != "" { - msg += fmt.Sprintf(",apn_context=%s", body.ApnContext) - } - if body.StaticIp != "" { - msg += fmt.Sprintf(",static_ip=%s", body.StaticIp) + telnetClient, err := s.neInfoService.NeRunTelnetClient("UDM", neId, 1) + if err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return } + defer telnetClient.Close() // 发送MML - data, err := mmlclient.MMLSendMsgToString(neInfo.IP, msg) + cmd := fmt.Sprintf("mod udmuser:imsi=%s", body.IMSI) + // 修改的参数名称 + if body.Msisdn != "" { + cmd += fmt.Sprintf(",msisdn=%s", body.Msisdn) + } + if body.Ambr != "" { + cmd += fmt.Sprintf(",ambr=%s", body.Ambr) + } + if body.Nssai != "" { + cmd += fmt.Sprintf(",nssai=%s", body.Nssai) + } + if body.Arfb != "" { + cmd += fmt.Sprintf(",arfb=%s", body.Arfb) + } + if body.Sar != "" { + cmd += fmt.Sprintf(",sar=%s", body.Sar) + } + if body.Rat != "" { + cmd += fmt.Sprintf(",rat=%s", body.Rat) + } + if body.Cn != "" { + cmd += fmt.Sprintf(",cn=%s", body.Cn) + } + if body.SmfSel != "" { + cmd += fmt.Sprintf(",smf_sel=%s", body.SmfSel) + } + if body.SmData != "" { + cmd += fmt.Sprintf(",sm_data=%s", body.SmData) + } + if body.EpsDat != "" { + cmd += fmt.Sprintf(",eps_dat=%s", body.EpsDat) + } + if body.EpsFlag != "" { + cmd += fmt.Sprintf(",eps_flag=%s", body.EpsFlag) + } + if body.EpsOdb != "" { + cmd += fmt.Sprintf(",eps_odb=%s", body.EpsOdb) + } + if body.HplmnOdb != "" { + cmd += fmt.Sprintf(",hplmn_odb=%s", body.HplmnOdb) + } + if body.Epstpl != "" { + cmd += fmt.Sprintf(",epstpl=%s", body.Epstpl) + } + if body.Ard != "" { + cmd += fmt.Sprintf(",ard=%s", body.Ard) + } + if body.ContextId != "" { + cmd += fmt.Sprintf(",context_id=%s", body.ContextId) + } + if body.ApnContext != "" { + cmd += fmt.Sprintf(",apn_context=%s", body.ApnContext) + } + if body.StaticIp != "" { + cmd += fmt.Sprintf(",static_ip=%s", body.StaticIp) + } + data, err := telnet.ConvertToStr(telnetClient, cmd) if err != nil { c.JSON(200, result.ErrMsg(err.Error())) return @@ -330,12 +358,12 @@ func (s *UDMSubController) Edit(c *gin.Context) { // 命令ok时 if strings.Contains(data, "ok") { neId = "" - s.udmSubService.Update(neId, body) + go s.udmSubService.Insert(neId, body) } c.JSON(200, result.OkData(data)) } -// UDM签约用户-删除 +// UDM签约用户删除 // // DELETE /:neId/:imsi func (s *UDMSubController) Remove(c *gin.Context) { @@ -362,27 +390,34 @@ func (s *UDMSubController) Remove(c *gin.Context) { return } + telnetClient, err := s.neInfoService.NeRunTelnetClient("UDM", neId, 1) + if err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return + } + defer telnetClient.Close() + resultData := map[string]string{} for _, imsi := range uniqueIDs { - msg := fmt.Sprintf("del udmuser:imsi=%s", imsi) - // 发送MML - data, err := mmlclient.MMLSendMsgToString(neInfo.IP, msg) + cmd := fmt.Sprintf("del udmuser:imsi=%s", imsi) + data, err := telnet.ConvertToStr(telnetClient, cmd) if err != nil { resultData[imsi] = err.Error() + continue } // 命令ok时 if strings.Contains(data, "ok") { neId = "" - s.udmSubService.Delete(neId, imsi) - resultData[imsi] = data + go s.udmSubService.Delete(neId, imsi) } + resultData[imsi] = data } c.JSON(200, result.OkData(resultData)) } -// UDM签约用户-批量删除 +// UDM签约用户批量删除 // // DELETE /:neId/:imsi/:num func (s *UDMSubController) Removes(c *gin.Context) { @@ -402,10 +437,16 @@ func (s *UDMSubController) Removes(c *gin.Context) { return } - msg := fmt.Sprintf("bde udmuser:start_imsi=%s,sub_num=%s", imsi, num) + telnetClient, err := s.neInfoService.NeRunTelnetClient("UDM", neId, 1) + if err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return + } + defer telnetClient.Close() // 发送MML - data, err := mmlclient.MMLSendMsgToString(neInfo.IP, msg) + cmd := fmt.Sprintf("bde udmuser:start_imsi=%s,sub_num=%s", imsi, num) + data, err := telnet.ConvertToStr(telnetClient, cmd) if err != nil { c.JSON(200, result.ErrMsg(err.Error())) return @@ -414,12 +455,12 @@ func (s *UDMSubController) Removes(c *gin.Context) { // 命令ok时 if strings.Contains(data, "ok") { neId = "" - s.udmSubService.Deletes(neId, imsi, num) + go s.udmSubService.LoadData(neId, imsi, num) } c.JSON(200, result.OkData(data)) } -// UDM签约用户-导出 +// UDM签约用户导出 // // POST /export func (s *UDMSubController) Export(c *gin.Context) { @@ -440,9 +481,9 @@ func (s *UDMSubController) Export(c *gin.Context) { } neId := "" - list := s.udmSubService.List(model.UDMSub{NeID: neId}) + list := s.udmSubService.SelectList(model.UDMSub{NeId: neId}) // 文件名 - fileName := fmt.Sprintf("OMC_SUB_USER_EXPORT_%s_%d.%s", neId, time.Now().UnixMilli(), body.Type) + fileName := fmt.Sprintf("udm_sub_user_export_%s_%d.%s", neId, time.Now().UnixMilli(), body.Type) filePath := fmt.Sprintf("%s/%s", file.ParseUploadFileDir(uploadsubpath.EXPORT), fileName) if body.Type == "csv" { @@ -451,7 +492,7 @@ func (s *UDMSubController) Export(c *gin.Context) { data = append(data, []string{"imsi", "msisdn", "ambr", "nssai", "arfb", "sar", "rat", "cn", "smf_sel", "sm_dat", "eps_dat"}) for _, v := range list { epsDat := fmt.Sprintf("%s,%s,%s,%s,%s,%s,%s,%s", v.EpsFlag, v.EpsOdb, v.HplmnOdb, v.Ard, v.Epstpl, v.ContextId, v.ApnContext, v.StaticIp) - data = append(data, []string{v.Imsi, v.Msisdn, v.Ambr, v.Nssai, v.Arfb, v.Sar, v.Rat, v.Cn, v.SmfSel, v.SmData, epsDat}) + data = append(data, []string{v.IMSI, v.Msisdn, v.Ambr, v.Nssai, v.Arfb, v.Sar, v.Rat, v.Cn, v.SmfSel, v.SmData, epsDat}) } // 输出到文件 err = file.WriterFileCSV(data, filePath) @@ -466,7 +507,7 @@ func (s *UDMSubController) Export(c *gin.Context) { data := [][]string{} for _, v := range list { epsDat := fmt.Sprintf("%s,%s,%s,%s,%s,%s,%s,%s", v.EpsFlag, v.EpsOdb, v.HplmnOdb, v.Ard, v.Epstpl, v.ContextId, v.ApnContext, v.StaticIp) - data = append(data, []string{v.Imsi, v.Msisdn, v.Ambr, v.Nssai, v.Arfb, v.Sar, v.Rat, v.Cn, v.SmfSel, v.SmData, epsDat}) + data = append(data, []string{v.IMSI, v.Msisdn, v.Ambr, v.Nssai, v.Arfb, v.Sar, v.Rat, v.Cn, v.SmfSel, v.SmData, epsDat}) } // 输出到文件 err = file.WriterFileTXT(data, ",", filePath) @@ -479,55 +520,68 @@ func (s *UDMSubController) Export(c *gin.Context) { c.FileAttachment(filePath, fileName) } -// UDM签约用户-导入 +// UDM签约用户导入 // // POST /import func (s *UDMSubController) Import(c *gin.Context) { language := ctx.AcceptLanguage(c) - neId := c.PostForm("neId") - if neId == "" { + var body struct { + NeId string `json:"neId" binding:"required"` + UploadPath string `json:"uploadPath" binding:"required"` + } + if err := c.ShouldBindBodyWith(&body, binding.JSON); err != nil { c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) return } - formFile, err := c.FormFile("file") - if err != nil { - c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) - return - } - // 获取文件名 - if !(strings.HasSuffix(formFile.Filename, ".csv") || strings.HasSuffix(formFile.Filename, ".txt")) { + + // 判断文件名 + if !(strings.HasSuffix(body.UploadPath, ".csv") || strings.HasSuffix(body.UploadPath, ".txt")) { c.JSON(200, result.ErrMsg(i18n.TKey(language, "ne.udm.errImportUserSubFileFormat"))) return } - // 上传文件转存 - upFilePath, err := file.TransferUploadFile(formFile, uploadsubpath.IMPORT, nil) - if err != nil { - c.JSON(200, result.ErrMsg(err.Error())) - return - } // 查询网元获取IP - neInfo := s.neInfoService.SelectNeInfoByNeTypeAndNeID("UDM", neId) - if neInfo.NeId != neId || neInfo.IP == "" { + neInfo := s.neInfoService.SelectNeInfoByNeTypeAndNeID("UDM", body.NeId) + if neInfo.NeId != body.NeId || neInfo.IP == "" { c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.noNEInfo"))) return } - // 本地文件 - localPath := file.ParseUploadFilePath(upFilePath) - nePath := "/tmp" //config.Get("mml.upload").(string) - // 复制到远程 - err = ssh.FileSCPLocalToNe(neInfo.IP, localPath, nePath) + // 网元主机的SSH客户端 + sshClient, err := s.neInfoService.NeRunSSHClient(neInfo.NeType, neInfo.NeId) if err != nil { c.JSON(200, result.ErrMsg(err.Error())) return } + defer sshClient.Close() + // 网元主机的SSH客户端进行文件传输 + sftpClient, err := sshClient.NewClientSFTP() + if err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return + } + defer sftpClient.Close() - fileName := localPath[strings.LastIndex(localPath, "/")+1:] - msg := fmt.Sprintf("import udmuser:path=%s", fmt.Sprintf("%s/%s", nePath, fileName)) + // 本地文件 + localFilePath := file.ParseUploadFilePath(body.UploadPath) + neFilePath := fmt.Sprintf("/tmp/%s", filepath.Base(localFilePath)) + // 复制到远程 + if err = sftpClient.CopyFileLocalToRemote(localFilePath, neFilePath); err != nil { + c.JSON(200, result.ErrMsg("error uploading file")) + return + } + + // 网元主机的Telnet客户端 + telnetClient, err := s.neInfoService.NeRunTelnetClient(neInfo.NeType, neInfo.NeId, 1) + if err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return + } + defer telnetClient.Close() // 发送MML - data, err := mmlclient.MMLSendMsgToString(neInfo.IP, msg) + cmd := fmt.Sprintf("import udmuser:path=%s", neFilePath) + data, err := telnet.ConvertToStr(telnetClient, cmd) if err != nil { c.JSON(200, result.ErrMsg(err.Error())) return @@ -535,15 +589,15 @@ func (s *UDMSubController) Import(c *gin.Context) { // 命令ok时 if strings.Contains(data, "ok") { - if strings.HasSuffix(fileName, ".csv") { - data := file.ReadFileCSV(localPath) - neId = "" - go s.udmSubService.InsertCSV(neId, data) + if strings.HasSuffix(body.UploadPath, ".csv") { + data := file.ReadFileCSV(localFilePath) + neId := "" + go s.udmSubService.InsertData(neId, "csv", data) } - if strings.HasSuffix(fileName, ".txt") { - data := file.ReadFileTXT(",", localPath) - neId = "" - go s.udmSubService.InsertTxt(neId, data) + if strings.HasSuffix(body.UploadPath, ".txt") { + data := file.ReadFileTXT(",", localFilePath) + neId := "" + go s.udmSubService.InsertData(neId, "txt", data) } } c.JSON(200, result.OkMsg(data)) diff --git a/src/modules/network_data/model/cdr_event.go b/src/modules/network_data/model/cdr_event.go deleted file mode 100644 index a4721d3..0000000 --- a/src/modules/network_data/model/cdr_event.go +++ /dev/null @@ -1,28 +0,0 @@ -package model - -import "time" - -// CDREvent CDR会话对象 cdr_event -type CDREvent struct { - ID string `json:"id" gorm:"column:id;primaryKey;autoIncrement"` - NeType string `json:"neType" gorm:"column:ne_type"` - NeName string `json:"neName" gorm:"column:ne_name"` - RmUID string `json:"rmUID" gorm:"column:rm_uid"` - Timestamp int64 `json:"timestamp" gorm:"column:timestamp"` - CDRJSONStr string `json:"cdrJSON" gorm:"column:cdr_json"` - CreatedAt time.Time `json:"createdAt" gorm:"column:created_at;default:CURRENT_TIMESTAMP"` -} - -// CDREventQuery CDR会话对象查询参数结构体 -type CDREventQuery struct { - NeType string `json:"neType" form:"neType" binding:"required"` // 网元类型, 暂时支持IMS - NeID string `json:"neId" form:"neId" binding:"required"` - RmUID string `json:"rmUID" form:"rmUID"` - RecordType string `json:"recordType" form:"recordType"` // 记录行为 MOC MTC MOSM MTSM - StartTime string `json:"startTime" form:"startTime"` - EndTime string `json:"endTime" form:"endTime"` - SortField string `json:"sortField" form:"sortField" binding:"omitempty,oneof=timestamp"` // 排序字段,填写结果字段 - SortOrder string `json:"sortOrder" form:"sortOrder" binding:"omitempty,oneof=asc desc"` // 排序升降序,asc desc - PageNum int64 `json:"pageNum" form:"pageNum" binding:"required"` - PageSize int64 `json:"pageSize" form:"pageSize" binding:"required"` -} diff --git a/src/modules/network_data/model/cdr_event_ims.go b/src/modules/network_data/model/cdr_event_ims.go new file mode 100644 index 0000000..ffe280c --- /dev/null +++ b/src/modules/network_data/model/cdr_event_ims.go @@ -0,0 +1,30 @@ +package model + +import "time" + +// CDREventIMS CDR会话对象IMS cdr_event_ims +type CDREventIMS struct { + ID string `json:"id" gorm:"column:id;primaryKey;autoIncrement"` + NeType string `json:"neType" gorm:"column:ne_type"` + NeName string `json:"neName" gorm:"column:ne_name"` + RmUID string `json:"rmUID" gorm:"column:rm_uid"` // 可能没有 + Timestamp int64 `json:"timestamp" gorm:"column:timestamp"` + CDRJSONStr string `json:"cdrJSON" gorm:"column:cdr_json"` + CreatedAt time.Time `json:"createdAt" gorm:"column:created_at;default:CURRENT_TIMESTAMP"` +} + +// CDREventIMSQuery CDR会话对象IMS查询参数结构体 +type CDREventIMSQuery struct { + NeType string `json:"neType" form:"neType" binding:"required"` // 网元类型IMS + NeID string `json:"neId" form:"neId" binding:"required"` + RmUID string `json:"rmUID" form:"rmUID"` + RecordType string `json:"recordType" form:"recordType"` // 记录行为 MOC MTC MOSM MTSM + CallerParty string `json:"callerParty" form:"callerParty"` // 主叫号码 + CalledParty string `json:"calledParty" form:"calledParty"` // 被叫号码 + StartTime string `json:"startTime" form:"startTime"` + EndTime string `json:"endTime" form:"endTime"` + SortField string `json:"sortField" form:"sortField" binding:"omitempty,oneof=timestamp"` // 排序字段,填写结果字段 + SortOrder string `json:"sortOrder" form:"sortOrder" binding:"omitempty,oneof=asc desc"` // 排序升降序,asc desc + PageNum int64 `json:"pageNum" form:"pageNum" binding:"required"` + PageSize int64 `json:"pageSize" form:"pageSize" binding:"required"` +} diff --git a/src/modules/network_data/model/cdr_event_smf.go b/src/modules/network_data/model/cdr_event_smf.go new file mode 100644 index 0000000..259c102 --- /dev/null +++ b/src/modules/network_data/model/cdr_event_smf.go @@ -0,0 +1,40 @@ +package model + +import "time" + +// CDREventSMF CDR会话对象SMF cdr_event_smf +type CDREventSMF struct { + ID string `json:"id" gorm:"column:id;primaryKey;autoIncrement"` + NeType string `json:"neType" gorm:"column:ne_type"` + NeName string `json:"neName" gorm:"column:ne_name"` + RmUID string `json:"rmUID" gorm:"column:rm_uid"` + Timestamp int64 `json:"timestamp" gorm:"column:timestamp"` + CDRJSONStr string `json:"cdrJSON" gorm:"column:cdr_json"` + CreatedAt time.Time `json:"createdAt" gorm:"column:created_at;default:CURRENT_TIMESTAMP"` + + // ====== 非数据库字段属性 ====== + + // RecordType string `json:"recordType" gorm:"column:record_type"` + // ChargingID string `json:"chargingID" gorm:"column:charging_id"` + // SubscriberID string `json:"subscriberID" gorm:"column:subscriber_id"` + // Duration string `json:"duration" gorm:"column:duration"` + // DataVolumeUplink string `json:"dataVolumeUplink" gorm:"column:data_volume_uplink"` + // DataVolumeDownlink string `json:"dataVolumeDownlink" gorm:"column:data_volume_downlink"` + // DataTotalVolume string `json:"dataTotalVolume" gorm:"column:data_total_volume"` + // PDUAddress string `json:"pduAddress" gorm:"column:pdu_address"` +} + +// CDREventSMFQuery CDR会话对象SMF查询参数结构体 +type CDREventSMFQuery struct { + NeType string `json:"neType" form:"neType" binding:"required"` // SMF + NeID string `json:"neId" form:"neId" binding:"required"` + RmUID string `json:"rmUID" form:"rmUID"` + RecordType string `json:"recordType" form:"recordType"` // 暂时没用到 + SubscriberID string `json:"subscriberID" form:"subscriberID"` + StartTime string `json:"startTime" form:"startTime"` + EndTime string `json:"endTime" form:"endTime"` + SortField string `json:"sortField" form:"sortField" binding:"omitempty,oneof=timestamp"` // 排序字段,填写结果字段 + SortOrder string `json:"sortOrder" form:"sortOrder" binding:"omitempty,oneof=asc desc"` // 排序升降序,asc desc + PageNum int64 `json:"pageNum" form:"pageNum" binding:"required"` + PageSize int64 `json:"pageSize" form:"pageSize" binding:"required"` +} diff --git a/src/modules/network_data/model/udm_auth.go b/src/modules/network_data/model/udm_auth.go new file mode 100644 index 0000000..6f7c1d1 --- /dev/null +++ b/src/modules/network_data/model/udm_auth.go @@ -0,0 +1,17 @@ +package model + +// UDMAuth UDM鉴权用户对象 u_auth_user +type UDMAuth struct { + ID string `json:"id" gorm:"column:id;primaryKey;autoIncrement"` // 默认ID + IMSI string `json:"imsi" gorm:"column:imsi"` // SIM卡号 + Amf string `json:"amf" gorm:"column:amf"` // ANF + Status string `json:"status" gorm:"column:status"` // 状态 默认给1 + Ki string `json:"ki" gorm:"column:ki"` // ki + AlgoIndex string `json:"algoIndex" gorm:"column:algo_index"` // AlgoIndex + Opc string `json:"opc" gorm:"column:opc"` // opc + NeId string `json:"neId" gorm:"column:ne_id"` // UDM网元标识-子系统 +} + +func (UDMAuth) TableName() string { + return "u_auth_user" +} diff --git a/src/modules/network_element/model/udm_sub.go b/src/modules/network_data/model/udm_sub.go similarity index 86% rename from src/modules/network_element/model/udm_sub.go rename to src/modules/network_data/model/udm_sub.go index 1aa345c..a4f3acd 100644 --- a/src/modules/network_element/model/udm_sub.go +++ b/src/modules/network_data/model/udm_sub.go @@ -4,7 +4,7 @@ package model type UDMSub struct { ID string `json:"id" gorm:"column:id;primaryKey;autoIncrement"` Msisdn string `json:"msisdn" gorm:"column:msisdn"` // 相当手机号 - Imsi string `json:"imsi" gorm:"column:imsi"` // SIM卡号 + IMSI string `json:"imsi" gorm:"column:imsi"` // SIM卡号 Ambr string `json:"ambr" gorm:"column:ambr"` Nssai string `json:"nssai" gorm:"column:nssai"` Rat string `json:"rat" gorm:"column:rat"` @@ -14,7 +14,7 @@ type UDMSub struct { SmData string `json:"smData" gorm:"column:sm_data"` SmfSel string `json:"smfSel" gorm:"column:smf_sel"` EpsDat string `json:"epsDat" gorm:"column:eps_dat"` - NeID string `json:"neId" gorm:"column:ne_id"` // UDM网元标识-子系统 + NeId string `json:"neId" gorm:"column:ne_id"` // UDM网元标识-子系统 EpsFlag string `json:"epsFlag" gorm:"column:eps_flag"` EpsOdb string `json:"epsOdb" gorm:"column:eps_odb"` @@ -25,7 +25,8 @@ type UDMSub struct { ApnContext string `json:"apnContext" gorm:"column:apn_context"` StaticIp string `json:"staticIp" gorm:"column:static_ip"` - SubNum string `json:"subNum,omitempty" gorm:"-"` // 批量数 + // ====== 非数据库字段属性 ====== + } func (UDMSub) TableName() string { diff --git a/src/modules/network_data/model/ue_event.go b/src/modules/network_data/model/ue_event_amf.go similarity index 79% rename from src/modules/network_data/model/ue_event.go rename to src/modules/network_data/model/ue_event_amf.go index d39dd63..6fa549b 100644 --- a/src/modules/network_data/model/ue_event.go +++ b/src/modules/network_data/model/ue_event_amf.go @@ -2,24 +2,25 @@ package model import "time" -// UEEvent UE会话对象 ue_event -type UEEvent struct { +// UEEventAMF UE会话对象AMF ue_event_amf +type UEEventAMF struct { ID string `json:"id" gorm:"column:id;primaryKey;autoIncrement"` NeType string `json:"neType" gorm:"column:ne_type"` NeName string `json:"neName" gorm:"column:ne_name"` - RmUID string `json:"rmUID" gorm:"column:rm_uid"` + RmUID string `json:"rmUID" gorm:"column:rm_uid"` // 可能没有 Timestamp int64 `json:"timestamp" gorm:"column:timestamp"` - EventType string `json:"eventType" gorm:"column:event_type"` + EventType string `json:"eventType" gorm:"column:event_type"` // 事件类型 auth-result detach cm-state EventJSONStr string `json:"eventJSON" gorm:"column:event_json"` CreatedAt time.Time `json:"createdAt" gorm:"column:created_at;default:CURRENT_TIMESTAMP"` } -// UEEventQuery UE会话对象查询参数结构体 -type UEEventQuery struct { +// UEEventAMFQuery UE会话对象AMF查询参数结构体 +type UEEventAMFQuery struct { NeType string `json:"neType" form:"neType" binding:"required"` // 网元类型, 暂时支持AMF NeID string `json:"neId" form:"neId" binding:"required"` RmUID string `json:"rmUID" form:"rmUID"` EventType string `json:"eventType" form:"eventType"` // 事件类型 auth-result detach cm-state + IMSI string `json:"imsi" form:"imsi"` // imsi StartTime string `json:"startTime" form:"startTime"` EndTime string `json:"endTime" form:"endTime"` SortField string `json:"sortField" form:"sortField" binding:"omitempty,oneof=timestamp"` // 排序字段,填写结果字段 diff --git a/src/modules/network_data/model/ue_event_mme.go b/src/modules/network_data/model/ue_event_mme.go new file mode 100644 index 0000000..8ceab12 --- /dev/null +++ b/src/modules/network_data/model/ue_event_mme.go @@ -0,0 +1,30 @@ +package model + +import "time" + +// UEEventMME UE会话对象MME ue_event_mme +type UEEventMME struct { + ID string `json:"id" gorm:"column:id;primaryKey;autoIncrement"` + NeType string `json:"neType" gorm:"column:ne_type"` + NeName string `json:"neName" gorm:"column:ne_name"` + RmUID string `json:"rmUID" gorm:"column:rm_uid"` // 可能没有 + Timestamp int64 `json:"timestamp" gorm:"column:timestamp"` + EventType string `json:"eventType" gorm:"column:event_type"` // 事件类型 auth-result detach cm-state + EventJSONStr string `json:"eventJSON" gorm:"column:event_json"` + CreatedAt time.Time `json:"createdAt" gorm:"column:created_at;default:CURRENT_TIMESTAMP"` +} + +// UEEventMMEQuery UE会话对象MME查询参数结构体 +type UEEventMMEQuery struct { + NeType string `json:"neType" form:"neType" binding:"required"` // 网元类型, 暂时支持MME + NeID string `json:"neId" form:"neId" binding:"required"` + RmUID string `json:"rmUID" form:"rmUID"` + EventType string `json:"eventType" form:"eventType"` // 事件类型 auth-result detach cm-state + IMSI string `json:"imsi" form:"imsi"` // imsi + StartTime string `json:"startTime" form:"startTime"` + EndTime string `json:"endTime" form:"endTime"` + SortField string `json:"sortField" form:"sortField" binding:"omitempty,oneof=timestamp"` // 排序字段,填写结果字段 + SortOrder string `json:"sortOrder" form:"sortOrder" binding:"omitempty,oneof=asc desc"` // 排序升降序,asc desc + PageNum int64 `json:"pageNum" form:"pageNum" binding:"required"` + PageSize int64 `json:"pageSize" form:"pageSize" binding:"required"` +} diff --git a/src/modules/network_data/network_data.go b/src/modules/network_data/network_data.go index e888bdc..69a75a2 100644 --- a/src/modules/network_data/network_data.go +++ b/src/modules/network_data/network_data.go @@ -4,6 +4,7 @@ import ( "nms_cxy/src/framework/logger" "nms_cxy/src/framework/middleware" "nms_cxy/src/framework/middleware/collectlogs" + "nms_cxy/src/framework/middleware/repeat" "nms_cxy/src/modules/network_data/controller" "github.com/gin-gonic/gin" @@ -44,33 +45,58 @@ func Setup(router *gin.Engine) { // 网元IMS imsGroup := neDataGroup.Group("/ims") { - // CDR会话事件列表 imsGroup.GET("/cdr/list", middleware.PreAuthorize(nil), controller.NewIMSController.CDRList, ) - // CDR会话删除 imsGroup.DELETE("/cdr/:cdrIds", middleware.PreAuthorize(nil), collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.imsCDR", collectlogs.BUSINESS_TYPE_DELETE)), controller.NewIMSController.CDRRemove, ) + imsGroup.POST("/cdr/export", + middleware.PreAuthorize(nil), + collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.imsCDR", collectlogs.BUSINESS_TYPE_EXPORT)), + controller.NewIMSController.CDRExport, + ) + } + + // 网元SMF + smfGroup := neDataGroup.Group("/smf") + { + smfGroup.GET("/cdr/list", + middleware.PreAuthorize(nil), + controller.NewSMFController.CDRList, + ) + smfGroup.DELETE("/cdr/:cdrIds", + middleware.PreAuthorize(nil), + collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.smfCDR", collectlogs.BUSINESS_TYPE_DELETE)), + controller.NewSMFController.CDRRemove, + ) + smfGroup.POST("/cdr/export", + middleware.PreAuthorize(nil), + collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.smfCDR", collectlogs.BUSINESS_TYPE_EXPORT)), + controller.NewSMFController.CDRExport, + ) } // 网元AMF amfGroup := neDataGroup.Group("/amf") { - // UE会话事件 amfGroup.GET("/ue/list", middleware.PreAuthorize(nil), controller.NewAMFController.UEList, ) - // UE会话删除 amfGroup.DELETE("/ue/:ueIds", middleware.PreAuthorize(nil), collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.amfUE", collectlogs.BUSINESS_TYPE_DELETE)), controller.NewAMFController.UERemove, ) + amfGroup.POST("/ue/export", + middleware.PreAuthorize(nil), + collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.amfUE", collectlogs.BUSINESS_TYPE_EXPORT)), + controller.NewAMFController.UEExport, + ) } // 网元UPF @@ -82,4 +108,130 @@ func Setup(router *gin.Engine) { ) } + // 网元UDM 鉴权用户信息 + udmAuthGroup := neDataGroup.Group("/udm/auth") + { + udmAuthGroup.PUT("/resetData/:neId", + repeat.RepeatSubmit(5), + middleware.PreAuthorize(nil), + collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmAuth", collectlogs.BUSINESS_TYPE_CLEAN)), + controller.NewUDMAuth.ResetData, + ) + udmAuthGroup.GET("/list", + middleware.PreAuthorize(nil), + controller.NewUDMAuth.List, + ) + udmAuthGroup.GET("/:neId/:imsi", + middleware.PreAuthorize(nil), + controller.NewUDMAuth.Info, + ) + udmAuthGroup.POST("/:neId", + middleware.PreAuthorize(nil), + collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmAuth", collectlogs.BUSINESS_TYPE_INSERT)), + controller.NewUDMAuth.Add, + ) + udmAuthGroup.POST("/:neId/:num", + middleware.PreAuthorize(nil), + collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmAuth", collectlogs.BUSINESS_TYPE_INSERT)), + controller.NewUDMAuth.Adds, + ) + udmAuthGroup.PUT("/:neId", + middleware.PreAuthorize(nil), + collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmAuth", collectlogs.BUSINESS_TYPE_UPDATE)), + controller.NewUDMAuth.Edit, + ) + udmAuthGroup.DELETE("/:neId/:imsi", + middleware.PreAuthorize(nil), + collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmAuth", collectlogs.BUSINESS_TYPE_DELETE)), + controller.NewUDMAuth.Remove, + ) + udmAuthGroup.DELETE("/:neId/:imsi/:num", + middleware.PreAuthorize(nil), + collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmAuth", collectlogs.BUSINESS_TYPE_DELETE)), + controller.NewUDMAuth.Removes, + ) + udmAuthGroup.POST("/export", + middleware.PreAuthorize(nil), + collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmAuth", collectlogs.BUSINESS_TYPE_EXPORT)), + controller.NewUDMAuth.Export, + ) + udmAuthGroup.POST("/import", + middleware.PreAuthorize(nil), + collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmAuth", collectlogs.BUSINESS_TYPE_IMPORT)), + controller.NewUDMAuth.Import, + ) + } + + // 网元UDM 签约用户信息 + udmSubGroup := neDataGroup.Group("/udm/sub") + { + udmSubGroup.PUT("/resetData/:neId", + repeat.RepeatSubmit(5), + middleware.PreAuthorize(nil), + collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmSub", collectlogs.BUSINESS_TYPE_CLEAN)), + controller.NewUDMSub.ResetData, + ) + udmSubGroup.GET("/list", + middleware.PreAuthorize(nil), + controller.NewUDMSub.List, + ) + udmSubGroup.GET("/:neId/:imsi", + middleware.PreAuthorize(nil), + controller.NewUDMSub.Info, + ) + udmSubGroup.POST("/:neId", + middleware.PreAuthorize(nil), + collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmSub", collectlogs.BUSINESS_TYPE_INSERT)), + controller.NewUDMSub.Add, + ) + udmSubGroup.POST("/:neId/:num", + middleware.PreAuthorize(nil), + collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmSub", collectlogs.BUSINESS_TYPE_INSERT)), + controller.NewUDMSub.Adds, + ) + udmSubGroup.PUT("/:neId", + middleware.PreAuthorize(nil), + collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmSub", collectlogs.BUSINESS_TYPE_UPDATE)), + controller.NewUDMSub.Edit, + ) + udmSubGroup.DELETE("/:neId/:imsi", + middleware.PreAuthorize(nil), + collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmSub", collectlogs.BUSINESS_TYPE_DELETE)), + controller.NewUDMSub.Remove, + ) + udmSubGroup.DELETE("/:neId/:imsi/:num", + middleware.PreAuthorize(nil), + collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmSub", collectlogs.BUSINESS_TYPE_DELETE)), + controller.NewUDMSub.Removes, + ) + udmSubGroup.POST("/export", + middleware.PreAuthorize(nil), + collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmSub", collectlogs.BUSINESS_TYPE_EXPORT)), + controller.NewUDMSub.Export, + ) + udmSubGroup.POST("/import", + middleware.PreAuthorize(nil), + collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmSub", collectlogs.BUSINESS_TYPE_IMPORT)), + controller.NewUDMSub.Import, + ) + } + + // 网元MME + mmeGroup := neDataGroup.Group("/mme") + { + mmeGroup.GET("/ue/list", + middleware.PreAuthorize(nil), + controller.NewMMEController.UEList, + ) + mmeGroup.DELETE("/ue/:ueIds", + middleware.PreAuthorize(nil), + collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.mmeUE", collectlogs.BUSINESS_TYPE_DELETE)), + controller.NewMMEController.UERemove, + ) + mmeGroup.POST("/ue/export", + middleware.PreAuthorize(nil), + collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.mmeUE", collectlogs.BUSINESS_TYPE_EXPORT)), + controller.NewMMEController.UEExport, + ) + } } diff --git a/src/modules/network_data/repository/cdr_event.go b/src/modules/network_data/repository/cdr_event_ims.go similarity index 54% rename from src/modules/network_data/repository/cdr_event.go rename to src/modules/network_data/repository/cdr_event_ims.go index cb86655..dd68b11 100644 --- a/src/modules/network_data/repository/cdr_event.go +++ b/src/modules/network_data/repository/cdr_event_ims.go @@ -2,13 +2,13 @@ package repository import "nms_cxy/src/modules/network_data/model" -// CDR会话事件 数据层接口 -type ICDREvent interface { +// CDR会话事件IMS 数据层接口 +type ICDREventIMS interface { // SelectPage 根据条件分页查询 - SelectPage(querys model.CDREventQuery) map[string]any + SelectPage(querys model.CDREventIMSQuery) map[string]any // SelectByIds 通过ID查询 - SelectByIds(cdrIds []string) []model.CDREvent + SelectByIds(cdrIds []string) []model.CDREventIMS // DeleteByIds 批量删除信息 DeleteByIds(cdrIds []string) int64 diff --git a/src/modules/network_data/repository/cdr_event.impl.go b/src/modules/network_data/repository/cdr_event_ims.impl.go similarity index 73% rename from src/modules/network_data/repository/cdr_event.impl.go rename to src/modules/network_data/repository/cdr_event_ims.impl.go index 45d8391..08fe879 100644 --- a/src/modules/network_data/repository/cdr_event.impl.go +++ b/src/modules/network_data/repository/cdr_event_ims.impl.go @@ -6,15 +6,14 @@ import ( "nms_cxy/src/framework/datasource" "nms_cxy/src/framework/logger" - "nms_cxy/src/framework/utils/date" "nms_cxy/src/framework/utils/parse" "nms_cxy/src/framework/utils/repo" "nms_cxy/src/modules/network_data/model" ) // 实例化数据层 CDREventImpl 结构体 -var NewCDREventImpl = &CDREventImpl{ - selectSql: `select id, ne_type, ne_name, rm_uid, timestamp, cdr_json, created_at from cdr_event`, +var NewCDREventIMSImpl = &CDREventIMSImpl{ + selectSql: `select id, ne_type, ne_name, rm_uid, timestamp, cdr_json, created_at from cdr_event_ims`, resultMap: map[string]string{ "id": "ID", @@ -27,8 +26,8 @@ var NewCDREventImpl = &CDREventImpl{ }, } -// CDREventImpl CDR会话事件 数据层处理 -type CDREventImpl struct { +// CDREventIMSImpl CDR会话事件IMS 数据层处理 +type CDREventIMSImpl struct { // 查询视图对象SQL selectSql string // 结果字段与实体映射 @@ -36,10 +35,10 @@ type CDREventImpl struct { } // convertResultRows 将结果记录转实体结果组 -func (r *CDREventImpl) convertResultRows(rows []map[string]any) []model.CDREvent { - arr := make([]model.CDREvent, 0) +func (r *CDREventIMSImpl) convertResultRows(rows []map[string]any) []model.CDREventIMS { + arr := make([]model.CDREventIMS, 0) for _, row := range rows { - item := model.CDREvent{} + item := model.CDREventIMS{} for key, value := range row { if keyMapper, ok := r.resultMap[key]; ok { repo.SetFieldValue(&item, keyMapper, value) @@ -51,7 +50,7 @@ func (r *CDREventImpl) convertResultRows(rows []map[string]any) []model.CDREvent } // SelectPage 根据条件分页查询 -func (r *CDREventImpl) SelectPage(querys model.CDREventQuery) map[string]any { +func (r *CDREventIMSImpl) SelectPage(querys model.CDREventIMSQuery) map[string]any { // 查询条件拼接 var conditions []string var params []any @@ -63,19 +62,27 @@ func (r *CDREventImpl) SelectPage(querys model.CDREventQuery) map[string]any { conditions = append(conditions, "rm_uid = ?") params = append(params, querys.RmUID) } - if querys.RmUID != "" { - conditions = append(conditions, "rm_uid = ?") - params = append(params, querys.RmUID) - } if querys.StartTime != "" { conditions = append(conditions, "timestamp >= ?") - beginDate := date.ParseStrToDate(querys.StartTime, date.YYYY_MM_DD_HH_MM_SS) - params = append(params, beginDate.Unix()) + if len(querys.StartTime) == 13 { + querys.StartTime = querys.StartTime[:10] + } + params = append(params, querys.StartTime) } if querys.EndTime != "" { conditions = append(conditions, "timestamp <= ?") - endDate := date.ParseStrToDate(querys.EndTime, date.YYYY_MM_DD_HH_MM_SS) - params = append(params, endDate.Unix()) + if len(querys.EndTime) == 13 { + querys.EndTime = querys.EndTime[:10] + } + params = append(params, querys.EndTime) + } + if querys.CallerParty != "" { + conditions = append(conditions, "JSON_EXTRACT(cdr_json, '$.callerParty') = ?") + params = append(params, querys.CallerParty) + } + if querys.CalledParty != "" { + conditions = append(conditions, "JSON_EXTRACT(cdr_json, '$.calledParty') = ?") + params = append(params, querys.CalledParty) } if querys.RecordType != "" { recordTypes := strings.Split(querys.RecordType, ",") @@ -94,11 +101,11 @@ func (r *CDREventImpl) SelectPage(querys model.CDREventQuery) map[string]any { result := map[string]any{ "total": 0, - "rows": []model.CDREvent{}, + "rows": []model.CDREventIMS{}, } // 查询数量 长度为0直接返回 - totalSql := "select count(1) as 'total' from cdr_event" + totalSql := "select count(1) as 'total' from cdr_event_ims" totalRows, err := datasource.RawDB("", totalSql+whereSql, params) if err != nil { logger.Errorf("total err => %v", err) @@ -144,23 +151,23 @@ func (r *CDREventImpl) SelectPage(querys model.CDREventQuery) map[string]any { } // SelectByIds 通过ID查询 -func (r *CDREventImpl) SelectByIds(cdrIds []string) []model.CDREvent { +func (r *CDREventIMSImpl) SelectByIds(cdrIds []string) []model.CDREventIMS { placeholder := repo.KeyPlaceholderByQuery(len(cdrIds)) querySql := r.selectSql + " where id in (" + placeholder + ")" parameters := repo.ConvertIdsSlice(cdrIds) results, err := datasource.RawDB("", querySql, parameters) if err != nil { logger.Errorf("query err => %v", err) - return []model.CDREvent{} + return []model.CDREventIMS{} } // 转换实体 return r.convertResultRows(results) } // DeleteByIds 批量删除信息 -func (r *CDREventImpl) DeleteByIds(cdrIds []string) int64 { +func (r *CDREventIMSImpl) DeleteByIds(cdrIds []string) int64 { placeholder := repo.KeyPlaceholderByQuery(len(cdrIds)) - sql := "delete from cdr_event where id in (" + placeholder + ")" + sql := "delete from cdr_event_ims where id in (" + placeholder + ")" parameters := repo.ConvertIdsSlice(cdrIds) results, err := datasource.ExecDB("", sql, parameters) if err != nil { diff --git a/src/modules/network_data/repository/cdr_event_smf.go b/src/modules/network_data/repository/cdr_event_smf.go new file mode 100644 index 0000000..69c188c --- /dev/null +++ b/src/modules/network_data/repository/cdr_event_smf.go @@ -0,0 +1,15 @@ +package repository + +import "nms_cxy/src/modules/network_data/model" + +// CDR会话事件SMF 数据层接口 +type ICDREventSMF interface { + // SelectPage 根据条件分页查询 + SelectPage(querys model.CDREventSMFQuery) map[string]any + + // SelectByIds 通过ID查询 + SelectByIds(cdrIds []string) []model.CDREventSMF + + // DeleteByIds 批量删除信息 + DeleteByIds(cdrIds []string) int64 +} diff --git a/src/modules/network_data/repository/cdr_event_smf.impl.go b/src/modules/network_data/repository/cdr_event_smf.impl.go new file mode 100644 index 0000000..9b40825 --- /dev/null +++ b/src/modules/network_data/repository/cdr_event_smf.impl.go @@ -0,0 +1,185 @@ +package repository + +import ( + "fmt" + "strings" + + "nms_cxy/src/framework/datasource" + "nms_cxy/src/framework/logger" + "nms_cxy/src/framework/utils/parse" + "nms_cxy/src/framework/utils/repo" + "nms_cxy/src/modules/network_data/model" +) + +// 实例化数据层 CDREventSMFImpl 结构体 +var NewCDREventSMFImpl = &CDREventSMFImpl{ + selectSql: `select id, ne_type, ne_name, rm_uid, timestamp, cdr_json, created_at from cdr_event_smf`, + // selectSql: `select id, ne_type, ne_name, rm_uid, timestamp, JSON_EXTRACT(cdr_json, '$.recordType') AS record_type, JSON_EXTRACT(cdr_json, '$.chargingID') AS charging_id, JSON_EXTRACT(cdr_json, '$.subscriberIdentifier.subscriptionIDData') AS subscriber_id, JSON_EXTRACT(cdr_json, '$.duration') AS duration, JSON_EXTRACT(cdr_json, '$.listOfMultipleUnitUsage[*].usedUnitContainer[*].dataVolumeUplink') AS data_volume_uplink, JSON_EXTRACT(cdr_json, '$.listOfMultipleUnitUsage[*].usedUnitContainer[*].dataVolumeDownlink') AS data_volume_downlink, JSON_EXTRACT(cdr_json, '$.listOfMultipleUnitUsage[*].usedUnitContainer[*].dataTotalVolume') AS data_total_volume, JSON_EXTRACT(cdr_json, '$.pDUSessionChargingInformation.pDUAddress') AS pdu_address, created_at from cdr_event_smf`, + + resultMap: map[string]string{ + "id": "ID", + "ne_type": "NeType", + "ne_name": "NeName", + "rm_uid": "RmUID", + "timestamp": "Timestamp", + "cdr_json": "CDRJSONStr", + "created_at": "CreatedAt", + // "id": "ID", + // "ne_type": "NeType", + // "ne_name": "NeName", + // "rm_uid": "RmUID", + // "timestamp": "Timestamp", + // "record_type": "RecordType", + // "charging_id": "ChargingID", + // "subscriber_id": "SubscriberID", + // "duration": "Duration", + // "data_volume_uplink": "DataVolumeUplink", + // "data_volume_downlink": "DataVolumeDownlink", + // "data_total_volume": "DataTotalVolume", + // "pdu_address": "PDUAddress", + // "created_at": "CreatedAt", + }, +} + +// CDREventSMFImpl CDR会话事件 数据层处理 +type CDREventSMFImpl struct { + // 查询视图对象SQL + selectSql string + // 结果字段与实体映射 + resultMap map[string]string +} + +// convertResultRows 将结果记录转实体结果组 +func (r *CDREventSMFImpl) convertResultRows(rows []map[string]any) []model.CDREventSMF { + arr := make([]model.CDREventSMF, 0) + for _, row := range rows { + item := model.CDREventSMF{} + for key, value := range row { + if keyMapper, ok := r.resultMap[key]; ok { + repo.SetFieldValue(&item, keyMapper, value) + } + } + arr = append(arr, item) + } + return arr +} + +// SelectPage 根据条件分页查询 +func (r *CDREventSMFImpl) SelectPage(querys model.CDREventSMFQuery) map[string]any { + // 查询条件拼接 + var conditions []string + var params []any + if querys.NeType != "" { + conditions = append(conditions, "ne_type = ?") + params = append(params, querys.NeType) + } + if querys.RmUID != "" { + conditions = append(conditions, "rm_uid = ?") + params = append(params, querys.RmUID) + } + if querys.StartTime != "" { + conditions = append(conditions, "timestamp >= ?") + if len(querys.StartTime) == 13 { + querys.StartTime = querys.StartTime[:10] + } + params = append(params, querys.StartTime) + } + if querys.EndTime != "" { + conditions = append(conditions, "timestamp <= ?") + if len(querys.EndTime) == 13 { + querys.EndTime = querys.EndTime[:10] + } + params = append(params, querys.EndTime) + } + if querys.RecordType != "" { + conditions = append(conditions, "JSON_EXTRACT(cdr_json, '$.recordType') = ?") + params = append(params, querys.RecordType) + } + if querys.SubscriberID != "" { + conditions = append(conditions, "JSON_EXTRACT(cdr_json, '$.subscriberIdentifier.subscriptionIDData') = ?") + params = append(params, querys.SubscriberID) + } + + // 构建查询条件语句 + whereSql := "" + if len(conditions) > 0 { + whereSql += " where " + strings.Join(conditions, " and ") + } + + result := map[string]any{ + "total": 0, + "rows": []model.CDREventSMF{}, + } + + // 查询数量 长度为0直接返回 + totalSql := "select count(1) as 'total' from cdr_event_smf" + totalRows, err := datasource.RawDB("", totalSql+whereSql, params) + if err != nil { + logger.Errorf("total err => %v", err) + return result + } + total := parse.Number(totalRows[0]["total"]) + if total == 0 { + return result + } else { + result["total"] = total + } + + // 分页 + pageNum, pageSize := repo.PageNumSize(querys.PageNum, querys.PageSize) + pageSql := " limit ?,? " + params = append(params, pageNum*pageSize) + params = append(params, pageSize) + + // 排序 + orderSql := "" + if querys.SortField != "" { + sortSql := querys.SortField + if querys.SortOrder != "" { + if querys.SortOrder == "desc" { + sortSql += " desc " + } else { + sortSql += " asc " + } + } + orderSql = fmt.Sprintf(" order by id desc, %s ", sortSql) + } + + // 查询数据 + querySql := r.selectSql + whereSql + orderSql + pageSql + results, err := datasource.RawDB("", querySql, params) + if err != nil { + logger.Errorf("query err => %v", err) + } + + // 转换实体 + result["rows"] = r.convertResultRows(results) + return result +} + +// SelectByIds 通过ID查询 +func (r *CDREventSMFImpl) SelectByIds(cdrIds []string) []model.CDREventSMF { + placeholder := repo.KeyPlaceholderByQuery(len(cdrIds)) + querySql := r.selectSql + " where id in (" + placeholder + ")" + parameters := repo.ConvertIdsSlice(cdrIds) + results, err := datasource.RawDB("", querySql, parameters) + if err != nil { + logger.Errorf("query err => %v", err) + return []model.CDREventSMF{} + } + // 转换实体 + return r.convertResultRows(results) +} + +// DeleteByIds 批量删除信息 +func (r *CDREventSMFImpl) DeleteByIds(cdrIds []string) int64 { + placeholder := repo.KeyPlaceholderByQuery(len(cdrIds)) + sql := "delete from cdr_event_smf where id in (" + placeholder + ")" + parameters := repo.ConvertIdsSlice(cdrIds) + results, err := datasource.ExecDB("", sql, parameters) + if err != nil { + logger.Errorf("delete err => %v", err) + return 0 + } + return results +} diff --git a/src/modules/network_data/repository/perf_kpi.go b/src/modules/network_data/repository/perf_kpi.go index ec2e302..478a70f 100644 --- a/src/modules/network_data/repository/perf_kpi.go +++ b/src/modules/network_data/repository/perf_kpi.go @@ -7,9 +7,15 @@ type IPerfKPI interface { // SelectGoldKPI 通过网元指标数据信息 SelectGoldKPI(query model.GoldKPIQuery, kpiIds []string) []map[string]any + // select from new kpi report table, exp. kpi_report_upf + SelectKpiReport(query model.GoldKPIQuery, kpiIds []string) []map[string]any + // SelectGoldKPITitle 网元对应的指标名称 SelectGoldKPITitle(neType string) []model.GoldKPITitle // SelectUPFTotalFlow 查询UPF总流量 N3上行 N6下行 SelectUPFTotalFlow(neType, rmUID, startDate, endDate string) map[string]any + + // select upf throughput from new kpi_report + SelectUPFThroughput(neType, rmUID, startDate, endDate string) map[string]any } diff --git a/src/modules/network_data/repository/perf_kpi.impl.go b/src/modules/network_data/repository/perf_kpi.impl.go index 4010e6d..bb78942 100644 --- a/src/modules/network_data/repository/perf_kpi.impl.go +++ b/src/modules/network_data/repository/perf_kpi.impl.go @@ -86,6 +86,108 @@ func (r *PerfKPIImpl) SelectGoldKPI(query model.GoldKPIQuery, kpiIds []string) [ return results } +func (r *PerfKPIImpl) SelectKpiReport(query model.GoldKPIQuery, kpiIds []string) []map[string]any { + // 查询条件拼接 + var conditions []string + var params []any + var tableName string = "kpi_report_" + if query.RmUID != "" { + conditions = append(conditions, "gk.rm_uid = ?") + params = append(params, query.RmUID) + } + if query.NeType != "" { + //conditions = append(conditions, "gk.ne_type = ?") + // params = append(params, query.NeType) + tableName += strings.ToLower(query.NeType) + } + + var dateStr1, dateStr2, timeStr1, timeStr2 string + if query.StartTime != "" { + dateStr1 = query.StartTime[:10] + timeStr1 = query.StartTime[11:] + } + if query.EndTime != "" { + dateStr2 = query.EndTime[:10] + timeStr2 = query.EndTime[11:] + } + if dateStr1 == dateStr2 && dateStr1 != "" { + conditions = append(conditions, "gk.`date` = ?") + params = append(params, dateStr1) + conditions = append(conditions, "gk.`start_time` >= ?") + params = append(params, timeStr1) + conditions = append(conditions, "gk.`start_time` <= ?") + params = append(params, timeStr2) + } else { + if dateStr1 != "" { + conditions = append(conditions, "(gk.`date` > ? OR (gk.`date` = ? AND gk.`start_time` >= ?))") + params = append(params, dateStr1, dateStr1, timeStr1) + } + if dateStr2 != "" { + conditions = append(conditions, "(gk.`date` < ? OR (gk.`date` = ? AND gk.`start_time` <= ?))") + params = append(params, dateStr2, dateStr2, timeStr2) + } + } + + // var dateTimeStr string = "CONCAT(gk.`date`, \" \", gk.start_time)" + // if query.StartTime != "" { + // conditions = append(conditions, dateTimeStr+" >= ?") + // params = append(params, query.StartTime) + // } + // if query.EndTime != "" { + // conditions = append(conditions, dateTimeStr+" <= ?") + // params = append(params, query.EndTime) + // } + // 构建查询条件语句 + whereSql := "" + if len(conditions) > 0 { + whereSql += " where " + strings.Join(conditions, " and ") + } + + // 查询字段列 + var dateTimeStr string = "CONCAT(gk.`date`, \" \", gk.start_time)" + timeFormat := "DATE_FORMAT(" + dateTimeStr + ", '%Y-%m-%d %H:%i:')" + secondGroup := fmt.Sprintf("LPAD(FLOOR(SECOND(gk.start_time) / %d) * %d, 2, '0')", query.Interval, query.Interval) + groupByField := fmt.Sprintf("CONCAT( %s, %s ) AS timeGroup", timeFormat, secondGroup) + if query.Interval > 60 { + minute := query.Interval / 60 + timeFormat = "DATE_FORMAT(" + dateTimeStr + ", '%Y-%m-%d %H:')" + minuteGroup := fmt.Sprintf("LPAD(FLOOR(MINUTE(gk.start_time) / %d) * %d, 2, '0')", minute, minute) + groupByField = fmt.Sprintf("CONCAT( %s, %s ) AS timeGroup", timeFormat, minuteGroup) + } + var fields = []string{ + groupByField, + "min(CASE WHEN gk.index != '' THEN gk.index ELSE 0 END) AS startIndex", + "min(CASE WHEN gk.ne_type != '' THEN gk.ne_type ELSE 0 END) AS neType", + "min(CASE WHEN gk.ne_name != '' THEN gk.ne_name ELSE 0 END) AS neName", + } + for i, kid := range kpiIds { + // 特殊字段,只取最后一次收到的非0值 + if kid == "AMF.01" || kid == "UDM.01" || kid == "UDM.02" || kid == "UDM.03" || kid == "SMF.01" { + str := fmt.Sprintf("IFNULL(SUBSTRING_INDEX(GROUP_CONCAT( CASE WHEN JSON_EXTRACT(gk.kpi_values, '$[%d].kpi_id') = '%s' THEN JSON_EXTRACT(gk.kpi_values, '$[%d].value') END ), ',', 1), 0) AS '%s'", i, kid, i, kid) + fields = append(fields, str) + } else { + str := fmt.Sprintf("sum(CASE WHEN JSON_EXTRACT(gk.kpi_values, '$[%d].kpi_id') = '%s' THEN JSON_EXTRACT(gk.kpi_values, '$[%d].value') ELSE 0 END) AS '%s'", i, kid, i, kid) + fields = append(fields, str) + } + } + fieldsSql := strings.Join(fields, ",") + + // 查询数据 + if query.SortField == "" { + query.SortField = "timeGroup" + } + if query.SortOrder == "" { + query.SortOrder = "desc" + } + orderSql := fmt.Sprintf(" order by %s %s", query.SortField, query.SortOrder) + querySql := fmt.Sprintf("SELECT %s FROM %s gk %s GROUP BY timeGroup %s", fieldsSql, tableName, whereSql, orderSql) + results, err := datasource.RawDB("", querySql, params) + if err != nil { + logger.Errorf("query err => %v", err) + } + return results +} + // SelectGoldKPITitle 网元对应的指标名称 func (r *PerfKPIImpl) SelectGoldKPITitle(neType string) []model.GoldKPITitle { result := []model.GoldKPITitle{} @@ -131,3 +233,39 @@ func (r *PerfKPIImpl) SelectUPFTotalFlow(neType, rmUID, startDate, endDate strin } return results[0] } + +// SelectUPFTotalFlow 查询UPF总流量 N3上行 N6下行 +func (r *PerfKPIImpl) SelectUPFThroughput(neType, rmUID, startDate, endDate string) map[string]any { + // 查询条件拼接 + var conditions []string + var params []any + if neType != "" { + conditions = append(conditions, "gk.ne_type = ?") + params = append(params, neType) + } + if rmUID != "" { + conditions = append(conditions, "gk.rm_uid = ?") + params = append(params, rmUID) + } + if startDate != "" { + conditions = append(conditions, "gk.date >= ?") + params = append(params, startDate) + } + if endDate != "" { + conditions = append(conditions, "gk.date <= ?") + params = append(params, endDate) + } + // 构建查询条件语句 + whereSql := "" + if len(conditions) > 0 { + whereSql += " where " + strings.Join(conditions, " and ") + } + + // 查询数据 + querySql := fmt.Sprintf("SELECT sum( CASE WHEN JSON_EXTRACT(gk.kpi_values, '$[2].kpi_id') = 'UPF.03' THEN JSON_EXTRACT(gk.kpi_values, '$[2].value') ELSE 0 END ) AS 'up', sum( CASE WHEN JSON_EXTRACT(gk.kpi_values, '$[5].kpi_id') = 'UPF.06' THEN JSON_EXTRACT(gk.kpi_values, '$[5].value') ELSE 0 END ) AS 'down' FROM kpi_report_upf gk %s", whereSql) + results, err := datasource.RawDB("", querySql, params) + if err != nil { + logger.Errorf("query err => %v", err) + } + return results[0] +} diff --git a/src/modules/network_data/repository/udm_auth.go b/src/modules/network_data/repository/udm_auth.go new file mode 100644 index 0000000..1f3610b --- /dev/null +++ b/src/modules/network_data/repository/udm_auth.go @@ -0,0 +1,26 @@ +package repository + +import ( + "nms_cxy/src/modules/network_data/model" +) + +// UDM鉴权信息 数据层接口 +type IUDMAuth interface { + // ClearAndInsert 清空ne_id后新增实体 + ClearAndInsert(neId string, uArr []model.UDMAuth) int64 + + // SelectPage 根据条件分页查询 + SelectPage(query map[string]any) map[string]any + + // SelectList 根据实体查询 + SelectList(u model.UDMAuth) []model.UDMAuth + + // Insert 批量添加 + Inserts(uArr []model.UDMAuth) int64 + + // Delete 删除实体 + Delete(neId, imsi string) int64 + + // DeletePrefixByIMSI 删除前缀匹配的实体 + DeletePrefixByIMSI(neId, imsi string) int64 +} diff --git a/src/modules/network_element/repository/udm_auth.impl.go b/src/modules/network_data/repository/udm_auth.impl.go similarity index 80% rename from src/modules/network_element/repository/udm_auth.impl.go rename to src/modules/network_data/repository/udm_auth.impl.go index 670462f..69968a9 100644 --- a/src/modules/network_element/repository/udm_auth.impl.go +++ b/src/modules/network_data/repository/udm_auth.impl.go @@ -1,13 +1,14 @@ package repository import ( + "fmt" "strings" "nms_cxy/src/framework/datasource" "nms_cxy/src/framework/logger" "nms_cxy/src/framework/utils/parse" "nms_cxy/src/framework/utils/repo" - "nms_cxy/src/modules/network_element/model" + "nms_cxy/src/modules/network_data/model" ) // 实例化数据层 UDMAuthImpl 结构体 @@ -16,13 +17,13 @@ var NewUDMAuthImpl = &UDMAuthImpl{ resultMap: map[string]string{ "id": "ID", - "imsi": "Imsi", + "imsi": "IMSI", "amf": "Amf", "status": "Status", "ki": "Ki", "algo_index": "AlgoIndex", "opc": "Opc", - "ne_id": "NeID", + "ne_id": "NeId", }, } @@ -50,14 +51,13 @@ func (r *UDMAuthImpl) convertResultRows(rows []map[string]any) []model.UDMAuth { } // ClearAndInsert 清空ne_id后新增实体 -func (r *UDMAuthImpl) ClearAndInsert(neID string, authArr []model.UDMAuth) int64 { - // 清空指定ne_id +func (r *UDMAuthImpl) ClearAndInsert(neId string, uArr []model.UDMAuth) int64 { + // 不指定neID时,用 TRUNCATE 清空表快 _, err := datasource.ExecDB("", "TRUNCATE TABLE u_auth_user", nil) if err != nil { logger.Errorf("TRUNCATE err => %v", err) } - - return r.Inserts(authArr) + return r.Inserts(uArr) } // SelectPage 根据条件分页查询 @@ -106,11 +106,9 @@ func (r *UDMAuthImpl) SelectPage(query map[string]any) map[string]any { params = append(params, pageSize) // 排序 - sortSql := "" + orderSql := "" if v, ok := query["sortField"]; ok && v != "" { - if v == "imsi" { - sortSql += " order by imsi " - } + sortSql := v.(string) if o, ok := query["sortOrder"]; ok && o != nil && v != "" { if o == "desc" { sortSql += " desc " @@ -118,10 +116,11 @@ func (r *UDMAuthImpl) SelectPage(query map[string]any) map[string]any { sortSql += " asc " } } + orderSql = fmt.Sprintf(" order by %s ", sortSql) } // 查询数据 - querySql := r.selectSql + whereSql + sortSql + pageSql + querySql := r.selectSql + whereSql + orderSql + pageSql results, err := datasource.RawDB("", querySql, params) if err != nil { logger.Errorf("query err => %v", err) @@ -133,17 +132,17 @@ func (r *UDMAuthImpl) SelectPage(query map[string]any) map[string]any { } // SelectList 根据实体查询 -func (r *UDMAuthImpl) SelectList(auth model.UDMAuth) []model.UDMAuth { +func (r *UDMAuthImpl) SelectList(u model.UDMAuth) []model.UDMAuth { // 查询条件拼接 var conditions []string var params []any - if auth.Imsi != "" { + if u.IMSI != "" { conditions = append(conditions, "imsi = ?") - params = append(params, auth.Imsi) + params = append(params, u.IMSI) } - if auth.NeID != "" { + if u.NeId != "" { conditions = append(conditions, "ne_id = ?") - params = append(params, auth.NeID) + params = append(params, u.NeId) } // 构建查询条件语句 @@ -164,8 +163,8 @@ func (r *UDMAuthImpl) SelectList(auth model.UDMAuth) []model.UDMAuth { } // Insert 批量添加 -func (r *UDMAuthImpl) Inserts(authUsers []model.UDMAuth) int64 { - tx := datasource.DefaultDB().CreateInBatches(authUsers, 3000) +func (r *UDMAuthImpl) Inserts(uArr []model.UDMAuth) int64 { + tx := datasource.DefaultDB().CreateInBatches(uArr, 3000) if err := tx.Error; err != nil { logger.Errorf("CreateInBatches err => %v", err) } @@ -173,19 +172,19 @@ func (r *UDMAuthImpl) Inserts(authUsers []model.UDMAuth) int64 { } // Delete 删除实体 -func (r *UDMAuthImpl) Delete(neID, imsi string) int64 { - tx := datasource.DefaultDB().Where("imsi = ? and ne_id = ?", imsi, neID).Delete(&model.UDMAuth{}) +func (r *UDMAuthImpl) Delete(neId, imsi string) int64 { + tx := datasource.DefaultDB().Where("imsi = ? and ne_id = ?", imsi, neId).Delete(&model.UDMAuth{}) if err := tx.Error; err != nil { logger.Errorf("Delete err => %v", err) } return tx.RowsAffected } -// DeletePrefixImsi 删除前缀匹配的实体 -func (r *UDMAuthImpl) DeletePrefixImsi(neID, imsi string) int64 { - tx := datasource.DefaultDB().Where("imsi like concat(?, '%') and ne_id = ?", imsi, neID).Delete(&model.UDMAuth{}) +// DeletePrefixByIMSI 删除前缀匹配的实体 +func (r *UDMAuthImpl) DeletePrefixByIMSI(neId, imsi string) int64 { + tx := datasource.DefaultDB().Where("imsi like concat(?, '%') and ne_id = ?", imsi, neId).Delete(&model.UDMAuth{}) if err := tx.Error; err != nil { - logger.Errorf("DeletePrefixImsi err => %v", err) + logger.Errorf("DeletePrefixByIMSI err => %v", err) } return tx.RowsAffected } diff --git a/src/modules/network_data/repository/udm_sub.go b/src/modules/network_data/repository/udm_sub.go new file mode 100644 index 0000000..2f5e410 --- /dev/null +++ b/src/modules/network_data/repository/udm_sub.go @@ -0,0 +1,26 @@ +package repository + +import ( + "nms_cxy/src/modules/network_data/model" +) + +// UDM签约信息 数据层接口 +type IUDMSub interface { + // ClearAndInsert 清空ne_id后新增实体 + ClearAndInsert(neId string, uArr []model.UDMSub) int64 + + // SelectPage 根据条件分页查询 + SelectPage(query map[string]any) map[string]any + + // SelectList 根据实体查询 + SelectList(u model.UDMSub) []model.UDMSub + + // Insert 批量添加 + Inserts(uArr []model.UDMSub) int64 + + // Delete 删除实体 + Delete(neId, imsi string) int64 + + // DeletePrefixByIMSI 删除前缀匹配的实体 + DeletePrefixByIMSI(neId, imsi string) int64 +} diff --git a/src/modules/network_element/repository/udm_sub.impl.go b/src/modules/network_data/repository/udm_sub.impl.go similarity index 58% rename from src/modules/network_element/repository/udm_sub.impl.go rename to src/modules/network_data/repository/udm_sub.impl.go index 19ae926..5c87af5 100644 --- a/src/modules/network_element/repository/udm_sub.impl.go +++ b/src/modules/network_data/repository/udm_sub.impl.go @@ -1,14 +1,14 @@ package repository import ( - "strconv" + "fmt" "strings" "nms_cxy/src/framework/datasource" "nms_cxy/src/framework/logger" "nms_cxy/src/framework/utils/parse" "nms_cxy/src/framework/utils/repo" - "nms_cxy/src/modules/network_element/model" + "nms_cxy/src/modules/network_data/model" ) // 实例化数据层 UDMSubImpl 结构体 @@ -20,7 +20,7 @@ var NewUDMSubImpl = &UDMSubImpl{ resultMap: map[string]string{ "id": "ID", "msisdn": "Msisdn", - "imsi": "Imsi", + "imsi": "IMSI", "ambr": "Ambr", "nssai": "Nssai", "rat": "Rat", @@ -30,7 +30,7 @@ var NewUDMSubImpl = &UDMSubImpl{ "sm_data": "SmData", "smf_sel": "SmfSel", "eps_dat": "EpsDat", - "ne_id": "NeID", + "ne_id": "NeId", "eps_flag": "EpsFlag", "eps_odb": "EpsOdb", "hplmn_odb": "HplmnOdb", @@ -66,14 +66,14 @@ func (r *UDMSubImpl) convertResultRows(rows []map[string]any) []model.UDMSub { } // ClearAndInsert 清空ne_id后新增实体 -func (r *UDMSubImpl) ClearAndInsert(neID string, subArr []model.UDMSub) int64 { - // 清空指定ne_id +func (r *UDMSubImpl) ClearAndInsert(neID string, u []model.UDMSub) int64 { + // 不指定neID时,用 TRUNCATE 清空表快 _, err := datasource.ExecDB("", "TRUNCATE TABLE u_sub_user", nil) if err != nil { logger.Errorf("TRUNCATE err => %v", err) } - return r.Inserts(subArr) + return r.Inserts(u) } // SelectPage 根据条件分页查询字典类型 @@ -126,14 +126,9 @@ func (r *UDMSubImpl) SelectPage(query map[string]any) map[string]any { params = append(params, pageSize) // 排序 - sortSql := "" + orderSql := "" if v, ok := query["sortField"]; ok && v != "" { - if v == "imsi" { - sortSql += " order by imsi " - } - if v == "msisdn" { - sortSql += " order by msisdn " - } + sortSql := v.(string) if o, ok := query["sortOrder"]; ok && o != nil && v != "" { if o == "desc" { sortSql += " desc " @@ -141,10 +136,11 @@ func (r *UDMSubImpl) SelectPage(query map[string]any) map[string]any { sortSql += " asc " } } + orderSql = fmt.Sprintf(" order by %s ", sortSql) } // 查询数据 - querySql := r.selectSql + whereSql + sortSql + pageSql + querySql := r.selectSql + whereSql + orderSql + pageSql results, err := datasource.RawDB("", querySql, params) if err != nil { logger.Errorf("query err => %v", err) @@ -157,17 +153,17 @@ func (r *UDMSubImpl) SelectPage(query map[string]any) map[string]any { } // SelectList 根据实体查询 -func (r *UDMSubImpl) SelectList(subUser model.UDMSub) []model.UDMSub { +func (r *UDMSubImpl) SelectList(u model.UDMSub) []model.UDMSub { // 查询条件拼接 var conditions []string var params []any - if subUser.Imsi != "" { + if u.IMSI != "" { conditions = append(conditions, "imsi = ?") - params = append(params, subUser.Imsi) + params = append(params, u.IMSI) } - if subUser.NeID != "" { + if u.NeId != "" { conditions = append(conditions, "ne_id = ?") - params = append(params, subUser.NeID) + params = append(params, u.NeId) } // 构建查询条件语句 @@ -187,126 +183,29 @@ func (r *UDMSubImpl) SelectList(subUser model.UDMSub) []model.UDMSub { return r.convertResultRows(results) } -// Insert 新增实体 -func (r *UDMSubImpl) Insert(subUser model.UDMSub) string { - err := datasource.DefaultDB().Create(&subUser).Error - if err != nil { - logger.Errorf("Create err => %v", err) - } - return subUser.ID -} - // Insert 批量添加 -func (r *UDMSubImpl) Inserts(subUser []model.UDMSub) int64 { - tx := datasource.DefaultDB().CreateInBatches(subUser, 2000) +func (r *UDMSubImpl) Inserts(uArr []model.UDMSub) int64 { + tx := datasource.DefaultDB().CreateInBatches(uArr, 2000) if err := tx.Error; err != nil { logger.Errorf("CreateInBatches err => %v", err) } return tx.RowsAffected } -// Update 修改更新 -func (r *UDMSubImpl) Update(neID string, subUser model.UDMSub) int64 { - // 查询先 - var user model.UDMSub - err := datasource.DefaultDB().Where("imsi = ? and ne_id = ?", subUser.Imsi, neID).First(&user).Error - if err != nil { - logger.Errorf("Update First err => %v", err) - } - - if user.Msisdn != subUser.Msisdn { - user.Msisdn = subUser.Msisdn - } - if user.Ambr != subUser.Ambr { - user.Ambr = subUser.Ambr - } - if user.Arfb != subUser.Arfb { - user.Arfb = subUser.Arfb - } - if user.Sar != subUser.Sar { - user.Sar = subUser.Sar - } - if user.Rat != subUser.Rat { - user.Rat = subUser.Rat - } - if user.Cn != subUser.Cn { - user.Cn = subUser.Cn - } - if user.SmfSel != subUser.SmfSel { - user.SmfSel = subUser.SmfSel - } - if user.SmData != subUser.SmData { - user.SmData = subUser.SmData - } - if user.EpsDat != subUser.EpsDat { - user.EpsDat = subUser.EpsDat - } - if user.EpsFlag != subUser.EpsFlag { - user.EpsFlag = subUser.EpsFlag - } - if user.EpsDat != subUser.EpsDat { - user.EpsOdb = subUser.EpsOdb - } - if user.HplmnOdb != subUser.HplmnOdb { - user.HplmnOdb = subUser.HplmnOdb - } - if user.Epstpl != subUser.Epstpl { - user.Epstpl = subUser.Epstpl - } - if user.Ard != subUser.Ard { - user.Ard = subUser.Ard - } - if user.ContextId != subUser.ContextId { - user.ContextId = subUser.ContextId - } - if user.ApnContext != subUser.ApnContext { - user.ApnContext = subUser.ApnContext - } - if user.StaticIp != subUser.StaticIp { - user.StaticIp = subUser.StaticIp - } - - tx := datasource.DefaultDB().Save(user) - if err := tx.Error; err != nil { - logger.Errorf("Update Save err => %v", err) - return 0 - } - return tx.RowsAffected -} - // Delete 删除实体 -func (r *UDMSubImpl) Delete(neID, imsi string) int64 { - tx := datasource.DefaultDB().Where("imsi = ? and ne_id = ?", imsi, neID).Delete(&model.UDMSub{}) +func (r *UDMSubImpl) Delete(neId, imsi string) int64 { + tx := datasource.DefaultDB().Where("imsi = ? and ne_id = ?", imsi, neId).Delete(&model.UDMSub{}) if err := tx.Error; err != nil { logger.Errorf("Delete err => %v", err) } return tx.RowsAffected } -// DeletePrefixImsi 删除前缀匹配的实体 -func (r *UDMSubImpl) DeletePrefixImsi(neID, imsi string) int64 { - tx := datasource.DefaultDB().Where("imsi like concat(?, '%') and ne_id = ?", imsi, neID).Delete(&model.UDMSub{}) +// DeletePrefixByIMSI 删除前缀匹配的实体 +func (r *UDMSubImpl) DeletePrefixByIMSI(neId, imsi string) int64 { + tx := datasource.DefaultDB().Where("imsi like concat(?, '%') and ne_id = ?", imsi, neId).Delete(&model.UDMSub{}) if err := tx.Error; err != nil { - logger.Errorf("DeletePrefixImsi err => %v", err) - } - return tx.RowsAffected -} - -// Delete 删除范围实体 -func (r *UDMSubImpl) Deletes(neID, imsi, num string) int64 { - imsiV, err := strconv.Atoi(imsi) - if err != nil { - return 0 - } - - numV, err := strconv.Atoi(num) - if err != nil { - return 0 - } - - tx := datasource.DefaultDB().Where("imsi >= ? and imsi < ? and ne_id = ?", imsiV, imsiV+numV, neID).Delete(&model.UDMSub{}) - if err := tx.Error; err != nil { - logger.Errorf("Deletes err => %v", err) + logger.Errorf("DeletePrefixByIMSI err => %v", err) } return tx.RowsAffected } diff --git a/src/modules/network_data/repository/ue_event.go b/src/modules/network_data/repository/ue_event_amf.go similarity index 55% rename from src/modules/network_data/repository/ue_event.go rename to src/modules/network_data/repository/ue_event_amf.go index ced87de..5608b9f 100644 --- a/src/modules/network_data/repository/ue_event.go +++ b/src/modules/network_data/repository/ue_event_amf.go @@ -2,13 +2,13 @@ package repository import "nms_cxy/src/modules/network_data/model" -// UE会话事件 数据层接口 -type IUEEvent interface { +// UE会话事件AMF 数据层接口 +type IUEEventAMF interface { // SelectPage 根据条件分页查询 - SelectPage(querys model.UEEventQuery) map[string]any + SelectPage(querys model.UEEventAMFQuery) map[string]any // SelectByIds 通过ID查询 - SelectByIds(ueIds []string) []model.UEEvent + SelectByIds(ueIds []string) []model.UEEventAMF // DeleteByIds 批量删除信息 DeleteByIds(ueIds []string) int64 diff --git a/src/modules/network_data/repository/ue_event.impl.go b/src/modules/network_data/repository/ue_event_amf.impl.go similarity index 75% rename from src/modules/network_data/repository/ue_event.impl.go rename to src/modules/network_data/repository/ue_event_amf.impl.go index ec64605..2643cb2 100644 --- a/src/modules/network_data/repository/ue_event.impl.go +++ b/src/modules/network_data/repository/ue_event_amf.impl.go @@ -6,15 +6,14 @@ import ( "nms_cxy/src/framework/datasource" "nms_cxy/src/framework/logger" - "nms_cxy/src/framework/utils/date" "nms_cxy/src/framework/utils/parse" "nms_cxy/src/framework/utils/repo" "nms_cxy/src/modules/network_data/model" ) -// 实例化数据层 UEEventImpl 结构体 -var NewUEEventImpl = &UEEventImpl{ - selectSql: `select id, ne_type, ne_name, rm_uid, timestamp, event_type, event_json, created_at from ue_event`, +// 实例化数据层 UEEventAMFImpl 结构体 +var NewUEEventAMFImpl = &UEEventAMFImpl{ + selectSql: `select id, ne_type, ne_name, rm_uid, timestamp, event_type, event_json, created_at from ue_event_amf`, resultMap: map[string]string{ "id": "ID", @@ -28,8 +27,8 @@ var NewUEEventImpl = &UEEventImpl{ }, } -// UEEventImpl UE会话事件 数据层处理 -type UEEventImpl struct { +// UEEventAMFImpl UE会话事件 数据层处理 +type UEEventAMFImpl struct { // 查询视图对象SQL selectSql string // 结果字段与实体映射 @@ -37,10 +36,10 @@ type UEEventImpl struct { } // convertResultRows 将结果记录转实体结果组 -func (r *UEEventImpl) convertResultRows(rows []map[string]any) []model.UEEvent { - arr := make([]model.UEEvent, 0) +func (r *UEEventAMFImpl) convertResultRows(rows []map[string]any) []model.UEEventAMF { + arr := make([]model.UEEventAMF, 0) for _, row := range rows { - item := model.UEEvent{} + item := model.UEEventAMF{} for key, value := range row { if keyMapper, ok := r.resultMap[key]; ok { repo.SetFieldValue(&item, keyMapper, value) @@ -52,7 +51,7 @@ func (r *UEEventImpl) convertResultRows(rows []map[string]any) []model.UEEvent { } // SelectPage 根据条件分页查询 -func (r *UEEventImpl) SelectPage(querys model.UEEventQuery) map[string]any { +func (r *UEEventAMFImpl) SelectPage(querys model.UEEventAMFQuery) map[string]any { // 查询条件拼接 var conditions []string var params []any @@ -66,13 +65,17 @@ func (r *UEEventImpl) SelectPage(querys model.UEEventQuery) map[string]any { } if querys.StartTime != "" { conditions = append(conditions, "timestamp >= ?") - beginDate := date.ParseStrToDate(querys.StartTime, date.YYYY_MM_DD_HH_MM_SS) - params = append(params, beginDate.Unix()) + if len(querys.StartTime) == 13 { + querys.StartTime = querys.StartTime[:10] + } + params = append(params, querys.StartTime) } if querys.EndTime != "" { conditions = append(conditions, "timestamp <= ?") - endDate := date.ParseStrToDate(querys.EndTime, date.YYYY_MM_DD_HH_MM_SS) - params = append(params, endDate.Unix()) + if len(querys.EndTime) == 13 { + querys.EndTime = querys.EndTime[:10] + } + params = append(params, querys.EndTime) } if querys.EventType != "" { eventTypes := strings.Split(querys.EventType, ",") @@ -82,6 +85,10 @@ func (r *UEEventImpl) SelectPage(querys model.UEEventQuery) map[string]any { params = append(params, eventType) } } + if querys.IMSI != "" { + conditions = append(conditions, "JSON_EXTRACT(event_json, '$.imsi') = ?") + params = append(params, querys.IMSI) + } // 构建查询条件语句 whereSql := "" @@ -91,11 +98,11 @@ func (r *UEEventImpl) SelectPage(querys model.UEEventQuery) map[string]any { result := map[string]any{ "total": 0, - "rows": []model.CDREvent{}, + "rows": []model.UEEventAMF{}, } // 查询数量 长度为0直接返回 - totalSql := "select count(1) as 'total' from ue_event" + totalSql := "select count(1) as 'total' from ue_event_amf" totalRows, err := datasource.RawDB("", totalSql+whereSql, params) if err != nil { logger.Errorf("total err => %v", err) @@ -141,23 +148,23 @@ func (r *UEEventImpl) SelectPage(querys model.UEEventQuery) map[string]any { } // SelectByIds 通过ID查询 -func (r *UEEventImpl) SelectByIds(ueIds []string) []model.UEEvent { +func (r *UEEventAMFImpl) SelectByIds(ueIds []string) []model.UEEventAMF { placeholder := repo.KeyPlaceholderByQuery(len(ueIds)) querySql := r.selectSql + " where id in (" + placeholder + ")" parameters := repo.ConvertIdsSlice(ueIds) results, err := datasource.RawDB("", querySql, parameters) if err != nil { logger.Errorf("query err => %v", err) - return []model.UEEvent{} + return []model.UEEventAMF{} } // 转换实体 return r.convertResultRows(results) } // DeleteByIds 批量删除信息 -func (r *UEEventImpl) DeleteByIds(ueIds []string) int64 { +func (r *UEEventAMFImpl) DeleteByIds(ueIds []string) int64 { placeholder := repo.KeyPlaceholderByQuery(len(ueIds)) - sql := "delete from ue_event where id in (" + placeholder + ")" + sql := "delete from ue_event_amf where id in (" + placeholder + ")" parameters := repo.ConvertIdsSlice(ueIds) results, err := datasource.ExecDB("", sql, parameters) if err != nil { diff --git a/src/modules/network_data/repository/ue_event_mme.go b/src/modules/network_data/repository/ue_event_mme.go new file mode 100644 index 0000000..6b9c5ce --- /dev/null +++ b/src/modules/network_data/repository/ue_event_mme.go @@ -0,0 +1,15 @@ +package repository + +import "nms_cxy/src/modules/network_data/model" + +// UE会话事件MME 数据层接口 +type IUEEventMME interface { + // SelectPage 根据条件分页查询 + SelectPage(querys model.UEEventMMEQuery) map[string]any + + // SelectByIds 通过ID查询 + SelectByIds(ueIds []string) []model.UEEventMME + + // DeleteByIds 批量删除信息 + DeleteByIds(ueIds []string) int64 +} diff --git a/src/modules/network_data/repository/ue_event_mme.impl.go b/src/modules/network_data/repository/ue_event_mme.impl.go new file mode 100644 index 0000000..4dbe7bf --- /dev/null +++ b/src/modules/network_data/repository/ue_event_mme.impl.go @@ -0,0 +1,175 @@ +package repository + +import ( + "fmt" + "strings" + + "nms_cxy/src/framework/datasource" + "nms_cxy/src/framework/logger" + "nms_cxy/src/framework/utils/parse" + "nms_cxy/src/framework/utils/repo" + "nms_cxy/src/modules/network_data/model" +) + +// 实例化数据层 UEEventMMEImpl 结构体 +var NewUEEventMMEImpl = &UEEventMMEImpl{ + selectSql: `select id, ne_type, ne_name, rm_uid, timestamp, event_type, event_json, created_at from ue_event_mme`, + + resultMap: map[string]string{ + "id": "ID", + "ne_type": "NeType", + "ne_name": "NeName", + "rm_uid": "RmUID", + "timestamp": "Timestamp", + "event_type": "EventType", + "event_json": "EventJSONStr", + "created_at": "CreatedAt", + }, +} + +// UEEventMMEImpl UE会话事件 数据层处理 +type UEEventMMEImpl struct { + // 查询视图对象SQL + selectSql string + // 结果字段与实体映射 + resultMap map[string]string +} + +// convertResultRows 将结果记录转实体结果组 +func (r *UEEventMMEImpl) convertResultRows(rows []map[string]any) []model.UEEventMME { + arr := make([]model.UEEventMME, 0) + for _, row := range rows { + item := model.UEEventMME{} + for key, value := range row { + if keyMapper, ok := r.resultMap[key]; ok { + repo.SetFieldValue(&item, keyMapper, value) + } + } + arr = append(arr, item) + } + return arr +} + +// SelectPage 根据条件分页查询 +func (r *UEEventMMEImpl) SelectPage(querys model.UEEventMMEQuery) map[string]any { + // 查询条件拼接 + var conditions []string + var params []any + if querys.NeType != "" { + conditions = append(conditions, "ne_type = ?") + params = append(params, querys.NeType) + } + if querys.RmUID != "" { + conditions = append(conditions, "rm_uid = ?") + params = append(params, querys.RmUID) + } + if querys.StartTime != "" { + conditions = append(conditions, "timestamp >= ?") + if len(querys.StartTime) == 13 { + querys.StartTime = querys.StartTime[:10] + } + params = append(params, querys.StartTime) + } + if querys.EndTime != "" { + conditions = append(conditions, "timestamp <= ?") + if len(querys.EndTime) == 13 { + querys.EndTime = querys.EndTime[:10] + } + params = append(params, querys.EndTime) + } + if querys.EventType != "" { + eventTypes := strings.Split(querys.EventType, ",") + placeholder := repo.KeyPlaceholderByQuery(len(eventTypes)) + conditions = append(conditions, fmt.Sprintf("event_type in (%s)", placeholder)) + for _, eventType := range eventTypes { + params = append(params, eventType) + } + } + if querys.IMSI != "" { + conditions = append(conditions, "JSON_EXTRACT(event_json, '$.imsi') = ?") + params = append(params, querys.IMSI) + } + + // 构建查询条件语句 + whereSql := "" + if len(conditions) > 0 { + whereSql += " where " + strings.Join(conditions, " and ") + } + + result := map[string]any{ + "total": 0, + "rows": []model.UEEventMME{}, + } + + // 查询数量 长度为0直接返回 + totalSql := "select count(1) as 'total' from ue_event_mme" + totalRows, err := datasource.RawDB("", totalSql+whereSql, params) + if err != nil { + logger.Errorf("total err => %v", err) + return result + } + total := parse.Number(totalRows[0]["total"]) + if total == 0 { + return result + } else { + result["total"] = total + } + + // 分页 + pageNum, pageSize := repo.PageNumSize(querys.PageNum, querys.PageSize) + pageSql := " limit ?,? " + params = append(params, pageNum*pageSize) + params = append(params, pageSize) + + // 排序 + orderSql := "" + if querys.SortField != "" { + sortSql := querys.SortField + if querys.SortOrder != "" { + if querys.SortOrder == "desc" { + sortSql += " desc " + } else { + sortSql += " asc " + } + } + orderSql = fmt.Sprintf(" order by id desc, %s ", sortSql) + } + + // 查询数据 + querySql := r.selectSql + whereSql + orderSql + pageSql + results, err := datasource.RawDB("", querySql, params) + if err != nil { + logger.Errorf("query err => %v", err) + } + + // 转换实体 + result["rows"] = r.convertResultRows(results) + return result +} + +// SelectByIds 通过ID查询 +func (r *UEEventMMEImpl) SelectByIds(ueIds []string) []model.UEEventMME { + placeholder := repo.KeyPlaceholderByQuery(len(ueIds)) + querySql := r.selectSql + " where id in (" + placeholder + ")" + parameters := repo.ConvertIdsSlice(ueIds) + results, err := datasource.RawDB("", querySql, parameters) + if err != nil { + logger.Errorf("query err => %v", err) + return []model.UEEventMME{} + } + // 转换实体 + return r.convertResultRows(results) +} + +// DeleteByIds 批量删除信息 +func (r *UEEventMMEImpl) DeleteByIds(ueIds []string) int64 { + placeholder := repo.KeyPlaceholderByQuery(len(ueIds)) + sql := "delete from ue_event_mme where id in (" + placeholder + ")" + parameters := repo.ConvertIdsSlice(ueIds) + results, err := datasource.ExecDB("", sql, parameters) + if err != nil { + logger.Errorf("delete err => %v", err) + return 0 + } + return results +} diff --git a/src/modules/network_data/service/cdr_event.go b/src/modules/network_data/service/cdr_event_ims.go similarity index 60% rename from src/modules/network_data/service/cdr_event.go rename to src/modules/network_data/service/cdr_event_ims.go index 5323a0b..9cba9df 100644 --- a/src/modules/network_data/service/cdr_event.go +++ b/src/modules/network_data/service/cdr_event_ims.go @@ -2,10 +2,10 @@ package service import "nms_cxy/src/modules/network_data/model" -// CDR会话事件 服务层接口 -type ICDREvent interface { +// CDR会话事件IMS 服务层接口 +type ICDREventIMS interface { // SelectPage 根据条件分页查询 - SelectPage(querys model.CDREventQuery) map[string]any + SelectPage(querys model.CDREventIMSQuery) map[string]any // DeleteByIds 批量删除信息 DeleteByIds(cdrIds []string) (int64, error) diff --git a/src/modules/network_data/service/cdr_event_ims.impl.go b/src/modules/network_data/service/cdr_event_ims.impl.go new file mode 100644 index 0000000..5a661b6 --- /dev/null +++ b/src/modules/network_data/service/cdr_event_ims.impl.go @@ -0,0 +1,40 @@ +package service + +import ( + "fmt" + + "nms_cxy/src/modules/network_data/model" + "nms_cxy/src/modules/network_data/repository" +) + +// 实例化数据层 NewCDREventIMSImpl 结构体 +var NewCDREventIMSImpl = &CDREventIMSImpl{ + cdrEventIMSRepository: repository.NewCDREventIMSImpl, +} + +// CDREventImpl CDR会话事件IMS 服务层处理 +type CDREventIMSImpl struct { + // CDR会话事件数据信息 + cdrEventIMSRepository repository.ICDREventIMS +} + +// SelectPage 根据条件分页查询 +func (r *CDREventIMSImpl) SelectPage(querys model.CDREventIMSQuery) map[string]any { + return r.cdrEventIMSRepository.SelectPage(querys) +} + +// DeleteByIds 批量删除信息 +func (r *CDREventIMSImpl) DeleteByIds(cdrIds []string) (int64, error) { + // 检查是否存在 + ids := r.cdrEventIMSRepository.SelectByIds(cdrIds) + if len(ids) <= 0 { + return 0, fmt.Errorf("not data") + } + + if len(ids) == len(cdrIds) { + rows := r.cdrEventIMSRepository.DeleteByIds(cdrIds) + return rows, nil + } + // 删除信息失败! + return 0, fmt.Errorf("delete fail") +} diff --git a/src/modules/network_data/service/cdr_event_smf.go b/src/modules/network_data/service/cdr_event_smf.go new file mode 100644 index 0000000..fa8fcc4 --- /dev/null +++ b/src/modules/network_data/service/cdr_event_smf.go @@ -0,0 +1,12 @@ +package service + +import "nms_cxy/src/modules/network_data/model" + +// CDR会话事件SMF 服务层接口 +type ICDREventSMF interface { + // SelectPage 根据条件分页查询 + SelectPage(querys model.CDREventSMFQuery) map[string]any + + // DeleteByIds 批量删除信息 + DeleteByIds(cdrIds []string) (int64, error) +} diff --git a/src/modules/network_data/service/cdr_event.impl.go b/src/modules/network_data/service/cdr_event_smf.impl.go similarity index 55% rename from src/modules/network_data/service/cdr_event.impl.go rename to src/modules/network_data/service/cdr_event_smf.impl.go index 2249041..e6d9743 100644 --- a/src/modules/network_data/service/cdr_event.impl.go +++ b/src/modules/network_data/service/cdr_event_smf.impl.go @@ -7,24 +7,21 @@ import ( "nms_cxy/src/modules/network_data/repository" ) -// 实例化数据层 CDREventImpl 结构体 -var NewCDREventImpl = &CDREventImpl{ - cdrEventRepository: repository.NewCDREventImpl, +var NewCDREventSMFImpl = &CDREventSMFImpl{ + cdrEventRepository: repository.NewCDREventSMFImpl, } -// CDREventImpl CDR会话事件 服务层处理 -type CDREventImpl struct { +type CDREventSMFImpl struct { // CDR会话事件数据信息 - cdrEventRepository repository.ICDREvent + cdrEventRepository repository.ICDREventSMF } -// SelectPage 根据条件分页查询 -func (r *CDREventImpl) SelectPage(querys model.CDREventQuery) map[string]any { +func (r *CDREventSMFImpl) SelectPage(querys model.CDREventSMFQuery) map[string]any { return r.cdrEventRepository.SelectPage(querys) } // DeleteByIds 批量删除信息 -func (r *CDREventImpl) DeleteByIds(cdrIds []string) (int64, error) { +func (r *CDREventSMFImpl) DeleteByIds(cdrIds []string) (int64, error) { // 检查是否存在 ids := r.cdrEventRepository.SelectByIds(cdrIds) if len(ids) <= 0 { diff --git a/src/modules/network_data/service/perf_kpi.impl.go b/src/modules/network_data/service/perf_kpi.impl.go index 875242a..c46fd2c 100644 --- a/src/modules/network_data/service/perf_kpi.impl.go +++ b/src/modules/network_data/service/perf_kpi.impl.go @@ -31,7 +31,8 @@ func (r *PerfKPIImpl) SelectGoldKPI(query model.GoldKPIQuery) []map[string]any { kpiIds = append(kpiIds, kpiId.KPIID) } - data := r.perfKPIRepository.SelectGoldKPI(query, kpiIds) + //data := r.perfKPIRepository.SelectGoldKPI(query, kpiIds) + data := r.perfKPIRepository.SelectKpiReport(query, kpiIds) if data == nil { return []map[string]any{} } @@ -66,7 +67,8 @@ func (r *PerfKPIImpl) SelectUPFTotalFlow(neType, rmUID string, day int) map[stri } } - info = r.perfKPIRepository.SelectUPFTotalFlow(neType, rmUID, startDate, endDate) + //info = r.perfKPIRepository.SelectUPFTotalFlow(neType, rmUID, startDate, endDate) + info = r.perfKPIRepository.SelectUPFThroughput(neType, rmUID, startDate, endDate) // 保存到缓存 infoJSON, _ := json.Marshal(info) diff --git a/src/modules/network_data/service/udm_auth.go b/src/modules/network_data/service/udm_auth.go new file mode 100644 index 0000000..f2cbadb --- /dev/null +++ b/src/modules/network_data/service/udm_auth.go @@ -0,0 +1,28 @@ +package service + +import "nms_cxy/src/modules/network_data/model" + +// UDM鉴权信息 服务层接口 +type IUDMAuth interface { + // ResetData 重置鉴权用户数据,清空数据库重新同步Redis数据 + ResetData(neId string) int64 + + // SelectPage 分页查询数据库 + SelectPage(query map[string]any) map[string]any + + // SelectList 查询数据库 + SelectList(u model.UDMAuth) []model.UDMAuth + + // Insert 从数据中读取后删除imsi再存入数据库 + // imsi长度15,ki长度32,opc长度0或者32 + Insert(neId string, u model.UDMAuth) int64 + + // InsertData 导入文件数据 dataType目前两种:txt/csv + InsertData(neId, dataType string, data any) int64 + + // Delete 删除单个不重新加载 + Delete(neID, imsi string) int64 + + // LoadData 删除范围后重新加载 num表示imsi后几位 + LoadData(neID, imsi, num string) int64 +} diff --git a/src/modules/network_data/service/udm_auth.impl.go b/src/modules/network_data/service/udm_auth.impl.go new file mode 100644 index 0000000..1ec7df9 --- /dev/null +++ b/src/modules/network_data/service/udm_auth.impl.go @@ -0,0 +1,146 @@ +package service + +import ( + "fmt" + "strings" + + "nms_cxy/src/framework/redis" + "nms_cxy/src/modules/network_data/model" + "nms_cxy/src/modules/network_data/repository" +) + +// 实例化服务层 UDMAuthImpl 结构体 +var NewUDMAuthImpl = &UDMAuthImpl{ + udmAuthRepository: repository.NewUDMAuthImpl, +} + +// UDM鉴权信息 服务层处理 +type UDMAuthImpl struct { + // UDM鉴权信息数据信息 + udmAuthRepository repository.IUDMAuth +} + +// dataByRedis UDM鉴权用户 db:0 中 ausf:* +func (r *UDMAuthImpl) dataByRedis(imsi, neId string) []model.UDMAuth { + arr := []model.UDMAuth{} + key := fmt.Sprintf("ausf:%s", imsi) + ausfArr, err := redis.GetKeys("udmuser", key) + if err != nil { + return arr + } + for _, key := range ausfArr { + m, err := redis.GetHash("udmuser", key) + if err != nil { + continue + } + + // 跳过-号数据 + imsi := key[5:] + if strings.Contains(imsi, "-") { + continue + } + + amf := "" + if v, ok := m["amf"]; ok { + amf = strings.Replace(v, "\r\n", "", 1) + } + a := model.UDMAuth{ + IMSI: imsi, + Amf: amf, + Status: "1", // 默认给1 + Ki: m["ki"], + AlgoIndex: m["algo"], + Opc: m["opc"], + NeId: neId, + } + arr = append(arr, a) + } + return arr +} + +// ResetData 重置鉴权用户数据,清空数据库重新同步Redis数据 +func (r *UDMAuthImpl) ResetData(neId string) int64 { + authArr := r.dataByRedis("*", neId) + // 数据清空后添加 + go r.udmAuthRepository.ClearAndInsert(neId, authArr) + return int64(len(authArr)) +} + +// SelectPage 分页查询数据库 +func (r *UDMAuthImpl) SelectPage(query map[string]any) map[string]any { + return r.udmAuthRepository.SelectPage(query) +} + +// SelectList 查询数据库 +func (r *UDMAuthImpl) SelectList(u model.UDMAuth) []model.UDMAuth { + return r.udmAuthRepository.SelectList(u) +} + +// Insert 从数据中读取后删除imsi再存入数据库 +// imsi长度15,ki长度32,opc长度0或者32 +func (r *UDMAuthImpl) Insert(neId string, u model.UDMAuth) int64 { + uArr := r.dataByRedis(u.IMSI, neId) + if len(uArr) > 0 { + r.udmAuthRepository.Delete(neId, u.IMSI) + return r.udmAuthRepository.Inserts(uArr) + } + return 0 +} + +// InsertData 导入文件数据 dataType目前两种:txt/csv +func (r *UDMAuthImpl) InsertData(neId, dataType string, data any) int64 { + // imsi截取前缀,重新获取部分数据 + prefixes := make(map[string]struct{}) + + if dataType == "csv" { + for _, v := range data.([]map[string]string) { + imsi := v["imsi"] + if len(imsi) < 6 { + continue + } + prefix := imsi[:len(imsi)-4] + prefixes[prefix] = struct{}{} + } + } + if dataType == "txt" { + for _, v := range data.([][]string) { + imsi := v[0] + if len(imsi) < 6 { + continue + } + prefix := imsi[:len(imsi)-4] + prefixes[prefix] = struct{}{} + } + } + + // 根据前缀重新加载插入 + var num int64 = 0 + for prefix := range prefixes { + // 直接删除前缀的记录 + r.udmAuthRepository.DeletePrefixByIMSI(neId, prefix) + // keys ausf:4600001000004* + authArr := r.dataByRedis(prefix+"*", neId) + if len(authArr) > 0 { + num += r.udmAuthRepository.Inserts(authArr) + } + } + return num +} + +// Delete 删除单个不重新加载 +func (r *UDMAuthImpl) Delete(neId, imsi string) int64 { + return r.udmAuthRepository.Delete(neId, imsi) +} + +// LoadData 删除范围后重新加载 num表示imsi后几位 +func (r *UDMAuthImpl) LoadData(neId, imsi, num string) int64 { + prefix := imsi[:len(imsi)-len(num)-1] + // 直接删除前缀的记录 + delNum := r.udmAuthRepository.DeletePrefixByIMSI(neId, prefix) + // keys ausf:4600001000004* + authArr := r.dataByRedis(prefix+"*", neId) + if len(authArr) > 0 { + return r.udmAuthRepository.Inserts(authArr) + } + return delNum +} diff --git a/src/modules/network_data/service/udm_sub.go b/src/modules/network_data/service/udm_sub.go new file mode 100644 index 0000000..9c480b4 --- /dev/null +++ b/src/modules/network_data/service/udm_sub.go @@ -0,0 +1,28 @@ +package service + +import "nms_cxy/src/modules/network_data/model" + +// UDM签约用户信息 服务层接口 +type IUDMSub interface { + // ResetData 重置鉴权用户数据,清空数据库重新同步Redis数据 + ResetData(neId string) int64 + + // SelectPage 分页查询数据库 + SelectPage(query map[string]any) map[string]any + + // SelectList 查询数据库 + SelectList(u model.UDMSub) []model.UDMSub + + // Insert 从数据中读取后删除imsi再存入数据库 + // imsi长度15,ki长度32,opc长度0或者32 + Insert(neId string, u model.UDMSub) int64 + + // InsertData 导入文件数据 dataType目前两种:txt/csv + InsertData(neId, dataType string, data any) int64 + + // Delete 删除单个不重新加载 + Delete(neId, imsi string) int64 + + // LoadData 删除范围后重新加载 num表示imsi后几位 + LoadData(neId, imsi, num string) int64 +} diff --git a/src/modules/network_data/service/udm_sub.impl.go b/src/modules/network_data/service/udm_sub.impl.go new file mode 100644 index 0000000..2cf48a8 --- /dev/null +++ b/src/modules/network_data/service/udm_sub.impl.go @@ -0,0 +1,164 @@ +package service + +import ( + "fmt" + "strings" + + "nms_cxy/src/framework/redis" + "nms_cxy/src/modules/network_data/model" + "nms_cxy/src/modules/network_data/repository" +) + +// 实例化服务层 UDMSubImpl 结构体 +var NewUDMSubImpl = &UDMSubImpl{ + udmSubRepository: repository.NewUDMSubImpl, +} + +// UDM签约信息 服务层处理 +type UDMSubImpl struct { + // UDM签约信息数据信息 + udmSubRepository repository.IUDMSub +} + +// dataByRedis UDM签约用户 db:0 中 udm-sd:* +func (r *UDMSubImpl) dataByRedis(imsi, neId string) []model.UDMSub { + arr := []model.UDMSub{} + key := fmt.Sprintf("udm-sd:%s", imsi) + udmsdArr, err := redis.GetKeys("udmuser", key) + if err != nil { + return arr + } + for _, key := range udmsdArr { + m, err := redis.GetHash("udmuser", key) + if err != nil { + continue + } + + a := model.UDMSub{ + IMSI: key[7:], + Msisdn: m["gpsi"], // 46003550072 + SmfSel: m["smf-sel"], + SmData: m["sm-dat"], // 1-000001&cmnet&ims&3gnet + NeId: neId, + } + + // def_ambr,def_nssai,0,def_arfb,def_sar,3,1,12000,1,1000,0,1,- + if v, ok := m["am-dat"]; ok { + arr := strings.Split(v, ",") + a.Ambr = arr[0] + a.Nssai = arr[1] + a.Rat = arr[2] + a.Arfb = arr[3] + a.Sar = arr[4] + a.Cn = arr[5] + } + // 1,64,24,65,def_eps,1,2,010200000000,- + if v, ok := m["eps-dat"]; ok { + arr := strings.Split(v, ",") + // 跳过非常规数据 + if len(arr) > 9 { + continue + } + a.EpsDat = v + a.EpsFlag = arr[0] + a.EpsOdb = arr[1] + a.HplmnOdb = arr[2] + a.Ard = arr[3] + a.Epstpl = arr[4] + a.ContextId = arr[5] + a.ApnContext = arr[7] + // [6] 是不要的,导入和导出不用 + a.StaticIp = arr[8] + } + + arr = append(arr, a) + } + return arr +} + +// ResetData 重置鉴权用户数据,清空数据库重新同步Redis数据 +func (r *UDMSubImpl) ResetData(neId string) int64 { + subArr := r.dataByRedis("*", neId) + // 数据清空后添加 + go r.udmSubRepository.ClearAndInsert(neId, subArr) + return int64(len(subArr)) +} + +// SelectPage 分页查询数据库 +func (r *UDMSubImpl) SelectPage(query map[string]any) map[string]any { + return r.udmSubRepository.SelectPage(query) +} + +// SelectList 查询数据库 +func (r *UDMSubImpl) SelectList(u model.UDMSub) []model.UDMSub { + return r.udmSubRepository.SelectList(u) +} + +// Insert 从数据中读取后删除imsi再存入数据库 +// imsi长度15,ki长度32,opc长度0或者32 +func (r *UDMSubImpl) Insert(neId string, u model.UDMSub) int64 { + uArr := r.dataByRedis(u.IMSI, neId) + if len(uArr) > 0 { + r.udmSubRepository.Delete(neId, u.IMSI) + return r.udmSubRepository.Inserts(uArr) + } + return 0 +} + +// InsertData 导入文件数据 dataType目前两种:txt/csv +func (r *UDMSubImpl) InsertData(neId, dataType string, data any) int64 { + // imsi截取前缀,重新获取部分数据 + prefixes := make(map[string]struct{}) + + if dataType == "csv" { + for _, v := range data.([]map[string]string) { + imsi := v["imsi"] + if len(imsi) < 6 { + continue + } + prefix := imsi[:len(imsi)-4] + prefixes[prefix] = struct{}{} + } + } + if dataType == "txt" { + for _, v := range data.([][]string) { + imsi := v[0] + if len(imsi) < 6 { + continue + } + prefix := imsi[:len(imsi)-4] + prefixes[prefix] = struct{}{} + } + } + + // 根据前缀重新加载插入 + var num int64 = 0 + for prefix := range prefixes { + // 直接删除前缀的记录 + r.udmSubRepository.DeletePrefixByIMSI(neId, prefix) + // keys udm-sd:4600001000004* + subArr := r.dataByRedis(prefix+"*", neId) + if len(subArr) > 0 { + num += r.udmSubRepository.Inserts(subArr) + } + } + return num +} + +// Delete 删除单个不重新加载 +func (r *UDMSubImpl) Delete(neId, imsi string) int64 { + return r.udmSubRepository.Delete(neId, imsi) +} + +// LoadData 删除范围后重新加载 num表示imsi后几位 +func (r *UDMSubImpl) LoadData(neId, imsi, num string) int64 { + prefix := imsi[:len(imsi)-len(num)-1] + // 直接删除前缀的记录 + delNum := r.udmSubRepository.DeletePrefixByIMSI(neId, prefix) + // keys udm-sd:4600001000004* + authArr := r.dataByRedis(prefix+"*", neId) + if len(authArr) > 0 { + return r.udmSubRepository.Inserts(authArr) + } + return delNum +} diff --git a/src/modules/network_data/service/ue_event.go b/src/modules/network_data/service/ue_event_amf.go similarity index 60% rename from src/modules/network_data/service/ue_event.go rename to src/modules/network_data/service/ue_event_amf.go index ed0097b..b780c5c 100644 --- a/src/modules/network_data/service/ue_event.go +++ b/src/modules/network_data/service/ue_event_amf.go @@ -2,10 +2,10 @@ package service import "nms_cxy/src/modules/network_data/model" -// UE会话事件 服务层接口 -type IUEEvent interface { +// UE会话事件AMF 服务层接口 +type IUEEventAMF interface { // SelectPage 根据条件分页查询 - SelectPage(querys model.UEEventQuery) map[string]any + SelectPage(querys model.UEEventAMFQuery) map[string]any // DeleteByIds 批量删除信息 DeleteByIds(ueIds []string) (int64, error) diff --git a/src/modules/network_data/service/ue_event.impl.go b/src/modules/network_data/service/ue_event_amf.impl.go similarity index 58% rename from src/modules/network_data/service/ue_event.impl.go rename to src/modules/network_data/service/ue_event_amf.impl.go index 38d18c6..96e4960 100644 --- a/src/modules/network_data/service/ue_event.impl.go +++ b/src/modules/network_data/service/ue_event_amf.impl.go @@ -7,24 +7,24 @@ import ( "nms_cxy/src/modules/network_data/repository" ) -// 实例化数据层 UEEventImpl 结构体 -var NewUEEventImpl = &UEEventImpl{ - ueEventRepository: repository.NewUEEventImpl, +// 实例化数据层 UEEventMMEImpl 结构体 +var NewUEEventMMEImpl = &UEEventMMEImpl{ + ueEventRepository: repository.NewUEEventMMEImpl, } -// UEEventImpl UE会话事件 服务层处理 -type UEEventImpl struct { +// UEEventMMEImpl UE会话事件MME 服务层处理 +type UEEventMMEImpl struct { // UE会话事件数据信息 - ueEventRepository repository.IUEEvent + ueEventRepository repository.IUEEventMME } // SelectPage 根据条件分页查询 -func (r *UEEventImpl) SelectPage(querys model.UEEventQuery) map[string]any { +func (r *UEEventMMEImpl) SelectPage(querys model.UEEventMMEQuery) map[string]any { return r.ueEventRepository.SelectPage(querys) } // DeleteByIds 批量删除信息 -func (r *UEEventImpl) DeleteByIds(ueIds []string) (int64, error) { +func (r *UEEventMMEImpl) DeleteByIds(ueIds []string) (int64, error) { // 检查是否存在 ids := r.ueEventRepository.SelectByIds(ueIds) if len(ids) <= 0 { diff --git a/src/modules/network_data/service/ue_event_mme.go b/src/modules/network_data/service/ue_event_mme.go new file mode 100644 index 0000000..da415fb --- /dev/null +++ b/src/modules/network_data/service/ue_event_mme.go @@ -0,0 +1,12 @@ +package service + +import "nms_cxy/src/modules/network_data/model" + +// UE会话事件MME 服务层接口 +type IUEEventMME interface { + // SelectPage 根据条件分页查询 + SelectPage(querys model.UEEventMMEQuery) map[string]any + + // DeleteByIds 批量删除信息 + DeleteByIds(ueIds []string) (int64, error) +} diff --git a/src/modules/network_data/service/ue_event_mme.impl.go b/src/modules/network_data/service/ue_event_mme.impl.go new file mode 100644 index 0000000..aee4c67 --- /dev/null +++ b/src/modules/network_data/service/ue_event_mme.impl.go @@ -0,0 +1,40 @@ +package service + +import ( + "fmt" + + "nms_cxy/src/modules/network_data/model" + "nms_cxy/src/modules/network_data/repository" +) + +// 实例化数据层 UEEventAMFImpl 结构体 +var NewUEEventAMFImpl = &UEEventAMFImpl{ + ueEventRepository: repository.NewUEEventAMFImpl, +} + +// UEEventAMFImpl UE会话事件AMF 服务层处理 +type UEEventAMFImpl struct { + // UE会话事件数据信息 + ueEventRepository repository.IUEEventAMF +} + +// SelectPage 根据条件分页查询 +func (r *UEEventAMFImpl) SelectPage(querys model.UEEventAMFQuery) map[string]any { + return r.ueEventRepository.SelectPage(querys) +} + +// DeleteByIds 批量删除信息 +func (r *UEEventAMFImpl) DeleteByIds(ueIds []string) (int64, error) { + // 检查是否存在 + ids := r.ueEventRepository.SelectByIds(ueIds) + if len(ids) <= 0 { + return 0, fmt.Errorf("no data") + } + + if len(ids) == len(ueIds) { + rows := r.ueEventRepository.DeleteByIds(ueIds) + return rows, nil + } + // 删除信息失败! + return 0, fmt.Errorf("delete fail") +} diff --git a/src/modules/network_element/controller/ne_action.go b/src/modules/network_element/controller/action.go similarity index 55% rename from src/modules/network_element/controller/ne_action.go rename to src/modules/network_element/controller/action.go index 2deb715..13ee7d4 100644 --- a/src/modules/network_element/controller/ne_action.go +++ b/src/modules/network_element/controller/action.go @@ -3,6 +3,7 @@ package controller import ( "fmt" "path/filepath" + "runtime" "strings" "nms_cxy/src/framework/i18n" @@ -51,19 +52,30 @@ func (s *NeActionController) PushFile(c *gin.Context) { return } - // 本地文件 - localPath := file.ParseUploadFilePath(body.UploadPath) - nePath := "/tmp" //config.Get("mml.upload").(string) - // 复制到远程 - err := ssh.FileSCPLocalToNe(neInfo.IP, localPath, nePath) + // 网元主机的SSH客户端 + sshClient, err := s.neInfoService.NeRunSSHClient(neInfo.NeType, neInfo.NeId) if err != nil { c.JSON(200, result.ErrMsg(err.Error())) return } + defer sshClient.Close() + // 网元主机的SSH客户端进行文件传输 + sftpClient, err := sshClient.NewClientSFTP() + if err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return + } + defer sftpClient.Close() + + // 本地文件 + localFilePath := file.ParseUploadFilePath(body.UploadPath) + neFilePath := fmt.Sprintf("/tmp/%s", filepath.Base(localFilePath)) + // 复制到远程 + if err = sftpClient.CopyFileLocalToRemote(localFilePath, neFilePath); err != nil { + c.JSON(200, result.ErrMsg(fmt.Sprintf("%s : please check if scp remote copy is allowed", neInfo.NeType))) + return + } - // 网元端文件路径 - fileName := localPath[strings.LastIndex(localPath, "/")+1:] - neFilePath := fmt.Sprintf("%s/%s", nePath, fileName) c.JSON(200, result.OkData(filepath.ToSlash(neFilePath))) } @@ -90,14 +102,32 @@ func (s *NeActionController) PullFile(c *gin.Context) { return } - nePath := fmt.Sprintf("%s/%s", querys.Path, querys.FileName) - localPath := fmt.Sprintf("/tmp/omc/pullFile/%s", querys.FileName) - err := ssh.FileSCPNeToLocal(neInfo.IP, nePath, localPath) + // 网元主机的SSH客户端 + sshClient, err := s.neInfoService.NeRunSSHClient(neInfo.NeType, neInfo.NeId) if err != nil { c.JSON(200, result.ErrMsg(err.Error())) return } - c.FileAttachment(localPath, querys.FileName) + defer sshClient.Close() + // 网元主机的SSH客户端进行文件传输 + sftpClient, err := sshClient.NewClientSFTP() + if err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return + } + defer sftpClient.Close() + + nePath := fmt.Sprintf("%s/%s", querys.Path, querys.FileName) + localFilePath := fmt.Sprintf("/tmp/omc/pullFile%s", nePath) + if runtime.GOOS == "windows" { + localFilePath = fmt.Sprintf("C:%s", localFilePath) + } + // 复制到本地 + if err = sftpClient.CopyFileRemoteToLocal(nePath, localFilePath); err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return + } + c.FileAttachment(localFilePath, querys.FileName) } // 网元端文件列表 @@ -125,7 +155,16 @@ func (s *NeActionController) Files(c *gin.Context) { return } - totalSize, rows, err := ssh.FileList(querys.Path, neInfo.IP, querys.Search) + // 网元主机的SSH客户端 + sshClient, err := s.neInfoService.NeRunSSHClient(neInfo.NeType, neInfo.NeId) + if err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return + } + defer sshClient.Close() + + // 获取文件列表 + totalSize, rows, err := ssh.FileList(sshClient, querys.Path, querys.Search) if err != nil { c.JSON(200, result.Ok(map[string]any{ "path": querys.Path, @@ -156,3 +195,52 @@ func (s *NeActionController) Files(c *gin.Context) { "rows": splitRows, })) } + +// 网元服务操作 +// +// PUT /service +func (s *NeActionController) Service(c *gin.Context) { + language := ctx.AcceptLanguage(c) + var body struct { + NeType string `json:"neType" binding:"required"` + NeID string `json:"neId" binding:"required"` + Action string `json:"action" binding:"required,oneof=start restart stop reboot poweroff"` // 操作行为 + } + if err := c.ShouldBindBodyWith(&body, binding.JSON); err != nil { + c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) + return + } + + // 查询网元获取IP + neInfo := s.neInfoService.SelectNeInfoByNeTypeAndNeID(body.NeType, body.NeID) + if neInfo.NeId != body.NeID || neInfo.IP == "" { + c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.noNEInfo"))) + return + } + + neTypeLower := strings.ToLower(neInfo.NeType) + cmdStr := fmt.Sprintf("sudo service %s %s", neTypeLower, body.Action) + if neTypeLower == "omc" { + cmdStr = fmt.Sprintf("nohup sh -c \"sudo systemctl stop restagent && sleep 5s && sudo systemctl %s restagent\" > /dev/null 2>&1 &", body.Action) + } else if neTypeLower == "ims" { + if body.Action == "restart" { + cmdStr = "ims-stop || true && ims-start" + } else { + cmdStr = fmt.Sprintf("sudo ims-%s", body.Action) + } + } + + if body.Action == "reboot" { + cmdStr = "sudo shutdown -r now" + } + if body.Action == "poweroff" { + cmdStr = "sudo shutdown -h now" + } + + _, err := s.neInfoService.NeRunSSHCmd(body.NeType, body.NeID, cmdStr) + if err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return + } + c.JSON(200, result.Ok(nil)) +} diff --git a/src/modules/network_element/controller/ne_config.go b/src/modules/network_element/controller/ne_config.go new file mode 100644 index 0000000..32e1f58 --- /dev/null +++ b/src/modules/network_element/controller/ne_config.go @@ -0,0 +1,203 @@ +package controller + +import ( + "encoding/json" + "strings" + + "nms_cxy/src/framework/i18n" + "nms_cxy/src/framework/utils/ctx" + "nms_cxy/src/framework/utils/parse" + "nms_cxy/src/framework/vo/result" + neFetchlink "nms_cxy/src/modules/network_element/fetch_link" + "nms_cxy/src/modules/network_element/model" + neService "nms_cxy/src/modules/network_element/service" + + "github.com/gin-gonic/gin" + "github.com/gin-gonic/gin/binding" +) + +// NewNeConfig 网元参数配置 实例化控制层 +var NewNeConfig = &NeConfigController{ + neConfigService: neService.NewNeConfigImpl, + neInfoService: neService.NewNeInfoImpl, +} + +// 网元参数配置 +// +// PATH /config +type NeConfigController struct { + // 网元参数配置可用属性值服务 + neConfigService neService.INeConfig + // 网元信息服务 + neInfoService neService.INeInfo +} + +// 网元参数配置可用属性值列表 +// +// GET /list +func (s *NeConfigController) List(c *gin.Context) { + querys := ctx.QueryMap(c) + data := s.neConfigService.SelectPage(querys) + + c.JSON(200, result.Ok(data)) +} + +// 网元参数配置可用属性值信息 +// +// GET /info/:id +func (s *NeConfigController) Info(c *gin.Context) { + language := ctx.AcceptLanguage(c) + id := c.Param("id") + if id == "" { + c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) + return + } + + data := s.neConfigService.SelectById(id) + if data.ID != id { + // 没有可访问参数配置数据! + c.JSON(200, result.ErrMsg(i18n.TKey(language, "neConfig.noData"))) + return + } + + // 将字符串转json数据 + if err := json.Unmarshal([]byte(data.ParamJSONStr), &data.ParamData); err != nil { + c.JSON(400, result.CodeMsg(400, err.Error())) + return + } + c.JSON(200, result.OkData(data)) +} + +// 网元参数配置可用属性值新增 +// +// POST / +func (s *NeConfigController) Add(c *gin.Context) { + language := ctx.AcceptLanguage(c) + var body model.NeConfig + if err := c.ShouldBindBodyWith(&body, binding.JSON); err != nil { + c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) + return + } + + // 将json数据转字符串存储 + paramDataByte, err := json.Marshal(body.ParamData) + if err != nil { + c.JSON(400, result.CodeMsg(400, err.Error())) + return + } + body.ParamJSONStr = string(paramDataByte) + + insertId := s.neConfigService.Insert(body) + if insertId != "" { + c.JSON(200, result.Ok(nil)) + return + } + c.JSON(200, result.Err(nil)) +} + +// 网元参数配置可用属性值修改 +// +// PUT / +func (s *NeConfigController) Edit(c *gin.Context) { + language := ctx.AcceptLanguage(c) + var body model.NeConfig + err := c.ShouldBindBodyWith(&body, binding.JSON) + if err != nil || body.ID == "" { + c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) + return + } + + // 检查是否存在 + data := s.neConfigService.SelectById(body.ID) + if data.ID != body.ID { + // 没有可访问主机命令数据! + c.JSON(200, result.ErrMsg(i18n.TKey(language, "neConfig.noData"))) + return + } + + // 将json数据转字符串存储 + paramDataByte, err := json.Marshal(body.ParamData) + if err != nil { + c.JSON(400, result.CodeMsg(400, err.Error())) + return + } + body.ParamJSONStr = string(paramDataByte) + + rows := s.neConfigService.Update(body) + if rows > 0 { + c.JSON(200, result.Ok(nil)) + return + } + c.JSON(200, result.Err(nil)) +} + +// 网元参数配置可用属性值删除 +// +// DELETE /:ids +func (s *NeConfigController) Remove(c *gin.Context) { + language := ctx.AcceptLanguage(c) + ids := c.Param("ids") + if ids == "" { + c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) + return + } + // 处理字符转id数组后去重 + idsArr := strings.Split(ids, ",") + uniqueIDs := parse.RemoveDuplicates(idsArr) + if len(uniqueIDs) <= 0 { + c.JSON(200, result.Err(nil)) + return + } + rows, err := s.neConfigService.DeleteByIds(uniqueIDs) + if err != nil { + c.JSON(200, result.ErrMsg(i18n.TKey(language, err.Error()))) + return + } + msg := i18n.TTemplate(language, "app.common.deleteSuccess", map[string]any{"num": rows}) + c.JSON(200, result.OkMsg(msg)) +} + +// 网元参数配置可用属性值列表指定网元类型全部无分页 +// +// GET /list/:neType +func (s *NeConfigController) ListByNeType(c *gin.Context) { + language := ctx.AcceptLanguage(c) + neType := c.Param("neType") + if neType == "" { + c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) + return + } + data := s.neConfigService.SelectNeConfigByNeType(neType) + c.JSON(200, result.OkData(data)) +} + +// 网元参数配置数据信息 +// +// GET /data +func (s *NeConfigController) Data(c *gin.Context) { + language := ctx.AcceptLanguage(c) + var querys struct { + NeType string `form:"neType" binding:"required"` // 网元类型 + NeId string `form:"neId" binding:"required"` // 网元ID + TopTag string `form:"topTag" binding:"required"` // 可用属性 + } + if err := c.ShouldBindQuery(&querys); err != nil { + c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) + return + } + + neInfo := s.neInfoService.SelectNeInfoByNeTypeAndNeID(querys.NeType, querys.NeId) + if neInfo.NeId != querys.NeId || neInfo.IP == "" { + c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.noNEInfo"))) + return + } + + // 网元直连 + resData, err := neFetchlink.NeConfigInfo(neInfo, querys.TopTag) + if err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return + } + + c.JSON(200, result.Ok(resData)) +} diff --git a/src/modules/network_element/controller/ne_host.go b/src/modules/network_element/controller/ne_host.go index 1fab3e8..7255e1f 100644 --- a/src/modules/network_element/controller/ne_host.go +++ b/src/modules/network_element/controller/ne_host.go @@ -168,8 +168,7 @@ func (s *NeHostController) Remove(c *gin.Context) { func (s *NeHostController) Test(c *gin.Context) { language := ctx.AcceptLanguage(c) var body model.NeHost - err := c.ShouldBindBodyWith(&body, binding.JSON) - if err != nil { + if err := c.ShouldBindBodyWith(&body, binding.JSON); err != nil { c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) return } @@ -177,8 +176,13 @@ func (s *NeHostController) Test(c *gin.Context) { if body.HostType == "ssh" { var connSSH ssh.ConnSSH body.CopyTo(&connSSH) - - client, err := connSSH.NewClient() + var client *ssh.ConnSSH + var err error + if body.AuthMode == "2" { + client, err = connSSH.NewClientByLocalPrivate() + } else { + client, err = connSSH.NewClient() + } if err != nil { // 连接主机失败,请检查连接参数后重试 c.JSON(200, result.ErrMsg(i18n.TKey(language, "neHost.errByHostInfo"))) @@ -200,7 +204,13 @@ func (s *NeHostController) Test(c *gin.Context) { return } defer client.Close() - c.JSON(200, result.Ok(nil)) + // 是否有终止符 + if strings.HasSuffix(client.LastResult, ">") || strings.HasSuffix(client.LastResult, "> ") || strings.HasSuffix(client.LastResult, "# ") { + c.JSON(200, result.Ok(nil)) + } else { + // 连接主机失败,请检查连接参数后重试 + c.JSON(200, result.ErrMsg(i18n.TKey(language, "neHost.errByHostInfo"))) + } return } } @@ -214,8 +224,7 @@ func (s *NeHostController) Cmd(c *gin.Context) { HostID string `json:"hostId" binding:"required"` // 主机ID Cmd string `json:"cmd" binding:"required"` // 执行命令 } - err := c.ShouldBindBodyWith(&body, binding.JSON) - if err != nil { + if err := c.ShouldBindBodyWith(&body, binding.JSON); err != nil { c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) return } @@ -231,8 +240,13 @@ func (s *NeHostController) Cmd(c *gin.Context) { if neHost.HostType == "ssh" { var connSSH ssh.ConnSSH neHost.CopyTo(&connSSH) - - client, err := connSSH.NewClient() + var client *ssh.ConnSSH + var err error + if neHost.AuthMode == "2" { + client, err = connSSH.NewClientByLocalPrivate() + } else { + client, err = connSSH.NewClient() + } if err != nil { // 连接主机失败,请检查连接参数后重试 c.JSON(200, result.ErrMsg(i18n.TKey(language, "neHost.errByHostInfo"))) @@ -279,17 +293,21 @@ func (s *NeHostController) Cmd(c *gin.Context) { func (s *NeHostController) CheckBySSH(c *gin.Context) { language := ctx.AcceptLanguage(c) var body model.NeHost - err := c.ShouldBindBodyWith(&body, binding.JSON) - if err != nil { + if err := c.ShouldBindBodyWith(&body, binding.JSON); err != nil { c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) return } var connSSH ssh.ConnSSH body.CopyTo(&connSSH) - // 创建链接SSH客户端 - client, err := connSSH.NewClient() + var client *ssh.ConnSSH + var err error + if body.AuthMode == "2" { + client, err = connSSH.NewClientByLocalPrivate() + } else { + client, err = connSSH.NewClient() + } if err != nil { // 连接主机失败,请检查连接参数后重试 c.JSON(200, result.ErrMsg(i18n.TKey(language, "neHost.errByHostInfo"))) @@ -340,6 +358,39 @@ func (s *NeHostController) CheckBySSH(c *gin.Context) { } // 本地免密创建链接直连 + if body.AuthMode == "2" { + data["sshLink"] = true + } else { + lcoalConnSSH := ssh.ConnSSH{ + User: body.User, + Addr: body.Addr, + Port: body.Port, + } + lcoalClient, err := lcoalConnSSH.NewClientByLocalPrivate() + if err == nil { + data["sshLink"] = true + defer lcoalClient.Close() + } else { + data["sshLink"] = false + } + } + + c.JSON(200, result.OkData(data)) +} + +// 网元主机SSH方式授权免密发送 +// +// POST /authorizedBySSH +func (s *NeHostController) AuthorizedBySSH(c *gin.Context) { + language := ctx.AcceptLanguage(c) + var body model.NeHost + if err := c.ShouldBindBodyWith(&body, binding.JSON); err != nil || body.AuthMode == "2" { + c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) + return + } + + // 本地免密创建链接直连 + sshLink := false lcoalConnSSH := ssh.ConnSSH{ User: body.User, Addr: body.Addr, @@ -347,11 +398,31 @@ func (s *NeHostController) CheckBySSH(c *gin.Context) { } lcoalClient, err := lcoalConnSSH.NewClientByLocalPrivate() if err == nil { - data["sshLink"] = true - } else { - data["sshLink"] = false + sshLink = true + defer lcoalClient.Close() + } + if sshLink { + // 连接主机成功,无需重复免密授权认证 + c.JSON(200, result.OkMsg(i18n.TKey(language, "neHost.okBySSHLink"))) + return } - defer lcoalClient.Close() - c.JSON(200, result.OkData(data)) + // 创建链接SSH客户端 + var connSSH ssh.ConnSSH + body.CopyTo(&connSSH) + client, err := connSSH.NewClient() + if err != nil { + // 连接主机失败,请检查连接参数后重试 + c.JSON(200, result.ErrMsg(i18n.TKey(language, "neHost.errByHostInfo"))) + return + } + defer client.Close() + + // 发送密钥 + err = client.SendToAuthorizedKeys() + if err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return + } + c.JSON(200, result.Ok(nil)) } diff --git a/src/modules/network_element/controller/ne_info.go b/src/modules/network_element/controller/ne_info.go index 3e71490..747828e 100644 --- a/src/modules/network_element/controller/ne_info.go +++ b/src/modules/network_element/controller/ne_info.go @@ -9,6 +9,7 @@ import ( "nms_cxy/src/framework/utils/ctx" "nms_cxy/src/framework/utils/parse" "nms_cxy/src/framework/vo/result" + neFetchlink "nms_cxy/src/modules/network_element/fetch_link" "nms_cxy/src/modules/network_element/model" neService "nms_cxy/src/modules/network_element/service" @@ -18,15 +19,21 @@ import ( // 实例化控制层 NeInfoController 结构体 var NewNeInfo = &NeInfoController{ - neInfoService: neService.NewNeInfoImpl, + neInfoService: neService.NewNeInfoImpl, + neLicenseService: neService.NewNeLicenseImpl, + neVersionService: neService.NewNeVersionImpl, } // 网元信息请求 // -// PATH / +// PATH /info type NeInfoController struct { // 网元信息服务 neInfoService neService.INeInfo + // 网元授权激活信息服务 + neLicenseService neService.INeLicense + // 网元版本信息服务 + neVersionService neService.INeVersion } // neStateCacheMap 网元状态缓存最后一次成功的信息 @@ -40,22 +47,22 @@ func (s *NeInfoController) State(c *gin.Context) { language := ctx.AcceptLanguage(c) var querys struct { NeType string `form:"neType" binding:"required"` - NeID string `form:"neId" binding:"required"` + NeId string `form:"neId" binding:"required"` } if err := c.ShouldBindQuery(&querys); err != nil { c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) return } - neInfo := s.neInfoService.SelectNeInfoByNeTypeAndNeID(querys.NeType, querys.NeID) - if neInfo.NeId != querys.NeID || neInfo.IP == "" { + neInfo := s.neInfoService.SelectNeInfoByNeTypeAndNeID(querys.NeType, querys.NeId) + if neInfo.NeId != querys.NeId || neInfo.IP == "" { c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.noNEInfo"))) return } neKey := fmt.Sprintf("%s_%s", neInfo.NeType, neInfo.NeId) // 网元直连 - resData, err := neService.NeState(neInfo) + resData, err := neFetchlink.NeState(neInfo) if err != nil { mutex.Lock() // 异常取上次缓存 @@ -85,17 +92,26 @@ func (s *NeInfoController) State(c *gin.Context) { c.JSON(200, result.OkData(resData)) } -// 网元信息列表 +// 网元neType和neID查询 // -// GET /list -func (s *NeInfoController) List(c *gin.Context) { - querys := ctx.QueryMap(c) - bandStatus := false - if v, ok := querys["bandStatus"]; ok && v != nil { - bandStatus = parse.Boolean(v) +// GET /byTypeAndID +func (s *NeInfoController) NeTypeAndID(c *gin.Context) { + language := ctx.AcceptLanguage(c) + var querys struct { + NeType string `form:"neType" binding:"required"` + NeID string `form:"neId" binding:"required"` } - data := s.neInfoService.SelectPage(querys, bandStatus) - c.JSON(200, result.Ok(data)) + if err := c.ShouldBindQuery(&querys); err != nil { + c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) + return + } + + neInfo := s.neInfoService.SelectNeInfoByNeTypeAndNeID(querys.NeType, querys.NeID) + if neInfo.NeId != querys.NeID || neInfo.IP == "" { + c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.noNEInfo"))) + return + } + c.JSON(200, result.OkData(neInfo)) } // 网元信息列表全部无分页 @@ -106,7 +122,8 @@ func (s *NeInfoController) ListAll(c *gin.Context) { var querys struct { NeType string `form:"neType"` NeId string `form:"neId"` - BandStatus string `form:"bandStatus"` + BandStatus bool `form:"bandStatus"` + BandHost bool `form:"bandHost"` } if err := c.ShouldBindQuery(&querys); err != nil { c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) @@ -121,8 +138,7 @@ func (s *NeInfoController) ListAll(c *gin.Context) { if querys.NeId != "" { ne.NeId = querys.NeId } - bandStatus := parse.Boolean(querys.BandStatus) - neList := s.neInfoService.SelectList(ne, bandStatus) + neList := s.neInfoService.SelectList(ne, querys.BandStatus, querys.BandHost) if len(neList) == 0 { c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.noNEInfo"))) return @@ -130,6 +146,106 @@ func (s *NeInfoController) ListAll(c *gin.Context) { c.JSON(200, result.OkData(neList)) } +// 网元端Para5G配置文件读取 +// +// GET /para5GFile +func (s *NeInfoController) Para5GFileRead(c *gin.Context) { + data, err := s.neInfoService.NeConfPara5GRead() + if err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return + } + c.JSON(200, result.OkData(data)) +} + +// 网元端Para5G配置文件写入 +// +// PUT /para5GFile +func (s *NeInfoController) Para5GFileWrite(c *gin.Context) { + language := ctx.AcceptLanguage(c) + var body struct { + Content map[string]any `json:"content" binding:"required"` // 内容 + SyncNE []string `json:"syncNe"` // 同步到网元 + } + if err := c.ShouldBindBodyWith(&body, binding.JSON); err != nil { + c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) + return + } + + err := s.neInfoService.NeConfPara5GWirte(body.Content, body.SyncNE) + if err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return + } + c.JSON(200, result.Ok(nil)) +} + +// 网元端OAM配置文件读取 +// +// GET /oamFile +func (s *NeInfoController) OAMFileRead(c *gin.Context) { + language := ctx.AcceptLanguage(c) + var querys struct { + NeType string `form:"neType" binding:"required"` + NeID string `form:"neId" binding:"required"` + } + if err := c.ShouldBindQuery(&querys); err != nil { + c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) + return + } + + data, err := s.neInfoService.NeConfOAMRead(querys.NeType, querys.NeID) + if err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return + } + c.JSON(200, result.OkData(data)) +} + +// 网元端OAM配置文件写入 +// +// PUT /oamFile +func (s *NeInfoController) OAMFileWrite(c *gin.Context) { + language := ctx.AcceptLanguage(c) + var body struct { + NeType string `json:"neType" binding:"required"` + NeID string `json:"neId" binding:"required"` + Content map[string]any `json:"content" binding:"required"` // 内容 + Sync bool `json:"sync"` // 同步到网元 + } + if err := c.ShouldBindBodyWith(&body, binding.JSON); err != nil { + c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) + return + } + + // 查询网元获取IP + neInfo := s.neInfoService.SelectNeInfoByNeTypeAndNeID(body.NeType, body.NeID) + if neInfo.NeId != body.NeID || neInfo.IP == "" { + c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.noNEInfo"))) + return + } + + err := s.neInfoService.NeConfOAMSync(neInfo, body.Content, body.Sync) + if err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return + } + c.JSON(200, result.Ok(nil)) +} + +// 网元信息列表 +// +// GET /list +func (s *NeInfoController) List(c *gin.Context) { + querys := ctx.QueryMap(c) + bandStatus := false + if v, ok := querys["bandStatus"]; ok && v != nil { + bandStatus = parse.Boolean(v) + } + data := s.neInfoService.SelectPage(querys, bandStatus) + c.JSON(200, result.Ok(data)) +} + // 网元信息 // // GET /:infoId @@ -151,28 +267,6 @@ func (s *NeInfoController) Info(c *gin.Context) { c.JSON(200, result.OkData(neHost)) } -// 网元neType和neID查询 -// -// GET / -func (s *NeInfoController) NeTypeAndID(c *gin.Context) { - language := ctx.AcceptLanguage(c) - var querys struct { - NeType string `form:"neType" binding:"required"` - NeID string `form:"neId" binding:"required"` - } - if err := c.ShouldBindQuery(&querys); err != nil { - c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) - return - } - - neInfo := s.neInfoService.SelectNeInfoByNeTypeAndNeID(querys.NeType, querys.NeID) - if neInfo.NeId != querys.NeID || neInfo.IP == "" { - c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.noNEInfo"))) - return - } - c.JSON(200, result.OkData(neInfo)) -} - // 网元信息新增 // // POST / @@ -195,22 +289,53 @@ func (s *NeInfoController) Add(c *gin.Context) { } // 获取网元状态是否正常 - _, err = neService.NeState(body) + body.ServerState, err = neFetchlink.NeState(body) if err != nil { - body.Status = "1" + body.Status = "0" } else { // 下发网管配置信息给网元 - _, err = neService.NeConfigOMC(body) + _, err = neFetchlink.NeConfigOMC(body) if err == nil { - body.Status = "0" + body.Status = "1" } else { - body.Status = "3" + body.Status = "2" } } + loginUserName := ctx.LoginUserToUserName(c) + // 新增Version信息 + neVersion := model.NeVersion{ + NeType: body.NeType, + NeId: body.NeId, + CreateBy: loginUserName, + } + // 新增License信息 + neLicense := model.NeLicense{ + NeType: body.NeType, + NeId: body.NeId, + CreateBy: loginUserName, + } + + // 已有网元可获取的信息 + if body.ServerState != nil { + if v, ok := body.ServerState["version"]; ok && v != nil { + neVersion.Version = v.(string) + } + if v, ok := body.ServerState["sn"]; ok && v != nil { + neLicense.SerialNum = v.(string) + } + if v, ok := body.ServerState["expire"]; ok && v != nil { + neLicense.ExpiryDate = v.(string) + neLicense.Status = "1" + } + } + + s.neVersionService.Insert(neVersion) + s.neLicenseService.Insert(neLicense) + body.CreateBy = loginUserName insertId := s.neInfoService.Insert(body) if insertId != "" { - c.JSON(200, result.Ok(nil)) + c.JSON(200, result.OkData(insertId)) return } c.JSON(200, result.Err(nil)) @@ -229,8 +354,8 @@ func (s *NeInfoController) Edit(c *gin.Context) { } // 检查属性值唯一 - uniqueHostCmd := s.neInfoService.CheckUniqueNeTypeAndNeId(body.NeType, body.NeId, body.ID) - if !uniqueHostCmd { + uniqueInfo := s.neInfoService.CheckUniqueNeTypeAndNeId(body.NeType, body.NeId, body.ID) + if !uniqueInfo { // 网元信息操作【%s】失败,同类型下标识已存在 msg := i18n.TTemplate(language, "neInfo.errKeyExists", map[string]any{"key": body.NeId}) c.JSON(200, result.ErrMsg(msg)) @@ -244,21 +369,64 @@ func (s *NeInfoController) Edit(c *gin.Context) { c.JSON(200, result.ErrMsg(i18n.TKey(language, "neInfo.noData"))) return } - - // 获取网元状态是否正常 - _, err = neService.NeState(body) - if err != nil { - body.Status = "1" - } else { - // 下发网管配置信息给网元 - _, err = neService.NeConfigOMC(body) - if err == nil { - body.Status = "0" - } else { - body.Status = "3" + // 赋予主机ID + if neInfo.HostIDs != "" && len(body.Hosts) > 0 { + hostIDs := strings.Split(neInfo.HostIDs, ",") + for index, id := range hostIDs { + body.Hosts[index].HostID = id } } + // 获取网元状态是否正常 + body.ServerState, err = neFetchlink.NeState(body) + if err != nil { + body.Status = "0" + } else { + // 下发网管配置信息给网元 + _, err = neFetchlink.NeConfigOMC(body) + if err == nil { + body.Status = "1" + } else { + body.Status = "2" + } + } + + loginUserName := ctx.LoginUserToUserName(c) + neLicense := s.neLicenseService.SelectByNeTypeAndNeID(neInfo.NeType, neInfo.NeId) + neVersion := s.neVersionService.SelectByNeTypeAndNeID(neInfo.NeType, neInfo.NeId) + + // 已有网元可获取的信息 + if body.ServerState != nil { + if v, ok := body.ServerState["version"]; ok && v != nil { + neVersion.Version = v.(string) + neVersion.UpdateBy = loginUserName + } + if v, ok := body.ServerState["sn"]; ok && v != nil { + neLicense.SerialNum = v.(string) + } + if v, ok := body.ServerState["expire"]; ok && v != nil { + neLicense.ExpiryDate = v.(string) + neLicense.Status = "1" + neLicense.UpdateBy = loginUserName + } + } + + if neVersion.ID != "" { + if neVersion.NeType != body.NeType || neVersion.NeId != body.NeId { + neVersion.NeType = body.NeType + neVersion.NeId = body.NeId + } + s.neVersionService.Update(neVersion) + } + if neLicense.ID != "" { + if neLicense.NeType != body.NeType || neLicense.NeId != body.NeId { + neLicense.NeType = body.NeType + neLicense.NeId = body.NeId + } + s.neLicenseService.Update(neLicense) + } + + body.UpdateBy = loginUserName rows := s.neInfoService.Update(body) if rows > 0 { c.JSON(200, result.Ok(nil)) diff --git a/src/modules/network_element/controller/ne_license.go b/src/modules/network_element/controller/ne_license.go new file mode 100644 index 0000000..9a25c7f --- /dev/null +++ b/src/modules/network_element/controller/ne_license.go @@ -0,0 +1,226 @@ +package controller + +import ( + "fmt" + + "nms_cxy/src/framework/i18n" + "nms_cxy/src/framework/utils/ctx" + "nms_cxy/src/framework/vo/result" + neFetchlink "nms_cxy/src/modules/network_element/fetch_link" + "nms_cxy/src/modules/network_element/model" + neService "nms_cxy/src/modules/network_element/service" + + "github.com/gin-gonic/gin" + "github.com/gin-gonic/gin/binding" +) + +// 实例化控制层 NeLicenseController 结构体 +var NewNeLicense = &NeLicenseController{ + neLicenseService: neService.NewNeLicenseImpl, + neInfoService: neService.NewNeInfoImpl, +} + +// 网元授权激活请求 +// +// PATH /license +type NeLicenseController struct { + // 网元授权激活服务 + neLicenseService neService.INeLicense + // 网元信息服务 + neInfoService neService.INeInfo +} + +// 网元授权激活列表 +// +// GET /list +func (s *NeLicenseController) List(c *gin.Context) { + querys := ctx.QueryMap(c) + data := s.neLicenseService.SelectPage(querys) + + // 过滤屏蔽授权文件 + rows := data["rows"].([]model.NeLicense) + arr := &rows + for i := range *arr { + (*arr)[i].ActivationRequestCode = "-" + (*arr)[i].LicensePath = "-" + } + + c.JSON(200, result.Ok(data)) +} + +// 网元授权激活信息 +// +// GET /:licenseId +func (s *NeLicenseController) Info(c *gin.Context) { + language := ctx.AcceptLanguage(c) + licenseId := c.Param("licenseId") + if licenseId == "" { + c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) + return + } + + neLicense := s.neLicenseService.SelectById(licenseId) + if neLicense.ID != licenseId { + // 没有可访问网元授权激活数据! + c.JSON(200, result.ErrMsg(i18n.TKey(language, "neLicense.noData"))) + return + } + + c.JSON(200, result.OkData(neLicense)) +} + +// 网元neType和neID查询 +// +// GET /byTypeAndID +func (s *NeLicenseController) NeTypeAndID(c *gin.Context) { + language := ctx.AcceptLanguage(c) + var querys struct { + NeType string `form:"neType" binding:"required"` + NeId string `form:"neId" binding:"required"` + } + if err := c.ShouldBindQuery(&querys); err != nil { + c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) + return + } + + neLicense := s.neLicenseService.SelectByNeTypeAndNeID(querys.NeType, querys.NeId) + if neLicense.NeId != querys.NeId { + // 没有可访问网元授权激活数据! + c.JSON(200, result.ErrMsg(i18n.TKey(language, "neLicense.noData"))) + return + } + + c.JSON(200, result.OkData(neLicense)) +} + +// 网元授权激活授权申请码 +// +// GET /code +func (s *NeLicenseController) Code(c *gin.Context) { + language := ctx.AcceptLanguage(c) + var querys struct { + NeType string `form:"neType" binding:"required"` + NeId string `form:"neId" binding:"required"` + } + if err := c.ShouldBindQuery(&querys); err != nil { + c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) + return + } + + // 检查是否存在授权记录 + neLicense := s.neLicenseService.SelectByNeTypeAndNeID(querys.NeType, querys.NeId) + if neLicense.NeId != querys.NeId { + // 没有可访问网元授权激活数据! + c.JSON(200, result.ErrMsg(i18n.TKey(language, "neLicense.noData"))) + return + } + + // 更新授权码 + code, licensePath := s.neLicenseService.ReadLicenseInfo(neLicense) + neLicense.ActivationRequestCode = code + if licensePath != "" { + neLicense.LicensePath = licensePath + } else { + neLicense.SerialNum = "" + neLicense.ExpiryDate = "" + neLicense.Status = "0" + } + neLicense.UpdateBy = ctx.LoginUserToUserName(c) + s.neLicenseService.Update(neLicense) + + c.JSON(200, result.OkData(code)) +} + +// 网元授权激活授权文件替换 +// +// POST /change +func (s *NeLicenseController) Change(c *gin.Context) { + language := ctx.AcceptLanguage(c) + var body model.NeLicense + err := c.ShouldBindBodyWith(&body, binding.JSON) + if err != nil || body.LicensePath == "" { + c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) + return + } + + // 检查是否存在授权记录 + neLicense := s.neLicenseService.SelectByNeTypeAndNeID(body.NeType, body.NeId) + if neLicense.NeId != body.NeId { + // 没有可访问网元授权激活数据! + c.JSON(200, result.ErrMsg(i18n.TKey(language, "neLicense.noData"))) + return + } + + // 更新授权记录 + if body.Remark != "" { + neLicense.Remark = body.Remark + } + neLicense.LicensePath = body.LicensePath + neLicense.Status = "0" + neLicense.UpdateBy = ctx.LoginUserToUserName(c) + upRows := s.neLicenseService.Update(neLicense) + if upRows > 0 { + // 进行上传替换 + err = s.neLicenseService.UploadLicense(body) + if err != nil { + c.JSON(200, result.ErrMsg(err.Error())) + return + } + c.JSON(200, result.Ok(nil)) + return + } + c.JSON(200, result.Err(nil)) +} + +// 网元授权激活状态 +// +// GET /state +func (s *NeLicenseController) State(c *gin.Context) { + language := ctx.AcceptLanguage(c) + var querys struct { + NeType string `form:"neType" binding:"required"` + NeId string `form:"neId" binding:"required"` + } + if err := c.ShouldBindQuery(&querys); err != nil { + c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) + return + } + + // 检查是否存在授权记录 + neLicense := s.neLicenseService.SelectByNeTypeAndNeID(querys.NeType, querys.NeId) + if neLicense.NeId != querys.NeId { + // 没有可访问网元授权激活数据! + c.JSON(200, result.ErrMsg(i18n.TKey(language, "neLicense.noData"))) + return + } + + // 查询网元获取IP获取网元状态 + neInfo := s.neInfoService.SelectNeInfoByNeTypeAndNeID(neLicense.NeType, neLicense.NeId) + if neInfo.NeId != neLicense.NeId || neInfo.IP == "" { + c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.noNEInfo"))) + return + } + if neState, err := neFetchlink.NeState(neInfo); err == nil && neState["sn"] != nil { + neLicense.Status = "1" + neLicense.SerialNum = fmt.Sprint(neState["sn"]) + neLicense.ExpiryDate = fmt.Sprint(neState["expire"]) + code, licensePath := s.neLicenseService.ReadLicenseInfo(neLicense) + neLicense.ActivationRequestCode = code + neLicense.LicensePath = licensePath + } else { + neLicense.Status = "0" + } + + // 更新授权信息 + neLicense.UpdateBy = ctx.LoginUserToUserName(c) + s.neLicenseService.Update(neLicense) + + if neLicense.Status == "1" { + c.JSON(200, result.OkData(map[string]string{ + "sn": neLicense.SerialNum, + "expire": neLicense.ExpiryDate, + })) + return + } + c.JSON(200, result.ErrMsg(fmt.Sprintf("%s service status exception", neLicense.NeType))) +} diff --git a/src/modules/network_element/controller/ne_software.go b/src/modules/network_element/controller/ne_software.go index 934af8d..9d73cce 100644 --- a/src/modules/network_element/controller/ne_software.go +++ b/src/modules/network_element/controller/ne_software.go @@ -19,15 +19,15 @@ var NewNeSoftware = &NeSoftwareController{ neSoftwareService: neService.NewNeSoftwareImpl, } -// 网元软件包信息请求 +// 网元软件包请求 // // PATH /software type NeSoftwareController struct { - // 网元软件包信息服务 + // 网元软件包服务 neSoftwareService neService.INeSoftware } -// 网元软件包信息列表 +// 网元软件包列表 // // GET /list func (s *NeSoftwareController) List(c *gin.Context) { @@ -37,7 +37,7 @@ func (s *NeSoftwareController) List(c *gin.Context) { c.JSON(200, result.Ok(data)) } -// 网元软件包信息信息 +// 网元软件包信息 // // GET /:softwareId func (s *NeSoftwareController) Info(c *gin.Context) { @@ -50,7 +50,7 @@ func (s *NeSoftwareController) Info(c *gin.Context) { neSoftware := s.neSoftwareService.SelectById(softwareId) if neSoftware.ID != softwareId { - // 没有可访问网元版本数据! + // 没有可访问网元包信息数据! c.JSON(200, result.ErrMsg(i18n.TKey(language, "neSoftware.noData"))) return } @@ -58,27 +58,39 @@ func (s *NeSoftwareController) Info(c *gin.Context) { c.JSON(200, result.OkData(neSoftware)) } -// 网元软件包信息新增 +// 网元软件包新增 // // POST / func (s *NeSoftwareController) Add(c *gin.Context) { language := ctx.AcceptLanguage(c) var body model.NeSoftware err := c.ShouldBindBodyWith(&body, binding.JSON) - if err != nil || body.ID != "" { + if err != nil || body.Path == "" || body.ID != "" { c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) return } - // 检查属性值唯一 - uniqueSoftware := s.neSoftwareService.CheckUniqueTypeAndFileNameAndVersion(body.NeType, body.FileName, body.Version, "") - if !uniqueSoftware { - // 网元软件包操作【%s】失败,网元类型与文件名版本已存在 - msg := i18n.TTemplate(language, "neSoftware.errKeyExists", map[string]any{"name": body.FileName}) - c.JSON(200, result.ErrMsg(msg)) - return + // 找到已存在的删除后重新添加 + neSoftwares := s.neSoftwareService.SelectList(model.NeSoftware{ + NeType: body.NeType, + Name: body.Name, + Version: body.Version, + }) + if len(neSoftwares) > 0 { + neSoftware := neSoftwares[0] + s.neSoftwareService.DeleteByIds([]string{neSoftware.ID}) } + // 检查属性值唯一 + // uniqueSoftware := s.neSoftwareService.CheckUniqueTypeAndNameAndVersion(body.NeType, body.Name, body.Version, "") + // if !uniqueSoftware { + // // 网元软件包操作【%s】失败,网元类型与文件名版本已存在 + // msg := i18n.TTemplate(language, "neSoftware.errKeyExists", map[string]any{"name": body.Name}) + // c.JSON(200, result.ErrMsg(msg)) + // return + // } + + body.CreateBy = ctx.LoginUserToUserName(c) insertId := s.neSoftwareService.Insert(body) if insertId != "" { c.JSON(200, result.Ok(nil)) @@ -87,23 +99,23 @@ func (s *NeSoftwareController) Add(c *gin.Context) { c.JSON(200, result.Err(nil)) } -// 网元软件包信息修改 +// 网元软件包修改 // // PUT / func (s *NeSoftwareController) Edit(c *gin.Context) { language := ctx.AcceptLanguage(c) var body model.NeSoftware err := c.ShouldBindBodyWith(&body, binding.JSON) - if err != nil || body.ID == "" { + if err != nil || body.Path == "" || body.ID == "" { c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) return } // 检查属性值唯一 - uniqueSoftware := s.neSoftwareService.CheckUniqueTypeAndFileNameAndVersion(body.NeType, body.FileName, body.Version, body.ID) + uniqueSoftware := s.neSoftwareService.CheckUniqueTypeAndNameAndVersion(body.NeType, body.Name, body.Version, body.ID) if !uniqueSoftware { // 网元软件包操作【%s】失败,网元类型与文件名版本已存在 - msg := i18n.TTemplate(language, "neSoftware.errKeyExists", map[string]any{"name": body.FileName}) + msg := i18n.TTemplate(language, "neSoftware.errKeyExists", map[string]any{"name": body.Name}) c.JSON(200, result.ErrMsg(msg)) return } @@ -111,11 +123,12 @@ func (s *NeSoftwareController) Edit(c *gin.Context) { // 检查是否存在 neSoftware := s.neSoftwareService.SelectById(body.ID) if neSoftware.ID != body.ID { - // 没有可访问网元版本数据! + // 没有可访问网元包信息数据! c.JSON(200, result.ErrMsg(i18n.TKey(language, "neSoftware.noData"))) return } + body.UpdateBy = ctx.LoginUserToUserName(c) rows := s.neSoftwareService.Update(body) if rows > 0 { c.JSON(200, result.Ok(nil)) @@ -124,7 +137,7 @@ func (s *NeSoftwareController) Edit(c *gin.Context) { c.JSON(200, result.Err(nil)) } -// 网元软件包信息删除 +// 网元软件包删除 // // DELETE /:softwareIds func (s *NeSoftwareController) Remove(c *gin.Context) { @@ -150,10 +163,10 @@ func (s *NeSoftwareController) Remove(c *gin.Context) { c.JSON(200, result.OkMsg(msg)) } -// 网元软件包安装 +// 网元软件包设为网元新版本 // -// POST /install -func (s *NeSoftwareController) Install(c *gin.Context) { +// POST /newNeVersion +func (s *NeSoftwareController) NewNeVersion(c *gin.Context) { language := ctx.AcceptLanguage(c) var body model.NeSoftware err := c.ShouldBindBodyWith(&body, binding.JSON) @@ -162,19 +175,19 @@ func (s *NeSoftwareController) Install(c *gin.Context) { return } - // 检查是否存在 - neSoftwares := s.neSoftwareService.SelectList(body) - if len(neSoftwares) == 0 { - // 没有可访问网元版本数据! - c.JSON(200, result.ErrMsg(i18n.TKey(language, "neSoftware.noData"))) - return - } - neSoftware := neSoftwares[0] - - // 进行安装 - output, err := s.neSoftwareService.Install(neSoftware) - if err != nil { - c.JSON(200, result.OkData(output)) + // 找到已存在的软件包信息 + neSoftwares := s.neSoftwareService.SelectList(model.NeSoftware{ + NeType: body.NeType, + Name: body.Name, + Version: body.Version, + }) + if len(neSoftwares) > 0 { + neSoftware := neSoftwares[0] + s.neSoftwareService.UpdateVersions(neSoftware, model.NeVersion{ + NeType: neSoftware.NeType, + UpdateBy: ctx.LoginUserToUserName(c), + }) + c.JSON(200, result.Ok(nil)) return } c.JSON(200, result.Err(nil)) diff --git a/src/modules/network_element/controller/ne_version.go b/src/modules/network_element/controller/ne_version.go index cb32f47..2d6064c 100644 --- a/src/modules/network_element/controller/ne_version.go +++ b/src/modules/network_element/controller/ne_version.go @@ -1,13 +1,9 @@ package controller import ( - "strings" - "nms_cxy/src/framework/i18n" "nms_cxy/src/framework/utils/ctx" - "nms_cxy/src/framework/utils/parse" "nms_cxy/src/framework/vo/result" - "nms_cxy/src/modules/network_element/model" neService "nms_cxy/src/modules/network_element/service" "github.com/gin-gonic/gin" @@ -19,15 +15,15 @@ var NewNeVersion = &NeVersionController{ neVersionService: neService.NewNeVersionImpl, } -// 网元版本信息请求 +// 网元版本请求 // // PATH /version type NeVersionController struct { - // 网元版本信息服务 + // 网元版本服务 neVersionService neService.INeVersion } -// 网元版本信息列表 +// 网元版本列表 // // GET /list func (s *NeVersionController) List(c *gin.Context) { @@ -37,7 +33,7 @@ func (s *NeVersionController) List(c *gin.Context) { c.JSON(200, result.Ok(data)) } -// 网元版本信息信息 +// 网元版本信息 // // GET /:versionId func (s *NeVersionController) Info(c *gin.Context) { @@ -58,94 +54,34 @@ func (s *NeVersionController) Info(c *gin.Context) { c.JSON(200, result.OkData(neVersion)) } -// 网元版本信息新增 +// 网元版本操作 // -// POST / -func (s *NeVersionController) Add(c *gin.Context) { +// POST /operate +func (s *NeVersionController) Operate(c *gin.Context) { language := ctx.AcceptLanguage(c) - var body model.NeVersion - err := c.ShouldBindBodyWith(&body, binding.JSON) - if err != nil || body.ID != "" { + var body struct { + Action string `json:"action" binding:"required,oneof=install upgrade rollback"` // 操作行为 + NeType string `json:"neType" gorm:"ne_type" binding:"required"` // 网元类型 + NeId string `json:"neId" gorm:"ne_id" binding:"required"` // 网元ID + Preinput map[string]string `json:"preinput" ` // 预先输入参数 + } + if err := c.ShouldBindBodyWith(&body, binding.JSON); err != nil { c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) return } - // 检查属性值唯一 - uniqueInfo := s.neVersionService.CheckUniqueTypeAndID(body.NeType, body.NeId, "") - if !uniqueInfo { - // 网元版本操作【%s】失败,网元类型信息已存在 - msg := i18n.TTemplate(language, "neVersion.errKeyExists", map[string]any{"name": body.NeType}) - c.JSON(200, result.ErrMsg(msg)) - return - } - - insertId := s.neVersionService.Insert(body) - if insertId != "" { - c.JSON(200, result.Ok(nil)) - return - } - c.JSON(200, result.Err(nil)) -} - -// 网元版本信息修改 -// -// PUT / -func (s *NeVersionController) Edit(c *gin.Context) { - language := ctx.AcceptLanguage(c) - var body model.NeVersion - err := c.ShouldBindBodyWith(&body, binding.JSON) - if err != nil || body.ID == "" { - c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) - return - } - - // 检查属性值唯一 - uniqueInfo := s.neVersionService.CheckUniqueTypeAndID(body.NeType, body.NeId, body.ID) - if !uniqueInfo { - // 网元版本操作【%s】失败,网元类型信息已存在 - msg := i18n.TTemplate(language, "neVersion.errKeyExists", map[string]any{"name": body.NeType}) - c.JSON(200, result.ErrMsg(msg)) - return - } - - // 检查是否存在 - neVersion := s.neVersionService.SelectById(body.ID) - if neVersion.ID != body.ID { + neVersion := s.neVersionService.SelectByNeTypeAndNeID(body.NeType, body.NeId) + if neVersion.NeId != body.NeId { // 没有可访问网元版本数据! c.JSON(200, result.ErrMsg(i18n.TKey(language, "neVersion.noData"))) return } - rows := s.neVersionService.Update(body) - if rows > 0 { - c.JSON(200, result.Ok(nil)) - return - } - c.JSON(200, result.Err(nil)) -} - -// 网元版本信息删除 -// -// DELETE /:versionIds -func (s *NeVersionController) Remove(c *gin.Context) { - language := ctx.AcceptLanguage(c) - versionIds := c.Param("versionIds") - if versionIds == "" { - c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) - return - } - // 处理字符转id数组后去重 - ids := strings.Split(versionIds, ",") - uniqueIDs := parse.RemoveDuplicates(ids) - if len(uniqueIDs) <= 0 { - c.JSON(200, result.Err(nil)) - return - } - rows, err := s.neVersionService.DeleteByIds(uniqueIDs) + // 进行相关命令操作 + output, err := s.neVersionService.Operate(body.Action, neVersion, body.Preinput) if err != nil { c.JSON(200, result.ErrMsg(i18n.TKey(language, err.Error()))) return } - msg := i18n.TTemplate(language, "app.common.deleteSuccess", map[string]any{"num": rows}) - c.JSON(200, result.OkMsg(msg)) + c.JSON(200, result.OkData(output)) } diff --git a/src/modules/network_element/service/ne_direct_link.go b/src/modules/network_element/fetch_link/ne_config.go similarity index 59% rename from src/modules/network_element/service/ne_direct_link.go rename to src/modules/network_element/fetch_link/ne_config.go index 15d1138..0457c56 100644 --- a/src/modules/network_element/service/ne_direct_link.go +++ b/src/modules/network_element/fetch_link/ne_config.go @@ -1,50 +1,15 @@ -package service +package fetchlink import ( "encoding/json" "fmt" "strings" - "time" "nms_cxy/src/framework/logger" "nms_cxy/src/framework/utils/fetch" "nms_cxy/src/modules/network_element/model" ) -// NeState 获取网元端服务状态 -func NeState(neInfo model.NeInfo) (map[string]any, error) { - // 网元状态 - neUrl := fmt.Sprintf("http://%s:%d/api/rest/systemManagement/v1/elementType/%s/objectType/systemState", neInfo.IP, neInfo.Port, strings.ToLower(neInfo.NeType)) - resBytes, err := fetch.Get(neUrl, nil, 250) - if err != nil { - logger.Warnf("NeState %s", err.Error()) - return nil, err - } - - // 序列化结果 - var resData map[string]any - err = json.Unmarshal(resBytes, &resData) - if err != nil { - logger.Warnf("NeState Unmarshal %s", err.Error()) - return nil, err - } - - return map[string]any{ - "neType": neInfo.NeType, - "neId": neInfo.NeId, - "neName": neInfo.NeName, - "neIP": neInfo.IP, - "refreshTime": time.Now().UnixMilli(), // 获取时间 - "version": resData["version"], - "capability": resData["capability"], - "sn": resData["serialNum"], - "expire": resData["expiryDate"], - "cpu": resData["cpuUsage"], - "mem": resData["memUsage"], - "disk": resData["diskSpace"], - }, nil -} - // NeConfigOMC 网元配置对端网管信息 func NeConfigOMC(neInfo model.NeInfo) (map[string]any, error) { // 网元配置对端网管信息 @@ -62,8 +27,8 @@ func NeConfigOMC(neInfo model.NeInfo) (map[string]any, error) { var resData map[string]any if err != nil { status := err.Error() - logger.Warnf("NeConfigOMC %s", status) - if strings.HasPrefix(status, "204") { + logger.Warnf("NeConfigOMC %s Put \"%s\"", status, neUrl) + if strings.HasPrefix(status, "201") || strings.HasPrefix(status, "204") { return resData, nil } return nil, err @@ -83,3 +48,23 @@ func NeConfigOMC(neInfo model.NeInfo) (map[string]any, error) { return resData, nil } + +// NeConfigInfo 网元配置信息 +func NeConfigInfo(neInfo model.NeInfo, name string) (map[string]any, error) { + // 网元配置对端网管信息 + neUrl := fmt.Sprintf("http://%s:%d/api/rest/systemManagement/v1/elementType/%s/objectType/config/%s", neInfo.IP, neInfo.Port, strings.ToLower(neInfo.NeType), name) + resBytes, err := fetch.Get(neUrl, nil, 1000) + if err != nil { + logger.Warnf("NeConfigInfo %s Get \"%s\"", err.Error(), neUrl) + return nil, err + } + + // 序列化结果 + var resData map[string]any + err = json.Unmarshal(resBytes, &resData) + if err != nil { + logger.Warnf("NeConfigInfo Unmarshal %s", err.Error()) + return nil, err + } + return resData, nil +} diff --git a/src/modules/network_element/fetch_link/ne_state.go b/src/modules/network_element/fetch_link/ne_state.go new file mode 100644 index 0000000..5915b96 --- /dev/null +++ b/src/modules/network_element/fetch_link/ne_state.go @@ -0,0 +1,56 @@ +package fetchlink + +import ( + "encoding/json" + "fmt" + "strings" + "time" + + "nms_cxy/src/framework/logger" + "nms_cxy/src/framework/utils/fetch" + "nms_cxy/src/modules/network_element/model" +) + +// NeState 获取网元端服务状态 +func NeState(neInfo model.NeInfo) (map[string]any, error) { + // 网元状态 + neUrl := fmt.Sprintf("http://%s:%d/api/rest/systemManagement/v1/elementType/%s/objectType/systemState", neInfo.IP, neInfo.Port, strings.ToLower(neInfo.NeType)) + resBytes, err := fetch.Get(neUrl, nil, 1000) + if err != nil { + logger.Warnf("NeState %s", err.Error()) + return nil, err + } + + // 序列化结果 + var resData map[string]any + err = json.Unmarshal(resBytes, &resData) + if err != nil { + logger.Warnf("NeState Unmarshal %s", err.Error()) + return nil, err + } + + // 检查是否有许可时间 + if v, ok := resData["expiryDate"]; ok && v != nil { + expiryDate := v.(string) + // UPF存在2000的许可时间,MME会有空字符 + if strings.HasPrefix(expiryDate, "2000") || expiryDate == "" { + logger.Warnf("NeState %s License Expiration Aanomaly. Get \"%s\"", neInfo.NeType, neUrl) + return nil, fmt.Errorf("%s License Expiration Aanomaly", neInfo.NeType) + } + } + + return map[string]any{ + "neType": neInfo.NeType, + "neId": neInfo.NeId, + "neName": neInfo.NeName, + "neIP": neInfo.IP, + "refreshTime": time.Now().UnixMilli(), // 获取时间 + "version": resData["version"], + "capability": resData["capability"], + "sn": resData["serialNum"], + "expire": resData["expiryDate"], + "cpu": resData["cpuUsage"], + "mem": resData["memUsage"], + "disk": resData["diskSpace"], + }, nil +} diff --git a/src/modules/network_element/model/ne_config.go b/src/modules/network_element/model/ne_config.go new file mode 100644 index 0000000..dcc7e05 --- /dev/null +++ b/src/modules/network_element/model/ne_config.go @@ -0,0 +1,21 @@ +package model + +// NeConfig 网元参数配置可用属性值 +type NeConfig struct { + ID string `json:"id" gorm:"id"` + NeType string `json:"neType" binding:"required" gorm:"ne_type"` // 网元类型 + NeId string `json:"-" gorm:"ne_id"` + TopTag string `json:"topTag" binding:"required" gorm:"top_tag"` + TopDisplay string `json:"topDisplay" binding:"required" gorm:"top_display"` + Method string `json:"method" gorm:"method"` // 操作属性 get只读强制不可编辑删除 put可编辑 delete可删除 post可新增 + ParamJSONStr string `json:"-" gorm:"param_json"` // accesss属性控制:只读read-only/read/ro 读写read-write + + // ====== 非数据库字段属性 ====== + + ParamData map[string]any `json:"paramData,omitempty" binding:"required" gorm:"-"` // 与ParamJSONStr配合转换 +} + +// TableName 表名称 +func (*NeConfig) TableName() string { + return "param_config" +} diff --git a/src/modules/network_element/model/ne_host.go b/src/modules/network_element/model/ne_host.go index a479635..ba7362b 100644 --- a/src/modules/network_element/model/ne_host.go +++ b/src/modules/network_element/model/ne_host.go @@ -11,7 +11,7 @@ type NeHost struct { Addr string `json:"addr" gorm:"column:addr" binding:"required"` // 主机地址 Port int64 `json:"port" gorm:"column:port" binding:"required,number,max=65535,min=1"` // SSH端口 User string `json:"user" gorm:"column:user" binding:"required"` // 主机用户名 - AuthMode string `json:"authMode" gorm:"column:auth_mode" binding:"oneof=0 1"` // 认证模式(0密码 1主机私钥) + AuthMode string `json:"authMode" gorm:"column:auth_mode" binding:"oneof=0 1 2"` // 认证模式(0密码 1主机私钥 2已免密) Password string `json:"password" gorm:"column:password"` // 认证密码 PrivateKey string `json:"privateKey" gorm:"column:private_key"` // 认证私钥 PassPhrase string `json:"passPhrase" gorm:"column:pass_phrase"` // 认证私钥密码 diff --git a/src/modules/network_element/model/ne_info.go b/src/modules/network_element/model/ne_info.go index c08e71a..373df59 100644 --- a/src/modules/network_element/model/ne_info.go +++ b/src/modules/network_element/model/ne_info.go @@ -2,21 +2,25 @@ package model // NeInfo 网元信息对象 ne_info type NeInfo struct { - ID string `json:"id"` - NeType string `json:"neType" binding:"required"` - NeId string `json:"neId" binding:"required"` - RmUID string `json:"rmUid"` - NeName string `json:"neName"` - IP string `json:"ip" binding:"required"` - Port int64 `json:"port" binding:"required,number,max=65535,min=1"` - PvFlag string `json:"pvFlag" binding:"oneof=PNF VNF"` // enum('PNF','VNF') - Province string `json:"province"` - VendorName string `json:"vendorName"` - Dn string `json:"dn"` - NeAddress string `json:"neAddress"` - Status string `json:"status"` // 0: 在线 1: 下线 2: 备用 3: 待下发配置 - UpdateTime string `json:"updateTime"` - HostIDs string `json:"hostIds"` // 网元主机ID组 数据格式(ssh,telnet,telnet) + ID string `json:"id" gorm:"id"` + NeType string `json:"neType" gorm:"ne_type" binding:"required"` + NeId string `json:"neId" gorm:"ne_id" binding:"required"` + RmUID string `json:"rmUid" gorm:"rm_uid"` + NeName string `json:"neName" gorm:"ne_name"` + IP string `json:"ip" gorm:"ip" binding:"required"` + Port int64 `json:"port" gorm:"port" binding:"required,number,max=65535,min=1"` + PvFlag string `json:"pvFlag" gorm:"pv_flag" binding:"oneof=PNF VNF"` // ''PNF'',''VNF'' + Province string `json:"province" gorm:"province"` // 省份地域 + VendorName string `json:"vendorName" gorm:"vendor_name"` + Dn string `json:"dn" gorm:"dn"` + NeAddress string `json:"neAddress" gorm:"ne_address"` // MAC地址 + HostIDs string `json:"hostIds" gorm:"host_ids"` // 网元主机ID组 数据格式(ssh,telnet,telnet) + Status string `json:"status" gorm:"status"` // 0离线 1在线 2配置待下发 + Remark string `json:"remark" gorm:"remark"` // 备注 + CreateBy string `json:"createBy" gorm:"create_by"` // 创建者 + CreateTime int64 `json:"createTime" gorm:"create_time"` // 创建时间 + UpdateBy string `json:"updateBy" gorm:"update_by"` // 更新者 + UpdateTime int64 `json:"updateTime" gorm:"update_time"` // 更新时间 // ====== 非数据库字段属性 ====== diff --git a/src/modules/network_element/model/ne_license.go b/src/modules/network_element/model/ne_license.go new file mode 100644 index 0000000..0a08802 --- /dev/null +++ b/src/modules/network_element/model/ne_license.go @@ -0,0 +1,27 @@ +package model + +// NeLicense 网元授权激活信息 ne_license +type NeLicense struct { + ID string `json:"id" gorm:"id"` + NeType string `json:"neType" gorm:"ne_type" binding:"required"` // 网元类型 + NeId string `json:"neId" gorm:"ne_id" binding:"required"` // 网元ID + ActivationRequestCode string `json:"activationRequestCode" gorm:"activation_request_code"` // 激活申请代码 + LicensePath string `json:"licensePath" gorm:"license_path"` // 激活授权文件 + SerialNum string `json:"serialNum" gorm:"serial_num"` // 序列号 + ExpiryDate string `json:"expiryDate" gorm:"expiry_date"` // 许可证到期日期 + Status string `json:"status" gorm:"status"` // 状态 0无效 1有效 + Remark string `json:"remark" gorm:"remark"` // 备注 + CreateBy string `json:"createBy" gorm:"create_by"` // 创建者 + CreateTime int64 `json:"createTime" gorm:"create_time"` // 创建时间 + UpdateBy string `json:"updateBy" gorm:"update_by"` // 更新者 + UpdateTime int64 `json:"updateTime" gorm:"update_time"` // 更新时间 + + // ====== 非数据库字段属性 ====== + + Reload bool `json:"reload,omitempty" gorm:"-"` // 刷新重启网元 +} + +// TableName 表名称 +func (*NeLicense) TableName() string { + return "ne_license" +} diff --git a/src/modules/network_element/model/ne_software.go b/src/modules/network_element/model/ne_software.go index afb6dff..53a5321 100644 --- a/src/modules/network_element/model/ne_software.go +++ b/src/modules/network_element/model/ne_software.go @@ -1,18 +1,20 @@ package model -import "time" - // NeSoftware 网元软件包 ne_software type NeSoftware struct { - ID string `json:"id" gorm:"id"` - NeType string `json:"neType" gorm:"ne_type" binding:"required"` // 网元类型 - FileName string `json:"fileName" gorm:"file_name" binding:"required"` // 包名称 - Path string `json:"path" gorm:"path"` // 包路径 - Version string `json:"version" gorm:"version" binding:"required"` // 包版本 - Md5Sum string `json:"md5Sum" gorm:"md5_sum"` // --无使用 md5签名 - Status string `json:"status" gorm:"status"` // --无使用 - Comment string `json:"comment" gorm:"comment"` // 包说明 - UpdateTime time.Time `json:"updateTime" gorm:"update_time"` // 上传时间 + ID string `json:"id" gorm:"id"` + NeType string `json:"neType" gorm:"ne_type" binding:"required"` // 网元类型 + Name string `json:"name" gorm:"name" binding:"required"` // 包名称 + Path string `json:"path" gorm:"path"` // 包路径 + Version string `json:"version" gorm:"version" binding:"required"` // 包版本 + Description string `json:"description" gorm:"description"` // 包说明 + CreateBy string `json:"createBy" gorm:"column:create_by"` // 创建者 + CreateTime int64 `json:"createTime" gorm:"column:create_time"` // 创建时间 + UpdateBy string `json:"updateBy" gorm:"column:update_by"` // 更新者 + UpdateTime int64 `json:"updateTime" gorm:"column:update_time"` // 更新时间 + + // ====== 非数据库字段属性 ====== + } // TableName 表名称 diff --git a/src/modules/network_element/model/ne_version.go b/src/modules/network_element/model/ne_version.go index 11a00e6..ddde0af 100644 --- a/src/modules/network_element/model/ne_version.go +++ b/src/modules/network_element/model/ne_version.go @@ -1,20 +1,24 @@ package model -import "time" - // NeVersion 网元版本信息 ne_version type NeVersion struct { - ID string `json:"id" gorm:"id"` - NeType string `json:"neType" gorm:"ne_type" binding:"required"` // 网元类型 - NeId string `json:"neId" gorm:"ne_id" binding:"required"` // 网元ID - Version string `json:"version" gorm:"version"` // 当前版本 - FilePath string `json:"filePath" gorm:"file_path"` // 当前软件包 - PreVersion string `json:"preVersion" gorm:"pre_version"` // 上一版本 - PreFile string `json:"preFile" gorm:"pre_file"` // 上一版本软件包 - NewVersion string `json:"newVersion" gorm:"new_version"` // 下一版本 - NewFile string `json:"newFile" gorm:"new_file"` // 下一版本软件包 - Status string `json:"status" gorm:"status" binding:"oneof=Uploaded Inactive Active"` // 当前状态 (Uploaded下一版本上传 Inactive下一版本待激活 Active当前已激活) - UpdateTime time.Time `json:"updateTime" gorm:"update_time"` // 更新时间 + ID string `json:"id" gorm:"id"` + NeType string `json:"neType" gorm:"ne_type" binding:"required"` // 网元类型 + NeId string `json:"neId" gorm:"ne_id" binding:"required"` // 网元ID + Name string `json:"name" gorm:"name"` // 当前包名 + Version string `json:"version" gorm:"version" binding:"required"` // 当前版本 + Path string `json:"path" gorm:"path" binding:"required"` // 当前软件包 + PreName string `json:"preName" gorm:"pre_name"` // 上一版本包名 + PreVersion string `json:"preVersion" gorm:"pre_version"` // 上一版本 + PrePath string `json:"prePath" gorm:"pre_path"` // 上一版本软件包 + NewName string `json:"newName" gorm:"new_name"` // 新版本包名 + NewVersion string `json:"newVersion" gorm:"new_version"` // 新版本 + NewPath string `json:"newPath" gorm:"new_path"` // 新版本软件包 + Status string `json:"status" gorm:"status"` // 当前状态 1当前版本 2上一版本 3有新版本 + CreateBy string `json:"createBy" gorm:"column:create_by"` // 创建者 + CreateTime int64 `json:"createTime" gorm:"column:create_time"` // 创建时间 + UpdateBy string `json:"updateBy" gorm:"column:update_by"` // 更新者 + UpdateTime int64 `json:"updateTime" gorm:"column:update_time"` // 更新时间 } // TableName 表名称 diff --git a/src/modules/network_element/model/udm_auth.go b/src/modules/network_element/model/udm_auth.go deleted file mode 100644 index 2fe70e2..0000000 --- a/src/modules/network_element/model/udm_auth.go +++ /dev/null @@ -1,17 +0,0 @@ -package model - -// UDMAuth UDM鉴权用户对象 u_auth_user -type UDMAuth struct { - ID string `json:"id" gorm:"column:id;primaryKey;autoIncrement"` - Imsi string `json:"imsi" gorm:"column:imsi"` // SIM卡号 - Amf string `json:"amf" gorm:"column:amf"` // ANF - Status string `json:"status" gorm:"column:status"` // 状态 - Ki string `json:"ki" gorm:"column:ki"` // ki - AlgoIndex string `json:"algoIndex" gorm:"column:algo_index"` // AlgoIndex - Opc string `json:"opc" gorm:"column:opc"` - NeID string `json:"neId" gorm:"column:ne_id"` // UDM网元标识-子系统 -} - -func (UDMAuth) TableName() string { - return "u_auth_user" -} diff --git a/src/modules/network_element/network_element.go b/src/modules/network_element/network_element.go index 2c53d53..68508bc 100644 --- a/src/modules/network_element/network_element.go +++ b/src/modules/network_element/network_element.go @@ -4,7 +4,6 @@ import ( "nms_cxy/src/framework/logger" "nms_cxy/src/framework/middleware" "nms_cxy/src/framework/middleware/collectlogs" - "nms_cxy/src/framework/middleware/repeat" "nms_cxy/src/modules/network_element/controller" "nms_cxy/src/modules/network_element/service" @@ -36,15 +35,46 @@ func Setup(router *gin.Engine) { collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.neAction", collectlogs.BUSINESS_TYPE_IMPORT)), controller.NewNeAction.PushFile, ) + neActionGroup.PUT("/service", + middleware.PreAuthorize(nil), + collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.neAction", collectlogs.BUSINESS_TYPE_OTHER)), + controller.NewNeAction.Service, + ) } // 网元信息 neInfoGroup := neGroup.Group("/info") { + neInfoGroup.GET("/state", + middleware.PreAuthorize(nil), + controller.NewNeInfo.State, + ) + neInfoGroup.GET("/byTypeAndID", + middleware.PreAuthorize(nil), + controller.NewNeInfo.NeTypeAndID, + ) neInfoGroup.GET("/listAll", middleware.PreAuthorize(nil), controller.NewNeInfo.ListAll, ) + neInfoGroup.GET("/para5GFile", + middleware.PreAuthorize(nil), + controller.NewNeInfo.Para5GFileRead, + ) + neInfoGroup.PUT("/para5GFile", + middleware.PreAuthorize(nil), + collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.neInfo", collectlogs.BUSINESS_TYPE_OTHER)), + controller.NewNeInfo.Para5GFileWrite, + ) + neInfoGroup.GET("/oamFile", + middleware.PreAuthorize(nil), + controller.NewNeInfo.OAMFileRead, + ) + neInfoGroup.PUT("/oamFile", + middleware.PreAuthorize(nil), + collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.neInfo", collectlogs.BUSINESS_TYPE_OTHER)), + controller.NewNeInfo.OAMFileWrite, + ) neInfoGroup.GET("/list", middleware.PreAuthorize(nil), controller.NewNeInfo.List, @@ -68,14 +98,6 @@ func Setup(router *gin.Engine) { collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.neInfo", collectlogs.BUSINESS_TYPE_DELETE)), controller.NewNeInfo.Remove, ) - neInfoGroup.GET("/state", - middleware.PreAuthorize(nil), - controller.NewNeInfo.State, - ) - neInfoGroup.GET("/byTypeAndID", - middleware.PreAuthorize(nil), - controller.NewNeInfo.NeTypeAndID, - ) } // 网元主机 @@ -119,6 +141,11 @@ func Setup(router *gin.Engine) { collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.neHost", collectlogs.BUSINESS_TYPE_OTHER)), controller.NewNeHost.CheckBySSH, ) + neHostGroup.POST("/authorizedBySSH", + middleware.PreAuthorize(nil), + collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.neHost", collectlogs.BUSINESS_TYPE_OTHER)), + controller.NewNeHost.AuthorizedBySSH, + ) } // 网元主机命令 @@ -160,20 +187,10 @@ func Setup(router *gin.Engine) { middleware.PreAuthorize(nil), controller.NewNeVersion.Info, ) - neVersionGroup.POST("", + neVersionGroup.POST("/operate", middleware.PreAuthorize(nil), - collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.neVersion", collectlogs.BUSINESS_TYPE_INSERT)), - controller.NewNeVersion.Add, - ) - neVersionGroup.PUT("", - middleware.PreAuthorize(nil), - collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.neVersion", collectlogs.BUSINESS_TYPE_UPDATE)), - controller.NewNeVersion.Edit, - ) - neVersionGroup.DELETE("/:versionIds", - middleware.PreAuthorize(nil), - collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.neVersion", collectlogs.BUSINESS_TYPE_DELETE)), - controller.NewNeVersion.Remove, + collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.neVersion", collectlogs.BUSINESS_TYPE_OTHER)), + controller.NewNeVersion.Operate, ) } @@ -203,118 +220,76 @@ func Setup(router *gin.Engine) { collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.neSoftware", collectlogs.BUSINESS_TYPE_DELETE)), controller.NewNeSoftware.Remove, ) - neSoftwareGroup.POST("/install", + neSoftwareGroup.POST("/newNeVersion", middleware.PreAuthorize(nil), - collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.neSoftware", collectlogs.BUSINESS_TYPE_DELETE)), - controller.NewNeSoftware.Install, + collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.neSoftware", collectlogs.BUSINESS_TYPE_OTHER)), + controller.NewNeSoftware.NewNeVersion, ) } - // UDM鉴权用户信息 - udmAuthGroup := neGroup.Group("/udm/auth") + // 网元授权激活信息 + neLicenseGroup := neGroup.Group("/license") { - udmAuthGroup.PUT("/resetData/:neId", - repeat.RepeatSubmit(5), + neLicenseGroup.GET("/list", middleware.PreAuthorize(nil), - collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmAuth", collectlogs.BUSINESS_TYPE_CLEAN)), - controller.NewUDMAuth.ResetData, + controller.NewNeLicense.List, ) - udmAuthGroup.GET("/list", + neLicenseGroup.GET("/:licenseId", middleware.PreAuthorize(nil), - controller.NewUDMAuth.List, + controller.NewNeLicense.Info, ) - udmAuthGroup.GET("/:neId/:imsi", + neLicenseGroup.GET("/byTypeAndID", middleware.PreAuthorize(nil), - controller.NewUDMAuth.Info, + controller.NewNeLicense.NeTypeAndID, ) - udmAuthGroup.POST("/:neId", + neLicenseGroup.GET("/code", middleware.PreAuthorize(nil), - collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmAuth", collectlogs.BUSINESS_TYPE_INSERT)), - controller.NewUDMAuth.Add, + controller.NewNeLicense.Code, ) - udmAuthGroup.POST("/:neId/:num", + neLicenseGroup.POST("/change", middleware.PreAuthorize(nil), - collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmAuth", collectlogs.BUSINESS_TYPE_INSERT)), - controller.NewUDMAuth.Adds, + collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.neLicense", collectlogs.BUSINESS_TYPE_OTHER)), + controller.NewNeLicense.Change, ) - udmAuthGroup.PUT("/:neId", + neLicenseGroup.GET("/state", middleware.PreAuthorize(nil), - collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmAuth", collectlogs.BUSINESS_TYPE_UPDATE)), - controller.NewUDMAuth.Edit, - ) - udmAuthGroup.DELETE("/:neId/:imsi", - middleware.PreAuthorize(nil), - collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmAuth", collectlogs.BUSINESS_TYPE_DELETE)), - controller.NewUDMAuth.Remove, - ) - udmAuthGroup.DELETE("/:neId/:imsi/:num", - middleware.PreAuthorize(nil), - collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmAuth", collectlogs.BUSINESS_TYPE_DELETE)), - controller.NewUDMAuth.Removes, - ) - udmAuthGroup.POST("/export", - middleware.PreAuthorize(nil), - collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmAuth", collectlogs.BUSINESS_TYPE_EXPORT)), - controller.NewUDMAuth.Export, - ) - udmAuthGroup.POST("/import", - middleware.PreAuthorize(nil), - collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmAuth", collectlogs.BUSINESS_TYPE_IMPORT)), - controller.NewUDMAuth.Import, + controller.NewNeLicense.State, ) } - // UDM签约用户信息 - udmSubGroup := neGroup.Group("/udm/sub") + // 网元参数配置 + neConfigGroup := neGroup.Group("/config") { - udmSubGroup.PUT("/resetData/:neId", - repeat.RepeatSubmit(5), + neConfigGroup.GET("/list", middleware.PreAuthorize(nil), - collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmSub", collectlogs.BUSINESS_TYPE_CLEAN)), - controller.NewUDMSub.ResetData, + controller.NewNeConfig.List, ) - udmSubGroup.GET("/list", + neConfigGroup.GET("/info/:id", middleware.PreAuthorize(nil), - controller.NewUDMSub.List, + controller.NewNeConfig.Info, ) - udmSubGroup.GET("/:neId/:imsi", + neConfigGroup.POST("", middleware.PreAuthorize(nil), - controller.NewUDMSub.Info, + collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.neConfig", collectlogs.BUSINESS_TYPE_INSERT)), + controller.NewNeConfig.Add, ) - udmSubGroup.POST("/:neId", + neConfigGroup.PUT("", middleware.PreAuthorize(nil), - collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmSub", collectlogs.BUSINESS_TYPE_INSERT)), - controller.NewUDMSub.Add, + collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.neConfig", collectlogs.BUSINESS_TYPE_UPDATE)), + controller.NewNeConfig.Edit, ) - udmSubGroup.POST("/:neId/:num", + neConfigGroup.DELETE("/:ids", middleware.PreAuthorize(nil), - collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmSub", collectlogs.BUSINESS_TYPE_INSERT)), - controller.NewUDMSub.Adds, + collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.neConfig", collectlogs.BUSINESS_TYPE_DELETE)), + controller.NewNeConfig.Remove, ) - udmSubGroup.PUT("/:neId", + neConfigGroup.GET("/list/:neType", middleware.PreAuthorize(nil), - collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmSub", collectlogs.BUSINESS_TYPE_UPDATE)), - controller.NewUDMSub.Edit, + controller.NewNeConfig.ListByNeType, ) - udmSubGroup.DELETE("/:neId/:imsi", + neConfigGroup.GET("/data", middleware.PreAuthorize(nil), - collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmSub", collectlogs.BUSINESS_TYPE_DELETE)), - controller.NewUDMSub.Remove, - ) - udmSubGroup.DELETE("/:neId/:imsi/:num", - middleware.PreAuthorize(nil), - collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmSub", collectlogs.BUSINESS_TYPE_DELETE)), - controller.NewUDMSub.Removes, - ) - udmSubGroup.POST("/export", - middleware.PreAuthorize(nil), - collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmSub", collectlogs.BUSINESS_TYPE_EXPORT)), - controller.NewUDMSub.Export, - ) - udmSubGroup.POST("/import", - middleware.PreAuthorize(nil), - collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmSub", collectlogs.BUSINESS_TYPE_IMPORT)), - controller.NewUDMSub.Import, + controller.NewNeConfig.Data, ) } } @@ -324,4 +299,11 @@ func InitLoad() { // 启动时,清除缓存-网元类型 service.NewNeInfoImpl.ClearNeCacheByNeType("*") service.NewNeInfoImpl.SelectNeInfoByRmuid("") + // 启动时,网元公共参数数据记录到全局变量 + if para5GMap, err := service.NewNeInfoImpl.NeConfPara5GRead(); para5GMap != nil && err == nil { + service.NewNeInfoImpl.NeConfPara5GWirte(para5GMap, nil) + } + // 启动时,清除缓存-网元参数配置可用属性值 + service.NewNeConfigImpl.ClearNeCacheByNeType("*") + service.NewNeConfigImpl.RefreshByNeTypeAndNeID("*") } diff --git a/src/modules/network_element/repository/ne_config.go b/src/modules/network_element/repository/ne_config.go new file mode 100644 index 0000000..b5abcac --- /dev/null +++ b/src/modules/network_element/repository/ne_config.go @@ -0,0 +1,24 @@ +package repository + +import "nms_cxy/src/modules/network_element/model" + +// INeConfig 网元参数配置可用属性值 数据层接口 +type INeConfig interface { + // SelectPage 根据条件分页查询字典类型 + SelectPage(query map[string]any) map[string]any + + // SelectList 根据实体查询 + SelectList(param model.NeConfig) []model.NeConfig + + // SelectByIds 通过ID查询 + SelectByIds(ids []string) []model.NeConfig + + // Insert 新增信息 + Insert(param model.NeConfig) string + + // Update 修改信息 + Update(param model.NeConfig) int64 + + // DeleteByIds 批量删除信息 + DeleteByIds(ids []string) int64 +} diff --git a/src/modules/network_element/repository/ne_config.impl.go b/src/modules/network_element/repository/ne_config.impl.go new file mode 100644 index 0000000..f60c818 --- /dev/null +++ b/src/modules/network_element/repository/ne_config.impl.go @@ -0,0 +1,254 @@ +package repository + +import ( + "strings" + + "nms_cxy/src/framework/datasource" + "nms_cxy/src/framework/logger" + "nms_cxy/src/framework/utils/parse" + "nms_cxy/src/framework/utils/repo" + "nms_cxy/src/modules/network_element/model" +) + +// NewNeConfigImpl 网元参数配置可用属性值 实例化数据层 +var NewNeConfigImpl = &NeConfigImpl{ + selectSql: `select + id, ne_type, ne_id, top_tag, top_display, method, param_json + from param_config`, + + resultMap: map[string]string{ + "id": "ID", + "ne_type": "NeType", + "ne_id": "NeId", + "top_tag": "TopTag", + "top_display": "TopDisplay", + "method": "Method", + "param_json": "ParamJSONStr", + }, +} + +// NeConfigImpl 网元参数配置可用属性值 数据层处理 +type NeConfigImpl struct { + // 查询视图对象SQL + selectSql string + // 结果字段与实体映射 + resultMap map[string]string +} + +// convertResultRows 将结果记录转实体结果组 +func (r *NeConfigImpl) convertResultRows(rows []map[string]any) []model.NeConfig { + arr := make([]model.NeConfig, 0) + for _, row := range rows { + item := model.NeConfig{} + for key, value := range row { + if keyMapper, ok := r.resultMap[key]; ok { + repo.SetFieldValue(&item, keyMapper, value) + } + } + arr = append(arr, item) + } + return arr +} + +// SelectPage 根据条件分页查询字典类型 +func (r *NeConfigImpl) SelectPage(query map[string]any) map[string]any { + // 查询条件拼接 + var conditions []string + var params []any + if v, ok := query["neType"]; ok && v != "" { + conditions = append(conditions, "ne_type = ?") + params = append(params, v) + } + if v, ok := query["topTag"]; ok && v != "" { + conditions = append(conditions, "top_tag = ?") + params = append(params, v) + } + + // 构建查询条件语句 + whereSql := "" + if len(conditions) > 0 { + whereSql += " where " + strings.Join(conditions, " and ") + } + + result := map[string]any{ + "total": 0, + "rows": []model.NeHost{}, + } + + // 查询数量 长度为0直接返回 + totalSql := "select count(id) as 'total' from param_config" + totalRows, err := datasource.RawDB("", totalSql+whereSql, params) + if err != nil { + logger.Errorf("total err => %v", err) + return result + } + total := parse.Number(totalRows[0]["total"]) + if total == 0 { + return result + } else { + result["total"] = total + } + + // 分页 + pageNum, pageSize := repo.PageNumSize(query["pageNum"], query["pageSize"]) + pageSql := " limit ?,? " + params = append(params, pageNum*pageSize) + params = append(params, pageSize) + + // 查询数据 + querySql := r.selectSql + whereSql + pageSql + results, err := datasource.RawDB("", querySql, params) + if err != nil { + logger.Errorf("query err => %v", err) + return result + } + + // 转换实体 + result["rows"] = r.convertResultRows(results) + return result +} + +// SelectList 根据实体查询 +func (r *NeConfigImpl) SelectList(param model.NeConfig) []model.NeConfig { + // 查询条件拼接 + var conditions []string + var params []any + if param.NeType != "" { + conditions = append(conditions, "ne_type = ?") + params = append(params, param.NeType) + } + if param.TopTag != "" { + conditions = append(conditions, "top_tag = ?") + params = append(params, param.TopTag) + } + + // 构建查询条件语句 + whereSql := "" + if len(conditions) > 0 { + whereSql += " where " + strings.Join(conditions, " and ") + } + + // 查询数据 + querySql := r.selectSql + whereSql + " order by id asc " + results, err := datasource.RawDB("", querySql, params) + if err != nil { + logger.Errorf("query err => %v", err) + } + + // 转换实体 + return r.convertResultRows(results) +} + +// SelectByIds 通过ID查询 +func (r *NeConfigImpl) SelectByIds(ids []string) []model.NeConfig { + placeholder := repo.KeyPlaceholderByQuery(len(ids)) + querySql := r.selectSql + " where id in (" + placeholder + ")" + parameters := repo.ConvertIdsSlice(ids) + results, err := datasource.RawDB("", querySql, parameters) + if err != nil { + logger.Errorf("query err => %v", err) + return []model.NeConfig{} + } + // 转换实体 + return r.convertResultRows(results) +} + +// Insert 新增信息 +func (r *NeConfigImpl) Insert(param model.NeConfig) string { + // 参数拼接 + params := make(map[string]any) + if param.NeType != "" { + params["ne_type"] = param.NeType + } + if param.NeId != "" { + params["ne_id"] = param.NeId + } + if param.TopTag != "" { + params["top_tag"] = param.TopTag + } + if param.TopDisplay != "" { + params["top_display"] = param.TopDisplay + } + if param.Method != "" { + params["method"] = param.Method + } + if param.ParamJSONStr != "" { + params["param_json"] = param.ParamJSONStr + } + + // 构建执行语句 + keys, placeholder, values := repo.KeyPlaceholderValueByInsert(params) + sql := "insert into param_config (" + strings.Join(keys, ",") + ")values(" + placeholder + ")" + + db := datasource.DefaultDB() + // 开启事务 + tx := db.Begin() + // 执行插入 + err := tx.Exec(sql, values...).Error + if err != nil { + logger.Errorf("insert row : %v", err.Error()) + tx.Rollback() + return "" + } + // 获取生成的自增 ID + var insertedID string + err = tx.Raw("select last_insert_id()").Row().Scan(&insertedID) + if err != nil { + logger.Errorf("insert last id : %v", err.Error()) + tx.Rollback() + return "" + } + // 提交事务 + tx.Commit() + return insertedID +} + +// Update 修改信息 +func (r *NeConfigImpl) Update(param model.NeConfig) int64 { + // 参数拼接 + params := make(map[string]any) + if param.NeType != "" { + params["ne_type"] = param.NeType + } + if param.NeId != "" { + params["ne_id"] = param.NeId + } + if param.TopTag != "" { + params["top_tag"] = param.TopTag + } + if param.TopDisplay != "" { + params["top_display"] = param.TopDisplay + } + if param.Method != "" { + params["method"] = param.Method + } + if param.ParamJSONStr != "" { + params["param_json"] = param.ParamJSONStr + } + + // 构建执行语句 + keys, values := repo.KeyValueByUpdate(params) + sql := "update param_config set " + strings.Join(keys, ",") + " where id = ?" + + // 执行更新 + values = append(values, param.ID) + rows, err := datasource.ExecDB("", sql, values) + if err != nil { + logger.Errorf("update row : %v", err.Error()) + return 0 + } + return rows +} + +// DeleteByIds 批量删除信息 +func (r *NeConfigImpl) DeleteByIds(ids []string) int64 { + placeholder := repo.KeyPlaceholderByQuery(len(ids)) + sql := "delete from param_config where id in (" + placeholder + ")" + parameters := repo.ConvertIdsSlice(ids) + results, err := datasource.ExecDB("", sql, parameters) + if err != nil { + logger.Errorf("delete err => %v", err) + return 0 + } + return results +} diff --git a/src/modules/network_element/repository/ne_host.impl.go b/src/modules/network_element/repository/ne_host.impl.go index 68bfa1a..6ae63b8 100644 --- a/src/modules/network_element/repository/ne_host.impl.go +++ b/src/modules/network_element/repository/ne_host.impl.go @@ -175,21 +175,21 @@ func (r *NeHostImpl) SelectByIds(hostIds []string) []model.NeHost { for i := range *arr { passwordDe, err := crypto.StringDecryptByAES((*arr)[i].Password) if err != nil { - logger.Errorf("selectById %s StringDecryptByAES : %v", (*arr)[i].HostID, err.Error()) + logger.Errorf("selectById %s decrypt: %v", (*arr)[i].HostID, err.Error()) (*arr)[i].Password = "" } else { (*arr)[i].Password = passwordDe } privateKeyDe, err := crypto.StringDecryptByAES((*arr)[i].PrivateKey) if err != nil { - logger.Errorf("selectById %s StringDecryptByAES : %v", (*arr)[i].HostID, err.Error()) + logger.Errorf("selectById %s decrypt: %v", (*arr)[i].HostID, err.Error()) (*arr)[i].PrivateKey = "" } else { (*arr)[i].PrivateKey = privateKeyDe } passPhraseDe, err := crypto.StringDecryptByAES((*arr)[i].PassPhrase) if err != nil { - logger.Errorf("selectById %s StringDecryptByAES : %v", (*arr)[i].HostID, err.Error()) + logger.Errorf("selectById %s decrypt: %v", (*arr)[i].HostID, err.Error()) (*arr)[i].PassPhrase = "" } else { (*arr)[i].PassPhrase = passPhraseDe @@ -265,7 +265,7 @@ func (r *NeHostImpl) Insert(neHost model.NeHost) string { if neHost.Password != "" { passwordEn, err := crypto.StringEncryptByAES(neHost.Password) if err != nil { - logger.Errorf("insert StringEncryptByAES : %v", err.Error()) + logger.Errorf("insert encrypt: %v", err.Error()) return "" } params["password"] = passwordEn @@ -273,7 +273,7 @@ func (r *NeHostImpl) Insert(neHost model.NeHost) string { if neHost.PrivateKey != "" { privateKeyEn, err := crypto.StringEncryptByAES(neHost.PrivateKey) if err != nil { - logger.Errorf("insert StringEncryptByAES : %v", err.Error()) + logger.Errorf("insert encrypt: %v", err.Error()) return "" } params["private_key"] = privateKeyEn @@ -281,7 +281,7 @@ func (r *NeHostImpl) Insert(neHost model.NeHost) string { if neHost.PassPhrase != "" { passPhraseEn, err := crypto.StringEncryptByAES(neHost.PassPhrase) if err != nil { - logger.Errorf("insert StringEncryptByAES : %v", err.Error()) + logger.Errorf("insert encrypt: %v", err.Error()) return "" } params["pass_phrase"] = passPhraseEn @@ -294,6 +294,20 @@ func (r *NeHostImpl) Insert(neHost model.NeHost) string { params["create_time"] = time.Now().UnixMilli() } + // 根据认证模式清除不必要的信息 + if neHost.AuthMode == "0" { + params["private_key"] = "" + params["pass_phrase"] = "" + } + if neHost.AuthMode == "1" { + params["password"] = "" + } + if neHost.AuthMode == "2" { + params["password"] = "" + params["private_key"] = "" + params["pass_phrase"] = "" + } + // 构建执行语句 keys, placeholder, values := repo.KeyPlaceholderValueByInsert(params) sql := "insert into ne_host (" + strings.Join(keys, ",") + ")values(" + placeholder + ")" @@ -349,7 +363,7 @@ func (r *NeHostImpl) Update(neHost model.NeHost) int64 { if neHost.Password != "" { passwordEn, err := crypto.StringEncryptByAES(neHost.Password) if err != nil { - logger.Errorf("update StringEncryptByAES : %v", err.Error()) + logger.Errorf("update encrypt: %v", err.Error()) return 0 } params["password"] = passwordEn @@ -357,7 +371,7 @@ func (r *NeHostImpl) Update(neHost model.NeHost) int64 { if neHost.PrivateKey != "" { privateKeyEn, err := crypto.StringEncryptByAES(neHost.PrivateKey) if err != nil { - logger.Errorf("update StringEncryptByAES : %v", err.Error()) + logger.Errorf("update encrypt: %v", err.Error()) return 0 } params["private_key"] = privateKeyEn @@ -365,7 +379,7 @@ func (r *NeHostImpl) Update(neHost model.NeHost) int64 { if neHost.PassPhrase != "" { passPhraseEn, err := crypto.StringEncryptByAES(neHost.PassPhrase) if err != nil { - logger.Errorf("update StringEncryptByAES : %v", err.Error()) + logger.Errorf("update encrypt: %v", err.Error()) return 0 } params["pass_phrase"] = passPhraseEn @@ -376,6 +390,20 @@ func (r *NeHostImpl) Update(neHost model.NeHost) int64 { params["update_time"] = time.Now().UnixMilli() } + // 根据认证模式清除不必要的信息 + if neHost.AuthMode == "0" { + params["private_key"] = "" + params["pass_phrase"] = "" + } + if neHost.AuthMode == "1" { + params["password"] = "" + } + if neHost.AuthMode == "2" { + params["password"] = "" + params["private_key"] = "" + params["pass_phrase"] = "" + } + // 构建执行语句 keys, values := repo.KeyValueByUpdate(params) sql := "update ne_host set " + strings.Join(keys, ",") + " where host_id = ?" diff --git a/src/modules/network_element/repository/ne_info.impl.go b/src/modules/network_element/repository/ne_info.impl.go index fb4921c..05e05da 100644 --- a/src/modules/network_element/repository/ne_info.impl.go +++ b/src/modules/network_element/repository/ne_info.impl.go @@ -16,25 +16,26 @@ import ( // neListSort 网元列表预设排序 var neListSort = []string{ "OMC", - "MME", + "IMS", "AMF", "AUSF", "UDM", "SMF", "PCF", - "UPF", - "NRF", "NSSF", - "IMS", - "N3IWF", - "NEF", + "NRF", + "UPF", "LMF", + "NEF", + "MME", + "N3IWF", "MOCNGW", + "SMSC", } // 实例化数据层 NeInfoImpl 结构体 var NewNeInfoImpl = &NeInfoImpl{ - selectSql: `select id, ne_type, ne_id, rm_uid, ne_name, ip, port, pv_flag, province, vendor_name, dn, ne_address, status, update_time, host_ids from ne_info`, + selectSql: `select id, ne_type, ne_id, rm_uid, ne_name, ip, port, pv_flag, province, vendor_name, dn, ne_address, host_ids, status, remark, create_by, create_time, update_by, update_time from ne_info`, resultMap: map[string]string{ "id": "ID", @@ -49,9 +50,13 @@ var NewNeInfoImpl = &NeInfoImpl{ "vendor_name": "VendorName", "dn": "Dn", "ne_address": "NeAddress", - "status": "Status", - "update_time": "UpdateTime", "host_ids": "HostIDs", + "status": "Status", + "remark": "Remark", + "create_by": "CreateBy", + "create_time": "CreateTime", + "update_by": "UpdateBy", + "update_time": "UpdateTime", }, } @@ -298,11 +303,19 @@ func (r *NeInfoImpl) Insert(neInfo model.NeInfo) string { if neInfo.NeAddress != "" { params["ne_address"] = neInfo.NeAddress } - params["status"] = neInfo.Status - params["update_time"] = time.Now() if neInfo.HostIDs != "" { params["host_ids"] = neInfo.HostIDs } + if neInfo.Status != "" { + params["status"] = neInfo.Status + } + if neInfo.Remark != "" { + params["remark"] = neInfo.Remark + } + if neInfo.CreateBy != "" { + params["create_by"] = neInfo.CreateBy + params["create_time"] = time.Now().UnixMilli() + } // 构建执行语句 keys, placeholder, values := repo.KeyPlaceholderValueByInsert(params) @@ -360,11 +373,17 @@ func (r *NeInfoImpl) Update(neInfo model.NeInfo) int64 { params["vendor_name"] = neInfo.VendorName params["dn"] = neInfo.Dn params["ne_address"] = neInfo.NeAddress - params["status"] = neInfo.Status - params["update_time"] = time.Now() if neInfo.HostIDs != "" { params["host_ids"] = neInfo.HostIDs } + params["remark"] = neInfo.Remark + if neInfo.Status != "" { + params["status"] = neInfo.Status + } + if neInfo.UpdateBy != "" { + params["update_by"] = neInfo.UpdateBy + params["update_time"] = time.Now().UnixMilli() + } // 构建执行语句 keys, values := repo.KeyValueByUpdate(params) diff --git a/src/modules/network_element/repository/ne_license.go b/src/modules/network_element/repository/ne_license.go new file mode 100644 index 0000000..4c56803 --- /dev/null +++ b/src/modules/network_element/repository/ne_license.go @@ -0,0 +1,24 @@ +package repository + +import "nms_cxy/src/modules/network_element/model" + +// INeLicense 网元授权激活信息 数据层接口 +type INeLicense interface { + // SelectPage 根据条件分页查询字典类型 + SelectPage(query map[string]any) map[string]any + + // SelectList 根据实体查询 + SelectList(neLicense model.NeLicense) []model.NeLicense + + // SelectByIds 通过ID查询 + SelectByIds(ids []string) []model.NeLicense + + // Insert 新增信息 + Insert(neLicense model.NeLicense) string + + // Update 修改信息 + Update(neLicense model.NeLicense) int64 + + // DeleteByIds 批量删除信息 + DeleteByIds(ids []string) int64 +} diff --git a/src/modules/network_element/repository/ne_license.impl.go b/src/modules/network_element/repository/ne_license.impl.go new file mode 100644 index 0000000..099a801 --- /dev/null +++ b/src/modules/network_element/repository/ne_license.impl.go @@ -0,0 +1,297 @@ +package repository + +import ( + "strings" + "time" + + "nms_cxy/src/framework/datasource" + "nms_cxy/src/framework/logger" + "nms_cxy/src/framework/utils/parse" + "nms_cxy/src/framework/utils/repo" + "nms_cxy/src/modules/network_element/model" +) + +// 实例化数据层 NewNeLicense 结构体 +var NewNeLicenseImpl = &NeLicenseImpl{ + selectSql: `select + id, ne_type, ne_id, activation_request_code, license_path, serial_num, expiry_date, status, remark, create_by, create_time, update_by, update_time + from ne_license`, + + resultMap: map[string]string{ + "id": "ID", + "ne_type": "NeType", + "ne_id": "NeId", + "activation_request_code": "ActivationRequestCode", + "license_path": "LicensePath", + "serial_num": "SerialNum", + "expiry_date": "ExpiryDate", + "status": "Status", + "remark": "Remark", + "create_by": "CreateBy", + "create_time": "CreateTime", + "update_by": "UpdateBy", + "update_time": "UpdateTime", + }, +} + +// NeLicenseImpl 网元授权激活信息 数据层处理 +type NeLicenseImpl struct { + // 查询视图对象SQL + selectSql string + // 结果字段与实体映射 + resultMap map[string]string +} + +// convertResultRows 将结果记录转实体结果组 +func (r *NeLicenseImpl) convertResultRows(rows []map[string]any) []model.NeLicense { + arr := make([]model.NeLicense, 0) + for _, row := range rows { + item := model.NeLicense{} + for key, value := range row { + if keyMapper, ok := r.resultMap[key]; ok { + repo.SetFieldValue(&item, keyMapper, value) + } + } + arr = append(arr, item) + } + return arr +} + +// SelectPage 根据条件分页查询字典类型 +func (r *NeLicenseImpl) SelectPage(query map[string]any) map[string]any { + // 查询条件拼接 + var conditions []string + var params []any + if v, ok := query["neType"]; ok && v != "" { + conditions = append(conditions, "ne_type = ?") + params = append(params, strings.Trim(v.(string), " ")) + } + if v, ok := query["neId"]; ok && v != "" { + conditions = append(conditions, "ne_id = ?") + params = append(params, strings.Trim(v.(string), " ")) + } + if v, ok := query["expiryDate"]; ok && v != "" { + conditions = append(conditions, "expiry_date = ?") + params = append(params, strings.Trim(v.(string), " ")) + } + if v, ok := query["createBy"]; ok && v != "" { + conditions = append(conditions, "create_by like concat(?, '%')") + params = append(params, strings.Trim(v.(string), " ")) + } + + // 构建查询条件语句 + whereSql := "" + if len(conditions) > 0 { + whereSql += " where " + strings.Join(conditions, " and ") + } + + result := map[string]any{ + "total": 0, + "rows": []model.NeHost{}, + } + + // 查询数量 长度为0直接返回 + totalSql := "select count(1) as 'total' from ne_license" + totalRows, err := datasource.RawDB("", totalSql+whereSql, params) + if err != nil { + logger.Errorf("total err => %v", err) + return result + } + total := parse.Number(totalRows[0]["total"]) + if total == 0 { + return result + } else { + result["total"] = total + } + + // 分页 + pageNum, pageSize := repo.PageNumSize(query["pageNum"], query["pageSize"]) + pageSql := " limit ?,? " + params = append(params, pageNum*pageSize) + params = append(params, pageSize) + + // 查询数据 + querySql := r.selectSql + whereSql + pageSql + results, err := datasource.RawDB("", querySql, params) + if err != nil { + logger.Errorf("query err => %v", err) + return result + } + + // 转换实体 + result["rows"] = r.convertResultRows(results) + return result +} + +// SelectList 根据实体查询 +func (r *NeLicenseImpl) SelectList(neLicense model.NeLicense) []model.NeLicense { + // 查询条件拼接 + var conditions []string + var params []any + if neLicense.NeType != "" { + conditions = append(conditions, "ne_type = ?") + params = append(params, neLicense.NeType) + } + if neLicense.NeId != "" { + conditions = append(conditions, "ne_id = ?") + params = append(params, neLicense.NeId) + } + if neLicense.ExpiryDate != "" { + conditions = append(conditions, "expiry_date = ?") + params = append(params, neLicense.ExpiryDate) + } + if neLicense.CreateBy != "" { + conditions = append(conditions, "create_by like concat(?, '%')") + params = append(params, neLicense.CreateBy) + } + + // 构建查询条件语句 + whereSql := "" + if len(conditions) > 0 { + whereSql += " where " + strings.Join(conditions, " and ") + } + + // 查询数据 + querySql := r.selectSql + whereSql + " order by id asc " + results, err := datasource.RawDB("", querySql, params) + if err != nil { + logger.Errorf("query err => %v", err) + } + + // 转换实体 + return r.convertResultRows(results) +} + +// SelectByIds 通过ID查询 +func (r *NeLicenseImpl) SelectByIds(cmdIds []string) []model.NeLicense { + placeholder := repo.KeyPlaceholderByQuery(len(cmdIds)) + querySql := r.selectSql + " where id in (" + placeholder + ")" + parameters := repo.ConvertIdsSlice(cmdIds) + results, err := datasource.RawDB("", querySql, parameters) + if err != nil { + logger.Errorf("query err => %v", err) + return []model.NeLicense{} + } + // 转换实体 + return r.convertResultRows(results) +} + +// Insert 新增信息 +func (r *NeLicenseImpl) Insert(neLicense model.NeLicense) string { + // 参数拼接 + params := make(map[string]any) + if neLicense.NeType != "" { + params["ne_type"] = neLicense.NeType + } + if neLicense.NeId != "" { + params["ne_id"] = neLicense.NeId + } + if neLicense.ActivationRequestCode != "" { + params["activation_request_code"] = neLicense.ActivationRequestCode + } + if neLicense.LicensePath != "" { + params["license_path"] = neLicense.LicensePath + } + if neLicense.SerialNum != "" { + params["serial_num"] = neLicense.SerialNum + } + if neLicense.ExpiryDate != "" { + params["expiry_date"] = neLicense.ExpiryDate + } + if neLicense.Status != "" { + params["status"] = neLicense.Status + } + if neLicense.Remark != "" { + params["remark"] = neLicense.Remark + } + if neLicense.CreateBy != "" { + params["create_by"] = neLicense.CreateBy + params["create_time"] = time.Now().UnixMilli() + } + + // 构建执行语句 + keys, placeholder, values := repo.KeyPlaceholderValueByInsert(params) + sql := "insert into ne_license (" + strings.Join(keys, ",") + ")values(" + placeholder + ")" + + db := datasource.DefaultDB() + // 开启事务 + tx := db.Begin() + // 执行插入 + err := tx.Exec(sql, values...).Error + if err != nil { + logger.Errorf("insert row : %v", err.Error()) + tx.Rollback() + return "" + } + // 获取生成的自增 ID + var insertedID string + err = tx.Raw("select last_insert_id()").Row().Scan(&insertedID) + if err != nil { + logger.Errorf("insert last id : %v", err.Error()) + tx.Rollback() + return "" + } + // 提交事务 + tx.Commit() + return insertedID +} + +// Update 修改信息 +func (r *NeLicenseImpl) Update(neLicense model.NeLicense) int64 { + // 参数拼接 + params := make(map[string]any) + if neLicense.NeType != "" { + params["ne_type"] = neLicense.NeType + } + if neLicense.NeId != "" { + params["ne_id"] = neLicense.NeId + } + if neLicense.ActivationRequestCode != "" { + params["activation_request_code"] = neLicense.ActivationRequestCode + } + if neLicense.LicensePath != "" { + params["license_path"] = neLicense.LicensePath + } + if neLicense.SerialNum != "" { + params["serial_num"] = neLicense.SerialNum + } + if neLicense.ExpiryDate != "" { + params["expiry_date"] = neLicense.ExpiryDate + } + if neLicense.Status != "" { + params["status"] = neLicense.Status + } + if neLicense.Remark != "" { + params["remark"] = neLicense.Remark + } + if neLicense.UpdateBy != "" { + params["update_by"] = neLicense.UpdateBy + params["update_time"] = time.Now().UnixMilli() + } + + // 构建执行语句 + keys, values := repo.KeyValueByUpdate(params) + sql := "update ne_license set " + strings.Join(keys, ",") + " where id = ?" + + // 执行更新 + values = append(values, neLicense.ID) + rows, err := datasource.ExecDB("", sql, values) + if err != nil { + logger.Errorf("update row : %v", err.Error()) + return 0 + } + return rows +} + +// DeleteByIds 批量删除信息 +func (r *NeLicenseImpl) DeleteByIds(cmdIds []string) int64 { + placeholder := repo.KeyPlaceholderByQuery(len(cmdIds)) + sql := "delete from ne_license where id in (" + placeholder + ")" + parameters := repo.ConvertIdsSlice(cmdIds) + results, err := datasource.ExecDB("", sql, parameters) + if err != nil { + logger.Errorf("delete err => %v", err) + return 0 + } + return results +} diff --git a/src/modules/network_element/repository/ne_software.go b/src/modules/network_element/repository/ne_software.go index dd2c574..317a948 100644 --- a/src/modules/network_element/repository/ne_software.go +++ b/src/modules/network_element/repository/ne_software.go @@ -22,6 +22,6 @@ type INeSoftware interface { // DeleteByIds 批量删除信息 DeleteByIds(ids []string) int64 - // CheckUniqueTypeAndFileNameAndVersion 校验网元类型和文件名版本是否唯一 - CheckUniqueTypeAndFileNameAndVersion(neSoftware model.NeSoftware) string + // CheckUniqueTypeAndNameAndVersion 校验网元类型和文件名版本是否唯一 + CheckUniqueTypeAndNameAndVersion(neSoftware model.NeSoftware) string } diff --git a/src/modules/network_element/repository/ne_software.impl.go b/src/modules/network_element/repository/ne_software.impl.go index 769f3a4..3b20f84 100644 --- a/src/modules/network_element/repository/ne_software.impl.go +++ b/src/modules/network_element/repository/ne_software.impl.go @@ -15,18 +15,19 @@ import ( // 实例化数据层 NewNeSoftware 结构体 var NewNeSoftwareImpl = &NeSoftwareImpl{ selectSql: `select - id, ne_type, file_name, path, version, md5_sum, status, comment, update_time + id, ne_type, name, path, version, description, create_by, create_time, update_by, update_time from ne_software`, resultMap: map[string]string{ "id": "ID", "ne_type": "NeType", - "file_name": "FileName", + "name": "Name", "path": "Path", "version": "Version", - "md5_sum": "Md5Sum", - "status": "Status", - "comment": "Comment", + "description": "Description", + "create_by": "CreateBy", + "create_time": "CreateTime", + "update_by": "UpdateBy", "update_time": "UpdateTime", }, } @@ -60,11 +61,20 @@ func (r *NeSoftwareImpl) SelectPage(query map[string]any) map[string]any { var conditions []string var params []any if v, ok := query["neType"]; ok && v != "" { - conditions = append(conditions, "ne_type = ?") - params = append(params, strings.Trim(v.(string), " ")) + softwareType := v.(string) + if strings.Contains(softwareType, ",") { + softwareTypeArr := strings.Split(softwareType, ",") + placeholder := repo.KeyPlaceholderByQuery(len(softwareTypeArr)) + conditions = append(conditions, "ne_type in ("+placeholder+")") + parameters := repo.ConvertIdsSlice(softwareTypeArr) + params = append(params, parameters...) + } else { + conditions = append(conditions, "ne_type = ?") + params = append(params, strings.Trim(softwareType, " ")) + } } - if v, ok := query["fileName"]; ok && v != "" { - conditions = append(conditions, "file_name like concat(?, '%')") + if v, ok := query["name"]; ok && v != "" { + conditions = append(conditions, "name like concat(?, '%')") params = append(params, strings.Trim(v.(string), " ")) } if v, ok := query["version"]; ok && v != "" { @@ -133,9 +143,9 @@ func (r *NeSoftwareImpl) SelectList(neSoftware model.NeSoftware) []model.NeSoftw conditions = append(conditions, "version = ?") params = append(params, neSoftware.Version) } - if neSoftware.FileName != "" { - conditions = append(conditions, "file_name like concat(?, '%')") - params = append(params, neSoftware.FileName) + if neSoftware.Name != "" { + conditions = append(conditions, "name like concat(?, '%')") + params = append(params, neSoftware.Name) } // 构建查询条件语句 @@ -169,8 +179,8 @@ func (r *NeSoftwareImpl) SelectByIds(cmdIds []string) []model.NeSoftware { return r.convertResultRows(results) } -// CheckUniqueTypeAndFileNameAndVersion 校验网元类型和文件名版本是否唯一 -func (r *NeSoftwareImpl) CheckUniqueTypeAndFileNameAndVersion(neSoftware model.NeSoftware) string { +// CheckUniqueTypeAndNameAndVersion 校验网元类型和文件名版本是否唯一 +func (r *NeSoftwareImpl) CheckUniqueTypeAndNameAndVersion(neSoftware model.NeSoftware) string { // 查询条件拼接 var conditions []string var params []any @@ -182,9 +192,9 @@ func (r *NeSoftwareImpl) CheckUniqueTypeAndFileNameAndVersion(neSoftware model.N conditions = append(conditions, "version = ?") params = append(params, neSoftware.Version) } - if neSoftware.FileName != "" { - conditions = append(conditions, "file_name = ?") - params = append(params, neSoftware.FileName) + if neSoftware.Name != "" { + conditions = append(conditions, "name = ?") + params = append(params, neSoftware.Name) } // 构建查询条件语句 @@ -215,8 +225,8 @@ func (r *NeSoftwareImpl) Insert(neSoftware model.NeSoftware) string { if neSoftware.NeType != "" { params["ne_type"] = neSoftware.NeType } - if neSoftware.FileName != "" { - params["file_name"] = neSoftware.FileName + if neSoftware.Name != "" { + params["name"] = neSoftware.Name } if neSoftware.Path != "" { params["path"] = neSoftware.Path @@ -224,19 +234,11 @@ func (r *NeSoftwareImpl) Insert(neSoftware model.NeSoftware) string { if neSoftware.Version != "" { params["version"] = neSoftware.Version } - if neSoftware.Md5Sum != "" { - params["md5_sum"] = neSoftware.Md5Sum + params["description"] = neSoftware.Description + if neSoftware.CreateBy != "" { + params["create_by"] = neSoftware.CreateBy + params["create_time"] = time.Now().UnixMilli() } - if neSoftware.Status != "" { - params["status"] = neSoftware.Status - } - if neSoftware.Comment != "" { - params["comment"] = neSoftware.Comment - } - if neSoftware.Status != "" { - params["status"] = neSoftware.Status - } - params["update_time"] = time.Now() // 构建执行语句 keys, placeholder, values := repo.KeyPlaceholderValueByInsert(params) @@ -272,8 +274,8 @@ func (r *NeSoftwareImpl) Update(neSoftware model.NeSoftware) int64 { if neSoftware.NeType != "" { params["ne_type"] = neSoftware.NeType } - if neSoftware.FileName != "" { - params["file_name"] = neSoftware.FileName + if neSoftware.Name != "" { + params["name"] = neSoftware.Name } if neSoftware.Path != "" { params["path"] = neSoftware.Path @@ -281,19 +283,11 @@ func (r *NeSoftwareImpl) Update(neSoftware model.NeSoftware) int64 { if neSoftware.Version != "" { params["version"] = neSoftware.Version } - if neSoftware.Md5Sum != "" { - params["md5_sum"] = neSoftware.Md5Sum + params["description"] = neSoftware.Description + if neSoftware.UpdateBy != "" { + params["update_by"] = neSoftware.UpdateBy + params["update_time"] = time.Now().UnixMilli() } - if neSoftware.Status != "" { - params["status"] = neSoftware.Status - } - if neSoftware.Comment != "" { - params["comment"] = neSoftware.Comment - } - if neSoftware.Status != "" { - params["status"] = neSoftware.Status - } - params["update_time"] = time.Now() // 构建执行语句 keys, values := repo.KeyValueByUpdate(params) diff --git a/src/modules/network_element/repository/ne_version.go b/src/modules/network_element/repository/ne_version.go index 60db37b..5c0db16 100644 --- a/src/modules/network_element/repository/ne_version.go +++ b/src/modules/network_element/repository/ne_version.go @@ -21,7 +21,4 @@ type INeVersion interface { // DeleteByIds 批量删除信息 DeleteByIds(ids []string) int64 - - // CheckUniqueTypeAndID 校验网元类型和网元ID是否唯一 - CheckUniqueTypeAndID(neVersion model.NeVersion) string } diff --git a/src/modules/network_element/repository/ne_version.impl.go b/src/modules/network_element/repository/ne_version.impl.go index 49b09a0..ab91056 100644 --- a/src/modules/network_element/repository/ne_version.impl.go +++ b/src/modules/network_element/repository/ne_version.impl.go @@ -1,7 +1,6 @@ package repository import ( - "fmt" "strings" "time" @@ -15,20 +14,26 @@ import ( // 实例化数据层 NewNeVersion 结构体 var NewNeVersionImpl = &NeVersionImpl{ selectSql: `select - id, ne_type, ne_id, version, file_path, pre_version, pre_file, new_version, new_file, status, update_time + id, ne_type, ne_id, name, version, path, pre_name, pre_version, pre_path, new_name, new_version, new_path, status, create_by, create_time, update_by, update_time from ne_version`, resultMap: map[string]string{ "id": "ID", "ne_type": "NeType", "ne_id": "NeId", + "name": "name", "version": "Version", - "file_path": "FilePath", + "path": "Path", + "pre_name": "preName", "pre_version": "PreVersion", - "pre_file": "PreFile", + "pre_path": "PrePath", + "new_name": "NewName", "new_version": "NewVersion", - "new_file": "NewFile", + "new_path": "NewPath", "status": "Status", + "create_by": "CreateBy", + "create_time": "CreateTime", + "update_by": "UpdateBy", "update_time": "UpdateTime", }, } @@ -73,8 +78,8 @@ func (r *NeVersionImpl) SelectPage(query map[string]any) map[string]any { conditions = append(conditions, "version like concat(?, '%')") params = append(params, strings.Trim(v.(string), " ")) } - if v, ok := query["filePath"]; ok && v != "" { - conditions = append(conditions, "file_path like concat(?, '%')") + if v, ok := query["path"]; ok && v != "" { + conditions = append(conditions, "path like concat(?, '%')") params = append(params, strings.Trim(v.(string), " ")) } @@ -105,7 +110,7 @@ func (r *NeVersionImpl) SelectPage(query map[string]any) map[string]any { // 分页 pageNum, pageSize := repo.PageNumSize(query["pageNum"], query["pageSize"]) - pageSql := " limit ?,? " + pageSql := " order by update_time desc limit ?,? " params = append(params, pageNum*pageSize) params = append(params, pageSize) @@ -139,9 +144,13 @@ func (r *NeVersionImpl) SelectList(neVersion model.NeVersion) []model.NeVersion conditions = append(conditions, "version like concat(?, '%')") params = append(params, neVersion.Version) } - if neVersion.FilePath != "" { - conditions = append(conditions, "file_path like concat(?, '%')") - params = append(params, neVersion.FilePath) + if neVersion.Path != "" { + conditions = append(conditions, "path like concat(?, '%')") + params = append(params, neVersion.Path) + } + if neVersion.Status != "" { + conditions = append(conditions, "status = ?") + params = append(params, neVersion.Status) } // 构建查询条件语句 @@ -151,7 +160,7 @@ func (r *NeVersionImpl) SelectList(neVersion model.NeVersion) []model.NeVersion } // 查询数据 - querySql := r.selectSql + whereSql + " order by update_time asc " + querySql := r.selectSql + whereSql + " order by id asc " results, err := datasource.RawDB("", querySql, params) if err != nil { logger.Errorf("query err => %v", err) @@ -175,41 +184,6 @@ func (r *NeVersionImpl) SelectByIds(cmdIds []string) []model.NeVersion { return r.convertResultRows(results) } -// CheckUniqueTypeAndID 校验网元类型和网元ID是否唯一 -func (r *NeVersionImpl) CheckUniqueTypeAndID(neVersion model.NeVersion) string { - // 查询条件拼接 - var conditions []string - var params []any - if neVersion.NeType != "" { - conditions = append(conditions, "ne_type = ?") - params = append(params, neVersion.NeType) - } - if neVersion.NeId != "" { - conditions = append(conditions, "ne_id = ?") - params = append(params, neVersion.NeId) - } - - // 构建查询条件语句 - whereSql := "" - if len(conditions) > 0 { - whereSql += " where " + strings.Join(conditions, " and ") - } else { - return "" - } - - // 查询数据 - querySql := "select id as 'str' from ne_version " + whereSql + " limit 1" - results, err := datasource.RawDB("", querySql, params) - if err != nil { - logger.Errorf("query err %v", err) - return "" - } - if len(results) > 0 { - return fmt.Sprint(results[0]["str"]) - } - return "" -} - // Insert 新增信息 func (r *NeVersionImpl) Insert(neVersion model.NeVersion) string { // 参数拼接 @@ -220,28 +194,40 @@ func (r *NeVersionImpl) Insert(neVersion model.NeVersion) string { if neVersion.NeId != "" { params["ne_id"] = neVersion.NeId } + if neVersion.Name != "" { + params["name"] = neVersion.Name + } if neVersion.Version != "" { params["version"] = neVersion.Version } - if neVersion.FilePath != "" { - params["file_path"] = neVersion.FilePath + if neVersion.Path != "" { + params["path"] = neVersion.Path + } + if neVersion.PreName != "" { + params["pre_name"] = neVersion.PreName } if neVersion.PreVersion != "" { params["pre_version"] = neVersion.PreVersion } - if neVersion.PreFile != "" { - params["pre_file"] = neVersion.PreFile + if neVersion.PrePath != "" { + params["pre_path"] = neVersion.PrePath + } + if neVersion.NewName != "" { + params["new_name"] = neVersion.NewName } if neVersion.NewVersion != "" { params["new_version"] = neVersion.NewVersion } - if neVersion.NewFile != "" { - params["new_file"] = neVersion.NewFile + if neVersion.NewPath != "" { + params["new_path"] = neVersion.NewPath } if neVersion.Status != "" { params["status"] = neVersion.Status } - params["update_time"] = time.Now() + if neVersion.CreateBy != "" { + params["create_by"] = neVersion.CreateBy + params["create_time"] = time.Now().UnixMilli() + } // 构建执行语句 keys, placeholder, values := repo.KeyPlaceholderValueByInsert(params) @@ -280,28 +266,40 @@ func (r *NeVersionImpl) Update(neVersion model.NeVersion) int64 { if neVersion.NeId != "" { params["ne_id"] = neVersion.NeId } + if neVersion.Name != "" { + params["name"] = neVersion.Name + } if neVersion.Version != "" { params["version"] = neVersion.Version } - if neVersion.FilePath != "" { - params["file_path"] = neVersion.FilePath + if neVersion.Path != "" { + params["path"] = neVersion.Path + } + if neVersion.PreName != "" { + params["pre_name"] = neVersion.PreName } if neVersion.PreVersion != "" { params["pre_version"] = neVersion.PreVersion } - if neVersion.PreFile != "" { - params["pre_file"] = neVersion.PreFile + if neVersion.PrePath != "" { + params["pre_path"] = neVersion.PrePath + } + if neVersion.NewName != "" { + params["new_name"] = neVersion.NewName } if neVersion.NewVersion != "" { params["new_version"] = neVersion.NewVersion } - if neVersion.NewFile != "" { - params["new_file"] = neVersion.NewFile + if neVersion.NewPath != "" { + params["new_path"] = neVersion.NewPath } if neVersion.Status != "" { params["status"] = neVersion.Status } - params["update_time"] = time.Now() + if neVersion.UpdateBy != "" { + params["update_by"] = neVersion.UpdateBy + params["update_time"] = time.Now().UnixMilli() + } // 构建执行语句 keys, values := repo.KeyValueByUpdate(params) diff --git a/src/modules/network_element/repository/udm_auth.go b/src/modules/network_element/repository/udm_auth.go deleted file mode 100644 index 61921c8..0000000 --- a/src/modules/network_element/repository/udm_auth.go +++ /dev/null @@ -1,26 +0,0 @@ -package repository - -import ( - "nms_cxy/src/modules/network_element/model" -) - -// UDM鉴权信息 数据层接口 -type IUDMAuth interface { - // ClearAndInsert 清空ne_id后新增实体 - ClearAndInsert(neID string, authArr []model.UDMAuth) int64 - - // SelectPage 根据条件分页查询 - SelectPage(query map[string]any) map[string]any - - // SelectList 根据实体查询 - SelectList(auth model.UDMAuth) []model.UDMAuth - - // Insert 批量添加 - Inserts(authUsers []model.UDMAuth) int64 - - // Delete 删除实体 - Delete(neID, imsi string) int64 - - // DeletePrefixImsi 删除前缀匹配的实体 - DeletePrefixImsi(neID, imsi string) int64 -} diff --git a/src/modules/network_element/repository/udm_sub.go b/src/modules/network_element/repository/udm_sub.go deleted file mode 100644 index cb46563..0000000 --- a/src/modules/network_element/repository/udm_sub.go +++ /dev/null @@ -1,35 +0,0 @@ -package repository - -import ( - "nms_cxy/src/modules/network_element/model" -) - -// UDM签约信息 数据层接口 -type IUDMSub interface { - // ClearAndInsert 清空ne_id后新增实体 - ClearAndInsert(neID string, subArr []model.UDMSub) int64 - - // SelectPage 根据条件分页查询字典类型 - SelectPage(query map[string]any) map[string]any - - // SelectList 根据实体查询 - SelectList(subUser model.UDMSub) []model.UDMSub - - // Insert 新增实体 - Insert(subUser model.UDMSub) string - - // Insert 批量添加 - Inserts(subUser []model.UDMSub) int64 - - // Update 修改更新 - Update(neID string, subUser model.UDMSub) int64 - - // Delete 删除实体 - Delete(neID, imsi string) int64 - - // DeletePrefixImsi 删除前缀匹配的实体 - DeletePrefixImsi(neID, imsi string) int64 - - // Delete 删除范围实体 - Deletes(neID, imsi, num string) int64 -} diff --git a/src/modules/network_element/service/ne_config.go b/src/modules/network_element/service/ne_config.go new file mode 100644 index 0000000..9949ea6 --- /dev/null +++ b/src/modules/network_element/service/ne_config.go @@ -0,0 +1,33 @@ +package service + +import "nms_cxy/src/modules/network_element/model" + +// INeConfig 网元参数配置可用属性值 服务层接口 +type INeConfig interface { + // RefreshByNeType 通过ne_type刷新redis中的缓存 + RefreshByNeTypeAndNeID(neType string) []model.NeConfig + + // ClearNeCacheByNeType 清除网元类型参数配置缓存 + ClearNeCacheByNeType(neType string) bool + + // SelectNeConfigByNeType 查询网元类型参数配置 + SelectNeConfigByNeType(neType string) []model.NeConfig + + // SelectNeHostPage 分页查询列表数据 + SelectPage(query map[string]any) map[string]any + + // SelectList 根据实体查询 + SelectList(param model.NeConfig) []model.NeConfig + + // SelectByIds 通过ID查询 + SelectById(id string) model.NeConfig + + // Insert 新增信息 + Insert(param model.NeConfig) string + + // Update 修改信息 + Update(param model.NeConfig) int64 + + // DeleteByIds 批量删除信息 + DeleteByIds(ids []string) (int64, error) +} diff --git a/src/modules/network_element/service/ne_config.impl.go b/src/modules/network_element/service/ne_config.impl.go new file mode 100644 index 0000000..bff06bc --- /dev/null +++ b/src/modules/network_element/service/ne_config.impl.go @@ -0,0 +1,151 @@ +package service + +import ( + "encoding/json" + "fmt" + "strings" + + "nms_cxy/src/framework/constants/cachekey" + "nms_cxy/src/framework/redis" + "nms_cxy/src/modules/network_element/model" + "nms_cxy/src/modules/network_element/repository" +) + +// NewNeConfigImpl 网元参数配置可用属性值 实例化服务层 +var NewNeConfigImpl = &NeConfigImpl{ + neConfigRepository: repository.NewNeConfigImpl, +} + +// NeConfigImpl 网元参数配置可用属性值 服务层处理 +type NeConfigImpl struct { + // 网元参数配置可用属性值表 + neConfigRepository repository.INeConfig +} + +// RefreshByNeType 通过ne_type刷新redis中的缓存 +func (r *NeConfigImpl) RefreshByNeTypeAndNeID(neType string) []model.NeConfig { + // 多个 + if neType == "" || neType == "*" { + neConfigList := r.neConfigRepository.SelectList(model.NeConfig{}) + if len(neConfigList) > 0 { + neConfigGroup := map[string][]model.NeConfig{} + for _, v := range neConfigList { + if item, ok := neConfigGroup[v.NeType]; ok { + neConfigGroup[v.NeType] = append(item, v) + } else { + neConfigGroup[v.NeType] = []model.NeConfig{v} + } + } + for k, v := range neConfigGroup { + key := fmt.Sprintf("%sparam_config:%s", cachekey.NE_DATA_KEY, strings.ToUpper(k)) + redis.Del("", key) + if len(v) > 0 { + for i, item := range v { + if err := json.Unmarshal([]byte(item.ParamJSONStr), &item.ParamData); err != nil { + continue + } + v[i] = item + } + values, _ := json.Marshal(v) + redis.Set("", key, string(values)) + } + } + } + return neConfigList + } + // 单个 + key := fmt.Sprintf("%sparam_config:%s", cachekey.NE_DATA_KEY, strings.ToUpper(neType)) + redis.Del("", key) + neConfigList := r.neConfigRepository.SelectList(model.NeConfig{ + NeType: neType, + }) + if len(neConfigList) > 0 { + for i, v := range neConfigList { + if err := json.Unmarshal([]byte(v.ParamJSONStr), &v.ParamData); err != nil { + continue + } + neConfigList[i] = v + } + values, _ := json.Marshal(neConfigList) + redis.Set("", key, string(values)) + } + return neConfigList +} + +// ClearNeCacheByNeType 清除网元类型参数配置缓存 +func (r *NeConfigImpl) ClearNeCacheByNeType(neType string) bool { + key := fmt.Sprintf("%sparam_config:%s", cachekey.NE_DATA_KEY, neType) + if neType == "*" { + key = fmt.Sprintf("%sparam_config:*", cachekey.NE_DATA_KEY) + } + keys, err := redis.GetKeys("", key) + if err != nil { + return false + } + delOk, _ := redis.DelKeys("", keys) + return delOk +} + +// SelectNeConfigByNeType 查询网元类型参数配置 +func (r *NeConfigImpl) SelectNeConfigByNeType(neType string) []model.NeConfig { + var neConfigList []model.NeConfig + key := fmt.Sprintf("%sparam_config:%s", cachekey.NE_DATA_KEY, strings.ToUpper(neType)) + jsonStr, _ := redis.Get("", key) + if len(jsonStr) > 7 { + err := json.Unmarshal([]byte(jsonStr), &neConfigList) + if err != nil { + neConfigList = []model.NeConfig{} + } + } else { + neConfigList = r.RefreshByNeTypeAndNeID(neType) + } + return neConfigList +} + +// SelectNeHostPage 分页查询列表数据 +func (r *NeConfigImpl) SelectPage(query map[string]any) map[string]any { + return r.neConfigRepository.SelectPage(query) +} + +// SelectConfigList 查询列表 +func (r *NeConfigImpl) SelectList(param model.NeConfig) []model.NeConfig { + return r.neConfigRepository.SelectList(param) +} + +// SelectByIds 通过ID查询 +func (r *NeConfigImpl) SelectById(id string) model.NeConfig { + if id == "" { + return model.NeConfig{} + } + neHosts := r.neConfigRepository.SelectByIds([]string{id}) + if len(neHosts) > 0 { + return neHosts[0] + } + return model.NeConfig{} +} + +// Insert 新增信息 +func (r *NeConfigImpl) Insert(param model.NeConfig) string { + return r.neConfigRepository.Insert(param) +} + +// Update 修改信息 +func (r *NeConfigImpl) Update(param model.NeConfig) int64 { + return r.neConfigRepository.Update(param) +} + +// DeleteByIds 批量删除信息 +func (r *NeConfigImpl) DeleteByIds(ids []string) (int64, error) { + // 检查是否存在 + data := r.neConfigRepository.SelectByIds(ids) + if len(data) <= 0 { + return 0, fmt.Errorf("param.noData") + } + + if len(data) == len(ids) { + rows := r.neConfigRepository.DeleteByIds(ids) + return rows, nil + } + // 删除信息失败! + return 0, fmt.Errorf("delete fail") +} diff --git a/src/modules/network_element/service/ne_info.go b/src/modules/network_element/service/ne_info.go index 6093cbd..fa152b0 100644 --- a/src/modules/network_element/service/ne_info.go +++ b/src/modules/network_element/service/ne_info.go @@ -1,6 +1,10 @@ package service -import "nms_cxy/src/modules/network_element/model" +import ( + "nms_cxy/src/framework/utils/ssh" + "nms_cxy/src/framework/utils/telnet" + "nms_cxy/src/modules/network_element/model" +) // 网元信息 服务层接口 type INeInfo interface { @@ -24,7 +28,8 @@ type INeInfo interface { // SelectList 查询列表 // // bandStatus 带状态信息 - SelectList(ne model.NeInfo, bandStatus bool) []model.NeInfo + // bandHost 带主机信息 + SelectList(ne model.NeInfo, bandStatus bool, bandHost bool) []model.NeInfo // SelectByIds 通过ID查询 // @@ -41,5 +46,27 @@ type INeInfo interface { DeleteByIds(infoIds []string) (int64, error) // CheckUniqueNeTypeAndNeId 校验同类型下标识是否唯一 - CheckUniqueNeTypeAndNeId(neType, neId, infoId string) bool + CheckUniqueNeTypeAndNeId(neType, neId, id string) bool + + // NeRunSSHClient 网元主机的SSH客户端-为创建相关连接,注意结束后 Close() + NeRunSSHClient(neType, neId string) (*ssh.ConnSSH, error) + + // NeRunSSHCmd 网元主机的SSH客户端发送cmd命令 + NeRunSSHCmd(neType, neId, cmd string) (string, error) + + // NeRunTelnetClient 网元主机的Telnet客户端-为创建相关连接,注意结束后 Close() + // num 是网元主机telnet 1:4100 2:5200 + NeRunTelnetClient(neType, neId string, num int) (*telnet.ConnTelnet, error) + + // neConfOAMRead 网元OAM配置文件读取 + NeConfOAMRead(neType, neId string) (map[string]any, error) + + // NeConfOAMSync 网元OAM配置文件生成并同步 + NeConfOAMSync(neInfo model.NeInfo, content map[string]any, sync bool) error + + // NeConfPara5GRead 网元公共配置文件读取 + NeConfPara5GRead() (map[string]any, error) + + // NeConfPara5GWirte 网元公共配置文件写入 content内容 syncNE同步到网元端NeType@NeId + NeConfPara5GWirte(content map[string]any, syncNE []string) error } diff --git a/src/modules/network_element/service/ne_info.impl.go b/src/modules/network_element/service/ne_info.impl.go index 9316afd..25a6a91 100644 --- a/src/modules/network_element/service/ne_info.impl.go +++ b/src/modules/network_element/service/ne_info.impl.go @@ -3,10 +3,18 @@ package service import ( "encoding/json" "fmt" + "os" + "path/filepath" + "runtime" "strings" "nms_cxy/src/framework/constants/cachekey" + "nms_cxy/src/framework/logger" "nms_cxy/src/framework/redis" + "nms_cxy/src/framework/utils/parse" + "nms_cxy/src/framework/utils/ssh" + "nms_cxy/src/framework/utils/telnet" + neFetchlink "nms_cxy/src/modules/network_element/fetch_link" "nms_cxy/src/modules/network_element/model" "nms_cxy/src/modules/network_element/repository" ) @@ -14,21 +22,20 @@ import ( // 实例化服务层 NeInfoImpl 结构体 var NewNeInfoImpl = &NeInfoImpl{ neInfoRepository: repository.NewNeInfoImpl, - neHostRepository: repository.NewNeHostImpl, + Para5GData: map[string]string{}, } // 网元信息 服务层处理 type NeInfoImpl struct { // 网元信息数据信息 neInfoRepository repository.INeInfo - // 网元主机连接表 - neHostRepository repository.INeHost + Para5GData map[string]string } // SelectNeInfoByNeTypeAndNeID 通过ne_type和ne_id查询网元信息 func (r *NeInfoImpl) SelectNeInfoByNeTypeAndNeID(neType, neID string) model.NeInfo { var neInfo model.NeInfo - key := fmt.Sprintf("%s%s:%s", cachekey.NE_KEY, neType, neID) + key := fmt.Sprintf("%s%s:%s", cachekey.NE_KEY, strings.ToUpper(neType), neID) jsonStr, _ := redis.Get("", key) if len(jsonStr) > 7 { err := json.Unmarshal([]byte(jsonStr), &neInfo) @@ -37,7 +44,7 @@ func (r *NeInfoImpl) SelectNeInfoByNeTypeAndNeID(neType, neID string) model.NeIn } } else { neInfo = r.neInfoRepository.SelectNeInfoByNeTypeAndNeID(neType, neID) - if neInfo.NeId == neID { + if neInfo.ID != "" && neInfo.NeId == neID { redis.Del("", key) values, _ := json.Marshal(neInfo) redis.Set("", key, string(values)) @@ -49,10 +56,10 @@ func (r *NeInfoImpl) SelectNeInfoByNeTypeAndNeID(neType, neID string) model.NeIn // RefreshByNeTypeAndNeID 通过ne_type和ne_id刷新redis中的缓存 func (r *NeInfoImpl) RefreshByNeTypeAndNeID(neType, neID string) model.NeInfo { var neInfo model.NeInfo - key := fmt.Sprintf("%s%s:%s", cachekey.NE_KEY, neType, neID) + key := fmt.Sprintf("%s%s:%s", cachekey.NE_KEY, strings.ToUpper(neType), neID) redis.Del("", key) neInfo = r.neInfoRepository.SelectNeInfoByNeTypeAndNeID(neType, neID) - if neInfo.NeId == neID { + if neInfo.ID != "" && neInfo.NeId == neID { values, _ := json.Marshal(neInfo) redis.Set("", key, string(values)) } @@ -90,9 +97,9 @@ func (r *NeInfoImpl) SelectNeInfoByRmuid(rmUid string) model.NeInfo { } } } else { - neInfos := r.SelectList(neInfo, false) + neInfos := r.SelectList(neInfo, false, false) for _, v := range neInfos { - key := fmt.Sprintf("%s%s:%s", cachekey.NE_KEY, v.NeType, v.NeId) + key := fmt.Sprintf("%s%s:%s", cachekey.NE_KEY, strings.ToUpper(v.NeType), v.NeId) redis.Del("", key) values, _ := json.Marshal(v) redis.Set("", key, string(values)) @@ -113,37 +120,7 @@ func (r *NeInfoImpl) SelectPage(query map[string]any, bandStatus bool) map[strin // 网元直连读取网元服务状态 if bandStatus { rows := data["rows"].([]model.NeInfo) - arr := &rows - for i := range *arr { - v := (*arr)[i] - result, err := NeState(v) - if err != nil { - (*arr)[i].ServerState = map[string]any{ - "online": false, - } - // 网元状态设置为离线 - if v.Status != "1" { - v.Status = "1" - (*arr)[i].Status = v.Status - r.neInfoRepository.Update(v) - } - continue - } - result["online"] = true - (*arr)[i].ServerState = result - // 网元状态设置为在线 - if v.Status != "0" { - // 下发网管配置信息给网元 - _, err = NeConfigOMC(v) - if err != nil { - v.Status = "3" - } else { - v.Status = "0" - } - (*arr)[i].Status = v.Status - r.neInfoRepository.Update(v) - } - } + r.bandNeStatus(&rows) } return data @@ -152,50 +129,70 @@ func (r *NeInfoImpl) SelectPage(query map[string]any, bandStatus bool) map[strin // SelectList 查询列表 // // bandStatus 带状态信息 -func (r *NeInfoImpl) SelectList(ne model.NeInfo, bandStatus bool) []model.NeInfo { +// bandHost 带主机信息 +func (r *NeInfoImpl) SelectList(ne model.NeInfo, bandStatus bool, bandHost bool) []model.NeInfo { list := r.neInfoRepository.SelectList(ne) // 网元直连读取网元服务状态 if bandStatus { - neList := &list - for i := range *neList { - v := (*neList)[i] - result, err := NeState(v) - if err != nil { - (*neList)[i].ServerState = map[string]any{ - "online": false, - } - // 网元状态设置为离线 - if v.Status != "1" { - v.Status = "1" - (*neList)[i].Status = v.Status - r.neInfoRepository.Update(v) - } - continue - } - result["online"] = true - (*neList)[i].ServerState = result - // 网元状态设置为在线 - if v.Status != "0" { - // 下发网管配置信息给网元 - _, err = NeConfigOMC(v) - if err != nil { - v.Status = "3" - } else { - v.Status = "0" - } - (*neList)[i].Status = v.Status - r.neInfoRepository.Update(v) - } - } + r.bandNeStatus(&list) + } + + // 网元主机信息 + if bandHost { + r.bandNeHosts(&list) } return list } +// bandNeStatus 网元列表项数据带网元服务状态 +func (r *NeInfoImpl) bandNeStatus(arr *[]model.NeInfo) { + for i := range *arr { + v := (*arr)[i] + result, err := neFetchlink.NeState(v) + if err != nil { + (*arr)[i].ServerState = map[string]any{ + "online": false, + } + // 网元状态设置为离线 + if v.Status != "0" { + v.Status = "0" + (*arr)[i].Status = v.Status + r.neInfoRepository.Update(v) + } + continue + } + result["online"] = true + (*arr)[i].ServerState = result + // 网元状态设置为在线 + if v.Status != "1" { + // 下发网管配置信息给网元 + _, err = neFetchlink.NeConfigOMC(v) + if err == nil { + v.Status = "1" + } else { + v.Status = "2" + } + (*arr)[i].Status = v.Status + r.neInfoRepository.Update(v) + } + } +} + +// bandNeHosts 网元列表项数据带网元主机信息 +func (r *NeInfoImpl) bandNeHosts(arr *[]model.NeInfo) { + for i := range *arr { + v := (*arr)[i] + if v.HostIDs != "" { + (*arr)[i].Hosts = NewNeHostImpl.neHostRepository.SelectByIds(strings.Split(v.HostIDs, ",")) + } + } +} + // SelectByIds 通过ID查询 // -// bandStatus 带主机信息 +// bandHost 带主机信息 func (r *NeInfoImpl) SelectById(infoId string, bandHost bool) model.NeInfo { if infoId == "" { return model.NeInfo{} @@ -205,7 +202,7 @@ func (r *NeInfoImpl) SelectById(infoId string, bandHost bool) model.NeInfo { neInfo := neInfos[0] // 带主机信息 if neInfo.HostIDs != "" && bandHost { - neInfo.Hosts = r.neHostRepository.SelectByIds(strings.Split(neInfo.HostIDs, ",")) + neInfo.Hosts = NewNeHostImpl.neHostRepository.SelectByIds(strings.Split(neInfo.HostIDs, ",")) } return neInfo } @@ -220,7 +217,7 @@ func (r *NeInfoImpl) Insert(neInfo model.NeInfo) string { for _, host := range neInfo.Hosts { host.Title = fmt.Sprintf("%s_%s_%d", strings.ToUpper(neInfo.NeType), neInfo.NeId, host.Port) host.GroupID = "1" - hostId := r.neHostRepository.Insert(host) + hostId := NewNeHostImpl.Insert(host) if hostId != "" { hostIDs = append(hostIDs, hostId) } @@ -244,7 +241,7 @@ func (r *NeInfoImpl) Update(neInfo model.NeInfo) int64 { if host.HostID != "" { host.Title = fmt.Sprintf("%s_%s_%d", strings.ToUpper(neInfo.NeType), neInfo.NeId, host.Port) host.GroupID = "1" - r.neHostRepository.Update(host) + NewNeHostImpl.Update(host) } } } @@ -269,12 +266,20 @@ func (r *NeInfoImpl) DeleteByIds(infoIds []string) (int64, error) { for _, v := range infos { // 主机信息删除 if v.HostIDs != "" { - hostIds := strings.Split(v.HostIDs, ",") - r.neHostRepository.DeleteByIds(hostIds) + NewNeHostImpl.DeleteByIds(strings.Split(v.HostIDs, ",")) + } + // 删除License + neLicense := NewNeLicenseImpl.SelectByNeTypeAndNeID(v.NeType, v.NeId) + if neLicense.NeId == v.NeId { + NewNeLicenseImpl.DeleteByIds([]string{neLicense.ID}) + } + // 删除Version + neVersion := NewNeVersionImpl.SelectByNeTypeAndNeID(v.NeType, v.NeId) + if neVersion.NeId == v.NeId { + NewNeVersionImpl.DeleteByIds([]string{neVersion.ID}) } // 缓存信息删除 - key := fmt.Sprintf("%s%s:%s", cachekey.NE_KEY, v.NeType, v.NeId) - redis.Del("", key) + redis.Del("", fmt.Sprintf("%s%s:%s", cachekey.NE_KEY, v.NeType, v.NeId)) } rows := r.neInfoRepository.DeleteByIds(infoIds) return rows, nil @@ -284,13 +289,510 @@ func (r *NeInfoImpl) DeleteByIds(infoIds []string) (int64, error) { } // CheckUniqueNeTypeAndNeId 校验同类型下标识是否唯一 -func (r *NeInfoImpl) CheckUniqueNeTypeAndNeId(neType, neId, infoId string) bool { +func (r *NeInfoImpl) CheckUniqueNeTypeAndNeId(neType, neId, id string) bool { uniqueId := r.neInfoRepository.CheckUniqueNeTypeAndNeId(model.NeInfo{ NeType: neType, NeId: neId, }) - if uniqueId == infoId { + if uniqueId == id { return true } return uniqueId == "" } + +// NeRunSSHClient 网元主机的SSH客户端-为创建相关连接,注意结束后 Close() +func (r *NeInfoImpl) NeRunSSHClient(neType, neId string) (*ssh.ConnSSH, error) { + neInfo := r.SelectNeInfoByNeTypeAndNeID(neType, neId) + if neInfo.NeId != neId { + logger.Errorf("NeRunSSHClient NeType:%s NeID:%s not found", neType, neId) + return nil, fmt.Errorf("neinfo not found") + } + // 取主机信息 + if neInfo.HostIDs == "" { + logger.Errorf("NeRunSSHClient NeType:%s NeID:%s hostId not found", neType, neId) + return nil, fmt.Errorf("neinfo hostId not found") + } + neInfo.Hosts = NewNeHostImpl.neHostRepository.SelectByIds(strings.Split(neInfo.HostIDs, ",")) + if len(neInfo.Hosts) <= 0 { + logger.Errorf("NeRunSSHClient Hosts %s not found", neInfo.HostIDs) + return nil, fmt.Errorf("neinfo host not found") + } + neHost := neInfo.Hosts[0] // 网元主机ssh 0:22 + if neHost.HostType != "ssh" { + logger.Errorf("NeRunSSHClient Hosts first HostType %s not ssh", neHost.HostType) + return nil, fmt.Errorf("neinfo host type not ssh") + } + + var connSSH ssh.ConnSSH + neHost.CopyTo(&connSSH) + var client *ssh.ConnSSH + var err error + if neHost.AuthMode == "2" { + client, err = connSSH.NewClientByLocalPrivate() + } else { + client, err = connSSH.NewClient() + } + if err != nil { + logger.Errorf("NeRunSSHClient NewClient err => %s", err.Error()) + return nil, fmt.Errorf("neinfo ssh client new err") + } + return client, nil +} + +// NeRunSSHCmd 网元主机的SSH客户端发送cmd命令 +func (r *NeInfoImpl) NeRunSSHCmd(neType, neId, cmd string) (string, error) { + sshClient, err := r.NeRunSSHClient(neType, neId) + if err != nil { + return "", err + } + defer sshClient.Close() + + // 执行命令 + output, err := sshClient.RunCMD(cmd) + if err != nil { + logger.Errorf("NeRunSSHCmd RunCMD %s err => %s", output, err.Error()) + return "", fmt.Errorf("neinfo ssh run cmd err") + } + return output, nil +} + +// NeRunTelnetClient 网元主机的Telnet客户端-为创建相关连接,注意结束后 Close() +// num 是网元主机telnet 1:4100 2:5200 +func (r *NeInfoImpl) NeRunTelnetClient(neType, neId string, num int) (*telnet.ConnTelnet, error) { + neInfo := r.SelectNeInfoByNeTypeAndNeID(neType, neId) + if neInfo.NeId != neId { + logger.Errorf("NeRunTelnetClient NeType:%s NeID:%s not found", neType, neId) + return nil, fmt.Errorf("neinfo not found") + } + // 取主机信息 + if neInfo.HostIDs == "" { + logger.Errorf("NeRunTelnetClient NeType:%s NeID:%s hostId not found", neType, neId) + return nil, fmt.Errorf("neinfo hostId not found") + } + neInfo.Hosts = NewNeHostImpl.neHostRepository.SelectByIds(strings.Split(neInfo.HostIDs, ",")) + if len(neInfo.Hosts) <= 0 { + logger.Errorf("NeRunTelnetClient Hosts %s not found", neInfo.HostIDs) + return nil, fmt.Errorf("neinfo host not found") + } + neHost := neInfo.Hosts[num] + + // 创建链接Telnet客户端 + var connTelnet telnet.ConnTelnet + neHost.CopyTo(&connTelnet) + telnetClient, err := connTelnet.NewClient() + if err != nil { + logger.Errorf("NeRunTelnetClient NewClient err => %s", err.Error()) + return nil, fmt.Errorf("neinfo telnet client new err") + } + return telnetClient, nil +} + +// neConfOAMData 网元OAM配置文件默认格式数据 +func (r *NeInfoImpl) neConfOAMData() map[string]any { + return map[string]any{ + "httpManageCfg": map[string]any{ + "ipType": "ipv4", + // 必改 + "ipv4": "172.60.5.2", + "ipv6": "", + "port": 33030, + "scheme": "http", + }, + "oamConfig": map[string]any{ + "enable": true, + "ipType": "ipv4", + "ipv4": "172.60.5.1", // 必改 + "ipv6": "", + "port": 33030, + "scheme": "http", + "neConfig": map[string]any{ // 必改 + "neId": "001", + "rmUid": "4400HX1XXX001", + "neName": "XXX_001", + "dn": "-", + "vendorName": "GD", + "province": "-", + "pvFlag": "PNF", + }, + }, + "snmpConfig": map[string]any{ + "enable": false, + "ipType": "ipv4", + "ipv4": "172.60.5.2", // 必改 + "ipv6": "", + "port": 4957, + }, + "kpiConfig": map[string]any{ + "enable": true, + "timer": 60, // 必改 + }, + // "pubConfigPath": "/usr/local/etc/conf/para5G.yaml", // 网元只会读一次后续会置空,建议不放 + } +} + +// neConfOAMRead 网元OAM配置文件读取 +func (r *NeInfoImpl) NeConfOAMRead(neType, neId string) (map[string]any, error) { + neTypeLower := strings.ToLower(neType) + // 网管本地路径 + omcPath := "/usr/local/etc/omc/ne_config" + if runtime.GOOS == "windows" { + omcPath = fmt.Sprintf("C:%s", omcPath) + } + localFilePath := fmt.Sprintf("%s/%s/%s/%s", omcPath, neTypeLower, neId, "oam_manager.yaml") + + // 读取文件内容 + bytes, err := os.ReadFile(localFilePath) + if err != nil { + // logger.Warnf("NeConfOAMRead ReadFile => %s", err.Error()) + // return nil, fmt.Errorf("read file error") + // 无保留文件时返回默认文件数据 + oamData := r.neConfOAMData() + r.neConfOAMWirte(neType, neId, oamData, false) + return oamData, nil + } + content := string(bytes) + + // 序列化Map + mapData, err := parse.ConvertConfigToMap("yaml", content) + if err != nil { + logger.Warnf("NeConfOAMRead ConvertConfigToMap => %s", err.Error()) + return nil, fmt.Errorf("content convert type error") + } + return mapData, nil +} + +// neConfOAMWirte 网元OAM配置文件写入 content内容 sync同步到网元端 +func (r *NeInfoImpl) neConfOAMWirte(neType, neId string, content any, sync bool) error { + neTypeLower := strings.ToLower(neType) + fileName := "oam_manager.yaml" + // 网管本地路径 + omcPath := "/usr/local/etc/omc/ne_config" + if runtime.GOOS == "windows" { + omcPath = fmt.Sprintf("C:%s", omcPath) + } + localFilePath := fmt.Sprintf("%s/%s/%s/%s", omcPath, neTypeLower, neId, fileName) + + // 写入文件 + if err := parse.ConvertConfigToFile("yaml", localFilePath, content); err != nil { + return fmt.Errorf("please check if the file exists or write permissions") + } + + // 同步到网元端 + if sync { + // 网元主机的SSH客户端 + sshClient, err := r.NeRunSSHClient(neType, neId) + if err != nil { + return err + } + defer sshClient.Close() + // 网元主机的SSH客户端进行文件传输 + sftpClient, err := sshClient.NewClientSFTP() + if err != nil { + return err + } + defer sftpClient.Close() + + // 网元端配置路径 + neFilePath := fmt.Sprintf("/usr/local/etc/%s/%s", neTypeLower, fileName) + neFileDir := filepath.ToSlash(filepath.Dir(neFilePath)) + // 修改网元文件权限 + sshClient.RunCMD(fmt.Sprintf("sudo mkdir -p %s && sudo chmod 775 %s && sudo touch %s && sudo chmod o+w %s", neFileDir, neFileDir, neFilePath, neFilePath)) + // 复制到网元进行覆盖 + if err = sftpClient.CopyFileLocalToRemote(localFilePath, neFilePath); err != nil { + return fmt.Errorf("please check if scp remote copy is allowed") + } + } + + return nil +} + +// NeConfOAMSync 网元OAM配置文件生成并同步 +func (r *NeInfoImpl) NeConfOAMSync(neInfo model.NeInfo, content map[string]any, sync bool) error { + oamData, err := r.NeConfOAMRead(neInfo.NeType, neInfo.NeId) + if oamData == nil || err != nil { + return fmt.Errorf("error read OAM file info") + } + // 网元HTTP服务 + if v, ok := oamData["httpManageCfg"]; ok { + item := v.(map[string]any) + item["port"] = neInfo.Port + if strings.Contains(neInfo.IP, ":") { + item["ipType"] = "ipv6" + item["ipv6"] = neInfo.IP + } + if strings.Contains(neInfo.IP, ".") { + item["ipType"] = "ipv4" + item["ipv4"] = neInfo.IP + } + + oamData["httpManageCfg"] = item + } + // 对网管HTTP配置 + if v, ok := oamData["oamConfig"]; ok { + item := v.(map[string]any) + item["neConfig"] = map[string]string{ + "neId": neInfo.NeId, + "rmUid": neInfo.RmUID, + "neName": neInfo.NeName, + "dn": neInfo.Dn, + "vendorName": neInfo.VendorName, + "province": neInfo.Province, + "pvFlag": neInfo.PvFlag, + } + + if omcIP, ok := r.Para5GData["OMC_IP"]; ok && omcIP != "" { + if strings.Contains(omcIP, ":") { + item["ipType"] = "ipv6" + item["ipv6"] = omcIP + } + if strings.Contains(omcIP, ".") { + item["ipType"] = "ipv4" + item["ipv4"] = omcIP + } + } + + if oamEnable, ok := content["oamEnable"]; ok && oamEnable != nil { + item["enable"] = parse.Boolean(oamEnable) + } + if oamPort, ok := content["oamPort"]; ok && oamPort != nil { + item["port"] = parse.Number(oamPort) + } + oamData["oamConfig"] = item + } + // 对网管SNMP配置 + if v, ok := oamData["snmpConfig"]; ok { + item := v.(map[string]any) + if strings.Contains(neInfo.IP, ":") { + item["ipType"] = "ipv6" + item["ipv6"] = neInfo.IP + } + if strings.Contains(neInfo.IP, ".") { + item["ipType"] = "ipv4" + item["ipv4"] = neInfo.IP + } + + if snmpEnable, ok := content["snmpEnable"]; ok && snmpEnable != nil { + item["enable"] = parse.Boolean(snmpEnable) + } + if snmpPort, ok := content["snmpPort"]; ok && snmpPort != nil { + item["port"] = parse.Number(snmpPort) + } + oamData["snmpConfig"] = item + } + // 对网管KPI上报配置 + if v, ok := oamData["kpiConfig"]; ok { + item := v.(map[string]any) + if neInfo.NeType == "UPF" { + item["timer"] = 5 + } + + if kpiEnable, ok := content["kpiEnable"]; ok && kpiEnable != nil { + item["enable"] = parse.Boolean(kpiEnable) + } + if kpiTimer, ok := content["kpiTimer"]; ok && kpiTimer != nil { + item["timer"] = parse.Number(kpiTimer) + } + oamData["kpiConfig"] = item + } + if err := NewNeInfoImpl.neConfOAMWirte(neInfo.NeType, neInfo.NeId, oamData, sync); err != nil { + return fmt.Errorf("error wirte OAM file info") + } + return nil +} + +// NeConfPara5GRead 网元公共配置文件读取 +func (r *NeInfoImpl) NeConfPara5GRead() (map[string]any, error) { + // 网管本地路径 + omcFilePath := "/usr/local/etc/omc/para5G.yaml" + if runtime.GOOS == "windows" { + omcFilePath = fmt.Sprintf("C:%s", omcFilePath) + } + // 读取文件内容 + bytes, err := os.ReadFile(omcFilePath) + if err != nil { + logger.Warnf("NeConfPara5GRead ReadFile => %s", err.Error()) + return nil, fmt.Errorf("read file error") + } + content := string(bytes) + + // 序列化Map + mapData, err := parse.ConvertConfigToMap("yaml", content) + if err != nil { + logger.Warnf("NeConfPara5GRead ConvertConfigToMap => %s", err.Error()) + return nil, fmt.Errorf("content convert type error") + } + return mapData, nil +} + +// NeConfPara5GWirte 网元公共配置文件写入 content内容 syncNE同步到网元端NeType@NeId +func (r *NeInfoImpl) NeConfPara5GWirte(content map[string]any, syncNE []string) error { + // 网管本地路径 + omcFilePath := "/usr/local/etc/omc/para5G.yaml" + if runtime.GOOS == "windows" { + omcFilePath = fmt.Sprintf("C:%s", omcFilePath) + } + + if err := parse.ConvertConfigToFile("yaml", omcFilePath, content); err != nil { + return fmt.Errorf("please check if the file exists or write permissions") + } + + // 同步到网元端 + if len(syncNE) > 0 { + errMsg := []string{} + for _, neTI := range syncNE { + ti := strings.SplitN(neTI, "@", 2) + // 网元主机的SSH客户端 + sshClient, err := r.NeRunSSHClient(ti[0], ti[1]) + if err != nil { + errMsg = append(errMsg, fmt.Sprintf("%s : %s", ti, err.Error())) + continue + } + defer sshClient.Close() + // 网元主机的SSH客户端进行文件传输 + sftpClient, err := sshClient.NewClientSFTP() + if err != nil { + errMsg = append(errMsg, fmt.Sprintf("%s : %s", ti, err.Error())) + continue + } + defer sftpClient.Close() + + // 网元端配置路径 + neFilePath := "/usr/local/etc/conf/para5G.yaml" + neFileDir := filepath.ToSlash(filepath.Dir(neFilePath)) + // 修改网元文件权限 + sshClient.RunCMD(fmt.Sprintf("sudo mkdir -p %s && sudo chmod 775 %s && sudo touch %s && sudo chmod o+rw %s", neFileDir, neFileDir, neFilePath, neFilePath)) + // 复制到网元进行覆盖 + if err = sftpClient.CopyFileLocalToRemote(omcFilePath, neFilePath); err != nil { + errMsg = append(errMsg, fmt.Sprintf("%s : please check if scp remote copy is allowed", ti)) + continue + } + } + if len(errMsg) > 0 { + return fmt.Errorf(strings.Join(errMsg, "\r\n")) + } + } + + // 转换一份数据到全局 + r.Para5GData = r.neConfPara5GDataConvert(content) + return nil +} + +// NeConfPara5GConvert 网元公共配置数据转化 content网元公共配置文件读取内容 +func (r *NeInfoImpl) neConfPara5GDataConvert(content map[string]any) map[string]string { + defer func() { + if err := recover(); err != nil { + logger.Errorf("NeConfPara5GDataConvert panic: %v", err) + // 文件异常就删除配置 + omcFilePath := "/usr/local/etc/omc/para5G.yaml" + if runtime.GOOS == "windows" { + omcFilePath = fmt.Sprintf("C:%s", omcFilePath) + } + os.Remove(omcFilePath) + } + }() + + basic := content["basic"].(map[string]any) + external := content["external"].(map[string]any) + sbi := content["sbi"].(map[string]any) + + mcc := "460" + mnc := "01" + mncDomain := "001" + if plmnId, plmnIdOk := basic["plmnId"].(map[string]any); plmnIdOk { + mcc = plmnId["mcc"].(string) + mnc = plmnId["mnc"].(string) + // If a user input two digit MNC, add a leading zero + if len(mnc) == 2 { + mncDomain = fmt.Sprintf("0%s", mnc) + } else { + mncDomain = mnc + } + } + + sst := "1" + sd := "000001" + if plmnId, plmnIdOk := basic["snssai"].(map[string]any); plmnIdOk { + sst = plmnId["sst"].(string) + sd = plmnId["sd"].(string) + } + + n3IPAmdMask := external["upfn3_ip"].(string) + n3Arr := strings.SplitN(n3IPAmdMask, "/", 2) + n3IP := n3Arr[0] + n3Mask := "255.255.255.0" + if len(n3Arr) > 1 { + n3Mask = parse.ConvertIPMask(parse.Number(n3Arr[1])) + } + + n6IPAmdMask := external["upfn6_ip"].(string) + n6Arr := strings.SplitN(n6IPAmdMask, "/", 2) + n6IP := n6Arr[0] + n6Mask := "255.255.255.0" + if len(n6Arr) > 1 { + n6Mask = parse.ConvertIPMask(parse.Number(n6Arr[1])) + } + + ueIPAmdMask := external["ue_pool"].(string) + ueArr := strings.SplitN(ueIPAmdMask, "/", 2) + ueIP := ueArr[0] + ueCicr := "24" + ueMask := "255.255.255.0" + if len(ueArr) > 1 { + ueCicr = ueArr[1] + ueMask = parse.ConvertIPMask(parse.Number(ueArr[1])) + } + + return map[string]string{ + // basic + "TAC": basic["tac"].(string), + "MCC": mcc, + "MNC": mnc, + "MNC_DOMAIN": mncDomain, + "SST": sst, + "SD": sd, + "DNN_DATA": basic["dnn_data"].(string), + "DNN_IMS": basic["dnn_ims"].(string), + + // external + "N2_IP": external["amfn2_ip"].(string), + "UE_POOL": external["ue_pool"].(string), + "UE_IP": ueIP, + "UE_MASK": ueMask, + "UE_CIDR": ueCicr, + "UPF_TYPE": external["upf_type"].(string), // StandardUPF LightUPF + "N3_IP": n3IP, + "N3_MASK": n3Mask, + "N3_GW": external["upfn3_gw"].(string), + "N3_PCI": external["upfn3_pci"].(string), + "N3_MAC": external["upfn3_mac"].(string), + "N6_IP": n6IP, + "N6_MASK": n6Mask, + "N6_GW": external["upfn6_gw"].(string), + "N6_PCI": external["upfn6_pci"].(string), + "N6_MAC": external["upfn6_mac"].(string), + + "SIP_IP": external["ims_sip_ip"].(string), + + "S1_MMEIP": external["mmes1_ip"].(string), + "S11_MMEIP": external["mmes11_ip"].(string), + "S10_MMEIP": external["mmes10_ip"].(string), + + // sbi + "OMC_IP": sbi["omc_ip"].(string), + "IMS_IP": sbi["ims_ip"].(string), + "AMF_IP": sbi["amf_ip"].(string), + "AUSF_IP": sbi["ausf_ip"].(string), + "UDM_IP": sbi["udm_ip"].(string), + "SMF_IP": sbi["smf_ip"].(string), + "PCF_IP": sbi["pcf_ip"].(string), + "NSSF_IP": sbi["nssf_ip"].(string), + "NRF_IP": sbi["nrf_ip"].(string), + "UPF_IP": sbi["upf_ip"].(string), + "LMF_IP": sbi["lmf_ip"].(string), + "NEF_IP": sbi["nef_ip"].(string), + "MME_IP": sbi["mme_ip"].(string), + "N3IWF_IP": sbi["n3iwf_ip"].(string), + + "DB_IP": sbi["db_ip"].(string), + } +} diff --git a/src/modules/network_element/service/ne_license.go b/src/modules/network_element/service/ne_license.go new file mode 100644 index 0000000..6dc8a35 --- /dev/null +++ b/src/modules/network_element/service/ne_license.go @@ -0,0 +1,34 @@ +package service + +import "nms_cxy/src/modules/network_element/model" + +// INeLicense 网元授权激活信息 服务层接口 +type INeLicense interface { + // SelectPage 根据条件分页查询字典类型 + SelectPage(query map[string]any) map[string]any + + // SelectList 根据实体查询 + SelectList(neLicense model.NeLicense) []model.NeLicense + + // SelectById 通过ID查询 + SelectById(id string) model.NeLicense + + // Insert 新增信息 + Insert(neLicense model.NeLicense) string + + // Update 修改信息 + Update(neLicense model.NeLicense) int64 + + // DeleteByIds 批量删除信息 + DeleteByIds(ids []string) (int64, error) + + // SelectByNeTypeAndNeID 通过ne_type和ne_id查询信息 + SelectByNeTypeAndNeID(neType, neId string) model.NeLicense + + // ReadLicenseInfo 读取授权文件信息 + // 返回激活申请码, 激活文件 + ReadLicenseInfo(neLicense model.NeLicense) (string, string) + + // UploadLicense 授权文件上传到网元主机 + UploadLicense(neLicense model.NeLicense) error +} diff --git a/src/modules/network_element/service/ne_license.impl.go b/src/modules/network_element/service/ne_license.impl.go new file mode 100644 index 0000000..8cd4698 --- /dev/null +++ b/src/modules/network_element/service/ne_license.impl.go @@ -0,0 +1,191 @@ +package service + +import ( + "fmt" + "os" + "path/filepath" + "runtime" + "strings" + "time" + + "nms_cxy/src/framework/utils/file" + "nms_cxy/src/modules/network_element/model" + "nms_cxy/src/modules/network_element/repository" +) + +// 实例化服务层 NeLicenseImpl 结构体 +var NewNeLicenseImpl = &NeLicenseImpl{ + neLicenseRepository: repository.NewNeLicenseImpl, +} + +// NeLicenseImpl 网元授权激活信息 服务层处理 +type NeLicenseImpl struct { + // 网元授权激活信息表 + neLicenseRepository repository.INeLicense +} + +// SelectNeHostPage 分页查询列表数据 +func (r *NeLicenseImpl) SelectPage(query map[string]any) map[string]any { + return r.neLicenseRepository.SelectPage(query) +} + +// SelectConfigList 查询列表 +func (r *NeLicenseImpl) SelectList(neLicense model.NeLicense) []model.NeLicense { + return r.neLicenseRepository.SelectList(neLicense) +} + +// SelectByIds 通过ID查询 +func (r *NeLicenseImpl) SelectById(id string) model.NeLicense { + if id == "" { + return model.NeLicense{} + } + neLicenses := r.neLicenseRepository.SelectByIds([]string{id}) + if len(neLicenses) > 0 { + return neLicenses[0] + } + return model.NeLicense{} +} + +// Insert 新增信息 +func (r *NeLicenseImpl) Insert(neLicense model.NeLicense) string { + return r.neLicenseRepository.Insert(neLicense) +} + +// Update 修改信息 +func (r *NeLicenseImpl) Update(neLicense model.NeLicense) int64 { + return r.neLicenseRepository.Update(neLicense) +} + +// DeleteByIds 批量删除信息 +func (r *NeLicenseImpl) DeleteByIds(ids []string) (int64, error) { + // 检查是否存在 + rowIds := r.neLicenseRepository.SelectByIds(ids) + if len(rowIds) <= 0 { + return 0, fmt.Errorf("neLicense.noData") + } + + if len(rowIds) == len(ids) { + rows := r.neLicenseRepository.DeleteByIds(ids) + return rows, nil + } + // 删除信息失败! + return 0, fmt.Errorf("delete fail") +} + +// SelectByTypeAndID 通过网元类型和网元ID查询 +func (r *NeLicenseImpl) SelectByTypeAndID(neType, neId string) model.NeLicense { + neLicenses := r.neLicenseRepository.SelectList(model.NeLicense{ + NeType: neType, + NeId: neId, + }) + if len(neLicenses) > 0 { + return neLicenses[0] + } + return model.NeLicense{} +} + +// SelectByNeTypeAndNeID 通过ne_type和ne_id查询信息 +func (r *NeLicenseImpl) SelectByNeTypeAndNeID(neType, neId string) model.NeLicense { + neLicenses := r.neLicenseRepository.SelectList(model.NeLicense{ + NeType: neType, + NeId: neId, + }) + if len(neLicenses) > 0 { + return neLicenses[0] + } + return model.NeLicense{} +} + +// ReadLicenseInfo 读取授权文件信息 +// 返回激活申请码, 激活文件 +func (r *NeLicenseImpl) ReadLicenseInfo(neLicense model.NeLicense) (string, string) { + neTypeLower := strings.ToLower(neLicense.NeType) + // 网管本地路径 + omcPath := "/usr/local/etc/omc/ne_license" + if runtime.GOOS == "windows" { + omcPath = fmt.Sprintf("C:%s", omcPath) + } + omcPath = fmt.Sprintf("%s/%s/%s", omcPath, neTypeLower, neLicense.NeId) + // 网元端授权文件路径 + nePath := fmt.Sprintf("/usr/local/etc/%s/license", neTypeLower) + + // 网元主机的SSH客户端 + sshClient, err := NewNeInfoImpl.NeRunSSHClient(neLicense.NeType, neLicense.NeId) + if err != nil { + return "", "" + } + defer sshClient.Close() + // 网元主机的SSH客户端进行文件传输 + sftpClient, err := sshClient.NewClientSFTP() + if err != nil { + return "", "" + } + defer sftpClient.Close() + + // 复制授权申请码到本地 + if err = sftpClient.CopyFileRemoteToLocal(nePath+"/Activation_request_code.txt", omcPath+"/Activation_request_code.txt"); err != nil { + return "", "" + } + // 读取文件内容 + bytes, err := os.ReadFile(omcPath + "/Activation_request_code.txt") + if err != nil { + return "", "" + } + + // 复制激活文件到本地 + licensePath := "" + if err = sftpClient.CopyFileRemoteToLocal(nePath+"/system.ini", omcPath+"/system.ini"); err == nil { + licensePath = omcPath + "/system.ini" + } + return strings.TrimSpace(string(bytes)), licensePath +} + +// UploadLicense 授权文件上传到网元主机 +func (r *NeLicenseImpl) UploadLicense(neLicense model.NeLicense) error { + // 检查文件是否存在 + omcLicensePath := file.ParseUploadFilePath(neLicense.LicensePath) + if _, err := os.Stat(omcLicensePath); err != nil { + return fmt.Errorf("file read failure") + } + + // 网元主机的SSH客户端 + sshClient, err := NewNeInfoImpl.NeRunSSHClient(neLicense.NeType, neLicense.NeId) + if err != nil { + return err + } + defer sshClient.Close() + // 网元主机的SSH客户端进行文件传输 + sftpClient, err := sshClient.NewClientSFTP() + if err != nil { + return err + } + defer sftpClient.Close() + + // 网元端授权文件路径 + neTypeLower := strings.ToLower(neLicense.NeType) + neLicensePath := fmt.Sprintf("/usr/local/etc/%s/license/system.ini", neTypeLower) + neLicenseDir := filepath.ToSlash(filepath.Dir(neLicensePath)) + // 修改网元文件权限 + sshClient.RunCMD(fmt.Sprintf("sudo mkdir -p %s && sudo chmod 775 %s && sudo touch %s && sudo chmod o+rw %s", neLicenseDir, neLicenseDir, neLicensePath, neLicensePath)) + + // 尝试备份授权文件 + neLicensePathBack := fmt.Sprintf("%s/system_%s.ini", neLicensePath, time.Now().Format("20060102_150405")) + sshClient.RunCMD(fmt.Sprintf("sudo cp -rf %s/system.ini %s", neLicensePath, neLicensePathBack)) + + // 上传授权文件去覆盖 + if err := sftpClient.CopyFileLocalToRemote(omcLicensePath, neLicensePath); err != nil { + return fmt.Errorf("please check if scp remote copy is allowed") + } + + // 重启服务 + if neLicense.Reload { + cmdStr := fmt.Sprintf("sudo service %s restart", neTypeLower) + if neTypeLower == "ims" { + cmdStr = "ims-stop || true && ims-start" + } else if neTypeLower == "omc" { + cmdStr = "sudo systemctl restart restagent" + } + sshClient.RunCMD(cmdStr) + } + return nil +} diff --git a/src/modules/network_element/service/ne_software.go b/src/modules/network_element/service/ne_software.go index 77bac86..2f52dbc 100644 --- a/src/modules/network_element/service/ne_software.go +++ b/src/modules/network_element/service/ne_software.go @@ -22,12 +22,9 @@ type INeSoftware interface { // DeleteByIds 批量删除信息 DeleteByIds(ids []string) (int64, error) - // SelectByVersionAndPath 通过文件版本和路径查询 - SelectByVersionAndPath(version, path string) model.NeSoftware + // CheckUniqueTypeAndNameAndVersion 校验网元类型和文件名版本是否唯一 + CheckUniqueTypeAndNameAndVersion(neType, name, version, id string) bool - // CheckUniqueTypeAndFileNameAndVersion 校验网元类型和文件名版本是否唯一 - CheckUniqueTypeAndFileNameAndVersion(neType, fileName, version, id string) bool - - // Install 安装软件包 - Install(neSoftware model.NeSoftware) (string, error) + // UpdateVersions 更新软件包对应网元的新版本 + UpdateVersions(neSoftware model.NeSoftware, neVersion model.NeVersion) int64 } diff --git a/src/modules/network_element/service/ne_software.impl.go b/src/modules/network_element/service/ne_software.impl.go index 8851e85..f23ca01 100644 --- a/src/modules/network_element/service/ne_software.impl.go +++ b/src/modules/network_element/service/ne_software.impl.go @@ -2,7 +2,9 @@ package service import ( "fmt" + "os" + "nms_cxy/src/framework/utils/file" "nms_cxy/src/modules/network_element/model" "nms_cxy/src/modules/network_element/repository" ) @@ -42,48 +44,79 @@ func (r *NeSoftwareImpl) SelectById(id string) model.NeSoftware { // Insert 新增信息 func (r *NeSoftwareImpl) Insert(neSoftware model.NeSoftware) string { - return r.neSoftwareRepository.Insert(neSoftware) + inserId := r.neSoftwareRepository.Insert(neSoftware) + if inserId != "" { + // 更新同类型的新包版本 + neVersions := NewNeVersionImpl.SelectList(model.NeVersion{NeType: neSoftware.NeType}) + if len(neVersions) > 0 { + for _, neVersion := range neVersions { + neVersion.NewName = neSoftware.Name + neVersion.NewVersion = neSoftware.Version + neVersion.NewPath = neSoftware.Path + neVersion.Status = "3" + neVersion.UpdateBy = neSoftware.CreateBy + NewNeVersionImpl.Update(neVersion) + } + } + } + return inserId } // Update 修改信息 func (r *NeSoftwareImpl) Update(neSoftware model.NeSoftware) int64 { - return r.neSoftwareRepository.Update(neSoftware) + rows := r.neSoftwareRepository.Update(neSoftware) + if rows > 0 { + // 更新同类型的新包版本 + neVersions := NewNeVersionImpl.SelectList(model.NeVersion{ + NeType: neSoftware.NeType, + Status: "3", + }) + if len(neVersions) > 0 { + for _, neVersion := range neVersions { + neVersion.NewName = neSoftware.Name + neVersion.NewVersion = neSoftware.Version + neVersion.NewPath = neSoftware.Path + neVersion.Status = "3" + neVersion.UpdateBy = neSoftware.UpdateBy + NewNeVersionImpl.Update(neVersion) + } + } + } + return rows } // DeleteByIds 批量删除信息 func (r *NeSoftwareImpl) DeleteByIds(ids []string) (int64, error) { // 检查是否存在 - rowIds := r.neSoftwareRepository.SelectByIds(ids) - if len(rowIds) <= 0 { + rows := r.neSoftwareRepository.SelectByIds(ids) + if len(rows) <= 0 { return 0, fmt.Errorf("neSoftware.noData") } - if len(rowIds) == len(ids) { + if len(rows) == len(ids) { + // 遍历软件包列表进行文件删除 + for _, row := range rows { + // 检查文件是否存在 + filePath := file.ParseUploadFilePath(row.Path) + if _, err := os.Stat(filePath); err != nil { + continue + } + os.Remove(filePath) + } rows := r.neSoftwareRepository.DeleteByIds(ids) return rows, nil } + // 删除信息失败! return 0, fmt.Errorf("delete fail") } -// SelectByVersionAndPath 通过文件版本和路径查询 -func (r *NeSoftwareImpl) SelectByVersionAndPath(version, path string) model.NeSoftware { - neSoftwares := r.neSoftwareRepository.SelectList(model.NeSoftware{ +// CheckUniqueTypeAndNameAndVersion 校验网元类型和文件名版本是否唯一 +func (r *NeSoftwareImpl) CheckUniqueTypeAndNameAndVersion(neType, name, version, id string) bool { + uniqueId := r.neSoftwareRepository.CheckUniqueTypeAndNameAndVersion(model.NeSoftware{ + NeType: neType, + Name: name, Version: version, - Path: path, - }) - if len(neSoftwares) > 0 { - return neSoftwares[0] - } - return model.NeSoftware{} -} - -// CheckUniqueTypeAndFileNameAndVersion 校验网元类型和文件名版本是否唯一 -func (r *NeSoftwareImpl) CheckUniqueTypeAndFileNameAndVersion(neType, fileName, version, id string) bool { - uniqueId := r.neSoftwareRepository.CheckUniqueTypeAndFileNameAndVersion(model.NeSoftware{ - NeType: neType, - FileName: fileName, - Version: version, }) if uniqueId == id { return true @@ -91,7 +124,20 @@ func (r *NeSoftwareImpl) CheckUniqueTypeAndFileNameAndVersion(neType, fileName, return uniqueId == "" } -// Install 安装软件包 -func (r *NeSoftwareImpl) Install(neSoftware model.NeSoftware) (string, error) { - return "", nil +// UpdateVersions 更新软件包对应网元的新版本 +func (r *NeSoftwareImpl) UpdateVersions(neSoftware model.NeSoftware, neVersion model.NeVersion) int64 { + var rows int64 = 0 + // 更新同类型的新包版本 + neVersions := NewNeVersionImpl.SelectList(neVersion) + if len(neVersions) > 0 { + for _, v := range neVersions { + v.NewName = neSoftware.Name + v.NewVersion = neSoftware.Version + v.NewPath = neSoftware.Path + v.Status = "3" + v.UpdateBy = neVersion.UpdateBy + rows += NewNeVersionImpl.Update(v) + } + } + return rows } diff --git a/src/modules/network_element/service/ne_version.go b/src/modules/network_element/service/ne_version.go index 9e7ac0c..b4cacdc 100644 --- a/src/modules/network_element/service/ne_version.go +++ b/src/modules/network_element/service/ne_version.go @@ -22,9 +22,11 @@ type INeVersion interface { // DeleteByIds 批量删除信息 DeleteByIds(ids []string) (int64, error) - // SelectByTypeAndID 通过网元类型和网元ID查询 - SelectByTypeAndID(neType, neId string) model.NeVersion + // SelectByNeTypeAndNeID 通过网元类型和网元ID查询 + SelectByNeTypeAndNeID(neType, neId string) model.NeVersion - // CheckUniqueTypeAndID 校验网元类型和网元ID是否唯一 - CheckUniqueTypeAndID(neType, neId, id string) bool + // Operate 操作版本上传到网元主机执行命令 + // + // action 安装行为:install upgrade rollback + Operate(action string, neVersion model.NeVersion, preinput map[string]string) (string, error) } diff --git a/src/modules/network_element/service/ne_version.impl.go b/src/modules/network_element/service/ne_version.impl.go index 2853db2..272443d 100644 --- a/src/modules/network_element/service/ne_version.impl.go +++ b/src/modules/network_element/service/ne_version.impl.go @@ -2,7 +2,14 @@ package service import ( "fmt" + "os" + "path/filepath" + "strings" + "time" + "nms_cxy/src/framework/logger" + "nms_cxy/src/framework/utils/file" + "nms_cxy/src/framework/utils/ssh" "nms_cxy/src/modules/network_element/model" "nms_cxy/src/modules/network_element/repository" ) @@ -66,8 +73,8 @@ func (r *NeVersionImpl) DeleteByIds(ids []string) (int64, error) { return 0, fmt.Errorf("delete fail") } -// SelectByTypeAndID 通过网元类型和网元ID查询 -func (r *NeVersionImpl) SelectByTypeAndID(neType, neId string) model.NeVersion { +// SelectByNeTypeAndNeID 通过网元类型和网元ID查询 +func (r *NeVersionImpl) SelectByNeTypeAndNeID(neType, neId string) model.NeVersion { neVersions := r.neVersionRepository.SelectList(model.NeVersion{ NeType: neType, NeId: neId, @@ -78,14 +85,561 @@ func (r *NeVersionImpl) SelectByTypeAndID(neType, neId string) model.NeVersion { return model.NeVersion{} } -// CheckUniqueTypeAndID 校验网元类型和网元ID是否唯一 -func (r *NeVersionImpl) CheckUniqueTypeAndID(neType, neId, id string) bool { - uniqueId := r.neVersionRepository.CheckUniqueTypeAndID(model.NeVersion{ - NeType: neType, - NeId: neId, - }) - if uniqueId == id { - return true +// Operate 操作版本上传到网元主机执行命令 +// +// action 安装行为:install upgrade rollback +func (r *NeVersionImpl) Operate(action string, neVersion model.NeVersion, preinput map[string]string) (string, error) { + // 网元主机的SSH客户端 + sshClient, err := NewNeInfoImpl.NeRunSSHClient(neVersion.NeType, neVersion.NeId) + if err != nil { + return "", err } - return uniqueId == "" + defer sshClient.Close() + + // ========= 文件传输阶段 ========= + softwarePath := neVersion.Path + if action == "install" || action == "upgrade" { + softwarePath = neVersion.NewPath + } + if action == "rollback" { + softwarePath = neVersion.PrePath + } + neFilePaths, err := r.operateFile(sshClient, softwarePath) + if err != nil { + return "", err + } + + // ========= 安装时设置 ========= + if action == "install" { + // 网元公共配置文件 + para5GMap, err := NewNeInfoImpl.NeConfPara5GRead() + if para5GMap == nil || err != nil { + return "", fmt.Errorf("error read para5G file info") + } + if err := NewNeInfoImpl.NeConfPara5GWirte(para5GMap, []string{fmt.Sprintf("%s@%s", neVersion.NeType, neVersion.NeId)}); err != nil { + return "", fmt.Errorf("error wirte para5G file info") + } + } + + // ========= 命令生成阶段 ========= + okFlagStr, cmdStrArr, err := r.operateCommand(action, neVersion.NeType, neFilePaths) + if err != nil { + return "", err + } + + // ========= 执行阶段 ========= + commandLine, err := r.operateRun(sshClient, preinput, cmdStrArr, neVersion.NeType, okFlagStr) + if err != nil { + return "", err + } + + // ========= 完成阶段 ========= + if strings.LastIndex(commandLine, okFlagStr) > 5 { + if err := r.operateDome(action, neVersion); err != nil { + return "", err + } + } + return commandLine, nil +} + +// operateDome 操作版本-文件传输阶段 +func (r *NeVersionImpl) operateFile(sshClient *ssh.ConnSSH, softwarePath string) ([]string, error) { + // 网元主机的SSH客户端进行文件传输 + sftpClient, err := sshClient.NewClientSFTP() + if err != nil { + return nil, err + } + defer sftpClient.Close() + + nePath := "/tmp" + copyFileToNeMap := map[string]string{} + + // 统一处理多个文件和单个文件的情况 + var softwarePaths []string + if strings.Contains(softwarePath, ",") { + softwarePaths = strings.Split(softwarePath, ",") + } else { + softwarePaths = []string{softwarePath} + } + + for _, path := range softwarePaths { + // 检查文件是否存在 + localFilePath := file.ParseUploadFilePath(path) + if _, err := os.Stat(localFilePath); err != nil { + return nil, fmt.Errorf("file read failure") + } + + fileName := filepath.Base(path) + neFilePath := fmt.Sprintf("%s/%s", nePath, fileName) + copyFileToNeMap[localFilePath] = neFilePath + } + + // 上传软件包到 /tmp + neFilePaths := []string{} + for k, v := range copyFileToNeMap { + if err = sftpClient.CopyFileLocalToRemote(k, v); err != nil { + return nil, fmt.Errorf("error uploading package") + } + neFilePaths = append(neFilePaths, v) + } + return neFilePaths, nil +} + +// operateDome 操作版本-命令生成阶段 +func (r *NeVersionImpl) operateCommand(action, neType string, neFilePaths []string) (string, []string, error) { + neTypeLower := strings.ToLower(neType) + // 命令终止结束标记 + okFlagStr := fmt.Sprintf("%s version %s successful!", neTypeLower, action) + // 安装软件包 + pkgCmdStr := fmt.Sprintf("sudo dpkg -i %s", strings.Join(neFilePaths, " ")) + fileExt := filepath.Ext(strings.ToLower(neFilePaths[0])) + if strings.HasSuffix(fileExt, "rpm") { + pkgCmdStr = fmt.Sprintf("sudo rpm -Uvh %s", strings.Join(neFilePaths, " ")) + } + + // 组合命令输入 + cmdStrArr := []string{} + if neType == "OMC" { + omcStrArr := []string{} + omcStrArr = append(omcStrArr, pkgCmdStr) + if action == "install" { + omcStrArr = append(omcStrArr, "sudo /usr/local/omc/bin/setomc.sh -m install") // 初始化数据库 + } else { + omcStrArr = append(omcStrArr, "sudo /usr/local/omc/bin/setomc.sh -m upgrade") // 升级数据库 + } + omcStrArr = append(omcStrArr, "sudo systemctl restart restagent") // 重启服务 + omcStrArr = append(omcStrArr, fmt.Sprintf("sudo rm %s", strings.Join(neFilePaths, " "))) // 删除软件包 + + // 2s后安装 + cmdStrArr = append(cmdStrArr, fmt.Sprintf("nohup sh -c \"sleep 2s && %s\" > /dev/null 2>&1 & \n", strings.Join(omcStrArr, " && "))) + // 结束 + cmdStrArr = append(cmdStrArr, fmt.Sprintf("echo '%s' \n", okFlagStr)) + return okFlagStr, cmdStrArr, nil + } else if neType == "IMS" { + if action == "install" { + para5GData := NewNeInfoImpl.Para5GData + cmdStrArr = append(cmdStrArr, pkgCmdStr+" \n") + + // 公网 PLMN地址 + cmdStrArr = append(cmdStrArr, fmt.Sprintf("/usr/local/etc/ims/default/tools/modipplmn.sh %s %s %s \n", para5GData["SIP_IP"], para5GData["MCC"], para5GData["MNC"])) + // 内网 服务地址 + cmdStrArr = append(cmdStrArr, fmt.Sprintf("/usr/local/etc/ims/default/tools/modintraip.sh %s \n", para5GData["IMS_IP"])) + // IWF连接PCF服务 + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/172.16.5.160/%s/g\" /usr/local/etc/iwf/iwf_conf.yaml \n", para5GData["PCF_IP"])) + // 设置 HOST + cmdStrArr = append(cmdStrArr, fmt.Sprintf("grep -qxF '%s ims' /etc/hosts || echo '%s ims' | sudo tee -a /etc/hosts \n", para5GData["IMS_IP"], para5GData["IMS_IP"])) + mnc_mcc := fmt.Sprintf("mnc%s.mcc%s", para5GData["MNC_DOMAIN"], para5GData["MCC"]) + hssHost := fmt.Sprintf("%s hss.ims.%s.3gppnetwork.org hss", para5GData["UDM_IP"], mnc_mcc) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("grep -qxF '%s' /etc/hosts || echo '%s' | sudo tee -a /etc/hosts \n", hssHost, hssHost)) + pcrfHost := fmt.Sprintf("%s pcrf.epc.%s.3gppnetwork.org pcrf", para5GData["IMS_IP"], mnc_mcc) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("grep -qxF '%s' /etc/hosts || echo '%s' | sudo tee -a /etc/hosts \n", pcrfHost, pcrfHost)) + imsOrgHost := fmt.Sprintf("ims.%s.3gppnetwork.org", mnc_mcc) + imsHost := fmt.Sprintf("%s %s ims", para5GData["SIP_IP"], imsOrgHost) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("grep -qxF '%s' /etc/hosts || echo '%s' | sudo tee -a /etc/hosts \n", imsHost, imsHost)) + pcscfHost := fmt.Sprintf("%s pcscf.%s pcscf", para5GData["SIP_IP"], imsOrgHost) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("grep -qxF '%s' /etc/hosts || echo '%s' | sudo tee -a /etc/hosts \n", pcscfHost, pcscfHost)) + icscfHost := fmt.Sprintf("%s icscf.%s icscf", para5GData["SIP_IP"], imsOrgHost) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("grep -qxF '%s' /etc/hosts || echo '%s' | sudo tee -a /etc/hosts \n", icscfHost, icscfHost)) + scscfHost := fmt.Sprintf("%s scscf.%s scscf", para5GData["SIP_IP"], imsOrgHost) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("grep -qxF '%s' /etc/hosts || echo '%s' | sudo tee -a /etc/hosts \n", scscfHost, scscfHost)) + mmtelHost := fmt.Sprintf("%s mmtel.%s mmtel", para5GData["SIP_IP"], imsOrgHost) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("grep -qxF '%s' /etc/hosts || echo '%s' | sudo tee -a /etc/hosts \n", mmtelHost, mmtelHost)) + mrfcHost := fmt.Sprintf("%s mrfc.%s mrfc", para5GData["SIP_IP"], imsOrgHost) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("grep -qxF '%s' /etc/hosts || echo '%s' | sudo tee -a /etc/hosts \n", mrfcHost, mrfcHost)) + smsHost := fmt.Sprintf("%s smsc.%s smsc", para5GData["SIP_IP"], imsOrgHost) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("grep -qxF '%s' /etc/hosts || echo '%s' | sudo tee -a /etc/hosts \n", smsHost, smsHost)) + + cmdStrArr = append(cmdStrArr, "ims-stop || true && ims-start \n") + // 30s后停止服务 + // cmdStrArr = append(cmdStrArr, "nohup sh -c \"sleep 30s && sudo ims-stop\" > /dev/null 2>&1 & \n") + } else { + cmdStrArr = append(cmdStrArr, "ims-stop \n") + cmdStrArr = append(cmdStrArr, pkgCmdStr+" \n") + cmdStrArr = append(cmdStrArr, "ims-start \n") + } + } else { + if action == "install" { + para5GData := NewNeInfoImpl.Para5GData + cmdStrArr = append(cmdStrArr, pkgCmdStr+" \n") + + // AMF配置修改 + if neTypeLower == "amf" { + cmdStrArr = append(cmdStrArr, "sudo cp /usr/local/etc/amf/default/amfcfg.yaml /usr/local/etc/amf/amfcfg.yaml \n") + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/172.16.5.120/%s/g\" /usr/local/etc/amf/amfcfg.yaml \n", para5GData["AMF_IP"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/192.168.8.120/%s/g\" /usr/local/etc/amf/amfcfg.yaml \n", para5GData["N2_IP"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/mcc: 001/mcc: %s/g\" /usr/local/etc/amf/amfcfg.yaml \n", para5GData["MCC"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/mnc: 01/mnc: %s/g\" /usr/local/etc/amf/amfcfg.yaml \n", para5GData["MNC"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/sst: 1/sst: %s/g\" /usr/local/etc/amf/amfcfg.yaml \n", para5GData["SST"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/sd: 000001/sd: %s/g\" /usr/local/etc/amf/amfcfg.yaml \n", para5GData["SD"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/- 4388/- %s/g\" /usr/local/etc/amf/amfcfg.yaml \n", para5GData["TAC"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/172.16.5.130/%s/g\" /usr/local/etc/amf/amfcfg.yaml \n", para5GData["AUSF_IP"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/172.16.5.140/%s/g\" /usr/local/etc/amf/amfcfg.yaml \n", para5GData["UDM_IP"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/172.16.5.150/%s/g\" /usr/local/etc/amf/amfcfg.yaml \n", para5GData["SMF_IP"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/172.16.5.160/%s/g\" /usr/local/etc/amf/amfcfg.yaml \n", para5GData["PCF_IP"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/172.16.5.180/%s/g\" /usr/local/etc/amf/amfcfg.yaml \n", para5GData["NRF_IP"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/172.16.5.200/%s/g\" /usr/local/etc/amf/amfcfg.yaml \n", para5GData["LMF_IP"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/172.16.5.210/%s/g\" /usr/local/etc/amf/amfcfg.yaml \n", para5GData["NEF_IP"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/- internet/- %s/g\" /usr/local/etc/amf/amfcfg.yaml \n", para5GData["DNN_DATA"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("grep -qxF '%s n2' /etc/hosts || echo '%s n2' | sudo tee -a /etc/hosts \n", para5GData["N2_IP"], para5GData["N2_IP"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("grep -qxF '%s amf' /etc/hosts || echo '%s amf' | sudo tee -a /etc/hosts \n", para5GData["AMF_IP"], para5GData["AMF_IP"])) + } + // AUSF配置修改 + if neTypeLower == "ausf" { + cmdStrArr = append(cmdStrArr, "sudo cp /usr/local/etc/ausf/default/ausfcfg.yaml /usr/local/etc/ausf/ausfcfg.yaml \n") + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/172.16.5.130/%s/g\" /usr/local/etc/ausf/ausfcfg.yaml \n", para5GData["AUSF_IP"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/172.16.5.140/%s/g\" /usr/local/etc/ausf/ausfcfg.yaml \n", para5GData["UDM_IP"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/172.16.5.180/%s/g\" /usr/local/etc/ausf/ausfcfg.yaml \n", para5GData["NRF_IP"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/mcc: 001/mcc: %s/g\" /usr/local/etc/ausf/ausfcfg.yaml \n", para5GData["MCC"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/mnc: 01/mnc: %s/g\" /usr/local/etc/ausf/ausfcfg.yaml \n", para5GData["MNC"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("grep -qxF '%s ausf' /etc/hosts || echo '%s ausf' | sudo tee -a /etc/hosts \n", para5GData["AUSF_IP"], para5GData["AUSF_IP"])) + } + // UDM配置修改 + if neTypeLower == "udm" { + cmdStrArr = append(cmdStrArr, "sudo cp /usr/local/etc/udm/default/udmcfg.yaml /usr/local/etc/udm/udmcfg.yaml \n") + cmdStrArr = append(cmdStrArr, "sudo cp /usr/local/etc/udm/default/nssai.yaml /usr/local/etc/udm/nssai.yaml \n") + cmdStrArr = append(cmdStrArr, "sudo cp /usr/local/etc/udm/default/snssai.yaml /usr/local/etc/udm/snssai.yaml \n") + cmdStrArr = append(cmdStrArr, "sudo cp /usr/local/etc/udm/default/as.yaml /usr/local/etc/udm/as.yaml \n") + cmdStrArr = append(cmdStrArr, "sudo cp /usr/local/etc/udm/default/dnn.yaml /usr/local/etc/udm/dnn.yaml \n") + cmdStrArr = append(cmdStrArr, "sudo cp /usr/local/etc/udm/default/scscfSet.yaml /usr/local/etc/udm/scscfSet.yaml \n") + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/172.16.5.180/%s/g\" /usr/local/etc/udm/udmcfg.yaml \n", para5GData["NRF_IP"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/172.16.5.140/%s/g\" /usr/local/etc/udm/udmcfg.yaml \n", para5GData["UDM_IP"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/172.16.5.130/%s/g\" /usr/local/etc/udm/udmcfg.yaml \n", para5GData["AUSF_IP"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/172.16.5.120/%s/g\" /usr/local/etc/udm/udmcfg.yaml \n", para5GData["AMF_IP"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/mcc: 001/mcc: %s/g\" /usr/local/etc/udm/udmcfg.yaml \n", para5GData["MCC"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/mnc: 01/mnc: %s/g\" /usr/local/etc/udm/udmcfg.yaml \n", para5GData["MNC"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/mnc001.mcc001/mnc%s.mcc%s/g\" /usr/local/etc/udm/udmcfg.yaml \n", para5GData["MNC_DOMAIN"], para5GData["MCC"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/mnc001.mcc001/mnc%s.mcc%s/g\" /usr/local/etc/udm/as.yaml \n", para5GData["MNC_DOMAIN"], para5GData["MCC"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/mnc001.mcc001/mnc%s.mcc%s/g\" /usr/local/etc/udm/scscfSet.yaml \n", para5GData["MNC_DOMAIN"], para5GData["MCC"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/sst: 1/sst: %s/g\" /usr/local/etc/udm/nssai.yaml \n", para5GData["SST"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/sst: 1/sst: %s/g\" /usr/local/etc/udm/snssai.yaml \n", para5GData["SST"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/sd: 000001/sd: %s/g\" /usr/local/etc/udm/nssai.yaml \n", para5GData["SD"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/sd: 000001/sd: %s/g\" /usr/local/etc/udm/snssai.yaml \n", para5GData["SD"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/dnn: internet/dnn: %s/g\" /usr/local/etc/udm/snssai.yaml \n", para5GData["DNN_DATA"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/dnn: ims/dnn: %s/g\" /usr/local/etc/udm/snssai.yaml \n", para5GData["DNN_IMS"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/serviceSelection: 'internet'/serviceSelection: '%s'/g\" /usr/local/etc/udm/epsApn.yaml \n", para5GData["DNN_DATA"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/serviceSelection: 'ims'/serviceSelection: '%s'/g\" /usr/local/etc/udm/epsApn.yaml \n", para5GData["DNN_IMS"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/dnn: internet/dnn: %s/g\" /usr/local/etc/udm/dnn.yaml \n", para5GData["DNN_DATA"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/dnn: ims/dnn: %s/g\" /usr/local/etc/udm/dnn.yaml \n", para5GData["DNN_IMS"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/192.168.8.110/%s/g\" /usr/local/etc/udm/as.yaml \n", para5GData["SIP_IP"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("grep -qxF '%s udm' /etc/hosts || echo '%s udm' | sudo tee -a /etc/hosts \n", para5GData["UDM_IP"], para5GData["UDM_IP"])) + } + // SMF配置修改 + if neTypeLower == "smf" { + cmdStrArr = append(cmdStrArr, "sudo cp /usr/local/etc/smf/default/smf_conf.yaml /usr/local/etc/smf/smf_conf.yaml \n") + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/192.168.8.110/%s/g\" /usr/local/etc/smf/smf_conf.yaml \n", para5GData["SIP_IP"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/172.16.5.120/%s/g\" /usr/local/etc/smf/smf_conf.yaml \n", para5GData["AMF_IP"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/172.16.5.140/%s/g\" /usr/local/etc/smf/smf_conf.yaml \n", para5GData["UDM_IP"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/172.16.5.150/%s/g\" /usr/local/etc/smf/smf_conf.yaml \n", para5GData["SMF_IP"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/172.16.5.160/%s/g\" /usr/local/etc/smf/smf_conf.yaml \n", para5GData["PCF_IP"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/172.16.5.180/%s/g\" /usr/local/etc/smf/smf_conf.yaml \n", para5GData["NRF_IP"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/172.16.5.190/%s/g\" /usr/local/etc/smf/smf_conf.yaml \n", para5GData["UPF_IP"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s|10.2.1.0/24|%s|g\" /usr/local/etc/smf/smf_conf.yaml \n", para5GData["UE_POOL"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/internet/%s/g\" /usr/local/etc/smf/smf_conf.yaml \n", para5GData["DNN_DATA"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("grep -qxF '%s smf' /etc/hosts || echo '%s smf' | sudo tee -a /etc/hosts \n", para5GData["SMF_IP"], para5GData["SMF_IP"])) + } + // PCF配置修改 + if neTypeLower == "pcf" { + cmdStrArr = append(cmdStrArr, "sudo cp /usr/local/etc/pcf/default/pcfcfg.yaml /usr/local/etc/pcf/pcfcfg.yaml \n") + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/172.16.5.120/%s/g\" /usr/local/etc/pcf/pcfcfg.yaml \n", para5GData["AMF_IP"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/172.16.5.140/%s/g\" /usr/local/etc/pcf/pcfcfg.yaml \n", para5GData["UDM_IP"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/172.16.5.160/%s/g\" /usr/local/etc/pcf/pcfcfg.yaml \n", para5GData["PCF_IP"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/172.16.5.180/%s/g\" /usr/local/etc/pcf/pcfcfg.yaml \n", para5GData["NRF_IP"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/172.16.5.210/%s/g\" /usr/local/etc/pcf/pcfcfg.yaml \n", para5GData["NEF_IP"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/mcc: 001/mcc: %s/g\" /usr/local/etc/pcf/pcfcfg.yaml \n", para5GData["MCC"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/mnc: 01/mnc: %s/g\" /usr/local/etc/pcf/pcfcfg.yaml \n", para5GData["MNC"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/mnc001.mcc001/mnc%s.mcc%s/g\" /usr/local/etc/pcf/pcfcfg.yaml \n", para5GData["MNC_DOMAIN"], para5GData["MCC"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("grep -qxF '%s pcf' /etc/hosts || echo '%s pcf' | sudo tee -a /etc/hosts \n", para5GData["PCF_IP"], para5GData["PCF_IP"])) + } + + // NSSF配置修改 + if neTypeLower == "nssf" { + cmdStrArr = append(cmdStrArr, "sudo cp /usr/local/etc/nssf/default/nssfcfg.yaml /usr/local/etc/nssf/nssfcfg.yaml \n") + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/172.16.5.170/%s/g\" /usr/local/etc/nssf/nssfcfg.yaml \n", para5GData["NSSF_IP"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/172.16.5.180/%s/g\" /usr/local/etc/nssf/nssfcfg.yaml \n", para5GData["NRF_IP"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/mcc: 001/mcc: %s/g\" /usr/local/etc/nssf/nssfcfg.yaml \n", para5GData["MCC"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/mnc: 01/mnc: %s/g\" /usr/local/etc/nssf/nssfcfg.yaml \n", para5GData["MNC"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("grep -qxF '%s nssf' /etc/hosts || echo '%s nssf' | sudo tee -a /etc/hosts \n", para5GData["NSSF_IP"], para5GData["NSSF_IP"])) + } + // NRF配置修改 + if neTypeLower == "nrf" { + cmdStrArr = append(cmdStrArr, "sudo cp /usr/local/etc/nrf/default/nrfcfg.yaml /usr/local/etc/nrf/nrfcfg.yaml \n") + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/172.16.5.180/%s/g\" /usr/local/etc/nrf/nrfcfg.yaml \n", para5GData["NRF_IP"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/mcc: 001/mcc: %s/g\" /usr/local/etc/nrf/nrfcfg.yaml \n", para5GData["MCC"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/mnc: 01/mnc: %s/g\" /usr/local/etc/nrf/nrfcfg.yaml \n", para5GData["MNC"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("grep -qxF '%s nrf' /etc/hosts || echo '%s nrf' | sudo tee -a /etc/hosts \n", para5GData["NRF_IP"], para5GData["NRF_IP"])) + } + + // UPF配置修改 + if neTypeLower == "upf" { + cmdStrArr = append(cmdStrArr, "sudo cp /usr/local/etc/upf/default/upfcfg.yaml /usr/local/etc/upf/upfcfg.yaml \n") + cmdStrArr = append(cmdStrArr, "sudo cp /usr/local/etc/upf/default/upfForwarder_1.yaml /usr/local/etc/upf/upfForwarder_1.yaml \n") + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/172.16.5.190/%s/g\" /usr/local/etc/upf/upfcfg.yaml \n", para5GData["UPF_IP"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/localhost/%s/g\" /usr/local/etc/upf/upfForwarder_1.yaml \n", para5GData["UPF_IP"])) + // UE + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i '/- interfaceType: \"N6\"/,/ueIpv4: 10.2.1.0/s/ueIpv4: 10.2.1.0/ueIpv4: %s/' /usr/local/etc/upf/upfForwarder_1.yaml \n", para5GData["UE_IP"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i '/- interfaceType: \"N6\"/,/ueIpv4Mask: 255.255.255.0/s/ueIpv4Mask: 255.255.255.0/ueIpv4Mask: %s/' /usr/local/etc/upf/upfForwarder_1.yaml \n", para5GData["UE_MASK"])) + // N3 + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/192.168.8.190/%s/g\" /usr/local/etc/upf/upfForwarder_1.yaml \n", para5GData["N3_IP"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i '/- interfaceType: \"N3\"/,/ipv4Mask: 255.255.240.0/s/ipv4Mask: 255.255.240.0/ipv4Mask: %s/' /usr/local/etc/upf/upfForwarder_1.yaml \n", para5GData["N3_MASK"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i '/- interfaceType: \"N3\"/,/gatewayIpv4: 192.168.1.254/s/gatewayIpv4: 192.168.1.254/gatewayIpv4: %s/' /usr/local/etc/upf/upfForwarder_1.yaml \n", para5GData["N3_GW"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i '/- interfaceType: \"N3\"/,/interfacePCI: \"0000:00:00.0\"/s/interfacePCI: \"0000:00:00.0\"/interfacePCI: \"%s\"/' /usr/local/etc/upf/upfForwarder_1.yaml \n", para5GData["N3_PCI"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i '/- interfaceType: \"N3\"/,/macAddr: \"00:00:00:00:00:00\"/s/macAddr: \"00:00:00:00:00:00\"/macAddr: \"%s\"/' /usr/local/etc/upf/upfForwarder_1.yaml \n", para5GData["N3_MAC"])) + // 标准版 N6 + if para5GData["UPF_TYPE"] == "StandardUPF" { + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/192.168.8.191/%s/g\" /usr/local/etc/upf/upfForwarder_1.yaml \n", para5GData["N6_IP"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i '/- interfaceType: \"N6\"/,/ipv4Mask: 255.255.240.0/s/ipv4Mask: 255.255.240.0/ipv4Mask: %s/' /usr/local/etc/upf/upfForwarder_1.yaml \n", para5GData["N6_MASK"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i '/- interfaceType: \"N6\"/,/gatewayIpv4: 192.168.1.254/s/gatewayIpv4: 192.168.1.254/gatewayIpv4: %s/' /usr/local/etc/upf/upfForwarder_1.yaml \n", para5GData["N6_GW"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i '/- interfaceType: \"N6\"/,/interfacePCI: \"0000:00:00.0\"/s/interfacePCI: \"0000:00:00.0\"/interfacePCI: \"%s\"/' /usr/local/etc/upf/upfForwarder_1.yaml \n", para5GData["N6_PCI"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i '/- interfaceType: \"N6\"/,/macAddr: \"00:00:00:00:00:00\"/s/macAddr: \"00:00:00:00:00:00\"/macAddr: \"%s\"/' /usr/local/etc/upf/upfForwarder_1.yaml \n", para5GData["N6_MAC"])) + // 路由 + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo ip route add '%s/%s' via '%s' \n", para5GData["UE_IP"], para5GData["UE_CIDR"], para5GData["N6_IP"])) + } + // 轻量版 + if para5GData["UPF_TYPE"] == "LightUPF" { + cmdStrArr = append(cmdStrArr, "sudo sed -i \"s/192.168.8.191/0.0.0.0/g\" /usr/local/etc/upf/upfForwarder_1.yaml \n") + cmdStrArr = append(cmdStrArr, "sudo sed -i \"s/type: upfd/type: tun/g\" /usr/local/etc/upf/upfForwarder_1.yaml \n") + cmdStrArr = append(cmdStrArr, "sudo sed -i 's/driverType: vmxnet3/driverType: \"\"/g' /usr/local/etc/upf/upfForwarder_1.yaml \n") + } + cmdStrArr = append(cmdStrArr, fmt.Sprintf("grep -qxF '%s upf' /etc/hosts || echo '%s upf' | sudo tee -a /etc/hosts \n", para5GData["UPF_IP"], para5GData["UPF_IP"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("grep -qxF '%s upfn3' /etc/hosts || echo '%s upfn3' | sudo tee -a /etc/hosts \n", para5GData["N3_IP"], para5GData["N3_IP"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("grep -qxF '%s upfn6' /etc/hosts || echo '%s upfn6' | sudo tee -a /etc/hosts \n", para5GData["N6_IP"], para5GData["N6_IP"])) + } + + // LMF配置修改 - 已不再维护,导致激活License失败 + // NEF配置修改 - SNMP无需License + if neTypeLower == "nef" { + cmdStrArr = append(cmdStrArr, "sudo cp /usr/local/etc/nef/default/nef_conf.yaml /usr/local/etc/nef/nef_conf.yaml \n") + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/172.16.5.110/%s/g\" /usr/local/etc/nef/nef_conf.yaml \n", para5GData["IMS_IP"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/172.16.5.120/%s/g\" /usr/local/etc/nef/nef_conf.yaml \n", para5GData["AMF_IP"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/172.16.5.130/%s/g\" /usr/local/etc/nef/nef_conf.yaml \n", para5GData["AUSF_IP"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/172.16.5.140/%s/g\" /usr/local/etc/nef/nef_conf.yaml \n", para5GData["UDM_IP"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/172.16.5.150/%s/g\" /usr/local/etc/nef/nef_conf.yaml \n", para5GData["SMF_IP"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/172.16.5.160/%s/g\" /usr/local/etc/nef/nef_conf.yaml \n", para5GData["PCF_IP"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/172.16.5.170/%s/g\" /usr/local/etc/nef/nef_conf.yaml \n", para5GData["NSSF_IP"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/172.16.5.180/%s/g\" /usr/local/etc/nef/nef_conf.yaml \n", para5GData["NRF_IP"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/172.16.5.190/%s/g\" /usr/local/etc/nef/nef_conf.yaml \n", para5GData["UPF_IP"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/172.16.5.210/%s/g\" /usr/local/etc/nef/nef_conf.yaml \n", para5GData["NEF_IP"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("grep -qxF '%s nef' /etc/hosts || echo '%s nef' | sudo tee -a /etc/hosts \n", para5GData["NEF_IP"], para5GData["NEF_IP"])) + } + + // MME配置修改 - 4G + if neTypeLower == "mme" { + cmdStrArr = append(cmdStrArr, "sudo cp /usr/local/etc/mme/default/mme.conf /usr/local/etc/mme/mme.conf \n") + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/172.16.5.120/%s/g\" /usr/local/etc/mme/mme.conf \n", para5GData["AMF_IP"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/172.16.5.150/%s/g\" /usr/local/etc/mme/mme.conf \n", para5GData["SMF_IP"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s|192.168.8.220/20|%s|g\" /usr/local/etc/mme/mme.conf \n", para5GData["S1_MMEIP"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s|172.16.5.220/24|%s|g\" /usr/local/etc/mme/mme.conf \n", para5GData["S11_MMEIP"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s|172.16.5.220|%s|g\" /usr/local/etc/mme/mme.conf \n", para5GData["MME_IP"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s|172.16.5.221/24|%s|g\" /usr/local/etc/mme/mme.conf \n", para5GData["S10_MMEIP"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/mnc001.mcc001/mnc%s.mcc%s/g\" /usr/local/etc/mme/mme.conf \n", para5GData["MNC_DOMAIN"], para5GData["MCC"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/\"00101\"/\"%s%s\"/g\" /usr/local/etc/mme/mme.conf \n", para5GData["MCC"], para5GData["MNC"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i 's/MCC=\"001\"/MCC=\"%s\"/g' /usr/local/etc/mme/mme.conf \n", para5GData["MCC"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i 's/MCC = \"001\"/MCC = \"%s\"/g' /usr/local/etc/mme/mme.conf \n", para5GData["MCC"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i 's/MNC=\"01\";/MNC=\"%s\";/g' /usr/local/etc/mme/mme.conf \n", para5GData["MNC"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i 's/MNC = \"01\";/MNC = \"%s\";/g' /usr/local/etc/mme/mme.conf \n", para5GData["MNC"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i 's/TAC = \"1\";/TAC = \"%s\";/g' /usr/local/etc/mme/mme.conf \n", para5GData["TAC"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i 's/TAC = 1;/TAC = %s;/g' /usr/local/etc/mme/mme.conf \n", para5GData["TAC"])) + // SMF开启 + cmdStrArr = append(cmdStrArr, "sudo sed -i \"/^ *gxcfg:/,/^ *[^ ]/{s/enable: false/enable: true/;b};\" /usr/local/etc/smf/smf_conf.yaml \n") + cmdStrArr = append(cmdStrArr, fmt.Sprintf("grep -qxF '%s mme' /etc/hosts || echo '%s mme' | sudo tee -a /etc/hosts \n", para5GData["MME_IP"], para5GData["MME_IP"])) + } + // N3IWF配置修改 + if neTypeLower == "n3iwf" { + cmdStrArr = append(cmdStrArr, "sudo cp /usr/local/etc/n3iwf/default/n3iwfcfg.yaml /usr/local/etc/n3iwf/n3iwfcfg.yaml \n") + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/MCC: 001/MCC: %s/g\" /usr/local/etc/n3iwf/n3iwfcfg.yaml \n", para5GData["MCC"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/MNC: 01/MNC: %s/g\" /usr/local/etc/n3iwf/n3iwfcfg.yaml \n", para5GData["MNC"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/192.168.12.161/%s/g\" /usr/local/etc/n3iwf/n3iwfcfg.yaml \n", para5GData["N3IWF_IP"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/192.168.12.160/%s/g\" /usr/local/etc/n3iwf/n3iwfcfg.yaml \n", para5GData["N3IWF_IP"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/192.168.8.27/%s/g\" /usr/local/etc/n3iwf/n3iwfcfg.yaml \n", para5GData["UDM_IP"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/192.168.1.239/%s/g\" /usr/local/etc/n3iwf/n3iwfcfg.yaml \n", para5GData["SMF_IP"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/192.168.8.22/%s/g\" /usr/local/etc/n3iwf/n3iwfcfg.yaml \n", para5GData["N2_IP"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/192.168.1.161/%s/g\" /usr/local/etc/n3iwf/n3iwfcfg.yaml \n", para5GData["N3_IP"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/192.168.1.160/%s/g\" /usr/local/etc/n3iwf/n3iwfcfg.yaml \n", para5GData["N6_IP"])) + cmdStrArr = append(cmdStrArr, fmt.Sprintf("grep -qxF '%s n3iwf' /etc/hosts || echo '%s n3iwf' | sudo tee -a /etc/hosts \n", para5GData["N3IWF_IP"], para5GData["N3IWF_IP"])) + } + + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo service %s restart \n", neTypeLower)) + // 30s后停止服务 + // cmdStrArr = append(cmdStrArr, fmt.Sprintf("nohup sh -c \"sleep 30s && sudo service %s stop\" > /dev/null 2>&1 & \n", neTypeLower)) + } else { + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo service %s stop \n", neTypeLower)) + cmdStrArr = append(cmdStrArr, pkgCmdStr+" \n") + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo service %s restart \n", neTypeLower)) + } + } + + // 安装操作有redis安装时需要重启 + if action == "install" && (neTypeLower == "ims" || neTypeLower == "udm") { + // adb + if strings.Contains(pkgCmdStr, "adb") { + para5GData := NewNeInfoImpl.Para5GData + cmdStrArr = append(cmdStrArr, "sudo cp /usr/local/etc/adb/default/adb.conf /usr/local/etc/adb/adb.conf \n") + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/bind 127.0.0.1/bind %s/g\" /usr/local/etc/adb/adb.conf \n", para5GData["DB_IP"])) + cmdStrArr = append(cmdStrArr, "sudo service adb restart \n") + } + // kvdb + if strings.Contains(pkgCmdStr, "kvdb") { + para5GData := NewNeInfoImpl.Para5GData + cmdStrArr = append(cmdStrArr, "sudo cp /usr/local/etc/kvdb/default/kvdb.conf /usr/local/etc/kvdb/kvdb.conf \n") + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo sed -i \"s/bind 127.0.0.1/bind %s/g\" /usr/local/etc/kvdb/kvdb.conf \n", para5GData["DB_IP"])) + cmdStrArr = append(cmdStrArr, "sudo service kvdb restart \n") + } + } + + // 删除软件包 + cmdStrArr = append(cmdStrArr, fmt.Sprintf("sudo rm %s \n", strings.Join(neFilePaths, " "))) + // 结束 + cmdStrArr = append(cmdStrArr, fmt.Sprintf("echo '%s' \n", okFlagStr)) + + return okFlagStr, cmdStrArr, nil +} + +// operateDome 操作版本-执行阶段 +func (r *NeVersionImpl) operateRun(sshClient *ssh.ConnSSH, preinput map[string]string, cmdStrArr []string, neType string, okFlagStr string) (string, error) { + // ssh连接会话 + clientSession, err := sshClient.NewClientSession(127, 42) + if err != nil { + return "", fmt.Errorf("neinfo ssh client session new err") + } + defer clientSession.Close() + + firstRead := true // 首次命令进行记录日志信息 + commandLineText := "" // 日志信息 + done := make(chan bool) // 完成信号 + // 超时退出 120s + timeoutTicker := time.NewTicker(120 * time.Second) + defer timeoutTicker.Stop() + // 实时读取SSH消息直接输出 + msTicker := time.NewTicker(100 * time.Millisecond) + defer msTicker.Stop() + go func() { + for { + select { + case <-timeoutTicker.C: + logger.Warnf("NeVersion operateRun %s", commandLineText) + logger.Errorf("neinfo ssh client session read timeout") + done <- true + return + case <-msTicker.C: + outputByte := clientSession.Read() + if len(outputByte) > 0 { + outputStr := string(outputByte) + // 非首次进行记录命令 + if !firstRead { + commandLineText += outputStr + } + + // IMS预输入 + if neType == "IMS" { + // IMS包 P/I/S-CSCF Config 配置覆盖 + if strings.Contains(outputStr, "(P/I/S-CSCF Config)? ") { + if pisCSCF, ok := preinput["pisCSCF"]; ok && pisCSCF != "" { + clientSession.Write(fmt.Sprintf("%s \n", pisCSCF)) + } else { + clientSession.Write("y \n") + } + continue + } + // MF包 etc下目录覆盖 + if strings.Contains(outputStr, "/usr/local/etc/mf directory? (Yes/No, default: No)") { + if pisCSCF, ok := preinput["updateMFetc"]; ok && pisCSCF != "" { + clientSession.Write(fmt.Sprintf("%s \n", pisCSCF)) + } else { + clientSession.Write("No \n") + } + continue + } + // MF包 share下目录覆盖 + if strings.Contains(outputStr, "/usr/local/share/mf directory? (Yes/No, default: No)") { + if pisCSCF, ok := preinput["updateMFshare"]; ok && pisCSCF != "" { + clientSession.Write(fmt.Sprintf("%s \n", pisCSCF)) + } else { + clientSession.Write("No \n") + } + continue + } + } + + // 命令终止符后继续执行命令 + suffix := strings.HasSuffix(outputStr, "~]# ") || strings.HasSuffix(outputStr, "~$ ") + if len(cmdStrArr) > 0 && suffix { + if firstRead { + firstRead = false + } + shiftElement := cmdStrArr[0] // 获取第一个元素 + cmdStrArr = cmdStrArr[1:] // 将第一个元素从切片中移除 + clientSession.Write(shiftElement) + continue + } + // 最后输出的退出标记 + if strings.LastIndex(outputStr, okFlagStr) > 5 { + done <- true + break + } + } + } + } + }() + // 等待写入协程完成 + <-done + + return commandLineText, nil +} + +// operateDome 操作版本-完成阶段 +func (r *NeVersionImpl) operateDome(action string, neVersion model.NeVersion) error { + if action == "install" { + // 网元信息 + neInfo := NewNeInfoImpl.SelectNeInfoByNeTypeAndNeID(neVersion.NeType, neVersion.NeId) + if neInfo.NeId != neVersion.NeId { + return fmt.Errorf("error found neinfo") + } + // ========= 网元OAM配置文件 start ========== + if err := NewNeInfoImpl.NeConfOAMSync(neInfo, nil, true); err != nil { + return fmt.Errorf("error wirte OAM file info") + } + // ========= 网元OAM配置文件 end =========== + } + + // 更新Version + verInfo := r.SelectByNeTypeAndNeID(neVersion.NeType, neVersion.NeId) + if verInfo.NeId == neVersion.NeId { + curName := verInfo.Name + curVersion := verInfo.Version + curPath := verInfo.Path + if action == "install" { + verInfo.Name = neVersion.NewName + verInfo.Version = neVersion.NewVersion + verInfo.Path = neVersion.NewPath + verInfo.PreName = "-" + verInfo.PreVersion = "-" + verInfo.PrePath = "-" + verInfo.NewName = "-" + verInfo.NewVersion = "-" + verInfo.NewPath = "-" + } + if action == "upgrade" { + verInfo.Name = neVersion.NewName + verInfo.Version = neVersion.NewVersion + verInfo.Path = neVersion.NewPath + verInfo.PreName = curName + verInfo.PreVersion = curVersion + verInfo.PrePath = curPath + verInfo.NewName = "-" + verInfo.NewVersion = "-" + verInfo.NewPath = "-" + } + if action == "rollback" { + verInfo.Name = neVersion.PreName + verInfo.Version = neVersion.PreVersion + verInfo.Path = neVersion.PrePath + verInfo.PreName = curName + verInfo.PreVersion = curVersion + verInfo.PrePath = curPath + } + + verInfo.Status = "1" + NewNeVersionImpl.Update(verInfo) + } + return nil } diff --git a/src/modules/network_element/service/udm_auth.go b/src/modules/network_element/service/udm_auth.go deleted file mode 100644 index d469ce5..0000000 --- a/src/modules/network_element/service/udm_auth.go +++ /dev/null @@ -1,37 +0,0 @@ -package service - -import "nms_cxy/src/modules/network_element/model" - -// UDM鉴权信息 服务层接口 -type IUDMAuth interface { - // Save UDM鉴权用户-获取redis全部保存数据库 - Save(neID string) int64 - - // Page UDM鉴权用户-分页查询数据库 - Page(query map[string]any) map[string]any - - // List UDM鉴权用户-查询数据库 - List(authUser model.UDMAuth) []model.UDMAuth - - // Insert UDM鉴权用户-新增单个 - // imsi长度15,ki长度32,opc长度0或者32 - Insert(neID string, authUser model.UDMAuth) int64 - - // Insert UDM鉴权用户-批量添加 - Inserts(neID string, authUser model.UDMAuth, num string) int64 - - // InsertCSV UDM鉴权用户-批量添加 - InsertCSV(neID string, data []map[string]string) int64 - - // InsertTxt UDM鉴权用户-批量添加 - InsertTxt(neID string, data [][]string) int64 - - // Insert UDM鉴权用户-修改更新 - Update(neID string, authUser model.UDMAuth) int64 - - // Insert UDM鉴权用户-删除单个 - Delete(neID, imsi string) int64 - - // Insert UDM鉴权用户-删除范围 - Deletes(neID, imsi, num string) int64 -} diff --git a/src/modules/network_element/service/udm_auth.impl.go b/src/modules/network_element/service/udm_auth.impl.go deleted file mode 100644 index b584f40..0000000 --- a/src/modules/network_element/service/udm_auth.impl.go +++ /dev/null @@ -1,179 +0,0 @@ -package service - -import ( - "fmt" - "strings" - - "nms_cxy/src/framework/redis" - "nms_cxy/src/modules/network_element/model" - "nms_cxy/src/modules/network_element/repository" -) - -// 实例化服务层 UDMAuthImpl 结构体 -var NewUDMAuthImpl = &UDMAuthImpl{ - udmAuthRepository: repository.NewUDMAuthImpl, -} - -// UDM鉴权信息 服务层处理 -type UDMAuthImpl struct { - // UDM鉴权信息数据信息 - udmAuthRepository repository.IUDMAuth -} - -// authDataByRedis UDM鉴权用户 -func (r *UDMAuthImpl) authDataByRedis(imsi, neID string) []model.UDMAuth { - arr := []model.UDMAuth{} - key := fmt.Sprintf("ausf:%s", imsi) - ausfArr, err := redis.GetKeys("udmuser", key) - if err != nil { - return arr - } - for _, key := range ausfArr { - m, err := redis.GetHash("udmuser", key) - if err != nil { - continue - } - - // 跳过-号数据 - imsi := key[5:] - if strings.Contains(imsi, "-") { - continue - } - - status := "1" // 默认给1 - - amf := "" - if v, ok := m["amf"]; ok { - amf = strings.Replace(v, "\r\n", "", 1) - } - a := model.UDMAuth{ - Imsi: imsi, - Amf: amf, - Status: status, - Ki: m["ki"], - AlgoIndex: m["algo"], - Opc: m["opc"], - NeID: neID, - } - arr = append(arr, a) - } - return arr -} - -// Save UDM鉴权用户-获取redis全部保存数据库 -func (r *UDMAuthImpl) Save(neID string) int64 { - authArr := r.authDataByRedis("*", neID) - // 数据清空后添加 - go r.udmAuthRepository.ClearAndInsert(neID, authArr) - return int64(len(authArr)) -} - -// Page UDM鉴权用户-分页查询数据库 -func (r *UDMAuthImpl) Page(query map[string]any) map[string]any { - return r.udmAuthRepository.SelectPage(query) -} - -// List UDM鉴权用户-查询数据库 -func (r *UDMAuthImpl) List(authUser model.UDMAuth) []model.UDMAuth { - return r.udmAuthRepository.SelectList(authUser) -} - -// Insert UDM鉴权用户-新增单个 -// imsi长度15,ki长度32,opc长度0或者32 -func (r *UDMAuthImpl) Insert(neID string, authUser model.UDMAuth) int64 { - authArr := r.authDataByRedis(authUser.Imsi, neID) - if len(authArr) > 0 { - r.udmAuthRepository.Delete(neID, authUser.Imsi) - r.udmAuthRepository.Inserts(authArr) - } - return 0 -} - -// Insert UDM鉴权用户-批量添加 -func (r *UDMAuthImpl) Inserts(neID string, authUser model.UDMAuth, num string) int64 { - startIMSI := authUser.Imsi - startIMSI = startIMSI[:len(startIMSI)-len(num)] + "*" - // keys udm-sd:4600001000004* - authArr := r.authDataByRedis(startIMSI, neID) - if len(authArr) > 0 { - for _, v := range authArr { - r.udmAuthRepository.Delete(neID, v.Imsi) - } - return r.udmAuthRepository.Inserts(authArr) - } - return 0 -} - -// InsertCSV UDM鉴权用户-批量添加 -func (r *UDMAuthImpl) InsertCSV(neID string, data []map[string]string) int64 { - prefixes := make(map[string]struct{}) - for _, v := range data { - imsi := v["imsi"] - if len(imsi) < 5 { - continue - } - prefix := imsi[:len(imsi)-4] - prefixes[prefix] = struct{}{} - } - // 分组插入 - var num int64 = 0 - for prefix := range prefixes { - r.udmAuthRepository.DeletePrefixImsi(neID, prefix) - subArr := r.authDataByRedis(prefix+"*", neID) - if len(subArr) > 0 { - num += r.udmAuthRepository.Inserts(subArr) - } - } - return num -} - -// InsertTxt UDM鉴权用户-批量添加 -func (r *UDMAuthImpl) InsertTxt(neID string, data [][]string) int64 { - prefixes := make(map[string]struct{}) - for _, v := range data { - imsi := v[0] - if len(imsi) < 5 { - continue - } - prefix := imsi[:len(imsi)-4] - prefixes[prefix] = struct{}{} - } - // 分组插入 - var num int64 = 0 - for prefix := range prefixes { - r.udmAuthRepository.DeletePrefixImsi(neID, prefix) - subArr := r.authDataByRedis(prefix+"*", neID) - if len(subArr) > 0 { - num += r.udmAuthRepository.Inserts(subArr) - } - } - return num -} - -// Insert UDM鉴权用户-修改更新 -func (r *UDMAuthImpl) Update(neID string, authUser model.UDMAuth) int64 { - authArr := r.authDataByRedis(authUser.Imsi, neID) - if len(authArr) > 0 { - r.udmAuthRepository.Delete(neID, authUser.Imsi) - return r.udmAuthRepository.Inserts(authArr) - } - return 0 -} - -// Insert UDM鉴权用户-删除单个 -func (r *UDMAuthImpl) Delete(neID, imsi string) int64 { - return r.udmAuthRepository.Delete(neID, imsi) -} - -// Insert UDM鉴权用户-删除范围 -func (r *UDMAuthImpl) Deletes(neID, imsi, num string) int64 { - prefix := imsi[:len(imsi)-len(num)-1] - // 直接删除前缀的记录 - r.udmAuthRepository.DeletePrefixImsi(neID, prefix) - // keys ausf:4600001000004* - authArr := r.authDataByRedis(prefix+"*", neID) - if len(authArr) > 0 { - return r.udmAuthRepository.Inserts(authArr) - } - return 0 -} diff --git a/src/modules/network_element/service/udm_sub.go b/src/modules/network_element/service/udm_sub.go deleted file mode 100644 index 8f6dd22..0000000 --- a/src/modules/network_element/service/udm_sub.go +++ /dev/null @@ -1,37 +0,0 @@ -package service - -import "nms_cxy/src/modules/network_element/model" - -// UDM签约用户信息 服务层接口 -type IUDMSub interface { - // Save UDM签约用户-获取redis全部保存数据库 - Save(neID string) int64 - - // Page UDM签约用户-分页查询数据库 - Page(query map[string]any) map[string]any - - // List UDM签约用户-查询数据库 - List(subUser model.UDMSub) []model.UDMSub - - // Insert UDM签约用户-新增单个 - // imsi长度15,ki长度32,opc长度0或者32 - Insert(neID string, subUser model.UDMSub) int64 - - // Insert UDM签约用户-批量添加 - Inserts(neID string, subUser model.UDMSub, num string) int64 - - // InsertCSV UDM签约用户-批量添加 - InsertCSV(neID string, data []map[string]string) int64 - - // InsertTxt UDM签约用户-批量添加 - InsertTxt(neID string, data [][]string) int64 - - // Insert UDM签约用户-修改更新 - Update(neID string, subUser model.UDMSub) int64 - - // Insert UDM签约用户-删除单个 - Delete(neID, imsi string) int64 - - // Insert UDM签约用户-删除范围 - Deletes(neID, imsi, num string) int64 -} diff --git a/src/modules/network_element/service/udm_sub.impl.go b/src/modules/network_element/service/udm_sub.impl.go deleted file mode 100644 index 0b424f6..0000000 --- a/src/modules/network_element/service/udm_sub.impl.go +++ /dev/null @@ -1,195 +0,0 @@ -package service - -import ( - "fmt" - "strings" - - "nms_cxy/src/framework/redis" - "nms_cxy/src/modules/network_element/model" - "nms_cxy/src/modules/network_element/repository" -) - -// 实例化服务层 UDMSubImpl 结构体 -var NewUDMSubImpl = &UDMSubImpl{ - udmSubRepository: repository.NewUDMSubImpl, -} - -// UDM签约信息 服务层处理 -type UDMSubImpl struct { - // UDM签约信息数据信息 - udmSubRepository repository.IUDMSub -} - -// subDataByRedis UDM签约用户 -func (r *UDMSubImpl) subDataByRedis(imsi, neID string) []model.UDMSub { - arr := []model.UDMSub{} - key := fmt.Sprintf("udm-sd:%s", imsi) - udmsdArr, err := redis.GetKeys("udmuser", key) - if err != nil { - return arr - } - for _, key := range udmsdArr { - m, err := redis.GetHash("udmuser", key) - if err != nil { - continue - } - - a := model.UDMSub{ - Imsi: key[7:], - Msisdn: m["gpsi"], // 46003550072 strings.TrimPrefix(m["gpsi"], "86"), - SmfSel: m["smf-sel"], - SmData: m["sm-dat"], // 1-000001&cmnet&ims&3gnet - NeID: neID, - } - - // def_ambr,def_nssai,0,def_arfb,def_sar,3,1,12000,1,1000,0,1,- - if v, ok := m["am-dat"]; ok { - arr := strings.Split(v, ",") - a.Ambr = arr[0] - a.Nssai = arr[1] - a.Rat = arr[2] - a.Arfb = arr[3] - a.Sar = arr[4] - a.Cn = arr[5] - } - // 1,64,24,65,def_eps,1,2,010200000000,- - if v, ok := m["eps-dat"]; ok { - arr := strings.Split(v, ",") - // 跳过非常规数据 - if len(arr) > 9 { - continue - } - a.EpsDat = v - a.EpsFlag = arr[0] - a.EpsOdb = arr[1] - a.HplmnOdb = arr[2] - a.Ard = arr[3] - a.Epstpl = arr[4] - a.ContextId = arr[5] - a.ApnContext = arr[7] - // [6] 是不要的,导入和导出不用 - a.StaticIp = arr[8] - } - - arr = append(arr, a) - } - return arr -} - -// Save UDM签约用户-获取redis全部保存数据库 -func (r *UDMSubImpl) Save(neID string) int64 { - subArr := r.subDataByRedis("*", neID) - // 数据清空后添加 - go r.udmSubRepository.ClearAndInsert(neID, subArr) - return int64(len(subArr)) -} - -// Page UDM签约用户-分页查询数据库 -func (r *UDMSubImpl) Page(query map[string]any) map[string]any { - return r.udmSubRepository.SelectPage(query) -} - -// List UDM签约用户-查询数据库 -func (r *UDMSubImpl) List(subUser model.UDMSub) []model.UDMSub { - return r.udmSubRepository.SelectList(subUser) -} - -// Insert UDM签约用户-新增单个 -// imsi长度15,ki长度32,opc长度0或者32 -func (r *UDMSubImpl) Insert(neID string, subUser model.UDMSub) int64 { - authArr := r.subDataByRedis(subUser.Imsi, neID) - if len(authArr) > 0 { - r.udmSubRepository.Delete(neID, subUser.Imsi) - r.udmSubRepository.Inserts(authArr) - } - return 0 -} - -// Insert UDM签约用户-批量添加 -func (r *UDMSubImpl) Inserts(neID string, subUser model.UDMSub, num string) int64 { - startIMSI := subUser.Imsi - startIMSI = startIMSI[:len(startIMSI)-len(num)] + "*" - // keys udm-sd:4600001000004* - subArr := r.subDataByRedis(startIMSI, neID) - if len(subArr) > 0 { - for _, v := range subArr { - r.udmSubRepository.Delete(neID, v.Imsi) - } - return r.udmSubRepository.Inserts(subArr) - } - return 0 -} - -// InsertCSV UDM签约用户-批量添加 -func (r *UDMSubImpl) InsertCSV(neID string, data []map[string]string) int64 { - prefixes := make(map[string]struct{}) - for _, v := range data { - imsi := v["imsi"] - if len(imsi) < 5 { - continue - } - prefix := imsi[:len(imsi)-4] - prefixes[prefix] = struct{}{} - } - // 分组插入 - var num int64 = 0 - for prefix := range prefixes { - r.udmSubRepository.DeletePrefixImsi(neID, prefix) - subArr := r.subDataByRedis(prefix+"*", neID) - if len(subArr) > 0 { - num += r.udmSubRepository.Inserts(subArr) - } - } - return num -} - -// InsertTxt UDM签约用户-批量添加 -func (r *UDMSubImpl) InsertTxt(neID string, data [][]string) int64 { - prefixes := make(map[string]struct{}) - for _, v := range data { - imsi := v[0] - if len(imsi) < 5 { - continue - } - prefix := imsi[:len(imsi)-4] - prefixes[prefix] = struct{}{} - } - // 分组插入 - var num int64 = 0 - for prefix := range prefixes { - r.udmSubRepository.DeletePrefixImsi(neID, prefix) - subArr := r.subDataByRedis(prefix+"*", neID) - if len(subArr) > 0 { - num += r.udmSubRepository.Inserts(subArr) - } - } - return num -} - -// Insert UDM签约用户-修改更新 -func (r *UDMSubImpl) Update(neID string, subUser model.UDMSub) int64 { - authArr := r.subDataByRedis(subUser.Imsi, neID) - if len(authArr) > 0 { - r.udmSubRepository.Delete(neID, subUser.Imsi) - return r.udmSubRepository.Inserts(authArr) - } - return 0 -} - -// Insert UDM签约用户-删除单个 -func (r *UDMSubImpl) Delete(neID, imsi string) int64 { - return r.udmSubRepository.Delete(neID, imsi) -} - -// Insert UDM签约用户-删除范围 -func (r *UDMSubImpl) Deletes(neID, imsi, num string) int64 { - prefix := imsi[:len(imsi)-len(num)-1] - // 直接删除前缀的记录 - r.udmSubRepository.DeletePrefixImsi(neID, prefix) - // keys udm-sd:4600001000004* - authArr := r.subDataByRedis(prefix+"*", neID) - if len(authArr) > 0 { - return r.udmSubRepository.Inserts(authArr) - } - return 0 -} diff --git a/src/modules/system/controller/sys_config.go b/src/modules/system/controller/sys_config.go index 5c645a5..b45c9a6 100644 --- a/src/modules/system/controller/sys_config.go +++ b/src/modules/system/controller/sys_config.go @@ -35,12 +35,17 @@ type SysConfigController struct { // // GET /list func (s *SysConfigController) List(c *gin.Context) { - querys := ctx.QueryMap(c) - data := s.sysConfigService.SelectConfigPage(querys) - - rows := data["rows"].([]model.SysConfig) - // 闭包函数处理多语言 language := ctx.AcceptLanguage(c) + querys := ctx.QueryMap(c) + // 多语言值转key查询 + if v, ok := querys["configName"]; ok && v != "" { + querys["configName"] = i18n.TFindKeyPrefix(language, "config", v.(string)) + } + + data := s.sysConfigService.SelectConfigPage(querys) + rows := data["rows"].([]model.SysConfig) + + // 闭包函数处理多语言 converI18n := func(language string, arr *[]model.SysConfig) { for i := range *arr { (*arr)[i].ConfigName = i18n.TKey(language, (*arr)[i].ConfigName) @@ -222,8 +227,10 @@ func (s *SysConfigController) Export(c *gin.Context) { language := ctx.AcceptLanguage(c) // 查询结果,根据查询条件结果,单页最大值限制 querys := ctx.BodyJSONMap(c) + querys["pageNum"] = 1 + querys["pageSize"] = 1000 data := s.sysConfigService.SelectConfigPage(querys) - if data["total"].(int64) == 0 { + if parse.Number(data["total"]) == 0 { // 导出数据记录为空 c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.exportEmpty"))) return diff --git a/src/modules/system/controller/sys_dept.go b/src/modules/system/controller/sys_dept.go index 6b72381..00c7580 100644 --- a/src/modules/system/controller/sys_dept.go +++ b/src/modules/system/controller/sys_dept.go @@ -35,13 +35,13 @@ func (s *SysDeptController) List(c *gin.Context) { language := ctx.AcceptLanguage(c) var querys struct { // 部门ID - DeptID string `json:"deptId"` + DeptID string `form:"deptId"` // 父部门ID - ParentID string `json:"parentId" ` + ParentID string `form:"parentId" ` // 部门名称 - DeptName string `json:"deptName" ` + DeptName string `form:"deptName" ` // 部门状态(0正常 1停用) - Status string `json:"status"` + Status string `form:"status"` } err := c.ShouldBindQuery(&querys) if err != nil { @@ -49,6 +49,11 @@ func (s *SysDeptController) List(c *gin.Context) { return } + // 多语言值转key查询 + if querys.DeptName != "" { + querys.DeptName = i18n.TFindKeyPrefix(language, "dept", querys.DeptName) + } + SysDeptController := model.SysDept{ DeptID: querys.DeptID, ParentID: querys.ParentID, diff --git a/src/modules/system/controller/sys_dict_data.go b/src/modules/system/controller/sys_dict_data.go index 1af4f9b..b7c8d46 100644 --- a/src/modules/system/controller/sys_dict_data.go +++ b/src/modules/system/controller/sys_dict_data.go @@ -241,14 +241,21 @@ func (s *SysDictDataController) DictType(c *gin.Context) { func (s *SysDictDataController) Export(c *gin.Context) { language := ctx.AcceptLanguage(c) // 查询结果,根据查询条件结果,单页最大值限制 - querys := ctx.BodyJSONMap(c) - data := s.sysDictDataService.SelectDictDataPage(querys) - if data["total"].(int64) == 0 { + // querys := ctx.BodyJSONMap(c) + // data := s.sysDictDataService.SelectDictDataPage(querys) + // if data["total"].(int64) == 0 { + // // 导出数据记录为空 + // c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.exportEmpty"))) + // return + // } + // rows := data["rows"].([]model.SysDictData) + + rows := s.sysDictDataService.SelectDictDataList(model.SysDictData{}) + if len(rows) <= 0 { // 导出数据记录为空 c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.exportEmpty"))) return } - rows := data["rows"].([]model.SysDictData) // 闭包函数处理多语言 converI18n := func(language string, arr *[]model.SysDictData) { @@ -267,11 +274,10 @@ func (s *SysDictDataController) Export(c *gin.Context) { // 第一行表头标题 headerCells := map[string]string{ "A1": i18n.TKey(language, "dictData.export.code"), - "B1": i18n.TKey(language, "dictData.export.sort"), - "C1": i18n.TKey(language, "dictData.export.label"), - "D1": i18n.TKey(language, "dictData.export.value"), - "E1": i18n.TKey(language, "dictData.export.type"), - "F1": i18n.TKey(language, "dictData.export.status"), + "B1": i18n.TKey(language, "dictData.export.label"), + "C1": i18n.TKey(language, "dictData.export.value"), + "D1": i18n.TKey(language, "dictData.export.sort"), + "E1": i18n.TKey(language, "dictData.export.status"), } // 从第二行开始的数据 dataCells := make([]map[string]any, 0) @@ -283,11 +289,10 @@ func (s *SysDictDataController) Export(c *gin.Context) { } dataCells = append(dataCells, map[string]any{ "A" + idx: row.DictCode, - "B" + idx: row.DictSort, - "C" + idx: row.DictLabel, - "D" + idx: row.DictValue, - "E" + idx: row.DictType, - "F" + idx: statusValue, + "B" + idx: row.DictLabel, + "C" + idx: row.DictValue, + "D" + idx: row.DictSort, + "E" + idx: statusValue, }) } diff --git a/src/modules/system/controller/sys_dict_type.go b/src/modules/system/controller/sys_dict_type.go index 5efc678..884a282 100644 --- a/src/modules/system/controller/sys_dict_type.go +++ b/src/modules/system/controller/sys_dict_type.go @@ -244,14 +244,21 @@ func (s *SysDictTypeController) DictOptionselect(c *gin.Context) { func (s *SysDictTypeController) Export(c *gin.Context) { language := ctx.AcceptLanguage(c) // 查询结果,根据查询条件结果,单页最大值限制 - querys := ctx.BodyJSONMap(c) - data := s.sysDictTypeService.SelectDictTypePage(querys) - if data["total"].(int64) == 0 { + // querys := ctx.BodyJSONMap(c) + // data := s.sysDictTypeService.SelectDictTypePage(querys) + // if data["total"].(int64) == 0 { + // // 导出数据记录为空 + // c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.exportEmpty"))) + // return + // } + // rows := data["rows"].([]model.SysDictType) + + rows := s.sysDictTypeService.SelectDictTypeList(model.SysDictType{}) + if len(rows) <= 0 { // 导出数据记录为空 c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.exportEmpty"))) return } - rows := data["rows"].([]model.SysDictType) // 闭包函数处理多语言 converI18n := func(language string, arr *[]model.SysDictType) { diff --git a/src/modules/system/controller/sys_log_login.go b/src/modules/system/controller/sys_log_login.go index 9ad2657..8aa23a8 100644 --- a/src/modules/system/controller/sys_log_login.go +++ b/src/modules/system/controller/sys_log_login.go @@ -40,7 +40,8 @@ type SysLogLoginController struct { // GET /list func (s *SysLogLoginController) List(c *gin.Context) { querys := ctx.QueryMap(c) - data := s.sysLogLoginService.SelectSysLogLoginPage(querys) + dataScopeSQL := ctx.LoginUserToDataScopeSQL(c, "d", "u") + data := s.sysLogLoginService.SelectSysLogLoginPage(querys, dataScopeSQL) rows := data["rows"].([]model.SysLogLogin) // 闭包函数处理多语言 @@ -60,17 +61,17 @@ func (s *SysLogLoginController) List(c *gin.Context) { // 系统登录日志删除 // -// DELETE /:infoIds +// DELETE /:loginIds func (s *SysLogLoginController) Remove(c *gin.Context) { language := ctx.AcceptLanguage(c) - infoIds := c.Param("infoIds") - if infoIds == "" { + loginIds := c.Param("loginIds") + if loginIds == "" { c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) return } // 处理字符转id数组后去重 - ids := strings.Split(infoIds, ",") + ids := strings.Split(loginIds, ",") uniqueIDs := parse.RemoveDuplicates(ids) if len(uniqueIDs) <= 0 { c.JSON(200, result.Err(nil)) @@ -121,14 +122,21 @@ func (s *SysLogLoginController) Unlock(c *gin.Context) { func (s *SysLogLoginController) Export(c *gin.Context) { language := ctx.AcceptLanguage(c) // 查询结果,根据查询条件结果,单页最大值限制 - querys := ctx.BodyJSONMap(c) - data := s.sysLogLoginService.SelectSysLogLoginPage(querys) - if data["total"].(int64) == 0 { + // querys := ctx.BodyJSONMap(c) + // data := s.sysLogLoginService.SelectSysLogLoginPage(querys) + // if data["total"].(int64) == 0 { + // // 导出数据记录为空 + // c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.exportEmpty"))) + // return + // } + // rows := data["rows"].([]model.SysLogLogin) + + rows := s.sysLogLoginService.SelectSysLogLoginList(model.SysLogLogin{}) + if len(rows) <= 0 { // 导出数据记录为空 c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.exportEmpty"))) return } - rows := data["rows"].([]model.SysLogLogin) // 闭包函数处理多语言 converI18n := func(language string, arr *[]model.SysLogLogin) { @@ -147,13 +155,13 @@ func (s *SysLogLoginController) Export(c *gin.Context) { headerCells := map[string]string{ "A1": i18n.TKey(language, "log.login.export.id"), "B1": i18n.TKey(language, "log.login.export.userName"), - "C1": i18n.TKey(language, "log.login.export.status"), - "D1": i18n.TKey(language, "log.login.export.ip"), - "E1": i18n.TKey(language, "log.login.export.location"), + "C1": i18n.TKey(language, "log.login.export.ip"), + "D1": i18n.TKey(language, "log.login.export.location"), + "E1": i18n.TKey(language, "log.login.export.os"), "F1": i18n.TKey(language, "log.login.export.browser"), - "G1": i18n.TKey(language, "log.login.export.os"), - "H1": i18n.TKey(language, "log.login.export.msg"), - "I1": i18n.TKey(language, "log.login.export.time"), + "G1": i18n.TKey(language, "log.login.export.status"), + "H1": i18n.TKey(language, "log.login.export.time"), + "I1": i18n.TKey(language, "log.login.export.msg"), } // 从第二行开始的数据 dataCells := make([]map[string]any, 0) @@ -167,13 +175,13 @@ func (s *SysLogLoginController) Export(c *gin.Context) { dataCells = append(dataCells, map[string]any{ "A" + idx: row.LoginID, "B" + idx: row.UserName, - "C" + idx: statusValue, - "D" + idx: row.IPAddr, - "E" + idx: row.LoginLocation, + "C" + idx: row.IPAddr, + "D" + idx: row.LoginLocation, + "E" + idx: row.OS, "F" + idx: row.Browser, - "G" + idx: row.OS, - "H" + idx: row.Msg, - "I" + idx: date.ParseDateToStr(row.LoginTime, date.YYYY_MM_DD_HH_MM_SS), + "G" + idx: statusValue, + "H" + idx: date.ParseDateToStr(row.LoginTime, date.YYYY_MM_DDTHH_MM_SSZ), + "I" + idx: row.Msg, }) } diff --git a/src/modules/system/controller/sys_log_operate.go b/src/modules/system/controller/sys_log_operate.go index 934af67..fdeb1fd 100644 --- a/src/modules/system/controller/sys_log_operate.go +++ b/src/modules/system/controller/sys_log_operate.go @@ -42,7 +42,8 @@ func (s *SysLogOperateController) List(c *gin.Context) { querys["title"] = i18n.TFindKeyPrefix(language, "log.operate.title", v.(string)) } - data := s.SysLogOperateService.SelectSysLogOperatePage(querys) + dataScopeSQL := ctx.LoginUserToDataScopeSQL(c, "d", "u") + data := s.SysLogOperateService.SelectSysLogOperatePage(querys, dataScopeSQL) rows := data["rows"].([]model.SysLogOperate) // 闭包函数处理多语言 @@ -102,14 +103,21 @@ func (s *SysLogOperateController) Clean(c *gin.Context) { func (s *SysLogOperateController) Export(c *gin.Context) { language := ctx.AcceptLanguage(c) // 查询结果,根据查询条件结果,单页最大值限制 - querys := ctx.BodyJSONMap(c) - data := s.SysLogOperateService.SelectSysLogOperatePage(querys) - if data["total"].(int64) == 0 { + // querys := ctx.BodyJSONMap(c) + // data := s.SysLogOperateService.SelectSysLogOperatePage(querys) + // if data["total"].(int64) == 0 { + // // 导出数据记录为空 + // c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.exportEmpty"))) + // return + // } + // rows := data["rows"].([]model.SysLogOperate) + + rows := s.SysLogOperateService.SelectSysLogOperateList(model.SysLogOperate{}) + if len(rows) <= 0 { // 导出数据记录为空 c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.exportEmpty"))) return } - rows := data["rows"].([]model.SysLogOperate) // 闭包函数处理多语言 converI18n := func(language string, arr *[]model.SysLogOperate) { @@ -127,19 +135,12 @@ func (s *SysLogOperateController) Export(c *gin.Context) { "A1": i18n.TKey(language, "log.operate.export.id"), "B1": i18n.TKey(language, "log.operate.export.title"), "C1": i18n.TKey(language, "log.operate.export.businessType"), - "D1": i18n.TKey(language, "log.operate.export.method"), - "E1": i18n.TKey(language, "log.operate.export.requestMethod"), - "F1": i18n.TKey(language, "log.operate.export.operatorType"), - "G1": i18n.TKey(language, "log.operate.export.operName"), - "H1": i18n.TKey(language, "log.operate.export.deptName"), - "I1": i18n.TKey(language, "log.operate.export.url"), - "J1": i18n.TKey(language, "log.operate.export.ip"), - "K1": i18n.TKey(language, "log.operate.export.location"), - "L1": i18n.TKey(language, "log.operate.export.param"), - "M1": i18n.TKey(language, "log.operate.export.msg"), - "N1": i18n.TKey(language, "log.operate.export.status"), - "O1": i18n.TKey(language, "log.operate.export.costTime"), - "P1": i18n.TKey(language, "log.operate.export.operTime"), + "D1": i18n.TKey(language, "log.operate.export.operName"), + "E1": i18n.TKey(language, "log.operate.export.method"), + "F1": i18n.TKey(language, "log.operate.export.ip"), + "G1": i18n.TKey(language, "log.operate.export.status"), + "H1": i18n.TKey(language, "log.operate.export.operTime"), + "I1": i18n.TKey(language, "log.operate.export.costTime"), } // 从第二行开始的数据 dataCells := make([]map[string]any, 0) @@ -147,8 +148,36 @@ func (s *SysLogOperateController) Export(c *gin.Context) { idx := strconv.Itoa(i + 2) // 业务类型 businessType := "" - // 操作类别 - operatorType := "" + switch row.BusinessType { + case "0": + // 业务操作类型-其它 + businessType = i18n.TKey(language, "dictData.operType.other") + case "1": + // 业务操作类型-新增 + businessType = i18n.TKey(language, "dictData.operType.add") + case "2": + // 业务操作类型-修改 + businessType = i18n.TKey(language, "dictData.operType.edit") + case "3": + // 业务操作类型-删除 + businessType = i18n.TKey(language, "dictData.operType.delete") + case "4": + // 业务操作类型-授权 + businessType = i18n.TKey(language, "dictData.operType.auth") + case "5": + // 业务操作类型-导出 + businessType = i18n.TKey(language, "dictData.operType.export") + case "6": + // 业务操作类型-导入 + businessType = i18n.TKey(language, "dictData.operType.import") + case "7": + // 业务操作类型-强退 + businessType = i18n.TKey(language, "dictData.operType.forced quit") + case "8": + // 业务操作类型-清空数据 + businessType = i18n.TKey(language, "dictData.operType.clear") + } + // 状态 statusValue := i18n.TKey(language, "dictData.fail") if row.Status == "1" { @@ -158,19 +187,12 @@ func (s *SysLogOperateController) Export(c *gin.Context) { "A" + idx: row.OperID, "B" + idx: row.Title, "C" + idx: businessType, - "D" + idx: row.Method, + "D" + idx: row.OperName, "E" + idx: row.RequestMethod, - "F" + idx: operatorType, - "G" + idx: row.OperName, - "H" + idx: row.DeptName, - "I" + idx: row.OperURL, - "J" + idx: row.OperIP, - "K" + idx: row.OperLocation, - "L" + idx: row.OperParam, - "M" + idx: row.OperMsg, - "N" + idx: statusValue, - "O" + idx: row.CostTime, - "P" + idx: date.ParseDateToStr(row.OperTime, date.YYYY_MM_DD_HH_MM_SS), + "F" + idx: row.OperIP, + "G" + idx: statusValue, + "H" + idx: date.ParseDateToStr(row.OperTime, date.YYYY_MM_DDTHH_MM_SSZ), + "I" + idx: row.CostTime, }) } diff --git a/src/modules/system/controller/sys_menu.go b/src/modules/system/controller/sys_menu.go index 5f1ddbc..6dad49e 100644 --- a/src/modules/system/controller/sys_menu.go +++ b/src/modules/system/controller/sys_menu.go @@ -33,9 +33,10 @@ type SysMenuController struct { // // GET /list func (s *SysMenuController) List(c *gin.Context) { + language := ctx.AcceptLanguage(c) query := model.SysMenu{} if v, ok := c.GetQuery("menuName"); ok && v != "" { - query.MenuName = v + query.MenuName = i18n.TFindKeyPrefix(language, "menu", v) } if v, ok := c.GetQuery("status"); ok && v != "" { query.Status = v @@ -48,7 +49,6 @@ func (s *SysMenuController) List(c *gin.Context) { data := s.sysMenuService.SelectMenuList(query, userId) // 闭包函数处理多语言 - language := ctx.AcceptLanguage(c) var converI18n func(language string, arr *[]model.SysMenu) converI18n = func(language string, arr *[]model.SysMenu) { for i := range *arr { diff --git a/src/modules/system/controller/sys_post.go b/src/modules/system/controller/sys_post.go index 810eb16..05efc2a 100644 --- a/src/modules/system/controller/sys_post.go +++ b/src/modules/system/controller/sys_post.go @@ -8,6 +8,7 @@ import ( "nms_cxy/src/framework/i18n" "nms_cxy/src/framework/utils/ctx" + "nms_cxy/src/framework/utils/date" "nms_cxy/src/framework/utils/file" "nms_cxy/src/framework/utils/parse" "nms_cxy/src/framework/vo/result" @@ -35,12 +36,17 @@ type SysPostController struct { // // GET /list func (s *SysPostController) List(c *gin.Context) { - querys := ctx.QueryMap(c) - data := s.sysPostService.SelectPostPage(querys) - - rows := data["rows"].([]model.SysPost) - // 闭包函数处理多语言 language := ctx.AcceptLanguage(c) + querys := ctx.QueryMap(c) + // 多语言值转key查询 + if v, ok := querys["postName"]; ok && v != "" { + querys["postName"] = i18n.TFindKeyPrefix(language, "post", v.(string)) + } + + data := s.sysPostService.SelectPostPage(querys) + rows := data["rows"].([]model.SysPost) + + // 闭包函数处理多语言 converI18n := func(language string, arr *[]model.SysPost) { for i := range *arr { (*arr)[i].PostName = i18n.TKey(language, (*arr)[i].PostName) @@ -204,7 +210,11 @@ func (s *SysPostController) Remove(c *gin.Context) { func (s *SysPostController) Export(c *gin.Context) { language := ctx.AcceptLanguage(c) // 查询结果,根据查询条件结果,单页最大值限制 - querys := ctx.BodyJSONMap(c) + // querys := ctx.BodyJSONMap(c) + querys := map[string]any{ + "pageNum": 1, + "pageSize": 1000, + } data := s.sysPostService.SelectPostPage(querys) if data["total"].(int64) == 0 { // 导出数据记录为空 @@ -227,10 +237,11 @@ func (s *SysPostController) Export(c *gin.Context) { // 第一行表头标题 headerCells := map[string]string{ "A1": i18n.TKey(language, "post.export.id"), - "B1": i18n.TKey(language, "post.export.code"), - "C1": i18n.TKey(language, "post.export.name"), + "B1": i18n.TKey(language, "post.export.name"), + "C1": i18n.TKey(language, "post.export.code"), "D1": i18n.TKey(language, "post.export.sort"), "E1": i18n.TKey(language, "post.export.status"), + "F1": i18n.TKey(language, "post.export.time"), } // 从第二行开始的数据 dataCells := make([]map[string]any, 0) @@ -242,10 +253,11 @@ func (s *SysPostController) Export(c *gin.Context) { } dataCells = append(dataCells, map[string]any{ "A" + idx: row.PostID, - "B" + idx: row.PostCode, - "C" + idx: row.PostName, + "B" + idx: row.PostName, + "C" + idx: row.PostCode, "D" + idx: row.PostSort, "E" + idx: statusValue, + "F" + idx: date.ParseDateToStr(row.CreateTime, date.YYYY_MM_DDTHH_MM_SSZ), }) } diff --git a/src/modules/system/controller/sys_profile.go b/src/modules/system/controller/sys_profile.go index 758a05b..deb2e24 100644 --- a/src/modules/system/controller/sys_profile.go +++ b/src/modules/system/controller/sys_profile.go @@ -60,7 +60,7 @@ func (s *SysProfileController) Info(c *gin.Context) { } isAdmin := config.IsAdmin(loginUser.UserID) if isAdmin { - roleGroup = append(roleGroup, i18n.TKey(language, "role.admin")) + roleGroup = append(roleGroup, i18n.TKey(language, "role.system")) } // 查询用户所属岗位组 diff --git a/src/modules/system/controller/sys_role.go b/src/modules/system/controller/sys_role.go index 7c79049..4e8ebeb 100644 --- a/src/modules/system/controller/sys_role.go +++ b/src/modules/system/controller/sys_role.go @@ -9,6 +9,7 @@ import ( "nms_cxy/src/framework/constants/admin" "nms_cxy/src/framework/i18n" "nms_cxy/src/framework/utils/ctx" + "nms_cxy/src/framework/utils/date" "nms_cxy/src/framework/utils/file" "nms_cxy/src/framework/utils/parse" "nms_cxy/src/framework/vo/result" @@ -42,13 +43,18 @@ type SysRoleController struct { // // GET /list func (s *SysRoleController) List(c *gin.Context) { + language := ctx.AcceptLanguage(c) querys := ctx.QueryMap(c) + // 多语言值转key查询 + if v, ok := querys["roleName"]; ok && v != "" { + querys["roleName"] = i18n.TFindKeyPrefix(language, "role", v.(string)) + } + dataScopeSQL := ctx.LoginUserToDataScopeSQL(c, "d", "") data := s.sysRoleService.SelectRolePage(querys, dataScopeSQL) - rows := data["rows"].([]model.SysRole) + // 闭包函数处理多语言 - language := ctx.AcceptLanguage(c) converI18n := func(language string, arr *[]model.SysRole) { for i := range *arr { (*arr)[i].RoleName = i18n.TKey(language, (*arr)[i].RoleName) @@ -407,7 +413,11 @@ func (s *SysRoleController) AuthUserChecked(c *gin.Context) { func (s *SysRoleController) Export(c *gin.Context) { language := ctx.AcceptLanguage(c) // 查询结果,根据查询条件结果,单页最大值限制 - querys := ctx.BodyJSONMap(c) + // querys := ctx.BodyJSONMap(c) + querys := map[string]any{ + "pageNum": 1, + "pageSize": 1000, + } dataScopeSQL := ctx.LoginUserToDataScopeSQL(c, "d", "") data := s.sysRoleService.SelectRolePage(querys, dataScopeSQL) if data["total"].(int64) == 0 { @@ -434,23 +444,24 @@ func (s *SysRoleController) Export(c *gin.Context) { "B1": i18n.TKey(language, "role.export.name"), "C1": i18n.TKey(language, "role.export.key"), "D1": i18n.TKey(language, "role.export.sort"), - "E1": i18n.TKey(language, "role.export.dataScope"), - "F1": i18n.TKey(language, "role.export.status"), + "E1": i18n.TKey(language, "role.export.status"), + "F1": i18n.TKey(language, "role.export.time"), + // "F1": i18n.TKey(language, "role.export.dataScope"), } // 读取系统角色数据范围字典数据 - dictSysRoleDatascope := s.sysDictDataService.SelectDictDataByType("sys_role_datascope") + // dictSysRoleDatascope := s.sysDictDataService.SelectDictDataByType("sys_role_datascope") // 从第二行开始的数据 dataCells := make([]map[string]any, 0) for i, row := range rows { idx := strconv.Itoa(i + 2) // 数据范围 - dataScope := row.DataScope - for _, v := range dictSysRoleDatascope { - if row.DataScope == v.DictValue { - dataScope = i18n.TKey(language, v.DictLabel) - break - } - } + // dataScope := row.DataScope + // for _, v := range dictSysRoleDatascope { + // if row.DataScope == v.DictValue { + // dataScope = i18n.TKey(language, v.DictLabel) + // break + // } + // } // 角色状态 statusValue := i18n.TKey(language, "dictData.disable") if row.Status == "1" { @@ -461,8 +472,9 @@ func (s *SysRoleController) Export(c *gin.Context) { "B" + idx: row.RoleName, "C" + idx: row.RoleKey, "D" + idx: row.RoleSort, - "E" + idx: dataScope, - "F" + idx: statusValue, + "E" + idx: statusValue, + "F" + idx: date.ParseDateToStr(row.CreateTime, date.YYYY_MM_DDTHH_MM_SSZ), + // "F" + idx: dataScope, }) } diff --git a/src/modules/system/controller/sys_user.go b/src/modules/system/controller/sys_user.go index e594ee3..eaca97f 100644 --- a/src/modules/system/controller/sys_user.go +++ b/src/modules/system/controller/sys_user.go @@ -473,7 +473,11 @@ func (s *SysUserController) Status(c *gin.Context) { func (s *SysUserController) Export(c *gin.Context) { language := ctx.AcceptLanguage(c) // 查询结果,根据查询条件结果,单页最大值限制 - querys := ctx.BodyJSONMap(c) + // querys := ctx.BodyJSONMap(c) + querys := map[string]any{ + "pageNum": 1, + "pageSize": 1000, + } dataScopeSQL := ctx.LoginUserToDataScopeSQL(c, "d", "u") data := s.sysUserService.SelectUserPage(querys, dataScopeSQL) if data["total"].(int64) == 0 { @@ -503,31 +507,31 @@ func (s *SysUserController) Export(c *gin.Context) { "A1": i18n.TKey(language, "user.export.id"), "B1": i18n.TKey(language, "user.export.name"), "C1": i18n.TKey(language, "user.export.nick"), - "D1": i18n.TKey(language, "user.export.email"), - "E1": i18n.TKey(language, "user.export.phone"), - "F1": i18n.TKey(language, "user.export.sex"), - "G1": i18n.TKey(language, "user.export.status"), - "H1": i18n.TKey(language, "user.export.role"), - "I1": i18n.TKey(language, "user.export.deptID"), - "J1": i18n.TKey(language, "user.export.deptName"), - "K1": i18n.TKey(language, "user.export.deptLeader"), - "L1": i18n.TKey(language, "user.export.loginIP"), - "M1": i18n.TKey(language, "user.export.loginDate"), + "D1": i18n.TKey(language, "user.export.role"), + "E1": i18n.TKey(language, "user.export.deptName"), + "F1": i18n.TKey(language, "user.export.loginIP"), + "G1": i18n.TKey(language, "user.export.loginDate"), + "H1": i18n.TKey(language, "user.export.status"), + // "F1": i18n.TKey(language, "user.export.sex"), + // "E1": i18n.TKey(language, "user.export.phone"), + // "D1": i18n.TKey(language, "user.export.email"), + // "I1": i18n.TKey(language, "user.export.deptID"), + // "K1": i18n.TKey(language, "user.export.deptLeader"), } // 读取用户性别字典数据 - dictSysUserSex := s.sysDictDataService.SelectDictDataByType("sys_user_sex") + // dictSysUserSex := s.sysDictDataService.SelectDictDataByType("sys_user_sex") // 从第二行开始的数据 dataCells := make([]map[string]any, 0) for i, row := range rows { idx := strconv.Itoa(i + 2) // 用户性别 - sysUserSex := row.Sex - for _, v := range dictSysUserSex { - if row.Sex == v.DictValue { - sysUserSex = i18n.TKey(language, v.DictLabel) - break - } - } + // sysUserSex := row.Sex + // for _, v := range dictSysUserSex { + // if row.Sex == v.DictValue { + // sysUserSex = i18n.TKey(language, v.DictLabel) + // break + // } + // } // 帐号状态 statusValue := i18n.TKey(language, "dictData.disable") if row.Status == "1" { @@ -536,24 +540,22 @@ func (s *SysUserController) Export(c *gin.Context) { // 用户角色, 默认导出首个 userRole := "" if len(row.Roles) > 0 { - roleID := row.Roles[0].RoleID - roleName := i18n.TKey(language, row.Roles[0].RoleName) - userRole = fmt.Sprintf("%s-%s", roleID, roleName) + userRole = i18n.TKey(language, row.Roles[0].RoleName) } dataCells = append(dataCells, map[string]any{ "A" + idx: row.UserID, "B" + idx: row.UserName, "C" + idx: row.NickName, - "D" + idx: row.Email, - "E" + idx: row.PhoneNumber, - "F" + idx: sysUserSex, - "G" + idx: statusValue, - "H" + idx: userRole, - "I" + idx: row.Dept.DeptID, - "J" + idx: row.Dept.DeptName, - "K" + idx: row.Dept.Leader, - "L" + idx: row.LoginIP, - "M" + idx: date.ParseDateToStr(row.LoginDate, date.YYYY_MM_DD_HH_MM_SS), + "D" + idx: userRole, + "E" + idx: row.Dept.DeptName, + "F" + idx: row.LoginIP, + "G" + idx: date.ParseDateToStr(row.LoginDate, date.YYYY_MM_DD_HH_MM_SS), + "H" + idx: statusValue, + // "E" + idx: row.PhoneNumber, + // "F" + idx: sysUserSex, + // "D" + idx: row.Email, + // "I" + idx: row.Dept.DeptID, + // "K" + idx: row.Dept.Leader, }) } diff --git a/src/modules/system/repository/sys_config.impl.go b/src/modules/system/repository/sys_config.impl.go index 026b6ea..4f29f2f 100644 --- a/src/modules/system/repository/sys_config.impl.go +++ b/src/modules/system/repository/sys_config.impl.go @@ -7,7 +7,6 @@ import ( "nms_cxy/src/framework/datasource" "nms_cxy/src/framework/logger" - "nms_cxy/src/framework/utils/date" "nms_cxy/src/framework/utils/parse" "nms_cxy/src/framework/utils/repo" "nms_cxy/src/modules/system/model" @@ -79,8 +78,7 @@ func (r *SysConfigImpl) SelectConfigPage(query map[string]any) map[string]any { } if ok && beginTime != "" { conditions = append(conditions, "create_time >= ?") - beginDate := date.ParseStrToDate(beginTime.(string), date.YYYY_MM_DD) - params = append(params, beginDate.UnixMilli()) + params = append(params, parse.Number(beginTime.(string))) } endTime, ok := query["endTime"] if !ok { @@ -88,8 +86,7 @@ func (r *SysConfigImpl) SelectConfigPage(query map[string]any) map[string]any { } if ok && endTime != "" { conditions = append(conditions, "create_time <= ?") - endDate := date.ParseStrToDate(endTime.(string), date.YYYY_MM_DD) - params = append(params, endDate.UnixMilli()) + params = append(params, parse.Number(endTime.(string))) } // 构建查询条件语句 diff --git a/src/modules/system/repository/sys_dict_type.impl.go b/src/modules/system/repository/sys_dict_type.impl.go index d2c3432..219ae97 100644 --- a/src/modules/system/repository/sys_dict_type.impl.go +++ b/src/modules/system/repository/sys_dict_type.impl.go @@ -7,7 +7,6 @@ import ( "nms_cxy/src/framework/datasource" "nms_cxy/src/framework/logger" - "nms_cxy/src/framework/utils/date" "nms_cxy/src/framework/utils/parse" "nms_cxy/src/framework/utils/repo" "nms_cxy/src/modules/system/model" @@ -78,8 +77,7 @@ func (r *SysDictTypeImpl) SelectDictTypePage(query map[string]any) map[string]an } if ok && beginTime != "" { conditions = append(conditions, "create_time >= ?") - beginDate := date.ParseStrToDate(beginTime.(string), date.YYYY_MM_DD) - params = append(params, beginDate.UnixMilli()) + params = append(params, parse.Number(beginTime.(string))) } endTime, ok := query["endTime"] if !ok { @@ -87,8 +85,7 @@ func (r *SysDictTypeImpl) SelectDictTypePage(query map[string]any) map[string]an } if ok && endTime != "" { conditions = append(conditions, "create_time <= ?") - endDate := date.ParseStrToDate(endTime.(string), date.YYYY_MM_DD) - params = append(params, endDate.UnixMilli()) + params = append(params, parse.Number(endTime.(string))) } // 构建查询条件语句 diff --git a/src/modules/system/repository/sys_log_login.go b/src/modules/system/repository/sys_log_login.go index 51efdd5..18ff3ef 100644 --- a/src/modules/system/repository/sys_log_login.go +++ b/src/modules/system/repository/sys_log_login.go @@ -5,7 +5,7 @@ import "nms_cxy/src/modules/system/model" // ISysLogLogin 系统登录日志表 数据层接口 type ISysLogLogin interface { // SelectSysLogLoginPage 分页查询系统登录日志集合 - SelectSysLogLoginPage(query map[string]any) map[string]any + SelectSysLogLoginPage(query map[string]any, dataScopeSQL string) map[string]any // SelectSysLogLoginList 查询系统登录日志集合 SelectSysLogLoginList(sysLogLogin model.SysLogLogin) []model.SysLogLogin diff --git a/src/modules/system/repository/sys_log_login.impl.go b/src/modules/system/repository/sys_log_login.impl.go index 8fcd52a..3c20966 100644 --- a/src/modules/system/repository/sys_log_login.impl.go +++ b/src/modules/system/repository/sys_log_login.impl.go @@ -6,7 +6,6 @@ import ( "nms_cxy/src/framework/datasource" "nms_cxy/src/framework/logger" - "nms_cxy/src/framework/utils/date" "nms_cxy/src/framework/utils/parse" "nms_cxy/src/framework/utils/repo" "nms_cxy/src/modules/system/model" @@ -54,7 +53,7 @@ func (r *SysLogLoginImpl) convertResultRows(rows []map[string]any) []model.SysLo } // SelectSysLogLoginPage 分页查询系统登录日志集合 -func (r *SysLogLoginImpl) SelectSysLogLoginPage(query map[string]any) map[string]any { +func (r *SysLogLoginImpl) SelectSysLogLoginPage(query map[string]any, dataScopeSQL string) map[string]any { // 查询条件拼接 var conditions []string var params []any @@ -76,8 +75,7 @@ func (r *SysLogLoginImpl) SelectSysLogLoginPage(query map[string]any) map[string } if ok && beginTime != "" { conditions = append(conditions, "login_time >= ?") - beginDate := date.ParseStrToDate(beginTime.(string), date.YYYY_MM_DD_HH_MM_SS) - params = append(params, beginDate.UnixMilli()) + params = append(params, parse.Number(beginTime.(string))) } endTime, ok := query["endTime"] if !ok { @@ -85,14 +83,27 @@ func (r *SysLogLoginImpl) SelectSysLogLoginPage(query map[string]any) map[string } if ok && endTime != "" { conditions = append(conditions, "login_time <= ?") - endDate := date.ParseStrToDate(endTime.(string), date.YYYY_MM_DD_HH_MM_SS) - params = append(params, endDate.UnixMilli()) + params = append(params, parse.Number(endTime.(string))) } // 构建查询条件语句 + selectSql := r.selectSql + totalSql := "select count(login_id) as 'total' from sys_log_login" whereSql := "" if len(conditions) > 0 { whereSql += " where " + strings.Join(conditions, " and ") + whereSql += dataScopeSQL + } else if dataScopeSQL != "" { + totalSql = `select count(o.login_id) as 'total' + from sys_log_login o + left join sys_user u on u.user_name = o.user_name + left join sys_dept d on u.dept_id = d.dept_id` + selectSql = `select o.login_id, o.user_name, o.ipaddr, o.login_location, + o.browser, o.os, o.status, o.msg, o.login_time + from sys_log_login o + left join sys_user u on u.user_name = o.user_name + left join sys_dept d on u.dept_id = d.dept_id` + whereSql += " where 1=1" + dataScopeSQL } // 查询结果 @@ -102,7 +113,6 @@ func (r *SysLogLoginImpl) SelectSysLogLoginPage(query map[string]any) map[string } // 查询数量 长度为0直接返回 - totalSql := "select count(1) as 'total' from sys_log_login" totalRows, err := datasource.RawDB("", totalSql+whereSql, params) if err != nil { logger.Errorf("total err => %v", err) @@ -122,7 +132,7 @@ func (r *SysLogLoginImpl) SelectSysLogLoginPage(query map[string]any) map[string params = append(params, pageSize) // 查询数据 - querySql := r.selectSql + whereSql + pageSql + querySql := selectSql + whereSql + dataScopeSQL + pageSql results, err := datasource.RawDB("", querySql, params) if err != nil { logger.Errorf("query err => %v", err) diff --git a/src/modules/system/repository/sys_log_operate.go b/src/modules/system/repository/sys_log_operate.go index 962f3ad..7595cb1 100644 --- a/src/modules/system/repository/sys_log_operate.go +++ b/src/modules/system/repository/sys_log_operate.go @@ -5,7 +5,7 @@ import "nms_cxy/src/modules/system/model" // ISysLogOperate 操作日志表 数据层接口 type ISysLogOperate interface { // SelectSysLogOperatePage 分页查询系统操作日志集合 - SelectSysLogOperatePage(query map[string]any) map[string]any + SelectSysLogOperatePage(query map[string]any, dataScopeSQL string) map[string]any // SelectSysLogOperateList 查询系统操作日志集合 SelectSysLogOperateList(sysLogOperate model.SysLogOperate) []model.SysLogOperate diff --git a/src/modules/system/repository/sys_log_operate.impl.go b/src/modules/system/repository/sys_log_operate.impl.go index ef28683..51adef2 100644 --- a/src/modules/system/repository/sys_log_operate.impl.go +++ b/src/modules/system/repository/sys_log_operate.impl.go @@ -6,7 +6,6 @@ import ( "nms_cxy/src/framework/datasource" "nms_cxy/src/framework/logger" - "nms_cxy/src/framework/utils/date" "nms_cxy/src/framework/utils/parse" "nms_cxy/src/framework/utils/repo" "nms_cxy/src/modules/system/model" @@ -63,7 +62,7 @@ func (r *SysLogOperateImpl) convertResultRows(rows []map[string]any) []model.Sys } // SelectSysLogOperatePage 分页查询系统操作日志集合 -func (r *SysLogOperateImpl) SelectSysLogOperatePage(query map[string]any) map[string]any { +func (r *SysLogOperateImpl) SelectSysLogOperatePage(query map[string]any, dataScopeSQL string) map[string]any { // 查询条件拼接 var conditions []string var params []any @@ -89,8 +88,7 @@ func (r *SysLogOperateImpl) SelectSysLogOperatePage(query map[string]any) map[st } if ok && beginTime != "" { conditions = append(conditions, "oper_time >= ?") - beginDate := date.ParseStrToDate(beginTime.(string), date.YYYY_MM_DD_HH_MM_SS) - params = append(params, beginDate.UnixMilli()) + params = append(params, parse.Number(beginTime.(string))) } endTime, ok := query["endTime"] if !ok { @@ -98,14 +96,28 @@ func (r *SysLogOperateImpl) SelectSysLogOperatePage(query map[string]any) map[st } if ok && endTime != "" { conditions = append(conditions, "oper_time <= ?") - endDate := date.ParseStrToDate(endTime.(string), date.YYYY_MM_DD_HH_MM_SS) - params = append(params, endDate.UnixMilli()) + params = append(params, parse.Number(endTime.(string))) } // 构建查询条件语句 + selectSql := r.selectSql + totalSql := "select count(oper_id) as 'total' from sys_log_operate" whereSql := "" if len(conditions) > 0 { whereSql += " where " + strings.Join(conditions, " and ") + whereSql += dataScopeSQL + } else if dataScopeSQL != "" { + totalSql = `select count(o.oper_id) as 'total' + from sys_log_operate o + left join sys_user u on u.user_name = o.oper_name + left join sys_dept d on u.dept_id = d.dept_id` + selectSql = `select + o.oper_id, o.title, o.business_type, o.method, o.request_method, o.operator_type, o.oper_name, o.dept_name, + o.oper_url, o.oper_ip, o.oper_location, o.oper_param, o.oper_msg, o.status, o.oper_time, o.cost_time + from sys_log_operate o + left join sys_user u on u.user_name = o.oper_name + left join sys_dept d on u.dept_id = d.dept_id` + whereSql += " where 1=1" + dataScopeSQL } // 查询结果 @@ -115,7 +127,6 @@ func (r *SysLogOperateImpl) SelectSysLogOperatePage(query map[string]any) map[st } // 查询数量 长度为0直接返回 - totalSql := "select count(1) as 'total' from sys_log_operate" totalRows, err := datasource.RawDB("", totalSql+whereSql, params) if err != nil { logger.Errorf("total err => %v", err) @@ -135,7 +146,7 @@ func (r *SysLogOperateImpl) SelectSysLogOperatePage(query map[string]any) map[st params = append(params, pageSize) // 查询数据 - querySql := r.selectSql + whereSql + pageSql + querySql := selectSql + whereSql + pageSql results, err := datasource.RawDB("", querySql, params) if err != nil { logger.Errorf("query err => %v", err) diff --git a/src/modules/system/repository/sys_role.impl.go b/src/modules/system/repository/sys_role.impl.go index bbbeeea..4f9a732 100644 --- a/src/modules/system/repository/sys_role.impl.go +++ b/src/modules/system/repository/sys_role.impl.go @@ -7,7 +7,6 @@ import ( "nms_cxy/src/framework/datasource" "nms_cxy/src/framework/logger" - "nms_cxy/src/framework/utils/date" "nms_cxy/src/framework/utils/parse" "nms_cxy/src/framework/utils/repo" "nms_cxy/src/modules/system/model" @@ -91,8 +90,7 @@ func (r *SysRoleImpl) SelectRolePage(query map[string]any, dataScopeSQL string) } if ok && beginTime != "" { conditions = append(conditions, "r.create_time >= ?") - beginDate := date.ParseStrToDate(beginTime.(string), date.YYYY_MM_DD) - params = append(params, beginDate.UnixMilli()) + params = append(params, parse.Number(beginTime.(string))) } endTime, ok := query["endTime"] if !ok { @@ -100,8 +98,7 @@ func (r *SysRoleImpl) SelectRolePage(query map[string]any, dataScopeSQL string) } if ok && endTime != "" { conditions = append(conditions, "r.create_time <= ?") - endDate := date.ParseStrToDate(endTime.(string), date.YYYY_MM_DD) - params = append(params, endDate.UnixMilli()) + params = append(params, parse.Number(endTime.(string))) } if v, ok := query["deptId"]; ok && v != "" { conditions = append(conditions, `(u.dept_id = ? or u.dept_id in ( @@ -112,7 +109,7 @@ func (r *SysRoleImpl) SelectRolePage(query map[string]any, dataScopeSQL string) } // 构建查询条件语句 - whereSql := " where r.del_flag = '0' " + whereSql := " where r.del_flag = '0' and r.role_id != '1' " if len(conditions) > 0 { whereSql += " and " + strings.Join(conditions, " and ") } diff --git a/src/modules/system/repository/sys_user.impl.go b/src/modules/system/repository/sys_user.impl.go index d97348d..707be56 100644 --- a/src/modules/system/repository/sys_user.impl.go +++ b/src/modules/system/repository/sys_user.impl.go @@ -8,7 +8,6 @@ import ( "nms_cxy/src/framework/datasource" "nms_cxy/src/framework/logger" "nms_cxy/src/framework/utils/crypto" - "nms_cxy/src/framework/utils/date" "nms_cxy/src/framework/utils/parse" "nms_cxy/src/framework/utils/repo" "nms_cxy/src/modules/system/model" @@ -156,8 +155,7 @@ func (r *SysUserImpl) SelectUserPage(query map[string]any, dataScopeSQL string) } if ok && beginTime != "" { conditions = append(conditions, "u.login_date >= ?") - beginDate := date.ParseStrToDate(beginTime.(string), date.YYYY_MM_DD) - params = append(params, beginDate.UnixMilli()) + params = append(params, parse.Number(beginTime.(string))) } endTime, ok := query["endTime"] if !ok { @@ -165,8 +163,7 @@ func (r *SysUserImpl) SelectUserPage(query map[string]any, dataScopeSQL string) } if ok && endTime != "" { conditions = append(conditions, "u.login_date <= ?") - endDate := date.ParseStrToDate(endTime.(string), date.YYYY_MM_DD) - params = append(params, endDate.UnixMilli()) + params = append(params, parse.Number(endTime.(string))) } if v, ok := query["deptId"]; ok && v != "" { conditions = append(conditions, "(u.dept_id = ? or u.dept_id in ( select t.dept_id from sys_dept t where find_in_set(?, ancestors) ))") @@ -175,7 +172,7 @@ func (r *SysUserImpl) SelectUserPage(query map[string]any, dataScopeSQL string) } // 构建查询条件语句 - whereSql := " where u.del_flag = '0' " + whereSql := " where u.del_flag = '0' and u.user_id != '1' " if len(conditions) > 0 { whereSql += " and " + strings.Join(conditions, " and ") } @@ -257,7 +254,7 @@ func (r *SysUserImpl) SelectAllocatedPage(query map[string]any, dataScopeSQL str } // 构建查询条件语句 - whereSql := " where u.del_flag = '0' " + whereSql := " where u.del_flag = '0' and u.user_id != '1' " if len(conditions) > 0 { whereSql += " and " + strings.Join(conditions, " and ") } @@ -515,7 +512,8 @@ func (r *SysUserImpl) UpdateUser(sysUser model.SysUser) int64 { // DeleteUserByIds 批量删除用户信息 func (r *SysUserImpl) DeleteUserByIds(userIds []string) int64 { placeholder := repo.KeyPlaceholderByQuery(len(userIds)) - sql := "update sys_user set del_flag = '1' where user_id in (" + placeholder + ")" + username := "CASE WHEN user_name = '' THEN user_name WHEN LENGTH(user_name) >= 36 THEN CONCAT('del_', SUBSTRING(user_name, 5, 36)) ELSE CONCAT('del_', user_name) END" + sql := fmt.Sprintf("update sys_user set del_flag = '1', user_name = %s where user_id in (%s)", username, placeholder) parameters := repo.ConvertIdsSlice(userIds) results, err := datasource.ExecDB("", sql, parameters) if err != nil { diff --git a/src/modules/system/service/sys_log_login.go b/src/modules/system/service/sys_log_login.go index 8bfbadb..80b329c 100644 --- a/src/modules/system/service/sys_log_login.go +++ b/src/modules/system/service/sys_log_login.go @@ -5,7 +5,7 @@ import "nms_cxy/src/modules/system/model" // ISysLogLogin 系统登录日志 服务层接口 type ISysLogLogin interface { // SelectSysLogLoginPage 分页查询系统登录日志集合 - SelectSysLogLoginPage(query map[string]any) map[string]any + SelectSysLogLoginPage(query map[string]any, dataScopeSQL string) map[string]any // SelectSysLogLoginList 查询系统登录日志集合 SelectSysLogLoginList(sysLogLogin model.SysLogLogin) []model.SysLogLogin diff --git a/src/modules/system/service/sys_log_login.impl.go b/src/modules/system/service/sys_log_login.impl.go index 1b529a2..66fa240 100644 --- a/src/modules/system/service/sys_log_login.impl.go +++ b/src/modules/system/service/sys_log_login.impl.go @@ -17,8 +17,8 @@ type SysLogLoginImpl struct { } // SelectSysLogLoginPage 分页查询系统登录日志集合 -func (s *SysLogLoginImpl) SelectSysLogLoginPage(query map[string]any) map[string]any { - return s.sysLogLoginService.SelectSysLogLoginPage(query) +func (s *SysLogLoginImpl) SelectSysLogLoginPage(query map[string]any, dataScopeSQL string) map[string]any { + return s.sysLogLoginService.SelectSysLogLoginPage(query, dataScopeSQL) } // SelectSysLogLoginList 查询系统登录日志集合 diff --git a/src/modules/system/service/sys_log_operate.go b/src/modules/system/service/sys_log_operate.go index e86120c..ae5bb96 100644 --- a/src/modules/system/service/sys_log_operate.go +++ b/src/modules/system/service/sys_log_operate.go @@ -5,7 +5,7 @@ import "nms_cxy/src/modules/system/model" // ISysLogOperate 操作日志表 服务层接口 type ISysLogOperate interface { // SelectSysLogOperatePage 分页查询系统操作日志集合 - SelectSysLogOperatePage(query map[string]any) map[string]any + SelectSysLogOperatePage(query map[string]any, dataScopeSQL string) map[string]any // SelectSysLogOperateList 查询系统操作日志集合 SelectSysLogOperateList(sysLogOperate model.SysLogOperate) []model.SysLogOperate diff --git a/src/modules/system/service/sys_log_operate.impl.go b/src/modules/system/service/sys_log_operate.impl.go index 4726acc..ff584cc 100644 --- a/src/modules/system/service/sys_log_operate.impl.go +++ b/src/modules/system/service/sys_log_operate.impl.go @@ -17,8 +17,8 @@ type SysLogOperateImpl struct { } // SelectSysLogOperatePage 分页查询系统操作日志集合 -func (r *SysLogOperateImpl) SelectSysLogOperatePage(query map[string]any) map[string]any { - return r.SysLogOperateService.SelectSysLogOperatePage(query) +func (r *SysLogOperateImpl) SelectSysLogOperatePage(query map[string]any, dataScopeSQL string) map[string]any { + return r.SysLogOperateService.SelectSysLogOperatePage(query, dataScopeSQL) } // SelectSysLogOperateList 查询系统操作日志集合 diff --git a/src/modules/system/service/sys_user.impl.go b/src/modules/system/service/sys_user.impl.go index 446488d..c8e63ac 100644 --- a/src/modules/system/service/sys_user.impl.go +++ b/src/modules/system/service/sys_user.impl.go @@ -32,7 +32,7 @@ func (r *SysUserImpl) SelectUserPage(query map[string]any, dataScopeSQL string) // SelectUserList 根据条件查询用户列表 func (r *SysUserImpl) SelectUserList(sysUser model.SysUser, dataScopeSQL string) []model.SysUser { - return []model.SysUser{} + return r.sysUserRepository.SelectUserList(sysUser, dataScopeSQL) } // SelectAllocatedPage 根据条件分页查询分配用户角色列表 diff --git a/src/modules/system/system.go b/src/modules/system/system.go index 794e04b..5bfd205 100644 --- a/src/modules/system/system.go +++ b/src/modules/system/system.go @@ -209,7 +209,7 @@ func Setup(router *gin.Engine) { controller.NewSysMenu.Remove, ) sysMenuGroup.GET("/treeSelect", - middleware.PreAuthorize(map[string][]string{"hasPerms": {"system:menu:list"}}), + middleware.PreAuthorize(map[string][]string{"hasPerms": {"system:menu:list", "system:dept:list"}}), controller.NewSysMenu.TreeSelect, ) sysMenuGroup.GET("/roleMenuTreeSelect/:roleId", diff --git a/src/modules/trace/service/tcpdump.impl.go b/src/modules/trace/service/tcpdump.impl.go index 00c3143..9fc6a57 100644 --- a/src/modules/trace/service/tcpdump.impl.go +++ b/src/modules/trace/service/tcpdump.impl.go @@ -5,9 +5,7 @@ import ( "strings" "time" - "nms_cxy/src/framework/config" "nms_cxy/src/framework/logger" - "nms_cxy/src/framework/utils/cmd" "nms_cxy/src/framework/utils/date" neService "nms_cxy/src/modules/network_element/service" ) @@ -28,23 +26,26 @@ type TcpdumpImpl struct { // DumpStart 触发tcpdump开始抓包 filePcapName, err func (s *TcpdumpImpl) DumpStart(neType, neId, cmdStr string) (string, error) { - // 检查网元信息 + // 查询网元获取IP neInfo := s.neInfoService.SelectNeInfoByNeTypeAndNeID(neType, neId) - if neInfo.NeId != neId { + if neInfo.NeId != neId || neInfo.IP == "" { return "", fmt.Errorf("noData") } - // SSH命令 - usernameNe := config.Get("ne.user").(string) // 网元统一用户 - sshHost := fmt.Sprintf("%s@%s", usernameNe, neInfo.IP) + // 网元主机的SSH客户端 + sshClient, err := s.neInfoService.NeRunSSHClient(neInfo.NeType, neInfo.NeId) + if err != nil { + return "", err + } + defer sshClient.Close() // 是否拥有sudo权限并拼接 withSudo := "" - if _, err := cmd.ExecWithCheck("ssh", sshHost, "sudo -n uname"); err == nil { + if _, err := sshClient.RunCMD("sudo -n uname"); err == nil { withSudo = "sudo " } - if msg, err := cmd.ExecWithCheck("ssh", sshHost, fmt.Sprintf("%s tcpdump --version", withSudo)); err != nil { + if msg, err := sshClient.RunCMD(fmt.Sprintf("%s tcpdump --version", withSudo)); err != nil { // stderr: bash: tcpdump:未找到命令 => exit status 127 msg = strings.TrimSpace(msg) logger.Warnf("DumpStart err: %s => %s", msg, err.Error()) @@ -58,7 +59,7 @@ func (s *TcpdumpImpl) DumpStart(neType, neId, cmdStr string) (string, error) { sendCmd := fmt.Sprintf("cd /tmp \n %s nohup timeout 30m tcpdump -i any %s -s0 -w %s.pcap > %s.log 2>&1 & \necho $!", withSudo, cmdStr, fileName, fileName) // cd /tmp // sudo nohup timeout 60m tcpdump -i any -n -s 0 -v -w -s0 -w 20240115140822_UDM_001.pcap > 20240115140822_UDM_001.log 2>&1 & echo $! - msg, err := cmd.ExecWithCheck("ssh", sshHost, sendCmd) + msg, err := sshClient.RunCMD(sendCmd) msg = strings.TrimSpace(msg) if err != nil || strings.HasPrefix(msg, "stderr:") { logger.Warnf("DumpStart err: %s => %s", msg, err.Error()) @@ -73,19 +74,22 @@ func (s *TcpdumpImpl) DumpStart(neType, neId, cmdStr string) (string, error) { // DumpStop 停止已存在抓包句柄 func (s *TcpdumpImpl) DumpStop(neType, neId, fileName string) (string, error) { - // 检查网元信息 + // 查询网元获取IP neInfo := s.neInfoService.SelectNeInfoByNeTypeAndNeID(neType, neId) - if neInfo.NeId != neId { + if neInfo.NeId != neId || neInfo.IP == "" { return "", fmt.Errorf("noData") } - // SSH命令 - usernameNe := config.Get("ne.user").(string) // 网元统一用户 - sshHost := fmt.Sprintf("%s@%s", usernameNe, neInfo.IP) + // 网元主机的SSH客户端 + sshClient, err := s.neInfoService.NeRunSSHClient(neInfo.NeType, neInfo.NeId) + if err != nil { + return "", err + } + defer sshClient.Close() // 是否拥有sudo权限并拼接 withSudo := "" - if _, err := cmd.ExecWithCheck("ssh", sshHost, "sudo -n uname"); err == nil { + if _, err := sshClient.RunCMD("sudo -n uname"); err == nil { withSudo = "sudo " } @@ -104,7 +108,7 @@ func (s *TcpdumpImpl) DumpStop(neType, neId, fileName string) (string, error) { // 拼装命令 sendCmd := fmt.Sprintf("cd /tmp \n %s kill %s %s", withSudo, pid, viewLogFile) - msg, err := cmd.ExecWithCheck("ssh", sshHost, sendCmd) + msg, err := sshClient.RunCMD(sendCmd) delete(s.tcpdumpPIDMap, neTypeID) if err != nil || strings.HasPrefix(msg, "stderr:") { logger.Warnf("DumpStop err: %s => %s", strings.TrimSpace(msg), err.Error()) @@ -115,23 +119,26 @@ func (s *TcpdumpImpl) DumpStop(neType, neId, fileName string) (string, error) { // DumpUPF UPF标准版抓包 func (s *TcpdumpImpl) DumpUPF(neType, neId, cmdStr string) (string, string, error) { - // 检查网元信息 + // 查询网元获取IP neInfo := s.neInfoService.SelectNeInfoByNeTypeAndNeID(neType, neId) - if neInfo.NeId != neId { + if neInfo.NeId != neId || neInfo.IP == "" { return "", "", fmt.Errorf("noData") } - // SSH命令 - usernameNe := config.Get("ne.user").(string) // 网元统一用户 - sshHost := fmt.Sprintf("%s@%s", usernameNe, neInfo.IP) + // 网元主机的SSH客户端 + sshClient, err := s.neInfoService.NeRunSSHClient(neInfo.NeType, neInfo.NeId) + if err != nil { + return "", "", err + } + defer sshClient.Close() // 是否拥有sudo权限并拼接 withSudo := "" - if _, err := cmd.ExecWithCheck("ssh", sshHost, "sudo -n uname"); err == nil { + if _, err := sshClient.RunCMD("sudo -n uname"); err == nil { withSudo = "sudo " } - if msg, err := cmd.ExecWithCheck("ssh", sshHost, fmt.Sprintf("%s expect -version", withSudo)); err != nil { + if msg, err := sshClient.RunCMD(fmt.Sprintf("%s expect -version", withSudo)); err != nil { // stderr: bash: expect:未找到命令 => exit status 127 msg = strings.TrimSpace(msg) logger.Warnf("DumpUPF err: %s => %s", msg, err.Error()) @@ -143,7 +150,8 @@ func (s *TcpdumpImpl) DumpUPF(neType, neId, cmdStr string) (string, string, erro timeStr := date.ParseDateToStr(time.Now(), date.YYYYMMDDHHMMSS) fileName := fmt.Sprintf("%s_%s", timeStr, neTypeID) // UPF标准版本telnet脚本 - scriptStr := "set pcapCmd [lindex $argv 0]\nspawn telnet localhost 5002\nexpect \"upfd1# \"\nsend \"$pcapCmd\\n\"\nexpect \"upfd1# \"\nsend \"quit\\n\"\nexpect \"eof\"" + scriptStr := "set pcapCmd [lindex $argv 0]\nspawn telnet " + neInfo.IP + " 5002\nexpect \"upfd1# \"\nsend \"$pcapCmd\\n\"\nexpect \"upfd1# \"\nsend \"quit\\n\"\nexpect \"eof\"" + // scriptStr := "set pcapCmd [lindex $argv 0]\nspawn telnet localhost 5002\nexpect \"upfd1# \"\nsend \"$pcapCmd\\n\"\nexpect \"upfd1# \"\nsend \"quit\\n\"\nexpect \"eof\"" writePcapFile := fmt.Sprintf("echo '%s' > pcapUPF.sh\n %s chmod +x pcapUPF.sh", scriptStr, withSudo) writeLogFile := fmt.Sprintf("> %s.log 2>&1 \ncat %s.log", fileName, fileName) @@ -159,7 +167,7 @@ func (s *TcpdumpImpl) DumpUPF(neType, neId, cmdStr string) (string, string, erro // sudo chmod +x pcapUPF.sh // expect ./cap.sh 'pcap dispatch trace off' > 20240115165701_UDM_001.log 2>&1 // cat 20240115165701_UDM_001.log - msg, err := cmd.ExecWithCheck("ssh", sshHost, sendCmd) + msg, err := sshClient.RunCMD(sendCmd) msg = strings.TrimSpace(msg) if err != nil || strings.HasPrefix(msg, "stderr:") { logger.Warnf("DumpUPF err: %s => %s", msg, err.Error()) diff --git a/src/modules/trace/trace.go b/src/modules/trace/trace.go index ad87290..2938b7a 100644 --- a/src/modules/trace/trace.go +++ b/src/modules/trace/trace.go @@ -13,8 +13,10 @@ import ( func Setup(router *gin.Engine) { logger.Infof("开始加载 ====> trace 模块路由") + traceGroup := router.Group("/trace") + // 信令抓包 - tcpdumpGroup := router.Group("/tcpdump") + tcpdumpGroup := traceGroup.Group("/tcpdump") { tcpdumpGroup.POST("/start", middleware.PreAuthorize(nil), diff --git a/src/modules/ws/controller/ws.go b/src/modules/ws/controller/ws.go index 91a15b8..fa3d042 100644 --- a/src/modules/ws/controller/ws.go +++ b/src/modules/ws/controller/ws.go @@ -145,8 +145,14 @@ func (s *WSController) SSH(c *gin.Context) { // 创建链接SSH客户端 var connSSH ssh.ConnSSH neHost.CopyTo(&connSSH) - client, err := connSSH.NewClient() - if err != nil { + var client *ssh.ConnSSH + var clientErr error + if neHost.AuthMode == "2" { + client, clientErr = connSSH.NewClientByLocalPrivate() + } else { + client, clientErr = connSSH.NewClient() + } + if clientErr != nil { // 连接主机失败,请检查连接参数后重试 c.JSON(200, result.ErrMsg(i18n.TKey(language, "neHost.errByHostInfo"))) return @@ -197,11 +203,11 @@ func (s *WSController) SSH(c *gin.Context) { wsClient.MsgChan <- msgByte // 退出ssh登录 - if strings.LastIndex(outputStr, "logout\r\n") != -1 { - time.Sleep(1 * time.Second) - s.wsService.CloseClient(wsClient.ID) - return - } + // if strings.LastIndex(outputStr, "logout\r\n") != -1 { + // time.Sleep(1 * time.Second) + // s.wsService.CloseClient(wsClient.ID) + // return + // } } } }() @@ -251,8 +257,19 @@ func (s *WSController) Telnet(c *gin.Context) { } defer client.Close() + // 终端单行字符数 + cols, err := strconv.Atoi(c.DefaultQuery("cols", "120")) + if err != nil { + cols = 120 + } + // 终端显示行数 + rows, err := strconv.Atoi(c.DefaultQuery("rows", "128")) + if err != nil { + rows = 128 + } + // 创建Telnet客户端会话 - clientSession, err := client.NewClientSession() + clientSession, err := client.NewClientSession(cols, rows) if err != nil { // 连接主机失败,请检查连接参数后重试 c.JSON(200, result.ErrMsg(i18n.TKey(language, "neHost.errByHostInfo"))) @@ -284,11 +301,11 @@ func (s *WSController) Telnet(c *gin.Context) { wsClient.MsgChan <- msgByte // 退出telnet登录 - if strings.LastIndex(outputStr, "logout\r\n") != -1 { - time.Sleep(1 * time.Second) - s.wsService.CloseClient(wsClient.ID) - return - } + // if strings.LastIndex(outputStr, "logout\r\n") != -1 { + // time.Sleep(1 * time.Second) + // s.wsService.CloseClient(wsClient.ID) + // return + // } } } }() diff --git a/src/modules/ws/processor/cdr_connect.go b/src/modules/ws/processor/cdr_connect.go index 6e8cf3e..f5a1eab 100644 --- a/src/modules/ws/processor/cdr_connect.go +++ b/src/modules/ws/processor/cdr_connect.go @@ -10,17 +10,35 @@ import ( neDataService "nms_cxy/src/modules/network_data/service" ) -// GetCDRConnect 获取CDR会话事件-IMS -func GetCDRConnect(requestID string, data any) ([]byte, error) { +// GetCDRConnectByIMS 获取CDR会话事件-IMS +func GetCDRConnectByIMS(requestID string, data any) ([]byte, error) { msgByte, _ := json.Marshal(data) - var query neDataModel.CDREventQuery + var query neDataModel.CDREventIMSQuery err := json.Unmarshal(msgByte, &query) if err != nil { logger.Warnf("ws processor GetCDRConnect err: %s", err.Error()) return nil, fmt.Errorf("query data structure error") } - dataMap := neDataService.NewCDREventImpl.SelectPage(query) + dataMap := neDataService.NewCDREventIMSImpl.SelectPage(query) + resultByte, err := json.Marshal(result.Ok(map[string]any{ + "requestId": requestID, + "data": dataMap, + })) + return resultByte, err +} + +// GetCDRConnectBySMF 获取CDR会话事件-SMF +func GetCDRConnectBySMF(requestID string, data any) ([]byte, error) { + msgByte, _ := json.Marshal(data) + var query neDataModel.CDREventSMFQuery + err := json.Unmarshal(msgByte, &query) + if err != nil { + logger.Warnf("ws processor GetCDRConnect err: %s", err.Error()) + return nil, fmt.Errorf("query data structure error") + } + + dataMap := neDataService.NewCDREventSMFImpl.SelectPage(query) resultByte, err := json.Marshal(result.Ok(map[string]any{ "requestId": requestID, "data": dataMap, diff --git a/src/modules/ws/processor/ne_state.go b/src/modules/ws/processor/ne_state.go index 689f392..c24f585 100644 --- a/src/modules/ws/processor/ne_state.go +++ b/src/modules/ws/processor/ne_state.go @@ -6,6 +6,7 @@ import ( "nms_cxy/src/framework/logger" "nms_cxy/src/framework/vo/result" + neFetchlink "nms_cxy/src/modules/network_element/fetch_link" neService "nms_cxy/src/modules/network_element/service" ) @@ -33,7 +34,7 @@ func GetNeState(requestID string, data any) ([]byte, error) { } // 网元直连 - resData, err := neService.NeState(neInfo) + resData, err := neFetchlink.NeState(neInfo) if err != nil { resultByte, err := json.Marshal(result.Ok(map[string]any{ "requestId": requestID, diff --git a/src/modules/ws/processor/ue_connect.go b/src/modules/ws/processor/ue_connect.go index 0fc9d9b..fc393e6 100644 --- a/src/modules/ws/processor/ue_connect.go +++ b/src/modules/ws/processor/ue_connect.go @@ -10,17 +10,35 @@ import ( neDataService "nms_cxy/src/modules/network_data/service" ) -// GetUEConnect 获取UE会话事件-AMF -func GetUEConnect(requestID string, data any) ([]byte, error) { +// GetUEConnectByAMF 获取UE会话事件-AMF +func GetUEConnectByAMF(requestID string, data any) ([]byte, error) { msgByte, _ := json.Marshal(data) - var query neDataModel.UEEventQuery + var query neDataModel.UEEventAMFQuery err := json.Unmarshal(msgByte, &query) if err != nil { - logger.Warnf("ws processor GetUEConnect err: %s", err.Error()) + logger.Warnf("ws processor GetUEConnectByAMF err: %s", err.Error()) return nil, fmt.Errorf("query data structure error") } - dataMap := neDataService.NewUEEventImpl.SelectPage(query) + dataMap := neDataService.NewUEEventAMFImpl.SelectPage(query) + resultByte, err := json.Marshal(result.Ok(map[string]any{ + "requestId": requestID, + "data": dataMap, + })) + return resultByte, err +} + +// GetUEConnectByMME 获取UE会话事件-MME +func GetUEConnectByMME(requestID string, data any) ([]byte, error) { + msgByte, _ := json.Marshal(data) + var query neDataModel.UEEventMMEQuery + err := json.Unmarshal(msgByte, &query) + if err != nil { + logger.Warnf("ws processor GetUEConnectByMME err: %s", err.Error()) + return nil, fmt.Errorf("query data structure error") + } + + dataMap := neDataService.NewUEEventMMEImpl.SelectPage(query) resultByte, err := json.Marshal(result.Ok(map[string]any{ "requestId": requestID, "data": dataMap, diff --git a/src/modules/ws/service/ws_receive.impl.go b/src/modules/ws/service/ws_receive.impl.go index 0d7e3f0..3f6dfb0 100644 --- a/src/modules/ws/service/ws_receive.impl.go +++ b/src/modules/ws/service/ws_receive.impl.go @@ -3,6 +3,7 @@ package service import ( "encoding/json" "fmt" + "io" "time" "nms_cxy/src/framework/logger" @@ -67,10 +68,14 @@ func (s *WSReceiveImpl) AsyncReceive(client *model.WSClient, reqMsg model.WSRequ resByte, err = processor.GetProcessData(reqMsg.RequestID, reqMsg.Data) case "net": resByte, err = processor.GetNetConnections(reqMsg.RequestID, reqMsg.Data) - case "cdr": - resByte, err = processor.GetCDRConnect(reqMsg.RequestID, reqMsg.Data) - case "ue": - resByte, err = processor.GetUEConnect(reqMsg.RequestID, reqMsg.Data) + case "ims_cdr": + resByte, err = processor.GetCDRConnectByIMS(reqMsg.RequestID, reqMsg.Data) + case "smf_cdr": + resByte, err = processor.GetCDRConnectBySMF(reqMsg.RequestID, reqMsg.Data) + case "amf_ue": + resByte, err = processor.GetUEConnectByAMF(reqMsg.RequestID, reqMsg.Data) + case "mme_ue": + resByte, err = processor.GetUEConnectByMME(reqMsg.RequestID, reqMsg.Data) case "upf_tf": resByte, err = processor.GetUPFTotalFlow(reqMsg.RequestID, reqMsg.Data) case "ne_state": @@ -83,6 +88,11 @@ func (s *WSReceiveImpl) AsyncReceive(client *model.WSClient, reqMsg model.WSRequ logger.Warnf("ws AsyncReceive UID %s err: %s", client.BindUid, err.Error()) msgByte, _ := json.Marshal(result.ErrMsg(err.Error())) client.MsgChan <- msgByte + if err == io.EOF { + // 等待1s后关闭连接 + time.Sleep(1 * time.Second) + client.StopChan <- struct{}{} + } return } if len(resByte) > 0 { diff --git a/src/modules/ws/service/ws_send.impl.go b/src/modules/ws/service/ws_send.impl.go index f429e5e..b4f7629 100644 --- a/src/modules/ws/service/ws_send.impl.go +++ b/src/modules/ws/service/ws_send.impl.go @@ -18,8 +18,12 @@ const ( GROUP_KPI_UPF = "12" // 组号-IMS_CDR会话事件 GROUP_IMS_CDR = "1005" + // 组号-SMF_CDR会话事件 + GROUP_SMF_CDR = "1006" // 组号-AMF_UE会话事件 GROUP_AMF_UE = "1010" + // 组号-MME_UE会话事件 + GROUP_MME_UE = "1011" ) // 实例化服务层 WSSendImpl 结构体