From 01a959db93a6ccbaf7c6ddeeb535ce2636666336 Mon Sep 17 00:00:00 2001 From: dengbiao Date: Mon, 1 Jul 2024 16:05:35 +0800 Subject: [PATCH 1/2] =?UTF-8?q?add=20=E8=B6=85=E7=BA=A7=E4=BA=91=E5=8F=91?= =?UTF-8?q?=E5=8D=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/cfg/cfg_app.go | 1 + app/cfg/init_cfg.go | 2 + cloud_issuance/svc/svc_deal_call_back.go | 3 +- consume/init.go | 14 +- consume/md/consume_key.go | 10 + consume/super_cloud_issuance_msg_callback.go | 72 ++ etc/cfg.yml | 11 + go.mod | 6 +- main.go | 4 + super_cloud_issuance/db/db_cloud_bundle.go | 40 ++ super_cloud_issuance/db/db_order.go | 21 + super_cloud_issuance/db/db_provider.go | 27 + super_cloud_issuance/db/db_sys_cfg.go | 104 +++ super_cloud_issuance/db/db_sys_mod.go | 79 +++ .../db/db_sys_mod_format_img.go | 156 +++++ super_cloud_issuance/db/db_user.go | 298 +++++++++ super_cloud_issuance/db/db_user_fin_flow.go | 15 + super_cloud_issuance/db/db_user_level.go | 92 +++ super_cloud_issuance/db/db_user_profile.go | 418 ++++++++++++ super_cloud_issuance/db/db_user_relate.go | 213 ++++++ .../db/db_user_virtual_amount.go | 35 + super_cloud_issuance/db/db_virtual_coin.go | 63 ++ .../db/db_virtual_coin_relate.go | 16 + super_cloud_issuance/db/dbs_sys_cfg.go | 55 ++ super_cloud_issuance/db/model/cloud_bundle.go | 17 + super_cloud_issuance/db/model/db_mapping.go | 18 + .../db/model/fin_user_flow.go | 30 + super_cloud_issuance/db/model/ord_list.go | 46 ++ .../db/model/provider_icon.go | 9 + super_cloud_issuance/db/model/sys_cfg.go | 7 + super_cloud_issuance/db/model/sys_module.go | 34 + .../db/model/sys_push_user.go | 18 + super_cloud_issuance/db/model/sys_template.go | 19 + super_cloud_issuance/db/model/user.go | 25 + .../db/model/user_app_domain.go | 8 + super_cloud_issuance/db/model/user_level.go | 20 + super_cloud_issuance/db/model/user_profile.go | 91 +++ super_cloud_issuance/db/model/user_relate.go | 13 + super_cloud_issuance/db/model/user_tag.go | 13 + .../db/model/user_virtual_amount.go | 8 + .../db/model/user_virtual_assets.go | 8 + .../db/model/user_virtual_coin_flow.go | 21 + super_cloud_issuance/db/model/virtual_coin.go | 17 + .../db/model/virtual_coin_relate.go | 12 + .../db/model/wx_applet_list.go | 41 ++ .../official/db_super_cloud_issuance_baisc.go | 15 + .../db_super_cloud_issuance_master.go | 117 ++++ .../db_super_cloud_issuance_master_buy_ord.go | 117 ++++ .../db_super_cloud_issuance_robot_records.go | 62 ++ .../model/super_cloud_issuance_basic.go | 15 + .../model/super_cloud_issuance_master.go | 14 + .../super_cloud_issuance_master_buy_ord.go | 22 + .../model/super_cloud_issuance_robot.go | 15 + .../super_cloud_issuance_robot_records.go | 8 + .../db/official/model/user_app_list.go | 8 + .../db/official/model/user_app_member.go | 8 + super_cloud_issuance/db/zhimeng_db.go | 41 ++ super_cloud_issuance/enum/enum_api.go | 88 +++ .../enum/enum_goods_category.go | 31 + ...loud_issuance_add_group_welcome_message.go | 19 + ...uance_keyword_reply_with_activate_group.go | 55 ++ ..._super_cloud_issuance_user_group_manage.go | 109 +++ ...um_super_cloud_issuance_user_robot_kind.go | 19 + ...um_super_cloud_issuance_user_robot_type.go | 31 + ...issuance_user_robot_with_activate_group.go | 19 + super_cloud_issuance/lib/auth/base.go | 23 + super_cloud_issuance/lib/baidu/shorten_url.go | 40 ++ .../lib/qiniu/bucket_create.go | 16 + .../lib/qiniu/bucket_delete.go | 18 + .../lib/qiniu/bucket_get_domain.go | 18 + super_cloud_issuance/lib/qiniu/init.go | 22 + .../lib/qiniu/req_img_upload.go | 54 ++ super_cloud_issuance/lib/zhimeng/api.go | 66 ++ super_cloud_issuance/lib/zhimeng/sdk.go | 162 +++++ super_cloud_issuance/md/alipay.go | 64 ++ super_cloud_issuance/md/app_redis_key.go | 11 + super_cloud_issuance/md/cfg_key.go | 19 + super_cloud_issuance/md/file.go | 54 ++ super_cloud_issuance/md/md_api.go | 183 ++++++ super_cloud_issuance/md/md_call_back.go | 18 + super_cloud_issuance/md/mod.go | 143 ++++ super_cloud_issuance/md/mq.go | 14 + super_cloud_issuance/md/pay.go | 49 ++ super_cloud_issuance/md/platform.go | 38 ++ super_cloud_issuance/md/split_db.go | 42 ++ super_cloud_issuance/md/user_info.go | 39 ++ super_cloud_issuance/md/wxpay.go | 30 + super_cloud_issuance/svc/copy_writing.go | 89 +++ super_cloud_issuance/svc/svc_auth.go | 14 + .../svc/svc_cloud_issuance.go | 369 +++++++++++ super_cloud_issuance/svc/svc_db.go | 11 + .../svc/svc_deal_call_back.go | 210 ++++++ super_cloud_issuance/svc/svc_domain_info.go | 58 ++ .../svc/svc_file_img_format.go | 71 ++ .../svc/svc_file_img_upload.go | 103 +++ super_cloud_issuance/svc/svc_fin_user_flow.go | 68 ++ .../svc/svc_redis_mutex_lock.go | 85 +++ super_cloud_issuance/svc/svc_sys_cfg_get.go | 137 ++++ .../svc/svc_validate_common.go | 26 + .../tool/super_cloud_issuance/api.go | 101 +++ super_cloud_issuance/utils/aes.go | 123 ++++ super_cloud_issuance/utils/auth.go | 46 ++ super_cloud_issuance/utils/base64.go | 95 +++ super_cloud_issuance/utils/boolean.go | 26 + super_cloud_issuance/utils/cache/base.go | 421 ++++++++++++ .../utils/cache/cache/cache.go | 107 +++ .../utils/cache/cache/conv.go | 86 +++ .../utils/cache/cache/file.go | 241 +++++++ .../utils/cache/cache/memory.go | 239 +++++++ super_cloud_issuance/utils/cache/redis.go | 408 ++++++++++++ .../utils/cache/redis_cluster.go | 622 ++++++++++++++++++ .../utils/cache/redis_pool.go | 324 +++++++++ .../utils/cache/redis_pool_cluster.go | 617 +++++++++++++++++ super_cloud_issuance/utils/commission.go | 89 +++ super_cloud_issuance/utils/convert.go | 330 ++++++++++ super_cloud_issuance/utils/crypto.go | 19 + super_cloud_issuance/utils/curl.go | 209 ++++++ super_cloud_issuance/utils/debug.go | 25 + super_cloud_issuance/utils/duplicate.go | 37 ++ super_cloud_issuance/utils/file.go | 22 + super_cloud_issuance/utils/file_and_dir.go | 29 + super_cloud_issuance/utils/format.go | 59 ++ super_cloud_issuance/utils/json.go | 38 ++ super_cloud_issuance/utils/logx/log.go | 245 +++++++ super_cloud_issuance/utils/logx/output.go | 105 +++ super_cloud_issuance/utils/logx/sugar.go | 192 ++++++ super_cloud_issuance/utils/map.go | 9 + super_cloud_issuance/utils/map_and_struct.go | 341 ++++++++++ super_cloud_issuance/utils/md5.go | 35 + .../utils/qrcode/decodeFile.go | 33 + .../utils/qrcode/getBase64.go | 43 ++ super_cloud_issuance/utils/qrcode/saveFile.go | 85 +++ super_cloud_issuance/utils/qrcode/writeWeb.go | 39 ++ super_cloud_issuance/utils/rand.go | 40 ++ super_cloud_issuance/utils/rsa.go | 170 +++++ super_cloud_issuance/utils/serialize.go | 23 + super_cloud_issuance/utils/shuffle.go | 48 ++ super_cloud_issuance/utils/sign_check.go | 125 ++++ super_cloud_issuance/utils/slice.go | 26 + .../utils/slice_and_string.go | 47 ++ super_cloud_issuance/utils/string.go | 155 +++++ super_cloud_issuance/utils/time.go | 234 +++++++ super_cloud_issuance/utils/uuid.go | 76 +++ .../utils/validator_err_trans.go | 55 ++ 144 files changed, 11836 insertions(+), 10 deletions(-) create mode 100644 consume/super_cloud_issuance_msg_callback.go create mode 100644 super_cloud_issuance/db/db_cloud_bundle.go create mode 100644 super_cloud_issuance/db/db_order.go create mode 100644 super_cloud_issuance/db/db_provider.go create mode 100644 super_cloud_issuance/db/db_sys_cfg.go create mode 100644 super_cloud_issuance/db/db_sys_mod.go create mode 100644 super_cloud_issuance/db/db_sys_mod_format_img.go create mode 100644 super_cloud_issuance/db/db_user.go create mode 100644 super_cloud_issuance/db/db_user_fin_flow.go create mode 100644 super_cloud_issuance/db/db_user_level.go create mode 100644 super_cloud_issuance/db/db_user_profile.go create mode 100644 super_cloud_issuance/db/db_user_relate.go create mode 100644 super_cloud_issuance/db/db_user_virtual_amount.go create mode 100644 super_cloud_issuance/db/db_virtual_coin.go create mode 100644 super_cloud_issuance/db/db_virtual_coin_relate.go create mode 100644 super_cloud_issuance/db/dbs_sys_cfg.go create mode 100644 super_cloud_issuance/db/model/cloud_bundle.go create mode 100644 super_cloud_issuance/db/model/db_mapping.go create mode 100644 super_cloud_issuance/db/model/fin_user_flow.go create mode 100644 super_cloud_issuance/db/model/ord_list.go create mode 100644 super_cloud_issuance/db/model/provider_icon.go create mode 100644 super_cloud_issuance/db/model/sys_cfg.go create mode 100644 super_cloud_issuance/db/model/sys_module.go create mode 100644 super_cloud_issuance/db/model/sys_push_user.go create mode 100644 super_cloud_issuance/db/model/sys_template.go create mode 100644 super_cloud_issuance/db/model/user.go create mode 100644 super_cloud_issuance/db/model/user_app_domain.go create mode 100644 super_cloud_issuance/db/model/user_level.go create mode 100644 super_cloud_issuance/db/model/user_profile.go create mode 100644 super_cloud_issuance/db/model/user_relate.go create mode 100644 super_cloud_issuance/db/model/user_tag.go create mode 100644 super_cloud_issuance/db/model/user_virtual_amount.go create mode 100644 super_cloud_issuance/db/model/user_virtual_assets.go create mode 100644 super_cloud_issuance/db/model/user_virtual_coin_flow.go create mode 100644 super_cloud_issuance/db/model/virtual_coin.go create mode 100644 super_cloud_issuance/db/model/virtual_coin_relate.go create mode 100644 super_cloud_issuance/db/model/wx_applet_list.go create mode 100644 super_cloud_issuance/db/official/db_super_cloud_issuance_baisc.go create mode 100644 super_cloud_issuance/db/official/db_super_cloud_issuance_master.go create mode 100644 super_cloud_issuance/db/official/db_super_cloud_issuance_master_buy_ord.go create mode 100644 super_cloud_issuance/db/official/db_super_cloud_issuance_robot_records.go create mode 100644 super_cloud_issuance/db/official/model/super_cloud_issuance_basic.go create mode 100644 super_cloud_issuance/db/official/model/super_cloud_issuance_master.go create mode 100644 super_cloud_issuance/db/official/model/super_cloud_issuance_master_buy_ord.go create mode 100644 super_cloud_issuance/db/official/model/super_cloud_issuance_robot.go create mode 100644 super_cloud_issuance/db/official/model/super_cloud_issuance_robot_records.go create mode 100644 super_cloud_issuance/db/official/model/user_app_list.go create mode 100644 super_cloud_issuance/db/official/model/user_app_member.go create mode 100644 super_cloud_issuance/db/zhimeng_db.go create mode 100644 super_cloud_issuance/enum/enum_api.go create mode 100644 super_cloud_issuance/enum/enum_goods_category.go create mode 100644 super_cloud_issuance/enum/enum_super_cloud_issuance_add_group_welcome_message.go create mode 100644 super_cloud_issuance/enum/enum_super_cloud_issuance_keyword_reply_with_activate_group.go create mode 100644 super_cloud_issuance/enum/enum_super_cloud_issuance_user_group_manage.go create mode 100644 super_cloud_issuance/enum/enum_super_cloud_issuance_user_robot_kind.go create mode 100644 super_cloud_issuance/enum/enum_super_cloud_issuance_user_robot_type.go create mode 100644 super_cloud_issuance/enum/enum_super_cloud_issuance_user_robot_with_activate_group.go create mode 100644 super_cloud_issuance/lib/auth/base.go create mode 100644 super_cloud_issuance/lib/baidu/shorten_url.go create mode 100644 super_cloud_issuance/lib/qiniu/bucket_create.go create mode 100644 super_cloud_issuance/lib/qiniu/bucket_delete.go create mode 100644 super_cloud_issuance/lib/qiniu/bucket_get_domain.go create mode 100644 super_cloud_issuance/lib/qiniu/init.go create mode 100644 super_cloud_issuance/lib/qiniu/req_img_upload.go create mode 100644 super_cloud_issuance/lib/zhimeng/api.go create mode 100644 super_cloud_issuance/lib/zhimeng/sdk.go create mode 100644 super_cloud_issuance/md/alipay.go create mode 100644 super_cloud_issuance/md/app_redis_key.go create mode 100644 super_cloud_issuance/md/cfg_key.go create mode 100644 super_cloud_issuance/md/file.go create mode 100644 super_cloud_issuance/md/md_api.go create mode 100644 super_cloud_issuance/md/md_call_back.go create mode 100644 super_cloud_issuance/md/mod.go create mode 100644 super_cloud_issuance/md/mq.go create mode 100644 super_cloud_issuance/md/pay.go create mode 100644 super_cloud_issuance/md/platform.go create mode 100644 super_cloud_issuance/md/split_db.go create mode 100644 super_cloud_issuance/md/user_info.go create mode 100644 super_cloud_issuance/md/wxpay.go create mode 100644 super_cloud_issuance/svc/copy_writing.go create mode 100644 super_cloud_issuance/svc/svc_auth.go create mode 100644 super_cloud_issuance/svc/svc_cloud_issuance.go create mode 100644 super_cloud_issuance/svc/svc_db.go create mode 100644 super_cloud_issuance/svc/svc_deal_call_back.go create mode 100644 super_cloud_issuance/svc/svc_domain_info.go create mode 100644 super_cloud_issuance/svc/svc_file_img_format.go create mode 100644 super_cloud_issuance/svc/svc_file_img_upload.go create mode 100644 super_cloud_issuance/svc/svc_fin_user_flow.go create mode 100644 super_cloud_issuance/svc/svc_redis_mutex_lock.go create mode 100644 super_cloud_issuance/svc/svc_sys_cfg_get.go create mode 100644 super_cloud_issuance/svc/svc_validate_common.go create mode 100644 super_cloud_issuance/tool/super_cloud_issuance/api.go create mode 100644 super_cloud_issuance/utils/aes.go create mode 100644 super_cloud_issuance/utils/auth.go create mode 100644 super_cloud_issuance/utils/base64.go create mode 100644 super_cloud_issuance/utils/boolean.go create mode 100644 super_cloud_issuance/utils/cache/base.go create mode 100644 super_cloud_issuance/utils/cache/cache/cache.go create mode 100644 super_cloud_issuance/utils/cache/cache/conv.go create mode 100644 super_cloud_issuance/utils/cache/cache/file.go create mode 100644 super_cloud_issuance/utils/cache/cache/memory.go create mode 100644 super_cloud_issuance/utils/cache/redis.go create mode 100644 super_cloud_issuance/utils/cache/redis_cluster.go create mode 100644 super_cloud_issuance/utils/cache/redis_pool.go create mode 100644 super_cloud_issuance/utils/cache/redis_pool_cluster.go create mode 100644 super_cloud_issuance/utils/commission.go create mode 100644 super_cloud_issuance/utils/convert.go create mode 100644 super_cloud_issuance/utils/crypto.go create mode 100644 super_cloud_issuance/utils/curl.go create mode 100644 super_cloud_issuance/utils/debug.go create mode 100644 super_cloud_issuance/utils/duplicate.go create mode 100644 super_cloud_issuance/utils/file.go create mode 100644 super_cloud_issuance/utils/file_and_dir.go create mode 100644 super_cloud_issuance/utils/format.go create mode 100644 super_cloud_issuance/utils/json.go create mode 100644 super_cloud_issuance/utils/logx/log.go create mode 100644 super_cloud_issuance/utils/logx/output.go create mode 100644 super_cloud_issuance/utils/logx/sugar.go create mode 100644 super_cloud_issuance/utils/map.go create mode 100644 super_cloud_issuance/utils/map_and_struct.go create mode 100644 super_cloud_issuance/utils/md5.go create mode 100644 super_cloud_issuance/utils/qrcode/decodeFile.go create mode 100644 super_cloud_issuance/utils/qrcode/getBase64.go create mode 100644 super_cloud_issuance/utils/qrcode/saveFile.go create mode 100644 super_cloud_issuance/utils/qrcode/writeWeb.go create mode 100644 super_cloud_issuance/utils/rand.go create mode 100644 super_cloud_issuance/utils/rsa.go create mode 100644 super_cloud_issuance/utils/serialize.go create mode 100644 super_cloud_issuance/utils/shuffle.go create mode 100644 super_cloud_issuance/utils/sign_check.go create mode 100644 super_cloud_issuance/utils/slice.go create mode 100644 super_cloud_issuance/utils/slice_and_string.go create mode 100644 super_cloud_issuance/utils/string.go create mode 100644 super_cloud_issuance/utils/time.go create mode 100644 super_cloud_issuance/utils/uuid.go create mode 100644 super_cloud_issuance/utils/validator_err_trans.go diff --git a/app/cfg/cfg_app.go b/app/cfg/cfg_app.go index 40cf15b..3d94740 100644 --- a/app/cfg/cfg_app.go +++ b/app/cfg/cfg_app.go @@ -26,6 +26,7 @@ type Config struct { WxappletFilepath WxappletFilepathCfg `yaml:"wxapplet_filepath"` Local bool AppComm AppCommCfg `yaml:"app_comm"` + ZhimengDB DBCfg `yaml:"zhimeng_db"` } // 公共模块 diff --git a/app/cfg/init_cfg.go b/app/cfg/init_cfg.go index 5e16535..41ba944 100644 --- a/app/cfg/init_cfg.go +++ b/app/cfg/init_cfg.go @@ -25,6 +25,7 @@ var ( Local bool AppComm *AppCommCfg WxappletFilepath *WxappletFilepathCfg + ZhimengDB *DBCfg ) //初始化配置文件,将cfg.yml读入到内存 @@ -63,4 +64,5 @@ func InitCfg() { ImBusinessRpc = &conf.ImBusinessRpc ImLogicRpc = &conf.ImLogicRpc WxappletFilepath = &conf.WxappletFilepath + ZhimengDB = &conf.ZhimengDB } diff --git a/cloud_issuance/svc/svc_deal_call_back.go b/cloud_issuance/svc/svc_deal_call_back.go index 2b3ecd1..fd9196b 100644 --- a/cloud_issuance/svc/svc_deal_call_back.go +++ b/cloud_issuance/svc/svc_deal_call_back.go @@ -8,6 +8,7 @@ import ( "applet/cloud_issuance/db" "applet/cloud_issuance/enum" "applet/cloud_issuance/md" + db3 "applet/super_cloud_issuance/db" "code.fnuoos.com/go_rely_warehouse/zyos_go_third_party_api.git/chain_transfer" cache2 "code.fnuoos.com/go_rely_warehouse/zyos_go_third_party_api.git/utils/cache" "fmt" @@ -63,7 +64,7 @@ func (dealCloudIssuanceCallBackService *DealCloudIssuanceCallBackService) DealCa utils.FilePutContents("cloud", utils.SerializeStr(args)) randInt := utils.RandIntRand(10, 100) time.Sleep(time.Millisecond * time.Duration(randInt)) // 等待10 ~ 100毫秒 - chain := chain_transfer.TurnChain(svc.MasterDb(c), db2.Db, args) + chain := chain_transfer.TurnChain(svc.MasterDb(c), db3.ZhimengDb, db2.Db, args) utils.FilePutContents("cloud_resp", utils.SerializeStr(chain)) if chain.Count != "" { req.Data.Content = chain.Count diff --git a/consume/init.go b/consume/init.go index 55d464e..1788ab6 100644 --- a/consume/init.go +++ b/consume/init.go @@ -79,12 +79,12 @@ func initConsumes() { //jobs[consumeMd.CanalUserVirtualCcoinFlowFunName] = CanalUserVirtualCoinFlowConsume //////////////////////////////////////// oneCircles ///////////////////////////////////////////////////// - - jobs[consumeMd.OneCirclesSignInGreenEnergyFunName] = OneCirclesSignInGreenEnergyConsume - jobs[consumeMd.OneCirclesStartLevelDividendFunName] = OneCirclesStartLevelDividendConsume - jobs[consumeMd.OneCirclesActivityCoinAutoExchangeGreenEnergyFunName] = OneCirclesActivityCoinAutoExchangeGreenEnergyConsume - jobs[consumeMd.OneCirclesActivityCoinAutoExchangeGreenEnergyForTeamFunName] = OneCirclesActivityCoinAutoExchangeGreenEnergyForTeamConsume - jobs[consumeMd.OneCirclesSettlementPublicGiveActivityCoinFunName] = OneCirclesSettlementPublicGiveActivityCoinConsume + // + //jobs[consumeMd.OneCirclesSignInGreenEnergyFunName] = OneCirclesSignInGreenEnergyConsume + //jobs[consumeMd.OneCirclesStartLevelDividendFunName] = OneCirclesStartLevelDividendConsume + //jobs[consumeMd.OneCirclesActivityCoinAutoExchangeGreenEnergyFunName] = OneCirclesActivityCoinAutoExchangeGreenEnergyConsume + //jobs[consumeMd.OneCirclesActivityCoinAutoExchangeGreenEnergyForTeamFunName] = OneCirclesActivityCoinAutoExchangeGreenEnergyForTeamConsume + //jobs[consumeMd.OneCirclesSettlementPublicGiveActivityCoinFunName] = OneCirclesSettlementPublicGiveActivityCoinConsume //jobs[consumeMd.OneCirclesSignInCopyGreenEnergyFunName] = OneCirclesSignInCopyGreenEnergyConsume //////////////////////////////////////// withdraw ///////////////////////////////////////////////////// @@ -98,6 +98,8 @@ func initConsumes() { //////////////////////////////////////// autoRepaid ///////////////////////////////////////////////////// //jobs[consumeMd.InstallmentPaymentAutoRepaidConsumeFunName] = InstallmentPaymentAutoRepaidConsume //分期付 - 自动扣款 + ////////////////////////////////////// SuperCloudIssuance ///////////////////////////////////////////////////// + jobs[consumeMd.SuperCloudIssuanceMsgCallBackFunName] = SuperCloudIssuanceMsgCallBackConsume } func Run() { diff --git a/consume/md/consume_key.go b/consume/md/consume_key.go index 0c3b002..571b0d3 100644 --- a/consume/md/consume_key.go +++ b/consume/md/consume_key.go @@ -29,6 +29,15 @@ var RabbitMqQueueKeyList = []*MqQueue{ BindKey: "", ConsumeFunName: "CloudIssuanceMsgCallBackConsume", }, + { + ExchangeName: "zhios.super.cloud.issuance.msg.callback.exchange", + Name: "super_cloud_issuance_msg_call_back", + Type: DirectQueueType, + IsPersistent: false, + RoutKey: "", + BindKey: "", + ConsumeFunName: "SuperCloudIssuanceMsgCallBackConsume", + }, { ExchangeName: "zhios.cloud_chain.fenxiao.newChange.exchange", Name: "cloud_chain_fenxiao_newChange", @@ -545,6 +554,7 @@ const ( ZhiosTikTokAllUpdateFunName = "ZhiosTikTokAllUpdate" CloudIssuanceAsyncMLoginFunName = "CloudIssuanceAsyncMLoginConsume" CloudIssuanceMsgCallBackFunName = "CloudIssuanceMsgCallBackConsume" + SuperCloudIssuanceMsgCallBackFunName = "SuperCloudIssuanceMsgCallBackConsume" ZhiosAcquisitionConditionFunName = "ZhiosAcquisitionCondition" ZhiosValidUserFunName = "ZhiosValidUser" ZhiosAppreciationFunName = "ZhiosAppreciation" diff --git a/consume/super_cloud_issuance_msg_callback.go b/consume/super_cloud_issuance_msg_callback.go new file mode 100644 index 0000000..fef7196 --- /dev/null +++ b/consume/super_cloud_issuance_msg_callback.go @@ -0,0 +1,72 @@ +package consume + +import ( + "applet/app/utils" + "applet/app/utils/logx" + "applet/consume/md" + db "applet/super_cloud_issuance/db/official" + md2 "applet/super_cloud_issuance/md" + "applet/super_cloud_issuance/svc" + "code.fnuoos.com/go_rely_warehouse/zyos_go_mq.git/rabbit" + "encoding/json" + "errors" + "fmt" + "github.com/gin-gonic/gin" + "github.com/streadway/amqp" + "time" +) + +func SuperCloudIssuanceMsgCallBackConsume(queue md.MqQueue) { + fmt.Println(">>>>>>>>>>>>>>>>>>>>>>>>") + ch, err := rabbit.Cfg.Pool.GetChannel() + if err != nil { + logx.Error(err) + return + } + defer ch.Release() + //2、取出数据进行消费 + ch.Qos(10) + delivery := ch.Consume(queue.Name, false) + + var res amqp.Delivery + var ok bool + for { + res, ok = <-delivery + if ok == true { + fmt.Println(">>>>>>>>>>>>>>>>CloudIssuanceMsgCallBackConsume<<<<<<<<<<<<<<<<<<<<<<<<<") + //解析mq中queue的数据结构体 + var msg *md2.CallbackRequest + err = json.Unmarshal(res.Body, &msg) + if err != nil { + panic(err) + } + randInt := utils.RandIntRand(100, 200) + time.Sleep(time.Millisecond * time.Duration(randInt)) // 等待100 ~ 200毫秒 + go func() { + //设置masterId + cloudIssuanceRobotRecords, err := db.SuperCloudIssuanceRobotRecordsGetOneByParams(map[string]interface{}{ + "key": "robot_id", + "value": msg.RobotId, + }) + if err != nil { + fmt.Println("CallBackErr:::::", err.Error()) + return + } + if cloudIssuanceRobotRecords == nil { + //TODO::未查询到机器人,不需要处理 + utils.FilePutContents("cloud_issuance_call_back_not_found", utils.SerializeStr(msg)) + return + } + var c = &gin.Context{} + c.Set("mid", cloudIssuanceRobotRecords.MasterId) + dealCloudIssuanceCallBackService := svc.DealSuperCloudIssuanceCallBackService{} + dealCloudIssuanceCallBackService.Set(c) + dealCloudIssuanceCallBackService.DealCallBack(c, *msg) + }() + _ = res.Ack(true) + } else { + panic(errors.New("error getting message")) + } + } + fmt.Println("get msg done") +} diff --git a/etc/cfg.yml b/etc/cfg.yml index cdeed99..fc3641f 100644 --- a/etc/cfg.yml +++ b/etc/cfg.yml @@ -39,6 +39,17 @@ db: max_idle_conns: 100 path: 'tmp/%s.log' +zhimeng_db: +host: '119.23.182.117:3306' +name: 'zhi_meng' +user: 'root' +psw: 'Fnuo123com@' +show_log: true +max_lifetime: 30 +max_open_conns: 100 +max_idle_conns: 100 +path: 'tmp/%s.log' + # 连接 big_data_screen 数据库 data_db: host: 'zhios123.rwlb.rds.aliyuncs.com:3306' diff --git a/go.mod b/go.mod index f7b9c82..e3d091b 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( code.fnuoos.com/go_rely_warehouse/zyos_go_mq.git v0.0.5 code.fnuoos.com/go_rely_warehouse/zyos_go_order_relate_rule.git v1.9.10-0.20240621133142-77a2bc0a37a1 code.fnuoos.com/go_rely_warehouse/zyos_go_pay.git v1.6.2-0.20231116085701-9ba6e19f877b - code.fnuoos.com/go_rely_warehouse/zyos_go_third_party_api.git v1.1.21-0.20240126015516-38ca248db2fd + code.fnuoos.com/go_rely_warehouse/zyos_go_third_party_api.git v1.1.21-0.20240611024753-7cd929a03014 github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5 github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 github.com/boombuler/barcode v1.0.1 @@ -25,7 +25,7 @@ require ( github.com/go-sql-driver/mysql v1.8.1 github.com/gomodule/redigo v2.0.0+incompatible github.com/iGoogle-ink/gopay v1.5.36 - github.com/jinzhu/copier v0.3.5 + github.com/jinzhu/copier v0.4.0 github.com/json-iterator/go v1.1.12 github.com/makiuchi-d/gozxing v0.1.1 github.com/mingrammer/commonregex v1.0.1 @@ -45,7 +45,7 @@ require ( ) require ( - code.fnuoos.com/go_rely_warehouse/zyos_model.git v0.0.4-0.20240620100400-9ebf54e21441 // indirect + code.fnuoos.com/go_rely_warehouse/zyos_model.git v0.0.4-0.20240627143928-f533f5e7e4a0 // indirect filippo.io/edwards25519 v1.1.0 // indirect github.com/KyleBanks/depth v1.2.1 // indirect github.com/PuerkitoBio/purell v1.1.1 // indirect diff --git a/main.go b/main.go index 08535b1..70eb40e 100644 --- a/main.go +++ b/main.go @@ -6,6 +6,7 @@ import ( "applet/app/utils" "applet/app/utils/logx" "applet/consume" + db2 "applet/super_cloud_issuance/db" "fmt" "os" "os/signal" @@ -29,6 +30,9 @@ func init() { if err := db.InitImDB(cfg.ImDB); err != nil { //im本身库初始化 panic(err) } + if err := db2.InitZhimengDB(cfg.ZhimengDB); err != nil { + panic(err) + } channel := make(chan int, 0) //开辟管道,缓冲为 go db.InitDBs(channel) <-channel diff --git a/super_cloud_issuance/db/db_cloud_bundle.go b/super_cloud_issuance/db/db_cloud_bundle.go new file mode 100644 index 0000000..5a3fbaa --- /dev/null +++ b/super_cloud_issuance/db/db_cloud_bundle.go @@ -0,0 +1,40 @@ +package db + +import ( + model2 "applet/super_cloud_issuance/db/model" + "errors" + + "xorm.io/xorm" +) + +// GetCloudBundleByVersion is 根据版本 获取打包记录 +func GetCloudBundleByVersion(Db *xorm.Engine, appverison string, os int) (*model2.CloudBundle, error) { + m := new(model2.CloudBundle) + has, err := Db.Where("version = ? and os = ?", appverison, os).Get(m) + if err != nil { + return nil, err + } + if !has { + return nil, errors.New("not Found") + } + return m, nil +} + +// GetCloudBundleByVersionPlatform is 根据版本\os 获取打包记录 +func GetCloudBundleByVersionPlatform(Db *xorm.Engine, appverison string, platform string) (*model2.CloudBundle, error) { + m := new(model2.CloudBundle) + var tag int + if platform == "ios" { + tag = 2 + } else { + tag = 1 + } + has, err := Db.Where("version = ? and os=?", appverison, tag).Get(m) + if err != nil { + return nil, err + } + if !has { + return nil, errors.New("not Found") + } + return m, nil +} diff --git a/super_cloud_issuance/db/db_order.go b/super_cloud_issuance/db/db_order.go new file mode 100644 index 0000000..598c882 --- /dev/null +++ b/super_cloud_issuance/db/db_order.go @@ -0,0 +1,21 @@ +package db + +import ( + "applet/app/db/model" + "applet/app/utils" + "fmt" + "xorm.io/xorm" +) + +func OrderListPaidPriceByUIDByOrderTypeByTime(Db *xorm.Engine, uid, buyType, state, stime, etime interface{}) (float64, error) { + + str := fmt.Sprintf("uid = %s AND order_type = %s AND ( state in (%s) or settle_at>0) AND create_at > %s AND create_at < %s", + utils.AnyToString(uid), buyType, state, stime, etime) + fmt.Println("============test订单数=================") + fmt.Println(str) + total, _ := Db.Where("is_game_invite=1 and uid = ? AND create_at > ? AND create_at < ? and settle_at=0", uid, stime, etime).In("state", state).Sum(&model.OrdList{}, "paid_price") + total1, _ := Db.Where("is_game_invite=1 and uid = ? AND create_at > ? AND create_at < ? and settle_at>0", uid, stime, etime).Sum(&model.OrdList{}, "paid_price") + fmt.Println(total) + + return total + total1, nil +} diff --git a/super_cloud_issuance/db/db_provider.go b/super_cloud_issuance/db/db_provider.go new file mode 100644 index 0000000..4dd1b9e --- /dev/null +++ b/super_cloud_issuance/db/db_provider.go @@ -0,0 +1,27 @@ +package db + +import ( + model2 "applet/super_cloud_issuance/db/model" + "xorm.io/xorm" +) + +func GetProvider(eg *xorm.Engine, types string) map[string]string { + var data []model2.ProviderIcon + err := eg.Where("type=?", types).Find(&data) + if err != nil { + return nil + } + list := make(map[string]string) + for _, v := range data { + list[v.Pvd] = v.Icon + } + return list +} +func GetProviderOne(eg *xorm.Engine, id string) *model2.ProviderIcon { + var data model2.ProviderIcon + get, err := eg.Where("id=?", id).Get(&data) + if get == false || err != nil { + return nil + } + return &data +} diff --git a/super_cloud_issuance/db/db_sys_cfg.go b/super_cloud_issuance/db/db_sys_cfg.go new file mode 100644 index 0000000..4914606 --- /dev/null +++ b/super_cloud_issuance/db/db_sys_cfg.go @@ -0,0 +1,104 @@ +package db + +import ( + "applet/app/db/model" + "applet/app/md" + "applet/app/utils/cache" + "applet/app/utils/logx" + "fmt" + "xorm.io/xorm" +) + +// 系统配置get +func SysCfgGetAll(Db *xorm.Engine) (*[]model.SysCfg, error) { + var cfgList []model.SysCfg + if err := Db.Cols("key,val,memo").Find(&cfgList); err != nil { + return nil, logx.Error(err) + } + return &cfgList, nil +} + +// 获取一条记录 +func SysCfgGetOne(Db *xorm.Engine, key string) (*model.SysCfg, error) { + var cfgList model.SysCfg + if has, err := Db.Where("`key`=?", key).Get(&cfgList); err != nil || has == false { + return nil, logx.Error(err) + } + return &cfgList, nil +} + +// 单条记录获取DB +func SysCfgGetWithDb(eg *xorm.Engine, masterId string, HKey string) string { + cacheKey := fmt.Sprintf(md.AppCfgCacheKey, masterId) + HKey + get, err := cache.GetString(cacheKey) + if err != nil || get == "" { + cfg, err := SysCfgGetOne(eg, HKey) + if err != nil || cfg == nil { + _ = logx.Error(err) + return "" + } + + // key是否存在 + cacheKeyExist := false + if cache.Exists(cacheKey) { + cacheKeyExist = true + } + + // 设置缓存 + _, err = cache.Set(cacheKey, cfg.Val) + if err != nil { + _ = logx.Error(err) + return "" + } + if !cacheKeyExist { // 如果是首次设置 设置过期时间 + _, err := cache.Expire(cacheKey, md.CfgCacheTime) + if err != nil { + _ = logx.Error(err) + return "" + } + } + return cfg.Val + } + return get +} + +// 多条记录获取DB +func SysCfgFindWithDb(eg *xorm.Engine, masterId string, keys ...string) map[string]string { + res := map[string]string{} + //TODO::判断keys长度(大于5个直接查数据库) + if len(keys) > 5 { + cfgList, _ := SysCfgGetAll(eg) + if cfgList == nil { + return nil + } + for _, v := range *cfgList { + res[v.Key] = v.Val + } + } else { + for _, key := range keys { + res[key] = SysCfgGetWithDb(eg, masterId, key) + } + } + return res +} + +// 返回最后插入id +func SysCfgInsert(Db *xorm.Engine, key, val, memo string) bool { + cfg := model.SysCfg{Key: key, Val: val, Memo: memo} + _, err := Db.InsertOne(&cfg) + if err != nil { + logx.Error(err) + return false + } + return true +} + +func SysCfgUpdate(Db *xorm.Engine, key, val, memo string) bool { + cfg := model.SysCfg{Key: key, Val: val, Memo: memo} + _, err := Db.Where("`key`=?", key).Cols("val,memo").Update(&cfg) + if err != nil { + logx.Error(err) + return false + } + return true +} diff --git a/super_cloud_issuance/db/db_sys_mod.go b/super_cloud_issuance/db/db_sys_mod.go new file mode 100644 index 0000000..c9c4ddf --- /dev/null +++ b/super_cloud_issuance/db/db_sys_mod.go @@ -0,0 +1,79 @@ +package db + +import ( + "applet/app/utils/logx" + model2 "applet/super_cloud_issuance/db/model" + "xorm.io/xorm" +) + +// 返回所有, 不管是否显示 +func SysModFindAll(Db *xorm.Engine) (*[]model2.SysModule, error) { + var m []model2.SysModule + if err := Db.Find(&m); err != nil { + return nil, err + } + return &m, nil +} + +// 查找主模块数据 +func SysModFindMain(Db *xorm.Engine) (*[]model2.SysModule, error) { + var m []model2.SysModule + if err := Db.Where("mod_pid = 0 AND state = 1 AND position = 'base'"). + Asc("sort"). + Find(&m); err != nil { + return nil, err + } + return &m, nil +} + +// 用IDS找对应模块数据 +func SysModFindByIds(Db *xorm.Engine, ids ...int) (*[]model2.SysModule, error) { + var m []model2.SysModule + if err := Db.In("mod_id", ids).Where("state = 1"). + Cols("mod_id,mod_pid,mod_name,position,skip_identifier,title,subtitle,url,margin,aspect_ratio,icon,img,font_color,bg_img,bg_color,bg_color_t,badge,path,data,sort"). + Asc("sort").Find(&m); err != nil { + return nil, err + } + + return &m, nil +} + +// SysModFindByPosition is 根据位置查找对应模块 +func SysModFindByPosition(Db *xorm.Engine, positions ...string) (*[]model2.SysModule, error) { + var m []model2.SysModule + if err := Db.In("position", positions).Where("state = 1").Find(&m); err != nil { + return nil, err + } + return &m, nil +} + +// SysModFindByTemplateIDAndSkip is 根据模板id 查找对应模块 +func SysModFindByTemplateIDAndSkip(Db *xorm.Engine, id interface{}, skip string) (*model2.SysModule, error) { + var m model2.SysModule + if has, err := Db.Where("state = 1 AND template_id = ? AND skip_identifier = ?", id, skip). + Get(&m); err != nil || has == false { + return nil, logx.Warn(err) + } + return &m, nil +} + +// SysModFindByTemplateIDAndPID is 根据模板id 和pid =0 查找父模块 +func SysModFindByTemplateIDAndPID(Db *xorm.Engine, id interface{}, pid interface{}) (*model2.SysModule, error) { + var m model2.SysModule + if has, err := Db.Where("state = 1 AND template_id = ? AND mod_pid = ?", id, pid). + Get(&m); err != nil || has == false { + return nil, logx.Warn(err) + } + + return &m, nil +} + +// SysModFindByTemplateIDAndModName is 根据模板id 和mod name 查找模块 +func SysModFindByTemplateIDAndModName(Db *xorm.Engine, id interface{}, modName string) (*model2.SysModule, error) { + var m model2.SysModule + if has, err := Db.Where("state = 1 AND template_id = ? AND mod_name = ?", id, modName). + Get(&m); err != nil || has == false { + return nil, logx.Warn(err) + } + return &m, nil +} diff --git a/super_cloud_issuance/db/db_sys_mod_format_img.go b/super_cloud_issuance/db/db_sys_mod_format_img.go new file mode 100644 index 0000000..3d29fb2 --- /dev/null +++ b/super_cloud_issuance/db/db_sys_mod_format_img.go @@ -0,0 +1,156 @@ +package db + +import ( + "applet/app/cfg" + "applet/app/utils/logx" + "fmt" + "github.com/syyongx/php2go" + "regexp" + "strings" + + "github.com/gin-gonic/gin" +) + +func ReformatStr(str string, c *gin.Context) string { + protocol := SysCfgGet(c, "file_bucket_scheme") + domain := SysCfgGet(c, "file_bucket_host") + + // PNG + replaceList := reformatPng(str) + l := removeDuplicateElement(replaceList) + for _, s := range l { + if strings.Contains(s, "http") { + continue + } + s = strings.ReplaceAll(s, `\`, "") + s = php2go.Rawurlencode(s) + new := fmt.Sprintf("%s://%s/%s", protocol, domain, s) + if skipHTTPPng(new) { + continue + } + ss := s + s = strings.ReplaceAll(s, `"`, "") + str = strings.Replace(str, ss, `"`+new+`"`, -1) + } + + // JPG + replaceList = reformatJPG(str) + l = removeDuplicateElement(replaceList) + for _, s := range l { + if strings.Contains(s, "http") { + continue + } + s = strings.ReplaceAll(s, `\`, "") + s = php2go.Rawurlencode(s) + new := fmt.Sprintf("%s://%s/%s", protocol, domain, s) + if skipHTTPPng(new) { + continue + } + ss := s + s = strings.ReplaceAll(s, `"`, "") + str = strings.Replace(str, ss, `"`+new+`"`, -1) + } + + // GIF + replaceList = reformatGIF(str) + l = removeDuplicateElement(replaceList) + for _, s := range l { + if strings.Contains(s, "http") { + continue + } + s = strings.ReplaceAll(s, `\`, "") + s = php2go.Rawurlencode(s) + new := fmt.Sprintf("%s://%s/%s", protocol, domain, s) + if skipHTTPPng(new) { + continue + } + ss := s + s = strings.ReplaceAll(s, `"`, "") + str = strings.Replace(str, ss, `"`+new+`"`, -1) + } + + return str +} + +// 正则匹配 +func reformatPng(data string) []string { + re, _ := regexp.Compile(`"([^\"]*.png")`) + list := re.FindAllString(data, -1) + return list +} + +func skipHTTPPng(data string) bool { + re, _ := regexp.Compile(`(http|https):\/\/([^\"]*.png)`) + return re.MatchString(data) +} + +// 正则匹配 +func reformatJPG(data string) []string { + re, _ := regexp.Compile(`"([^\"]*.jpg")`) + list := re.FindAllString(data, -1) + return list +} + +// 正则匹配 +func reformatGIF(data string) []string { + re, _ := regexp.Compile(`"([^\"]*.gif")`) + list := re.FindAllString(data, -1) + return list +} + +func removeDuplicateElement(addrs []string) []string { + result := make([]string, 0, len(addrs)) + temp := map[string]int{} + i := 1 + for _, item := range addrs { + if _, ok := temp[item]; !ok { + temp[item] = i + result = append(result, item) + continue + } + temp[item] = temp[item] + 1 + } + // fmt.Println(temp) + return result +} + +// 单挑记录获取 +func SysCfgGet(c *gin.Context, key string) string { + eg := DBs[c.GetString("mid")] + if !cfg.Prd { + myCfg, err := SysCfgGetOne(eg, key) + if err != nil || myCfg == nil { + _ = logx.Error(err) + return "" + } + return myCfg.Val + } + res := SysCfgFind(c, key) + //fmt.Println(res) + if _, ok := res[key]; !ok { + return "" + } + return res[key] +} + +// 多条记录获取 +func SysCfgFind(c *gin.Context, keys ...string) map[string]string { + masterId := c.GetString("mid") + eg := DBs[c.GetString("mid")] + res := map[string]string{} + //TODO::判断keys长度(大于5个直接查数据库) + if len(keys) > 5 { + cfgList, _ := SysCfgGetAll(eg) + if cfgList == nil { + return nil + } + for _, v := range *cfgList { + res[v.Key] = v.Val + } + } else { + for _, key := range keys { + res[key] = SysCfgGetWithDb(eg, masterId, key) + } + } + return res +} diff --git a/super_cloud_issuance/db/db_user.go b/super_cloud_issuance/db/db_user.go new file mode 100644 index 0000000..1860539 --- /dev/null +++ b/super_cloud_issuance/db/db_user.go @@ -0,0 +1,298 @@ +package db + +import ( + "applet/app/db/model" + "applet/app/utils" + "applet/app/utils/logx" + "fmt" + "xorm.io/xorm" +) + +// UserisExistByUsernameAndPassword is usernameAndPassword exist +func UserisExistByUsernameAndPassword(Db *xorm.Engine, username string, password string) (bool, error) { + + has, err := Db.Where("username = ? AND password = ?", username, utils.Md5(password)).Exist(&model.User{}) + + if err != nil { + return false, err + } + return has, nil +} + +// UserisExistByMobile is exist +func UserisExistByMobile(Db *xorm.Engine, n string) (bool, error) { + has, err := Db.Where("phone = ?", n).Exist(&model.User{}) + + if err != nil { + return false, err + } + return has, nil +} + +// UserInByUIDByLevel is In查询 以及是否是有效用户 +func UserInByUIDByLevel(Db *xorm.Engine, ids []int, levelID interface{}) (*[]model.User, error) { + var m []model.User + if err := Db.In("uid", ids).Where("level = ?", levelID). + Find(&m); err != nil { + return nil, logx.Warn(err) + } + return &m, nil +} + +// UserFindByMobile search user by mobile +func UserFindByMobile(Db *xorm.Engine, mobile string) (*model.User, error) { + var m model.User + if has, err := Db.Where("(phone = ? OR uid = ?) AND delete_at = 0", mobile, mobile). + Get(&m); err != nil || has == false { + return nil, logx.Warn(err) + } + return &m, nil +} + +// UserFindExistByMobile search user by mobile +func UserFindExistByMobile(Db *xorm.Engine, mobile string) (*model.User, bool, error) { + var m model.User + has, err := Db.Where("(phone = ? OR uid = ?) AND delete_at = 0", mobile, mobile).Get(&m) + if err != nil { + logx.Infof("UserFindExistByMobile err") + return nil, false, logx.Warn(err) + } + return &m, has, nil +} + +// UserFindByMobile search user by mobile +func UserFindByMobileAll(Db *xorm.Engine, mobile string) (*model.User, error) { + var m model.User + if has, err := Db.Where("(phone = ? OR uid = ?)", mobile, mobile). + Get(&m); err != nil || has == false { + return nil, logx.Warn(err) + } + return &m, nil +} + +// UserGetByMobileIgnoreDelete search user by mobile ignore delete +func UserGetByMobileIgnoreDelete(Db *xorm.Engine, mobile string) (*model.User, bool, error) { + m := new(model.User) + has, err := Db.Where("phone = ?", mobile).Get(m) + if err != nil { + return nil, false, logx.Warn(err) + } + return m, has, nil +} + +// UsersFindByMobileLike search users by mobile +func UsersFindByMobileLike(Db *xorm.Engine, mobile string) (*[]model.User, error) { + var m []model.User + if err := Db.Where("phone like ?", "%"+mobile+"%"). + Find(&m); err != nil { + return nil, logx.Warn(err) + } + return &m, nil +} + +// UsersFindByNickNameLike search users by nickname +func UsersFindByNickNameLike(Db *xorm.Engine, nickname string) (*[]model.User, error) { + var m []model.User + if err := Db.Where("nickname like ?", "%"+nickname+"%"). + Find(&m); err != nil { + return nil, logx.Warn(err) + } + return &m, nil +} + +//UsersInByIds is 根据ids 查找users +func UsersInByIds(Db *xorm.Engine, ids []int, limit, start int) (*[]model.User, error) { + var m []model.User + if limit == 0 && start == 0 { + if err := Db.In("uid", ids). + Find(&m); err != nil { + return nil, logx.Warn(err) + } + return &m, nil + } + if err := Db.In("uid", ids).Limit(limit, start). + Find(&m); err != nil { + return nil, logx.Warn(err) + } + return &m, nil +} + +//UsersInByIdsWhereLv is 根据ids和 lv会员等级 查找users +func UsersInByIdsWhereLv(Db *xorm.Engine, ids []int, lv interface{}, limit, start int) (*[]model.User, error) { + var m []model.User + if limit == 0 && start == 0 { + if err := Db.Where("level = ?", lv).In("uid", ids). + Find(&m); err != nil { + return nil, logx.Warn(err) + } + return &m, nil + } + if err := Db.Where("level = ?", lv).In("uid", ids).Limit(limit, start). + Find(&m); err != nil { + return nil, logx.Warn(err) + } + return &m, nil +} + +//UsersInByIdsByAscWhereLv is 根据ids和 lv会员等级 查找users 升排序 +func UsersInByIdsByAscWhereLv(Db *xorm.Engine, ids []int, lv interface{}, limit, start int, c string) (*[]model.User, error) { + var m []model.User + if limit == 0 && start == 0 { + if err := Db.Where("level = ?", lv).In("uid", ids).Asc(c). + Find(&m); err != nil { + return nil, logx.Warn(err) + } + return &m, nil + } + if err := Db.Where("level = ?", lv).In("uid", ids).Asc(c).Limit(limit, start). + Find(&m); err != nil { + return nil, logx.Warn(err) + } + return &m, nil +} + +//UsersInByIdsByDescWhereLv is 根据ids和 lv会员等级 查找users 降排序 +func UsersInByIdsByDescWhereLv(Db *xorm.Engine, ids []int, lv interface{}, limit, start int, c string) (*[]model.User, error) { + var m []model.User + if limit == 0 && start == 0 { + if err := Db.Where("level = ?", lv).In("uid", ids).Desc(c). + Find(&m); err != nil { + return nil, logx.Warn(err) + } + return &m, nil + } + if err := Db.Where("level = ?", lv).In("uid", ids).Desc(c).Limit(limit, start). + Find(&m); err != nil { + return nil, logx.Warn(err) + } + return &m, nil +} + +// UserFindByArkidUserName search user by mobile +func UserFindByArkidUserName(Db *xorm.Engine, name string) (*model.User, error) { + var m model.User + if has, err := Db.Where("username = ?", name). + Get(&m); err != nil || has == false { + return nil, logx.Warn(err) + } + return &m, nil +} + +// UserFindByID is find user byid +func UserFindByID(Db *xorm.Engine, id interface{}) (*model.User, error) { + var m model.User + if has, err := Db.Where("uid = ?", id). + Get(&m); err != nil || has == false { + return nil, logx.Warn(err) + } + return &m, nil +} + +func UserFindByIDs(Db *xorm.Engine, uids []int) (*[]model.User, error) { + var m []model.User + if err := Db.In("uid", uids).Find(&m); err != nil { + return nil, logx.Warn(err) + } + return &m, nil +} + +// UsersInByIdsByDesc is 根据某列 降序 +func UsersInByIdsByDesc(Db *xorm.Engine, ids []int, limit, start int, c string) (*[]model.User, error) { + var m []model.User + if limit == 0 && start == 0 { + if err := Db.In("uid", ids).Desc(c). + Find(&m); err != nil { + return nil, logx.Warn(err) + } + return &m, nil + } + if err := Db.In("uid", ids).Desc(c).Limit(limit, start). + Find(&m); err != nil { + return nil, logx.Warn(err) + } + return &m, nil +} + +// UsersInByIdsByAsc is 根据某列 升序 +func UsersInByIdsByAsc(Db *xorm.Engine, ids []int, limit, start int, c string) (*[]model.User, error) { + var m []model.User + if limit == 0 && start == 0 { + if err := Db.In("uid", ids).Asc(c). + Find(&m); err != nil { + return nil, logx.Warn(err) + } + return &m, nil + } + if err := Db.In("uid", ids).Asc(c).Limit(limit, start). + Find(&m); err != nil { + return nil, logx.Warn(err) + } + return &m, nil +} + +//UserInsert is insert user +func UserInsert(Db *xorm.Engine, user *model.User) (int64, error) { + affected, err := Db.Insert(user) + if err != nil { + return 0, err + } + return affected, nil +} + +// UserIsExistByMobile is mobile exist +func UserIsExistByMobile(Db *xorm.Engine, mobile string) (bool, error) { + //fmt.Println(mobile) + has, err := Db.Where("phone = ? OR uid = ?", mobile, mobile).Exist(&model.User{}) + fmt.Println(has, mobile) + if err != nil { + return false, err + } + return has, nil +} + +// UserIsExistByID is mobile exist by id +func UserIsExistByID(Db *xorm.Engine, id string) (bool, error) { + has, err := Db.Where("uid = ?", id).Exist(&model.User{}) + if err != nil { + return false, err + } + return has, nil +} + +// UserUpdate is update user +func UserUpdate(Db *xorm.Engine, uid interface{}, user *model.User, forceColums ...string) (int64, error) { + var ( + affected int64 + err error + ) + if forceColums != nil { + affected, err = Db.Where("uid=?", uid).Cols(forceColums...).Update(user) + } else { + affected, err = Db.Where("uid=?", uid).Update(user) + } + if err != nil { + return 0, err + } + return affected, nil +} + +func UserUpdateWithSession(Db *xorm.Session, uid interface{}, user *model.User, forceColums ...string) (int64, error) { + var ( + affected int64 + err error + ) + if forceColums != nil { + affected, err = Db.Where("uid=?", uid).Cols(forceColums...).Update(user) + } else { + affected, err = Db.Where("uid=?", uid).Update(user) + } + if err != nil { + return 0, err + } + return affected, nil +} + +// UserDelete is delete user +func UserDelete(Db *xorm.Engine, uid interface{}) (int64, error) { + return Db.Where("uid = ?", uid).Delete(model.User{}) +} diff --git a/super_cloud_issuance/db/db_user_fin_flow.go b/super_cloud_issuance/db/db_user_fin_flow.go new file mode 100644 index 0000000..9d8627f --- /dev/null +++ b/super_cloud_issuance/db/db_user_fin_flow.go @@ -0,0 +1,15 @@ +package db + +import ( + "applet/app/db/model" + "xorm.io/xorm" +) + +// 在事务中使用,插入一条流水记录 +func FinUserFlowInsertOneWithSession(session *xorm.Session, m *model.FinUserFlow) error { + _, err := session.InsertOne(m) + if err != nil { + return err + } + return nil +} diff --git a/super_cloud_issuance/db/db_user_level.go b/super_cloud_issuance/db/db_user_level.go new file mode 100644 index 0000000..26ea1fc --- /dev/null +++ b/super_cloud_issuance/db/db_user_level.go @@ -0,0 +1,92 @@ +package db + +import ( + "applet/app/db/model" + "applet/app/utils/logx" + "xorm.io/xorm" +) + +//UserLevelByID is 根据用户id 获取对应的等级信息 +func UserLevelByID(Db *xorm.Engine, id interface{}) (*model.UserLevel, error) { + m := new(model.UserLevel) + has, err := Db.Where("id = ?", id).Get(m) + if err != nil { + return nil, logx.Warn(err) + } + if !has { + return nil, logx.Error("Not found") + } + + return m, nil +} + +//UserLevelTop is 查询最高的等级 +func UserLevelTop(Db *xorm.Engine) (*model.UserLevel, error) { + m := new(model.UserLevel) + has, err := Db.OrderBy("level_weight DESC").Get(m) + if err != nil { + return nil, logx.Warn(err) + } + if !has { + return nil, logx.Error("Not found") + } + + return m, nil +} + +//UserLevelNext is 查询下一等级 +func UserLevelNext(Db *xorm.Engine, curLevelWeight int) (*model.UserLevel, error) { + m := new(model.UserLevel) + has, err := Db.Where("level_weight > ?", curLevelWeight).OrderBy("level_weight ASC").Get(m) + if err != nil { + return nil, logx.Warn(err) + } + if !has { + return nil, logx.Error("Not found") + } + + return m, nil +} + +// UserLevelByWeight is 根据权重获取对应的等级 +func UserLevelByWeight(Db *xorm.Engine, w interface{}) (*model.UserLevel, error) { + m := new(model.UserLevel) + has, err := Db.Where("level_weight = ?", w).Get(m) + if err != nil { + return nil, logx.Warn(err) + } + if !has { + return nil, logx.Warn("Not found") + } + return m, nil +} + +//UserLevelInIDescByWeight is In 查询获取 权重最低 对应等级 +func UserLevelInIDescByWeightLow(Db *xorm.Engine) ([]*model.UserLevel, error) { + var ms []*model.UserLevel + if err := Db.Asc("level_weight").Limit(1).Find(&ms); err != nil { + return nil, err + } + return ms, nil + +} + +//UserLevelInIDescByWeight is In 查询获取对应等级 根据权重排序 +func UserLevelInIDescByWeight(Db *xorm.Engine, ids []int) ([]*model.UserLevel, error) { + var ms []*model.UserLevel + if err := Db.In("id", ids).Desc("level_weight").Find(&ms); err != nil { + return nil, err + } + return ms, nil + +} + +// UserLevlEgAll is 获取所有开启等级并且升序返回 +func UserLevlEgAll(Db *xorm.Engine) ([]*model.UserLevel, error) { + var m []*model.UserLevel + err := Db.Where("is_use = ?", 1).Asc("level_weight").Find(&m) + if err != nil { + return nil, logx.Warn(err) + } + return m, nil +} diff --git a/super_cloud_issuance/db/db_user_profile.go b/super_cloud_issuance/db/db_user_profile.go new file mode 100644 index 0000000..38326dd --- /dev/null +++ b/super_cloud_issuance/db/db_user_profile.go @@ -0,0 +1,418 @@ +package db + +import ( + "applet/app/db/model" + "applet/app/utils/logx" + "xorm.io/xorm" +) + +// UserProfileFindByArkID is get userprofile by arkid +func UserProfileFindByArkID(Db *xorm.Engine, id interface{}) (*model.UserProfile, error) { + var m model.UserProfile + if has, err := Db.Where("arkid_uid = ?", id).Get(&m); err != nil || has == false { + return nil, logx.Warn(err) + } + return &m, nil +} + +// UserProfileFindByInviteCode is get userprofile by InviteCode +func UserProfileFindByInviteCode(Db *xorm.Engine, code string) (*model.UserProfile, error) { + var m model.UserProfile + if has, err := Db.Where("invite_code = ?", code).Get(&m); err != nil || has == false { + return nil, logx.Warn(err) + } + return &m, nil +} + +// UserProfileFindByInviteCode is get userprofile by InviteCode +func UserProfileFindByCustomInviteCode(Db *xorm.Engine, code string) (*model.UserProfile, error) { + var m model.UserProfile + if has, err := Db.Where("custom_invite_code = ?", code).Get(&m); err != nil || has == false { + return nil, logx.Warn(err) + } + return &m, nil +} + +// UserProfileFindByInviteCodes is get userprofile by InviteCode +func UserProfileFindByInviteCodes(Db *xorm.Engine, codes ...string) (*[]model.UserProfile, error) { + var m []model.UserProfile + if err := Db.In("invite_code", codes).Find(&m); err != nil { + return nil, logx.Warn(err) + } + return &m, nil +} + +// UserProfileFindByCustomInviteCodes is get userprofile by CustomInviteCode +func UserProfileFindByCustomInviteCodes(Db *xorm.Engine, codes ...string) (*[]model.UserProfile, error) { + var m []model.UserProfile + if err := Db.In("custom_invite_code", codes).Find(&m); err != nil { + return nil, logx.Warn(err) + } + return &m, nil +} + +// UserProfileFindByID search user_profile by userid +func UserProfileFindByID(Db *xorm.Engine, id interface{}) (*model.UserProfile, error) { + var m model.UserProfile + if has, err := Db.Where("uid = ?", id).Get(&m); err != nil || has == false { + return nil, logx.Warn(err) + } + return &m, nil +} + +// UserProfileOrderByNew 找最新的记录 +func UserProfileOrderByNew(Db *xorm.Engine) (*model.UserProfile, error) { + var m model.UserProfile + if has, err := Db.Where("invite_code != ''").OrderBy("uid desc").Get(&m); err != nil || has == false { + return nil, logx.Warn(err) + } + return &m, nil +} + +// UserProfileFindByTaobaoOpenID search user_profile ByTaobaoOpenID +func UserProfileFindByTaobaoOpenID(Db *xorm.Engine, openid interface{}) (*model.UserProfile, error) { + var m model.UserProfile + if has, err := Db.Where("third_party_taobao_oid = ?", openid).Get(&m); err != nil || has == false { + return nil, logx.Warn(err) + } + return &m, nil +} + +// UserProfileFindByQQOpenID search user_profile ByTaobaoOpenID +func UserProfileFindByQQOpenID(Db *xorm.Engine, openid interface{}) (*model.UserProfile, error) { + var m model.UserProfile + if has, err := Db.Where("third_party_qq_openid = ?", openid).Get(&m); err != nil || has == false { + return nil, logx.Warn(err) + } + return &m, nil +} + +// UserProfileFindByAppleToken search user_profile AppleToken +func UserProfileFindByAppleToken(Db *xorm.Engine, token interface{}) (*model.UserProfile, error) { + var m model.UserProfile + if has, err := Db.Where("third_party_apple_token = ?", token).Get(&m); err != nil || has == false { + return nil, logx.Warn(err) + } + return &m, nil +} + +// UserProfileFindByWeChatOpenID search user_profile By 微信openid +func UserProfileFindByWeChatOpenID(Db *xorm.Engine, openid interface{}) (*model.UserProfile, error) { + var m model.UserProfile + if has, err := Db.Where("third_party_wechat_openid = ?", openid).Get(&m); err != nil || has == false { + return nil, logx.Warn(err) + } + return &m, nil +} + +// UserProfileFindByWeChatMiniOpenID search user_profile By 小程序openid +func UserProfileFindByWeChatMiniOpenID(Db *xorm.Engine, openid interface{}) (*model.UserProfile, error) { + var m model.UserProfile + if has, err := Db.Where("third_party_wechat_mini_openid = ?", openid).Get(&m); err != nil || has == false { + return nil, logx.Warn(err) + } + return &m, nil +} + +// UserProfileFindByWeChatUnionID search user_profile By 微信唯一id +func UserProfileFindByWeChatUnionID(Db *xorm.Engine, openid interface{}) (*model.UserProfile, error) { + var m model.UserProfile + if has, err := Db.Where("third_party_wechat_unionid = ?", openid).Get(&m); err != nil || has == false { + return nil, logx.Warn(err) + } + return &m, nil +} + +// UserProfileisExistByTaobaoOpenID is exist by Taobao +func UserProfileisExistByTaobaoOpenID(Db *xorm.Engine, openid string) (bool, error) { + has, err := Db.Where("third_party_taobao_oid = ?", openid).Exist(&model.UserProfile{}) + + if err != nil { + return false, err + } + return has, nil +} + +// UserProfileisExistByQQOpenID is exist by QQ openid +func UserProfileisExistByQQOpenID(Db *xorm.Engine, openid string) (bool, error) { + has, err := Db.Where("third_party_qq_openid = ?", openid).Exist(&model.UserProfile{}) + + if err != nil { + return false, err + } + return has, nil +} + +// UserProfileisExistByAppleToken is exist by apple token +func UserProfileisExistByAppleToken(Db *xorm.Engine, token string) (bool, error) { + has, err := Db.Where("third_party_apple_token = ?", token).Exist(&model.UserProfile{}) + + if err != nil { + return false, err + } + return has, nil +} + +// UserProfileisExistByWeChatOpenID is exist by Wecaht openid +func UserProfileisExistByWeChatOpenID(Db *xorm.Engine, openid string) (bool, error) { + has, err := Db.Where("third_party_wechat_openid = ?", openid).Exist(&model.UserProfile{}) + + if err != nil { + return false, err + } + return has, nil +} + +// UserProfileisExistByWeChatMiniOpenID is exist by Wecaht openid +func UserProfileisExistByWeChatMiniOpenID(Db *xorm.Engine, openid string) (bool, error) { + has, err := Db.Where("third_party_wechat_mini_openid = ?", openid).Exist(&model.UserProfile{}) + + if err != nil { + return false, err + } + return has, nil +} + +// UserProfileisExistByWeChatUnionID is exist by Wecaht openid +func UserProfileisExistByWeChatUnionID(Db *xorm.Engine, openid string) (bool, error) { + has, err := Db.Where("third_party_wechat_unionid = ?", openid).Exist(&model.UserProfile{}) + + if err != nil { + return false, err + } + return has, nil +} + +// UserProfileisExistByRelationIDAndSpecialID is exist by RelationIdAndSpecialId +func UserProfileisExistByRelationIDAndSpecialID(Db *xorm.Engine, SpecialID, RelationID int64) (bool, error) { + has, err := Db.Where("acc_taobao_self_id = ? AND acc_taobao_share_id = ?", SpecialID, RelationID).Exist(&model.UserProfile{}) + + if err != nil { + return false, err + } + return has, nil +} + +// UserProfileisExistBySpecialID is exist by SpecialId +func UserProfileisExistBySpecialID(Db *xorm.Engine, SpecialID string) (bool, error) { + has, err := Db.Where("acc_taobao_self_id = ? ", SpecialID).Exist(&model.UserProfile{}) + + if err != nil { + return false, err + } + return has, nil +} + +// UserProfileCountByRelationID 统计relationID数量 +func UserProfileCountByRelationID(Db *xorm.Engine) (total int64, err error) { + relate := new(model.UserProfile) + total, err = Db.Where("acc_taobao_share_id > 0").Count(relate) + return +} + +// UserProfileCountByPUID 统计直推下级数量 +func UserProfileCountByPUID(Db *xorm.Engine, puid int) (total int64, err error) { + relate := new(model.UserProfile) + total, err = Db.Where("parent_uid = ?", puid).Count(relate) + return +} + +// UserProfileisExistByRelationID is exist by RelationID +func UserProfileisExistByRelationID(Db *xorm.Engine, RelationID string) (bool, error) { + has, err := Db.Where("acc_taobao_share_id = ? ", RelationID).Exist(&model.UserProfile{}) + + if err != nil { + return false, err + } + return has, nil +} + +// UserProfileFindByIDs is in sql by ids +func UserProfileFindByIDs(Db *xorm.Engine, uids ...int) (*[]model.UserProfile, error) { + var m []model.UserProfile + if err := Db.In("uid", uids).Find(&m); err != nil { + return nil, logx.Warn(err) + } + return &m, nil +} + +// UserProfileByPuid search user_profile by parent_uid +func UserProfileByPuid(Db *xorm.Engine, puid interface{}) (*[]model.UserProfile, error) { + var m []model.UserProfile + if err := Db.Where("parent_uid = ?", puid).Find(&m); err != nil { + return nil, logx.Warn(err) + } + return &m, nil +} + +// UsersProfileInByIds is profiles by ids +func UsersProfileInByIds(Db *xorm.Engine, ids []int, limit, start int) (*[]model.UserProfile, error) { + var m []model.UserProfile + if limit == 0 && start == 0 { + if err := Db.In("uid", ids).Find(&m); err != nil { + return nil, logx.Warn(err) + } + return &m, nil + } + if err := Db.In("uid", ids).Limit(limit, start).Find(&m); err != nil { + return nil, logx.Warn(err) + } + return &m, nil +} + +// UsersProfileInByUIDByisVerify is In查询 以及是否是有效用户 +func UsersProfileInByUIDByisVerify(Db *xorm.Engine, ids []int, isVerify interface{}) (*[]model.UserProfile, error) { + var m []model.UserProfile + if err := Db.In("uid", ids).Where("is_verify = ?", isVerify). + Find(&m); err != nil { + return nil, logx.Warn(err) + } + return &m, nil +} +func UsersProfileInByUIDByisVerifyByTime(Db *xorm.Engine, puid, stime, etime interface{}) (*[]model.UserProfile, error) { + var m []model.UserProfile + if err := Db.Where("parent_uid = ? and is_verify = ? and is_old=0 and is_game_invite = ? AND create_time > ? AND create_time < ?", puid, 1, 1, stime, etime). + Find(&m); err != nil { + return nil, logx.Warn(err) + } + return &m, nil +} + +// UsersProfileInByIdsByDesc is 根据某列 降序 +func UsersProfileInByIdsByDesc(Db *xorm.Engine, ids []int, limit, start int, c string) (*[]model.UserProfile, error) { + var m []model.UserProfile + if limit == 0 && start == 0 { + if err := Db.In("uid", ids).Desc(c).Find(&m); err != nil { + return nil, logx.Warn(err) + } + return &m, nil + } + if err := Db.In("uid", ids).Desc(c).Limit(limit, start).Find(&m); err != nil { + return nil, logx.Warn(err) + } + return &m, nil +} + +// UsersProfileInByIdsByAsc is 根据某列 升序 +func UsersProfileInByIdsByAsc(Db *xorm.Engine, ids []int, limit, start int, c string) (*[]model.UserProfile, error) { + var m []model.UserProfile + if limit == 0 && start == 0 { + if err := Db.In("uid", ids).Asc(c).Find(&m); err != nil { + return nil, logx.Warn(err) + } + return &m, nil + } + if err := Db.In("uid", ids).Asc(c).Limit(limit, start).Find(&m); err != nil { + return nil, logx.Warn(err) + } + return &m, nil +} + +// UsersProfileByAll is 查询所有分享id大于0的数据 +func UsersProfileByTaobaoShateIdNotNull(Db *xorm.Engine, limit, start int) (*[]model.UserProfile, error) { + var m []model.UserProfile + if err := Db.Where("acc_taobao_share_id > 0").Limit(limit, start).Find(&m); err != nil { + return nil, logx.Warn(err) + } + return &m, nil +} + +// UserProfileIsExistByUserID is mobile exist +func UserProfileIsExistByUserID(Db *xorm.Engine, id int) (bool, error) { + has, err := Db.Where("uid = ?", id).Exist(&model.UserProfile{}) + if err != nil { + return false, err + } + return has, nil +} + +// UserProfileIsExistByInviteCode is exist ? +func UserProfileIsExistByInviteCode(Db *xorm.Engine, code string) (bool, error) { + has, err := Db.Where("invite_code = ?", code).Exist(&model.UserProfile{}) + if err != nil { + return false, err + } + return has, nil +} + +// UserProfileIsExistByCustomInviteCode is exist ? +func UserProfileIsExistByCustomInviteCode(Db *xorm.Engine, code string) (bool, error) { + has, err := Db.Where("custom_invite_code = ?", code).Exist(&model.UserProfile{}) + if err != nil { + return false, err + } + return has, nil +} + +// UserProfileInsert is insert user +func UserProfileInsert(Db *xorm.Engine, userProfile *model.UserProfile) (int64, error) { + affected, err := Db.Insert(userProfile) + if err != nil { + return 0, err + } + return affected, nil +} + +// UserProfileUpdate is update userprofile +func UserProfileUpdate(Db *xorm.Engine, uid interface{}, userProfile *model.UserProfile, forceCols ...string) (int64, error) { + var ( + affected int64 + err error + ) + if forceCols != nil { + affected, err = Db.Where("uid=?", uid).Cols(forceCols...).Update(userProfile) + } else { + affected, err = Db.Where("uid=?", uid).Update(userProfile) + } + if err != nil { + return 0, logx.Warn(err) + } + return affected, nil +} + +// UserProfileUpdateByArkID is update userprofile +func UserProfileUpdateByArkID(Db *xorm.Engine, arkid interface{}, userProfile *model.UserProfile, forceCols ...string) (int64, error) { + var ( + affected int64 + err error + ) + if forceCols != nil { + affected, err = Db.Where("arkid_uid=?", arkid).Cols(forceCols...).Update(userProfile) + } else { + affected, err = Db.Where("arkid_uid=?", arkid).Update(userProfile) + } + if err != nil { + return 0, logx.Warn(err) + } + return affected, nil +} + +// UserProfileDelete is delete user profile +func UserProfileDelete(Db *xorm.Engine, uid interface{}) (int64, error) { + return Db.Where("uid = ?", uid).Delete(model.UserProfile{}) +} + +func UserProfileFindByIdWithSession(session *xorm.Session, uid int) (*model.UserProfile, error) { + var m model.UserProfile + if has, err := session.Where("uid = ?", uid).Get(&m); err != nil || has == false { + return nil, logx.Warn(err) + } + return &m, nil +} + +// 在事务中更新用户信息 +func UserProfileUpdateWithSession(session *xorm.Session, uid interface{}, userProfile *model.UserProfile, forceCols ...string) (int64, error) { + var ( + affected int64 + err error + ) + if forceCols != nil { + affected, err = session.Where("uid=?", uid).Cols(forceCols...).Update(userProfile) + } else { + affected, err = session.Where("uid=?", uid).Update(userProfile) + } + if err != nil { + return 0, logx.Warn(err) + } + return affected, nil +} diff --git a/super_cloud_issuance/db/db_user_relate.go b/super_cloud_issuance/db/db_user_relate.go new file mode 100644 index 0000000..e16fd8e --- /dev/null +++ b/super_cloud_issuance/db/db_user_relate.go @@ -0,0 +1,213 @@ +package db + +import ( + "applet/app/db/model" + "applet/app/utils/logx" + + "xorm.io/xorm" +) + +// UserRelateInsert is 插入一条数据到用户关系表 +func UserRelateInsert(Db *xorm.Engine, userRelate *model.UserRelate) (int64, error) { + affected, err := Db.Insert(userRelate) + if err != nil { + return 0, err + } + return affected, nil +} + +//UserRelateByPuid is 获取用户关系列表 by puid +func UserRelatesByPuid(Db *xorm.Engine, puid interface{}, limit, start int) (*[]model.UserRelate, error) { + var m []model.UserRelate + if limit == 0 && start == 0 { + if err := Db.Where("parent_uid = ?", puid). + Cols(`id,parent_uid,uid,level,invite_time`). + Find(&m); err != nil { + return nil, logx.Warn(err) + } + return &m, nil + } + if err := Db.Where("parent_uid = ?", puid). + Cols(`id,parent_uid,uid,level,invite_time`).Limit(limit, start). + Find(&m); err != nil { + return nil, logx.Warn(err) + } + + return &m, nil +} + +//UserRelatesByPuidByLv is 获取用户关系列表 by puid 和lv +func UserRelatesByPuidByLv(Db *xorm.Engine, puid, lv interface{}, limit, start int) (*[]model.UserRelate, error) { + var m []model.UserRelate + if limit == 0 && start == 0 { + if err := Db.Where("parent_uid = ? AND level = ?", puid, lv). + Cols(`id,parent_uid,uid,level,invite_time`). + Find(&m); err != nil { + return nil, logx.Warn(err) + } + return &m, nil + } + if err := Db.Where("parent_uid = ? AND level = ?", puid, lv). + Cols(`id,parent_uid,uid,level,invite_time`).Limit(limit, start). + Find(&m); err != nil { + return nil, logx.Warn(err) + } + + return &m, nil +} + +//UserRelatesByPuidByLvByTime is 获取直属 level =1用户关系列表 by puid 和lv by time +func UserRelatesByPuidByLvByTime(Db *xorm.Engine, puid, lv, stime, etime interface{}, limit, start int) (*[]model.UserRelate, error) { + var m []model.UserRelate + if limit == 0 && start == 0 { + if err := Db.Where("parent_uid = ? AND level = ? AND invite_time > ? AND invite_time < ?", puid, lv, stime, etime). + Find(&m); err != nil { + return nil, logx.Warn(err) + } + return &m, nil + } + if err := Db.Where("parent_uid = ? AND level = ? AND invite_time > ? AND invite_time < ?", puid, lv, stime, etime). + Limit(limit, start). + Find(&m); err != nil { + return nil, logx.Warn(err) + } + + return &m, nil +} + +//UserRelatesByPuidByTime is 获取户关系列表 by puid 和lv by time +func UserRelatesByPuidByTime(Db *xorm.Engine, puid, stime, etime interface{}, limit, start int) (*[]model.UserRelate, error) { + var m []model.UserRelate + if limit == 0 && start == 0 { + if err := Db.Where("parent_uid = ? AND invite_time > ? AND invite_time < ?", puid, stime, etime). + Cols(`id,parent_uid,uid,level,invite_time`). + Find(&m); err != nil { + return nil, logx.Warn(err) + } + return &m, nil + } + if err := Db.Where("parent_uid = ? AND invite_time > ? AND invite_time < ?", puid, stime, etime). + Cols(`id,parent_uid,uid,level,invite_time`).Limit(limit, start). + Find(&m); err != nil { + return nil, logx.Warn(err) + } + + return &m, nil +} + +//UserRelatesByPuidExceptLv is 获取用户关系列表 by puid 和非 lv +func UserRelatesByPuidExceptLv(Db *xorm.Engine, puid, lv interface{}, limit, start int) (*[]model.UserRelate, error) { + var m []model.UserRelate + if limit == 0 && start == 0 { + if err := Db.Where("parent_uid = ? AND level != ?", puid, lv). + Cols(`id,parent_uid,uid,level,invite_time`). + Find(&m); err != nil { + return nil, logx.Warn(err) + } + return &m, nil + } + if err := Db.Where("parent_uid = ? AND level != ?", puid, lv). + Cols(`id,parent_uid,uid,level,invite_time`).Limit(limit, start). + Find(&m); err != nil { + return nil, logx.Warn(err) + } + + return &m, nil +} + +//UserRelateByUID is 获取用户关系表 by uid +func UserRelateByUID(Db *xorm.Engine, uid interface{}) (*model.UserRelate, bool, error) { + r := new(model.UserRelate) + has, err := Db.Where("uid=?", uid).Get(r) + if err != nil { + return nil, false, err + } + return r, has, nil +} + +//UserRelateByUIDByLv is 获取用户关系表 by uid +func UserRelateByUIDByLv(Db *xorm.Engine, uid, lv interface{}) (*model.UserRelate, bool, error) { + r := new(model.UserRelate) + has, err := Db.Where("uid=? AND level=?", uid, lv).Get(r) + if err != nil { + return nil, false, err + } + return r, has, nil +} + +//UserRelateByUIDAndPUID 根据 Puid 和uid 查找 ,用于确认关联 +func UserRelateByUIDAndPUID(Db *xorm.Engine, uid, puid interface{}) (*model.UserRelate, bool, error) { + r := new(model.UserRelate) + has, err := Db.Where("uid=? AND parent_uid=?", uid, puid).Get(r) + if err != nil { + return nil, false, err + } + return r, has, nil +} + +//UserRelatesByPuIDAndLv is 查询用户关系表 获取指定等级和puid的关系 +func UserRelatesByPuIDAndLv(Db *xorm.Engine, puid, lv interface{}) (*[]model.UserRelate, error) { + var m []model.UserRelate + if err := Db.Where("parent_uid = ? AND level = ?", puid, lv). + Cols(`id,parent_uid,uid,level,invite_time`). + Find(&m); err != nil { + return nil, logx.Warn(err) + } + return &m, nil +} + +// UserRelateInByUID is In查询 +func UserRelateInByUID(Db *xorm.Engine, ids []int) (*[]model.UserRelate, error) { + var m []model.UserRelate + if err := Db.In("uid", ids). + Find(&m); err != nil { + return nil, logx.Warn(err) + } + return &m, nil +} + +// UserRelatesByUIDDescLv is Where 查询 根据level 降序 +func UserRelatesByUIDDescLv(Db *xorm.Engine, id interface{}) (*[]model.UserRelate, error) { + var m []model.UserRelate + if err := Db.Where("uid = ?", id).Desc("level"). + Find(&m); err != nil { + return nil, logx.Warn(err) + } + return &m, nil +} + +//UserRelateCountByPUID is 根据puid 计数 +func UserRelateCountByPUID(Db *xorm.Engine, pid interface{}) (int64, error) { + + count, err := Db.Where("parent_uid = ?", pid).Count(model.UserRelate{}) + if err != nil { + return 0, nil + } + return count, nil +} + +//UserRelateDelete is 删除关联他上级的关系记录,以及删除他下级的关联记录 +func UserRelateDelete(Db *xorm.Engine, uid interface{}) (int64, error) { + // 删除与之上级的记录 + _, err := Db.Where("uid = ?", uid).Delete(model.UserRelate{}) + if err != nil { + return 0, err + } + // 删除与之下级的记录 + _, err = Db.Where("parent_uid = ?", uid).Delete(model.UserRelate{}) + if err != nil { + return 0, err + } + + return 1, nil +} + +//UserRelateDelete is 删除关联他上级的关系记录 +func UserRelateExtendDelete(Db *xorm.Engine, uid interface{}) (int64, error) { + // 删除与之上级的记录 + _, err := Db.Where("uid = ?", uid).Delete(model.UserRelate{}) + if err != nil { + return 0, err + } + return 1, nil +} diff --git a/super_cloud_issuance/db/db_user_virtual_amount.go b/super_cloud_issuance/db/db_user_virtual_amount.go new file mode 100644 index 0000000..4906fca --- /dev/null +++ b/super_cloud_issuance/db/db_user_virtual_amount.go @@ -0,0 +1,35 @@ +package db + +import ( + "applet/app/db/model" + "applet/app/utils" + "xorm.io/xorm" +) + +func GetUserVirtualAmountOne(session *xorm.Session, uid int, coinId int) (*model.UserVirtualAmount, error) { + + var m model.UserVirtualAmount + isExist, err := session.Table("user_virtual_amount").Where("uid = ? AND coin_id = ?", uid, coinId).Get(&m) + if err != nil { + return nil, err + } + if !isExist { + return nil, nil + } + return &m, nil + +} +func GetUserVirtualAmountSum(eg *xorm.Engine, uid int, coinId int) (string, error) { + //TODO 后面针对单个虚拟币 + var m model.UserVirtualAmount + sum, err := eg.Table("user_virtual_amount").Where("uid = ? ", uid).Sum(&m, "amount") + if err != nil { + return "0", err + } + return utils.Float64ToStr(sum), nil + +} + +/*func UserVirtualAmountUpdateWithSession(session *xorm.Session, m *model.UserVirtualAmount) bool { + +}*/ diff --git a/super_cloud_issuance/db/db_virtual_coin.go b/super_cloud_issuance/db/db_virtual_coin.go new file mode 100644 index 0000000..b69b2c3 --- /dev/null +++ b/super_cloud_issuance/db/db_virtual_coin.go @@ -0,0 +1,63 @@ +package db + +import ( + "applet/app/db/model" + "applet/app/md" + "applet/app/utils/cache" + "errors" + "fmt" + "xorm.io/xorm" +) + +func GetVirtualCoinList(eg *xorm.Engine, masterId string) ([]*model.VirtualCoin, error) { + var m []*model.VirtualCoin + cacheKey := fmt.Sprintf(md.VirtualCoinCfgCacheKey, masterId) + + err := cache.GetJson(cacheKey, &m) + if err != nil || len(m) == 0 { + err := eg.Where("is_use=1").Find(&m) + if err != nil { + return nil, err + } + cache.SetJson(cacheKey, m, md.CfgCacheTime) + } + + return m, nil +} + +// InsertUserVirtualFlow 插入一条虚拟币流水 +func InsertUserVirtualFlow(eg *xorm.Engine, m model.UserVirtualCoinFlow) error { + insert, err := eg.Insert(m) + if err != nil { + return err + } + if insert == 0 { + return errors.New("插入虚拟币流水错误") + } + + return nil +} + +func InsertUserVirtualFlowWithSess(sess *xorm.Session, m model.UserVirtualCoinFlow) error { + insert, err := sess.Insert(m) + if err != nil { + return err + } + if insert == 0 { + return errors.New("插入虚拟币流水错误") + } + + return nil +} + +func GetBlockCoin(eg *xorm.Engine) (*model.VirtualCoin, error) { + var m model.VirtualCoin + get, err := eg.Where("is_block = 1").Get(&m) + if err != nil { + return nil, err + } + if get { + return &m, nil + } + return nil, errors.New("查询有误!") +} diff --git a/super_cloud_issuance/db/db_virtual_coin_relate.go b/super_cloud_issuance/db/db_virtual_coin_relate.go new file mode 100644 index 0000000..ee1ff9c --- /dev/null +++ b/super_cloud_issuance/db/db_virtual_coin_relate.go @@ -0,0 +1,16 @@ +package db + +import ( + "applet/app/db/model" + "xorm.io/xorm" +) + +// 根据订单id查出相关的数据 +func GetVirtualCoinRelateListWithOrdId(engine *xorm.Engine, ordId int64) ([]*model.VirtualCoinRelate, error) { + var list []*model.VirtualCoinRelate + err := engine.Table("virtual_coin_relate").Where("oid = ?", ordId).Find(&list) + if err != nil { + return nil, err + } + return list, nil +} diff --git a/super_cloud_issuance/db/dbs_sys_cfg.go b/super_cloud_issuance/db/dbs_sys_cfg.go new file mode 100644 index 0000000..25c0a14 --- /dev/null +++ b/super_cloud_issuance/db/dbs_sys_cfg.go @@ -0,0 +1,55 @@ +package db + +import ( + "xorm.io/xorm" + + "applet/app/db/model" + "applet/app/utils/logx" +) + +// 系统配置get +func DbsSysCfgGetAll(eg *xorm.Engine) (*[]model.SysCfg, error) { + var cfgList []model.SysCfg + if err := eg.Cols("`key`,`val`").Find(&cfgList); err != nil { + return nil, logx.Error(err) + } + return &cfgList, nil +} + +// 获取一条记录 +func DbsSysCfgGet(eg *xorm.Engine, key string) (*model.SysCfg, error) { + var cfgList model.SysCfg + if has, err := eg.Where("`key`=?", key).Get(&cfgList); err != nil || has == false { + return nil, logx.Error(err) + } + return &cfgList, nil +} + +func DbsSysCfgInsert(eg *xorm.Engine, key, val string) bool { + cfg := model.SysCfg{Key: key, Val: val} + _, err := eg.Where("`key`=?", key).Cols("val,memo").Update(&cfg) + if err != nil { + logx.Error(err) + return false + } + return true +} +func DbsSysCfgInserts(eg *xorm.Engine, key, val string) bool { + cfg := model.SysCfg{Key: key, Val: val} + _, err := eg.InsertOne(&cfg) + if err != nil { + logx.Error(err) + return false + } + return true +} + +func DbsSysCfgUpdate(eg *xorm.Engine, key, val string) bool { + cfg := model.SysCfg{Key: key, Val: val} + _, err := eg.Where("`key`=?", key).Cols("val").Update(&cfg) + if err != nil { + logx.Error(err) + return false + } + return true +} diff --git a/super_cloud_issuance/db/model/cloud_bundle.go b/super_cloud_issuance/db/model/cloud_bundle.go new file mode 100644 index 0000000..1497d9d --- /dev/null +++ b/super_cloud_issuance/db/model/cloud_bundle.go @@ -0,0 +1,17 @@ +package model + +type CloudBundle struct { + Id int `json:"id" xorm:"not null pk autoincr INT(10)"` + Os int `json:"os" xorm:"not null default 1 comment('系统类型:1.Android; 2.IOS') TINYINT(1)"` + Version string `json:"version" xorm:"not null default '' comment('版本号') VARCHAR(255)"` + Modules string `json:"modules" xorm:"not null default '' comment('包含的模块') VARCHAR(255)"` + ApplyAt int `json:"apply_at" xorm:"comment('申请时间') INT(11)"` + FinishAt int `json:"finish_at" xorm:"comment('完成时间') INT(11)"` + State int `json:"state" xorm:"not null default 1 comment('状态:正在排队0,正在同步代码1,正在更新配置2,正在混淆3,正在打包4,正在上传5,打包成功999,异常-1') SMALLINT(5)"` + Memo string `json:"memo" xorm:"comment('备注') TEXT"` + ErrorMsg string `json:"error_msg" xorm:"comment('错误信息') TEXT"` + Src string `json:"src" xorm:"comment('包源地址') VARCHAR(255)"` + BuildId string `json:"build_id" xorm:"comment('build版本ID') VARCHAR(255)"` + BuildNumber string `json:"build_number" xorm:"default '' VARCHAR(255)"` + TemplateDuringAudit string `json:"template_during_audit" xorm:"not null default '' VARCHAR(255)"` +} diff --git a/super_cloud_issuance/db/model/db_mapping.go b/super_cloud_issuance/db/model/db_mapping.go new file mode 100644 index 0000000..f2f5d06 --- /dev/null +++ b/super_cloud_issuance/db/model/db_mapping.go @@ -0,0 +1,18 @@ +package model + +import ( + "time" +) + +type DbMapping struct { + DbMasterId string `json:"db_master_id" xorm:"not pk null comment('站长id') VARCHAR(32)"` + DbHost string `json:"db_host" xorm:"not null default '' comment('数据库连接(带port)') VARCHAR(255)"` + DbUsername string `json:"db_username" xorm:"not null default '' comment('数据库用户名') VARCHAR(255)"` + DbPassword string `json:"db_password" xorm:"not null default '' comment('数据库用户名密码') VARCHAR(255)"` + DbName string `json:"db_name" xorm:"not null comment('数据库名') VARCHAR(255)"` + ExternalMysql string `json:"external_mysql" xorm:"not null default '0' comment('是否外部mysql(0是内部,1是外部)') VARCHAR(255)"` + IsDev int `json:"is_dev" xorm:"not null default 0 comment('开发库是1,0是生产库') TINYINT(1)"` + CreatedAt time.Time `json:"created_at" xorm:"not null default CURRENT_TIMESTAMP comment('创建时间') TIMESTAMP"` + UpdatedAt time.Time `json:"updated_at" xorm:"not null default CURRENT_TIMESTAMP comment('更新时间') TIMESTAMP"` + DeletedAt int `json:"deleted_at" xorm:"not null default 0 comment('是否已删除') TINYINT(1)"` +} diff --git a/super_cloud_issuance/db/model/fin_user_flow.go b/super_cloud_issuance/db/model/fin_user_flow.go new file mode 100644 index 0000000..76fc502 --- /dev/null +++ b/super_cloud_issuance/db/model/fin_user_flow.go @@ -0,0 +1,30 @@ +package model + +import ( + "time" +) + +type FinUserFlow struct { + Id int64 `json:"id" xorm:"pk autoincr comment('流水编号') BIGINT(20)"` + Uid int `json:"uid" xorm:"not null default 0 comment('用户id') INT(11)"` + Type int `json:"type" xorm:"not null default 0 comment('0收入,1支出') TINYINT(1)"` + Amount string `json:"amount" xorm:"not null default 0.0000 comment('变动金额') DECIMAL(11,4)"` + BeforeAmount string `json:"before_amount" xorm:"not null default 0.0000 comment('变动前金额') DECIMAL(11,4)"` + AfterAmount string `json:"after_amount" xorm:"not null default 0.0000 comment('变动后金额') DECIMAL(11,4)"` + SysFee string `json:"sys_fee" xorm:"not null default 0.0000 comment('手续费') DECIMAL(11,4)"` + PaymentType int `json:"payment_type" xorm:"not null default 1 comment('1支付宝,2微信.3手动转账') TINYINT(1)"` + OrdType string `json:"ord_type" xorm:"not null default '' comment('订单类型taobao,jd,pdd,vip,suning,kaola,own自营,withdraw提现') VARCHAR(20)"` + OrdId string `json:"ord_id" xorm:"not null default '' comment('对应订单编号') VARCHAR(50)"` + OrdTitle string `json:"ord_title" xorm:"not null default '' comment('订单标题') VARCHAR(50)"` + OrdAction int `json:"ord_action" xorm:"not null default 0 comment('10自购,11推广,12团队,20提现,21消费') TINYINT(2)"` + OrdTime int `json:"ord_time" xorm:"not null default 0 comment('下单时间or提现时间') INT(11)"` + OrdDetail string `json:"ord_detail" xorm:"not null default '' comment('记录商品ID或提现账号') VARCHAR(50)"` + ExpectedTime string `json:"expected_time" xorm:"not null default '0' comment('预期到账时间,字符串用于直接显示,结算后清除内容') VARCHAR(30)"` + State int `json:"state" xorm:"not null default 1 comment('1未到账,2已到账') TINYINT(1)"` + Memo string `json:"memo" xorm:"not null default '' comment('备注') VARCHAR(2000)"` + OtherId int64 `json:"other_id" xorm:"not null default 0 comment('其他关联订单,具体根据订单类型判断') BIGINT(20)"` + AliOrdId string `json:"ali_ord_id" xorm:"default '' comment('支付宝订单号') VARCHAR(128)"` + CreateAt time.Time `json:"create_at" xorm:"created not null default CURRENT_TIMESTAMP comment('创建时间') TIMESTAMP"` + UpdateAt time.Time `json:"update_at" xorm:"updated not null default CURRENT_TIMESTAMP comment('更新时间') TIMESTAMP"` + TransferData string `json:"transfer_data" xorm:" comment('支付宝订单号') TEXT"` +} diff --git a/super_cloud_issuance/db/model/ord_list.go b/super_cloud_issuance/db/model/ord_list.go new file mode 100644 index 0000000..a8e904d --- /dev/null +++ b/super_cloud_issuance/db/model/ord_list.go @@ -0,0 +1,46 @@ +package model + +type OrdList struct { + OrdId int64 `xorm:"pk autoincr BIGINT(20)" json:"ord_id"` + Uid int `xorm:"not null index INT(10)" json:"uid"` + PvdOid string `xorm:"not null index(IDX_PVD) VARCHAR(50)" json:"pvd_oid"` + ParentOrdId int64 `xorm:" BIGINT(20)" json:"parent_ord_id"` + Pvd string `xorm:"not null default '' index(IDX_PVD) index(IDX_PVD_ITEM) VARCHAR(8)" json:"pvd"` + ItemId string `xorm:"not null default '' index(IDX_PVD_ITEM) VARCHAR(50)" json:"item_id"` + ItemNum int `xorm:"not null default 1 TINYINT(3)" json:"item_num"` + ItemPrice float64 `xorm:"not null default 0.00 FLOAT(10,2)" json:"item_price"` + ItemCommissionRate float64 `xorm:"not null default 0.00 FLOAT(6,4)" json:"item_commission_rate"` + PaidPrice float64 `xorm:"not null default 0.00 FLOAT(10,2)" json:"paid_price"` + CostPrice float64 `xorm:"not null default 0.00 FLOAT(10,2)" json:"cost_price"` + OrderType int `xorm:"not null default 0 TINYINT(1)" json:"order_type"` + PriceType int `xorm:"not null default 0 INT(1)" json:"price_type"` + OrderCompare int `xorm:"not null default 0 TINYINT(1)" json:"order_compare"` + SubsidyFee float64 `xorm:"not null default 0.00 FLOAT(8,2)" json:"subsidy_fee"` + SubsidyRate float64 `xorm:"not null default 0.0000 FLOAT(10,4)" json:"subsidy_rate"` + UserCommission float64 `xorm:"not null default 0.000 FLOAT(8,3)" json:"user_commission"` + UserCommissionRate float64 `xorm:"not null default 0.0000 FLOAT(6,4)" json:"user_commission_rate"` + PvdCommission float64 `xorm:"not null default 0.0000 FLOAT(8,4)" json:"pvd_commission"` + PvdCommissionRate float64 `xorm:"not null default 0.0000 FLOAT(6,4)" json:"pvd_commission_rate"` + SysCommission float64 `xorm:"not null default 0.0000 FLOAT(8,4)" json:"sys_commission"` + SysCommissionRate float64 `xorm:"not null default 0.0000 FLOAT(6,4)" json:"sys_commission_rate"` + PlanCommissionId int `xorm:"not null default 0 INT(10)" json:"plan_commission_id"` + PlanCommissionState int `xorm:"not null default 0 TINYINT(1)" json:"plan_commission_state"` + Reason string `xorm:"not null default '' VARCHAR(32)" json:"reason"` + State int `xorm:"not null default 0 TINYINT(1)" json:"state"` + LockState int `xorm:"not null default 0 TINYINT(1)" json:"lock_state"` + CreateAt int `xorm:"not null default 0 INT(10)" json:"create_at"` + UpdateAt int `xorm:"not null default 0 INT(11)" json:"update_at"` + ConfirmAt int `xorm:"not null default 0 INT(10)" json:"confirm_at"` + PvdSettleAt int `xorm:"not null default 0 INT(10)" json:"pvd_settle_at"` + SettleAt int `xorm:"not null default 0 INT(10)" json:"settle_at"` + SubsidyAt int `xorm:"not null default 0 INT(10)" json:"subsidy_at"` + BenefitList string `xorm:"not null default '' index VARCHAR(200)" json:"benefit_list"` + BenefitAll float64 `xorm:"not null default 0.00 FLOAT(8,2)" json:"benefit_all"` + Data string `xorm:"not null default '' VARCHAR(2000)" json:"data"` + UpdateFrom int `xorm:"not null default 0 TINYINT(1)" json:"update_from"` + CreateFrom int `xorm:"not null default 0 TINYINT(1)" json:"create_from"` + PvdPid string `xorm:"not null default '' index VARCHAR(100)" json:"pvd_pid"` + UserReturnMoney float64 `xorm:"not null default 0.000 FLOAT(8,3)" json:"user_return_money"` + ReturnMoneySettleAt int `xorm:"not null default 0 INT(10)" json:"return_money_settle_at"` + IsSetReduce int `json:"is_set_reduce" xorm:"default 0 comment('小口袋定制设置退回 0否 1是') INT(1)"` +} diff --git a/super_cloud_issuance/db/model/provider_icon.go b/super_cloud_issuance/db/model/provider_icon.go new file mode 100644 index 0000000..cc226c6 --- /dev/null +++ b/super_cloud_issuance/db/model/provider_icon.go @@ -0,0 +1,9 @@ +package model + +type ProviderIcon struct { + Id int `json:"id" xorm:"not null pk autoincr INT(11)"` + Icon string `json:"icon" xorm:"VARCHAR(255)"` + IconUrl string `json:"icon_url" xorm:"VARCHAR(255)"` + Pvd string `json:"pvd" xorm:"VARCHAR(255)"` + Type string `json:"type" xorm:"comment('list列表 detail 详情') VARCHAR(255)"` +} diff --git a/super_cloud_issuance/db/model/sys_cfg.go b/super_cloud_issuance/db/model/sys_cfg.go new file mode 100644 index 0000000..22d906b --- /dev/null +++ b/super_cloud_issuance/db/model/sys_cfg.go @@ -0,0 +1,7 @@ +package model + +type SysCfg struct { + Key string `json:"key" xorm:"not null pk comment('键') VARCHAR(127)"` + Val string `json:"val" xorm:"comment('值') TEXT"` + Memo string `json:"memo" xorm:"not null default '' comment('备注') VARCHAR(255)"` +} diff --git a/super_cloud_issuance/db/model/sys_module.go b/super_cloud_issuance/db/model/sys_module.go new file mode 100644 index 0000000..82b4e88 --- /dev/null +++ b/super_cloud_issuance/db/model/sys_module.go @@ -0,0 +1,34 @@ +package model + +import ( + "time" +) + +type SysModule struct { + ModId int `json:"mod_id" xorm:"not null pk autoincr INT(10)"` + ModPid int `json:"mod_pid" xorm:"not null default 0 comment('父级模块ID') INT(10)"` + TemplateId int `json:"template_id" xorm:"not null default 0 comment('模板ID') INT(11)"` + ModName string `json:"mod_name" xorm:"not null default '' comment('模块名称') VARCHAR(250)"` + Position string `json:"position" xorm:"not null default '' comment('位置') VARCHAR(250)"` + SkipIdentifier string `json:"skip_identifier" xorm:"not null default '' comment('跳转标识') VARCHAR(250)"` + Title string `json:"title" xorm:"not null default '' comment('标题') VARCHAR(128)"` + Subtitle string `json:"subtitle" xorm:"not null default '' comment('副标题') VARCHAR(255)"` + Url string `json:"url" xorm:"not null default '' comment('跳转链接') VARCHAR(512)"` + Margin string `json:"margin" xorm:"not null default '0,0,0,0' comment('边距,上右下左') VARCHAR(64)"` + AspectRatio string `json:"aspect_ratio" xorm:"not null default 0.00 comment('宽高比,宽/高保留两位小数') DECIMAL(4,2)"` + Icon string `json:"icon" xorm:"not null default '' comment('图标') VARCHAR(512)"` + Img string `json:"img" xorm:"not null default '' comment('图片') VARCHAR(512)"` + FontColor string `json:"font_color" xorm:"not null default '' comment('文字颜色') VARCHAR(128)"` + BgImg string `json:"bg_img" xorm:"not null default '' comment('背景图片') VARCHAR(512)"` + BgColor string `json:"bg_color" xorm:"not null default '' comment('背景颜色') VARCHAR(512)"` + BgColorT string `json:"bg_color_t" xorm:"not null default '' comment('背景颜色过度') VARCHAR(255)"` + Badge string `json:"badge" xorm:"not null default '' comment('badge图片') VARCHAR(512)"` + Path string `json:"path" xorm:"not null default '' comment('跳转路径') VARCHAR(255)"` + Data string `json:"data" xorm:"comment('内容') TEXT"` + Sort int `json:"sort" xorm:"not null default 0 comment('排序') INT(11)"` + State int `json:"state" xorm:"not null default 1 comment('0不显示,1显示') TINYINT(1)"` + IsGlobal int `json:"is_global" xorm:"not null default 0 comment('是否全局显示') TINYINT(1)"` + Platform int `json:"platform" xorm:"not null default 1 comment('平台;1:全平台;2:App应用(ios和android);3:H5(wap);4:微信小程序;5:抖音小程序;6:百度小程序') TINYINT(1)"` + CreateAt time.Time `json:"create_at" xorm:"not null default CURRENT_TIMESTAMP comment('创建时间') TIMESTAMP"` + UpdateAt time.Time `json:"update_at" xorm:"not null default CURRENT_TIMESTAMP comment('更新时间') TIMESTAMP"` +} diff --git a/super_cloud_issuance/db/model/sys_push_user.go b/super_cloud_issuance/db/model/sys_push_user.go new file mode 100644 index 0000000..d4a2157 --- /dev/null +++ b/super_cloud_issuance/db/model/sys_push_user.go @@ -0,0 +1,18 @@ +package model + +import ( + "time" +) + +type SysPushUser struct { + Id int `json:"id" xorm:"not null pk autoincr INT(11)"` + PushId int `json:"push_id" xorm:"not null default 0 comment('sys_push_app表ID') index INT(11)"` + Uid int `json:"uid" xorm:"not null default 0 INT(11)"` + State int `json:"state" xorm:"not null default 0 comment('发送状态;0:失败;1:成功') TINYINT(1)"` + Time time.Time `json:"time" xorm:"default CURRENT_TIMESTAMP comment('发送时间') TIMESTAMP"` + SendData string `json:"send_data" xorm:"comment('发送内容,json格式') TEXT"` + Provider string `json:"provider" xorm:"not null default 'mob' comment('平台供应商,如:mob,official:官方推送') VARCHAR(16)"` + Type string `json:"type" xorm:"not null default '' comment('模板类型 | 推送类型;public;:普通推送;activity:活动通知;order_self:新订单提醒(导购自购新订单),order_team:新订单提醒(团队新订单),order_share:新订单提醒(导购分享新订单),member_register:团队成员注册成功,level_upgrade:团队成员等级升级成功,withdraw_fail:提现失败提醒,withdraw_success:提现成功提醒,comission_settle_success:佣金结算提醒(平台结算)') VARCHAR(50)"` + SendAt int `json:"send_at" xorm:"not null default 0 comment('官方活动显示时间(大于当前时间戳才显示);0为即可显示') INT(11)"` + IsRead int `json:"is_read" xorm:"not null default 0 comment('是否已读;0:未读;1:已读') TINYINT(1)"` +} diff --git a/super_cloud_issuance/db/model/sys_template.go b/super_cloud_issuance/db/model/sys_template.go new file mode 100644 index 0000000..4ee3b05 --- /dev/null +++ b/super_cloud_issuance/db/model/sys_template.go @@ -0,0 +1,19 @@ +package model + +import ( + "time" +) + +type SysTemplate struct { + Id int `json:"id" xorm:"not null pk autoincr INT(11)"` + Uid int `json:"uid" xorm:"not null default 0 INT(11)"` + Name string `json:"name" xorm:"not null default '' comment('模板名称') VARCHAR(32)"` + Title string `json:"title" xorm:"not null default '' comment('页面title字段') VARCHAR(32)"` + Type string `json:"type" xorm:"not null default 'index' comment('模板类型;index:首页;bottom:底部导航栏;member:会员中心;custom:自定义模板;share_goods_image:商品图文分享;share_goods_link:商品链接分享;share_goods_platform_xx:商品分享平台(xx对应平台类型)') VARCHAR(64)"` + Image string `json:"image" xorm:"not null default '' VARCHAR(128)"` + IsUse int `json:"is_use" xorm:"default 0 comment('是否使用;1:使用;0未使用') TINYINT(1)"` + Remark string `json:"remark" xorm:"not null default '' comment('备注') VARCHAR(128)"` + IsSystem int `json:"is_system" xorm:"not null default 0 comment('是否系统模板;0:否;1:是') TINYINT(1)"` + CreateAt time.Time `json:"create_at" xorm:"default CURRENT_TIMESTAMP TIMESTAMP"` + UpdateAt time.Time `json:"update_at" xorm:"default CURRENT_TIMESTAMP TIMESTAMP"` +} diff --git a/super_cloud_issuance/db/model/user.go b/super_cloud_issuance/db/model/user.go new file mode 100644 index 0000000..6569667 --- /dev/null +++ b/super_cloud_issuance/db/model/user.go @@ -0,0 +1,25 @@ +package model + +import ( + "time" +) + +type User struct { + Uid int `json:"uid" xorm:"not null pk autoincr comment('主键ID') INT(10)"` + Username string `json:"username" xorm:"not null default '' comment('用户名') index VARCHAR(50)"` + Password string `json:"password" xorm:"not null default '' comment('密码') CHAR(32)"` + Email string `json:"email" xorm:"not null default '' comment('邮箱') VARCHAR(128)"` + Phone string `json:"phone" xorm:"not null default '' comment('联系电话') VARCHAR(20)"` + Nickname string `json:"nickname" xorm:"not null default '' comment('昵称') VARCHAR(20)"` + Level int `json:"level" xorm:"not null default 0 comment('用户等级id') INT(11)"` + InviteTotal int `json:"invite_total" xorm:"not null default 0 comment('直推邀请总人数') INT(11)"` + LevelArriveAt time.Time `json:"level_arrive_at" xorm:"not null default CURRENT_TIMESTAMP comment('到达该等级的时间') TIMESTAMP"` + LevelExpireAt time.Time `json:"level_expire_at" xorm:"not null default CURRENT_TIMESTAMP comment('该等级过期时间') TIMESTAMP"` + CreateAt time.Time `json:"create_at" xorm:"created not null default CURRENT_TIMESTAMP comment('创建时间') TIMESTAMP"` + UpdateAt time.Time `json:"update_at" xorm:"updated default CURRENT_TIMESTAMP comment('最后修改资料时间') TIMESTAMP"` + LastLoginAt time.Time `json:"last_login_at" xorm:"default CURRENT_TIMESTAMP comment('最近登录时间') TIMESTAMP"` + DeleteAt int `json:"delete_at" xorm:"not null default 0 comment('是否删除;0未删除;1已删除') TINYINT(1)"` + State int `json:"state" xorm:"not null default 1 comment('0未激活,1正常,2冻结,3删除') TINYINT(1)"` + LastLoginIp string `json:"last_login_ip" xorm:"not null default '' comment('最后登录IP') VARCHAR(64)"` + RegisterIp string `json:"register_ip" xorm:"not null default '' comment('注册IP') VARCHAR(64)"` +} diff --git a/super_cloud_issuance/db/model/user_app_domain.go b/super_cloud_issuance/db/model/user_app_domain.go new file mode 100644 index 0000000..4522cef --- /dev/null +++ b/super_cloud_issuance/db/model/user_app_domain.go @@ -0,0 +1,8 @@ +package model + +type UserAppDomain struct { + Domain string `json:"domain" xorm:"not null pk comment('绑定域名') VARCHAR(100)"` + Uuid int `json:"uuid" xorm:"not null comment('对应APP ID编号') index unique(IDX_UUID_TYPE) INT(10)"` + Type string `json:"type" xorm:"not null comment('api接口域名,wap.h5域名,admin管理后台') unique(IDX_UUID_TYPE) ENUM('admin','api','wap')"` + IsSsl int `json:"is_ssl" xorm:"not null default 0 comment('是否开启ssl:0否;1是') TINYINT(255)"` +} diff --git a/super_cloud_issuance/db/model/user_level.go b/super_cloud_issuance/db/model/user_level.go new file mode 100644 index 0000000..21f078c --- /dev/null +++ b/super_cloud_issuance/db/model/user_level.go @@ -0,0 +1,20 @@ +package model + +import ( + "time" +) + +type UserLevel struct { + Id int `json:"id" xorm:"not null pk autoincr comment('等级id') INT(11)"` + BenefitIds string `json:"benefit_ids" xorm:"comment('该等级拥有的权益id【json】') TEXT"` + LevelName string `json:"level_name" xorm:"not null default '' comment('等级名称') VARCHAR(255)"` + LevelWeight int `json:"level_weight" xorm:"not null default 0 comment('等级权重') INT(11)"` + LevelUpdateCondition int `json:"level_update_condition" xorm:"not null default 2 comment('2是条件升级,1是无条件升级') TINYINT(1)"` + AutoAudit int `json:"auto_audit" xorm:"not null default 0 comment('(自动审核)0关闭,1开启') TINYINT(1)"` + LevelDate int `json:"level_date" xorm:"default 0 comment('会员有效期(0永久有效,单位月)') INT(11)"` + IsUse int `json:"is_use" xorm:"not null default 1 comment('是否开启(0否,1是)') TINYINT(1)"` + ChoosableNum int `json:"choosable_num" xorm:"default 0 comment('可选任务数量(当is_must_task为0时生效)') INT(6)"` + Memo string `json:"memo" xorm:"default '' comment('备注') VARCHAR(255)"` + CssSet string `json:"css_set" xorm:"TEXT"` + CreateAt time.Time `json:"create_at" xorm:"not null default CURRENT_TIMESTAMP TIMESTAMP"` +} diff --git a/super_cloud_issuance/db/model/user_profile.go b/super_cloud_issuance/db/model/user_profile.go new file mode 100644 index 0000000..8816a99 --- /dev/null +++ b/super_cloud_issuance/db/model/user_profile.go @@ -0,0 +1,91 @@ +package model + +import ( + "time" +) + +type UserProfile struct { + Uid int `json:"uid" xorm:"not null pk comment('关联userID') INT(20)"` + ArkidUid int `json:"arkid_uid" xorm:"not null default 0 comment('Arkid 用户ID') INT(20)"` + ParentUid int `json:"parent_uid" xorm:"not null default 0 comment('上级ID') INT(20)"` + ArkidToken string `json:"arkid_token" xorm:"not null default '' comment('token') VARCHAR(2000)"` + AvatarUrl string `json:"avatar_url" xorm:"not null default '' comment('头像URL') VARCHAR(2000)"` + CustomInviteCode string `json:"custom_invite_code" xorm:"not null default '' comment('邀请码(自定义)') VARCHAR(16)"` + InviteCode string `json:"invite_code" xorm:"not null default '' comment('邀请码(系统)') VARCHAR(16)"` + Gender int `json:"gender" xorm:"not null default 2 comment('性别0女,1男,2未知') TINYINT(1)"` + Birthday int `json:"birthday" xorm:"not null default 0 comment('出生日期') INT(10)"` + AccWxId string `json:"acc_wx_id" xorm:"not null default '' comment('账户_微信id') VARCHAR(50)"` + AccWxOpenid string `json:"acc_wx_openid" xorm:"not null default '' comment('账户_微信openid') VARCHAR(80)"` + AccTaobaoNickname string `json:"acc_taobao_nickname" xorm:"not null default '' comment('淘宝昵称') VARCHAR(50)"` + AccTaobaoAuthTime int64 `json:"acc_taobao_auth_time" xorm:"not null default 0 comment('淘宝授权备案时间') BIGINT(11)"` + AccTaobaoShareId int64 `json:"acc_taobao_share_id" xorm:"not null default 0 comment('淘宝分享relationId,') index BIGINT(12)"` + AccTaobaoSelfId int64 `json:"acc_taobao_self_id" xorm:"not null default 0 comment('淘宝自购specialId') index BIGINT(12)"` + AccJdSelfId string `json:"acc_jd_self_id" xorm:"not null default '' comment('京东自购ID') index VARCHAR(50)"` + AccJdShareId string `json:"acc_jd_share_id" xorm:"not null default '' comment('京东分享ID') index VARCHAR(50)"` + AccJdFreeId string `json:"acc_jd_free_id" xorm:"not null default '' comment('京东新人免单ID') VARCHAR(50)"` + AccSuningSelfId string `json:"acc_suning_self_id" xorm:"not null default '' comment('苏宁自购ID') index VARCHAR(50)"` + AccSuningShareId string `json:"acc_suning_share_id" xorm:"not null default '' comment('苏宁分享ID') index VARCHAR(50)"` + AccSuningFreeId string `json:"acc_suning_free_id" xorm:"not null default '' comment('苏宁新人免单ID') VARCHAR(50)"` + AccPddSelfId string `json:"acc_pdd_self_id" xorm:"not null default '' comment('拼多多自购ID') index VARCHAR(50)"` + AccPddShareId string `json:"acc_pdd_share_id" xorm:"not null default '' comment('拼多多分享ID') index VARCHAR(50)"` + AccPddFreeId string `json:"acc_pdd_free_id" xorm:"not null default '' comment('拼多多新人免单ID') VARCHAR(50)"` + AccPddBind int `json:"acc_pdd_bind" xorm:"not null default 0 comment('拼多多是否授权绑定') TINYINT(1)"` + AccVipSelfId string `json:"acc_vip_self_id" xorm:"not null default '' comment('唯品会自购ID') index VARCHAR(50)"` + AccVipShareId string `json:"acc_vip_share_id" xorm:"not null default '' comment('唯品会分享ID') index VARCHAR(50)"` + AccVipFreeId string `json:"acc_vip_free_id" xorm:"not null default '' comment('唯品会新人免单ID') VARCHAR(50)"` + AccKaolaSelfId string `json:"acc_kaola_self_id" xorm:"not null default '' comment('考拉自购ID') index VARCHAR(50)"` + AccKaolaShareId string `json:"acc_kaola_share_id" xorm:"not null default '' comment('考拉分享ID') index VARCHAR(50)"` + AccKaolaFreeId string `json:"acc_kaola_free_id" xorm:"not null default '' comment('考拉新人免单ID') VARCHAR(50)"` + AccDuomaiShareId int64 `json:"acc_duomai_share_id" xorm:"not null pk default 0 comment('多麦联盟分享ID') BIGINT(12)"` + AccAlipay string `json:"acc_alipay" xorm:"not null default '' comment('支付宝账号') VARCHAR(50)"` + AccAlipayRealName string `json:"acc_alipay_real_name" xorm:"not null default '' comment('支付宝账号真实姓名') VARCHAR(50)"` + CertTime int `json:"cert_time" xorm:"not null default 0 comment('认证时间') INT(10)"` + CertName string `json:"cert_name" xorm:"not null default '' comment('证件上名字,也是真实姓名') VARCHAR(50)"` + CertNum string `json:"cert_num" xorm:"not null default '' comment('证件号码') VARCHAR(50)"` + CertState int `json:"cert_state" xorm:"not null default 0 comment('认证状态(0为未认证,1为认证中,2为已认证,3为认证失败)') TINYINT(1)"` + FinCommission string `json:"fin_commission" xorm:"not null default 0.0000 comment('累计佣金') DECIMAL(10,4)"` + FinValid string `json:"fin_valid" xorm:"not null default 0.0000 comment('可用余额,fin=>finance财务') DECIMAL(10,4)"` + FinInvalid string `json:"fin_invalid" xorm:"not null default 0.0000 comment('不可用余额,冻结余额') DECIMAL(10,4)"` + FinSelfOrderCount int `json:"fin_self_order_count" xorm:"not null default 0 comment('自购订单数,包括未完成') INT(11)"` + FinSelfOrderCountDone int `json:"fin_self_order_count_done" xorm:"not null default 0 comment('自购已完成订单') INT(11)"` + FinSelfRebate float32 `json:"fin_self_rebate" xorm:"not null default 0.000000 comment('累积自购获得返利金额') FLOAT(14,6)"` + FinTotal float32 `json:"fin_total" xorm:"not null default 0.000000 comment('累计总收益') FLOAT(14,6)"` + Lat float32 `json:"lat" xorm:"not null default 0.000000 comment('纬度') FLOAT(15,6)"` + Lng float32 `json:"lng" xorm:"not null default 0.000000 comment('经度') FLOAT(15,6)"` + Memo string `json:"memo" xorm:"not null default '' comment('用户简述备注') VARCHAR(2048)"` + IsNew int `json:"is_new" xorm:"not null default 1 comment('是否是新用户') TINYINT(1)"` + IsVerify int `json:"is_verify" xorm:"not null default 0 comment('是否有效会员') TINYINT(1)"` + IsOrdered int `json:"is_ordered" xorm:"not null default 0 comment('是否已完成首单(0否,1是)') TINYINT(1)"` + FromWay string `json:"from_way" xorm:"not null default '' comment('注册来源: +no_captcha_phone:免验证码手机号注册; +manual_phone:手动手机验证码注册; +wx:微信授权; +wx_mp:小程序授权; +wx_pub:公众号授权; +wx_bind_phone:微信注册绑定手机号; +admin:管理员添加;taobao_bind_phone:淘宝注册绑定手机号,apple_bind_phone:苹果注册绑定手机号') VARCHAR(16)"` + HidOrder int `json:"hid_order" xorm:"not null default 0 comment('隐藏订单') TINYINT(3)"` + HidContact int `json:"hid_contact" xorm:"not null default 0 comment('隐藏联系方式') TINYINT(4)"` + NewMsgNotice int `json:"new_msg_notice" xorm:"not null default 1 comment('新消息通知') TINYINT(1)"` + WxAccount string `json:"wx_account" xorm:"not null default '' comment('微信号') VARCHAR(100)"` + WxQrcode string `json:"wx_qrcode" xorm:"not null default '' comment('微信二维码') VARCHAR(100)"` + ThirdPartyTaobaoOid string `json:"third_party_taobao_oid" xorm:"not null default '' comment('淘宝第三方登录openID') VARCHAR(100)"` + ThirdPartyTaobaoSid string `json:"third_party_taobao_sid" xorm:"not null default '' comment('淘宝第三方登录sID') VARCHAR(255)"` + ThirdPartyTaobaoAcctoken string `json:"third_party_taobao_acctoken" xorm:"not null default '' comment('淘宝第三方登录topaccesstoken') VARCHAR(100)"` + ThirdPartyTaobaoAuthcode string `json:"third_party_taobao_authcode" xorm:"not null default '' comment('淘宝第三方登录topAuthCode') VARCHAR(100)"` + ThirdPartyAppleToken string `json:"third_party_apple_token" xorm:"not null default '' comment('苹果第三方登录token') VARCHAR(1024)"` + ThirdPartyQqAccessToken string `json:"third_party_qq_access_token" xorm:"not null default '' comment('QQ第三方登录access_token') VARCHAR(255)"` + ThirdPartyQqExpiresIn string `json:"third_party_qq_expires_in" xorm:"not null default '' comment('QQ第三方登录expires_in(剩余时长)') VARCHAR(255)"` + ThirdPartyQqOpenid string `json:"third_party_qq_openid" xorm:"not null default '' comment('QQ第三方登陆openid(不变,用于认证)') VARCHAR(255)"` + ThirdPartyQqUnionid string `json:"third_party_qq_unionid" xorm:"not null default '' comment('QQ第三方登陆unionid') VARCHAR(255)"` + ThirdPartyWechatExpiresIn string `json:"third_party_wechat_expires_in" xorm:"not null default '' comment('微信第三方登录expires_in(剩余时长)') VARCHAR(255)"` + ThirdPartyWechatOpenid string `json:"third_party_wechat_openid" xorm:"not null default '' comment('微信第三方登陆openid(不变,用于认证)') VARCHAR(255)"` + ThirdPartyWechatUnionid string `json:"third_party_wechat_unionid" xorm:"not null default '' comment('微信第三方登陆unionid') VARCHAR(255)"` + ThirdPartyWechatMiniOpenid string `json:"third_party_wechat_mini_openid" xorm:"not null default '' comment('微信小程序登录open_id') VARCHAR(255)"` + ThirdPartyWechatH5Openid string `json:"third_party_wechat_h5_openid" xorm:"not null default '' comment('微信H5登录open_id') VARCHAR(255)"` + FreeRemainTime int `json:"free_remain_time" xorm:"not null default 0 comment('免单剩余次数') INT(11)"` + FreeCumulativeTime int `json:"free_cumulative_time" xorm:"not null default 0 comment('免单累计次数') INT(11)"` + IsDelete int `json:"is_delete" xorm:"not null default 0 comment('是否已删除') TINYINT(1)"` + UpdateAt time.Time `json:"update_at" xorm:"updated not null default CURRENT_TIMESTAMP comment('更新时间') TIMESTAMP"` + CreateAt time.Time `json:"create_at" xorm:" not null default '' comment('更新时间') TIMESTAMP"` +} diff --git a/super_cloud_issuance/db/model/user_relate.go b/super_cloud_issuance/db/model/user_relate.go new file mode 100644 index 0000000..375562f --- /dev/null +++ b/super_cloud_issuance/db/model/user_relate.go @@ -0,0 +1,13 @@ +package model + +import ( + "time" +) + +type UserRelate struct { + Id int64 `json:"id" xorm:"pk autoincr comment('主键') BIGINT(10)"` + ParentUid int `json:"parent_uid" xorm:"not null default 0 comment('上级会员ID') unique(idx_union_u_p_id) INT(20)"` + Uid int `json:"uid" xorm:"not null default 0 comment('关联UserID') unique(idx_union_u_p_id) INT(20)"` + Level int `json:"level" xorm:"not null default 1 comment('推广等级(1直属,大于1非直属)') INT(10)"` + InviteTime time.Time `json:"invite_time" xorm:"not null default CURRENT_TIMESTAMP comment('邀请时间') TIMESTAMP"` +} diff --git a/super_cloud_issuance/db/model/user_tag.go b/super_cloud_issuance/db/model/user_tag.go new file mode 100644 index 0000000..19b3d8f --- /dev/null +++ b/super_cloud_issuance/db/model/user_tag.go @@ -0,0 +1,13 @@ +package model + +import ( + "time" +) + +type UserTag struct { + TagId int `json:"tag_id" xorm:"not null pk autoincr INT(10)"` + TagName string `json:"tag_name" xorm:"not null default '' comment('tag名') index VARCHAR(16)"` + Uid int `json:"uid" xorm:"not null default 0 comment('用户ID,uid为0表示标签本身,用于标签管理') index INT(11)"` + Memo string `json:"memo" xorm:"not null default '' comment('备注') VARCHAR(80)"` + CreateAt time.Time `json:"create_at" xorm:"not null default CURRENT_TIMESTAMP comment('创建时间') TIMESTAMP"` +} diff --git a/super_cloud_issuance/db/model/user_virtual_amount.go b/super_cloud_issuance/db/model/user_virtual_amount.go new file mode 100644 index 0000000..73f066c --- /dev/null +++ b/super_cloud_issuance/db/model/user_virtual_amount.go @@ -0,0 +1,8 @@ +package model + +type UserVirtualAmount struct { + Id int64 `json:"id" xorm:"pk autoincr BIGINT(20)"` + Uid int `json:"uid" xorm:"index INT(11)"` + CoinId int `json:"coin_id" xorm:"INT(11)"` + Amount string `json:"amount" xorm:"DECIMAL(16,6)"` +} diff --git a/super_cloud_issuance/db/model/user_virtual_assets.go b/super_cloud_issuance/db/model/user_virtual_assets.go new file mode 100644 index 0000000..22eaa2c --- /dev/null +++ b/super_cloud_issuance/db/model/user_virtual_assets.go @@ -0,0 +1,8 @@ +package model + +type UserVirtualAssets struct { + Id int `json:"id" xorm:"not null pk autoincr INT(11)"` + Uid int `json:"uid" xorm:"default 0 comment('用户id') INT(11)"` + Integral string `json:"integral" xorm:"default 0.0000 comment('用户积分') DECIMAL(12,4)"` + BlockIcons string `json:"block_icons" xorm:"default 0.0000 comment('区块币') DECIMAL(12,4)"` +} diff --git a/super_cloud_issuance/db/model/user_virtual_coin_flow.go b/super_cloud_issuance/db/model/user_virtual_coin_flow.go new file mode 100644 index 0000000..2d48b87 --- /dev/null +++ b/super_cloud_issuance/db/model/user_virtual_coin_flow.go @@ -0,0 +1,21 @@ +package model + +import ( + "time" +) + +type UserVirtualCoinFlow struct { + Id int64 `json:"id" xorm:"pk autoincr BIGINT(20)"` + Uid int `json:"uid" xorm:"not null comment('用户id') index INT(11)"` + CoinId int `json:"coin_id" xorm:"not null comment('虚拟币id') INT(11)"` + Direction int `json:"direction" xorm:"not null comment('方向:1收入 2支出') TINYINT(255)"` + Title string `json:"title" xorm:"comment('标题') VARCHAR(255)"` + OrdId string `json:"ord_id" xorm:"comment('相关的订单id') VARCHAR(255)"` + Amout string `json:"amout" xorm:"not null comment('变更数量') DECIMAL(16,6)"` + BeforeAmout string `json:"before_amout" xorm:"not null comment('变更前数量') DECIMAL(16,6)"` + AfterAmout string `json:"after_amout" xorm:"not null comment('变更后数量') DECIMAL(16,6)"` + SysFee string `json:"sys_fee" xorm:"not null default 0.000000 comment('手续费') DECIMAL(16,6)"` + CreateTime time.Time `json:"create_time" xorm:"created default 'CURRENT_TIMESTAMP' comment('创建时间') DATETIME"` + TransferType int `json:"transfer_type" xorm:"comment('转账类型:1全球分红,2管理员修改,3消费,4退回,5虚拟币兑换') TINYINT(100)"` + CoinIdTo int `json:"coin_id_to" xorm:"not null default 0 comment('兑换时目标币种id') INT(11)"` +} diff --git a/super_cloud_issuance/db/model/virtual_coin.go b/super_cloud_issuance/db/model/virtual_coin.go new file mode 100644 index 0000000..3baaa55 --- /dev/null +++ b/super_cloud_issuance/db/model/virtual_coin.go @@ -0,0 +1,17 @@ +package model + +type VirtualCoin struct { + Id int `json:"id" xorm:"not null pk autoincr INT(11)"` + Name string `json:"name" xorm:"not null default '' comment('名称') VARCHAR(255)"` + ExchangeRatio string `json:"exchange_ratio" xorm:"not null comment('兑换比例(与金额)') DECIMAL(5,2)"` + IsUse int `json:"is_use" xorm:"comment('是否开启:0否 1是') TINYINT(1)"` + CanExchange string `json:"can_exchange" xorm:"comment('能兑换的虚拟币id和手续费列表json') VARCHAR(255)"` + CanExchangeMoney int `json:"can_exchange_money" xorm:"not null default 0 comment('现金能否兑换:0否 1是') TINYINT(1)"` + IsBlock int `json:"is_block" xorm:"not null default 0 comment('是否区块币:0否 1是') TINYINT(1)"` + FunctionType string `json:"function_type" xorm:"comment('功能类型') VARCHAR(255)"` + CanCny int `json:"can_cny" xorm:"not null default 0 comment('是否能兑换余额:0否 1是') TINYINT(1)"` + CanTransfer int `json:"can_transfer" xorm:"not null default 0 comment('是否能支持转账:0否 1是') TINYINT(1)"` + CanBackout int `json:"can_backout" xorm:"not null default 0 comment('是否能支持转账撤回:0否 1是') TINYINT(1)"` + LimitLevelTransfer string `json:"limit_level_transfer" xorm:"default '' comment('能支持转账的用户等级') VARCHAR(600)"` + LimitLevelBackout string `json:"limit_level_backout" xorm:"comment('能支持撤回的用户等级') VARCHAR(600)"` +} diff --git a/super_cloud_issuance/db/model/virtual_coin_relate.go b/super_cloud_issuance/db/model/virtual_coin_relate.go new file mode 100644 index 0000000..a629564 --- /dev/null +++ b/super_cloud_issuance/db/model/virtual_coin_relate.go @@ -0,0 +1,12 @@ +package model + +type VirtualCoinRelate struct { + Id int64 `json:"id" xorm:"pk autoincr BIGINT(20)"` + Oid int64 `json:"oid" xorm:"not null default 0 comment('订单号') index unique(IDX_ORD) BIGINT(20)"` + Uid int `json:"uid" xorm:"not null default 0 comment('用户ID') unique(IDX_ORD) index INT(10)"` + CoinId int `json:"coin_id" xorm:"comment('虚拟币id') INT(11)"` + Amount string `json:"amount" xorm:"not null default 0.000000 comment('数量') DECIMAL(16,6)"` + Pvd string `json:"pvd" xorm:"not null default '' comment('供应商taobao,jd,pdd,vip,suning,kaola,mall_goods,group_buy') index VARCHAR(255)"` + CreateAt int `json:"create_at" xorm:"not null default 0 comment('订单创建时间') index INT(10)"` + Level int `json:"level" xorm:"not null default 0 comment('0自购 1直推 大于1:间推') INT(10)"` +} diff --git a/super_cloud_issuance/db/model/wx_applet_list.go b/super_cloud_issuance/db/model/wx_applet_list.go new file mode 100644 index 0000000..4a1dac8 --- /dev/null +++ b/super_cloud_issuance/db/model/wx_applet_list.go @@ -0,0 +1,41 @@ +package model + +import ( + "time" +) + +type WxAppletList struct { + Id int `json:"id" xorm:"not null pk autoincr INT(10)"` + Memo string `json:"memo" xorm:"not null default '' comment('备注') unique VARCHAR(255)"` + CompanyName string `json:"company_name" xorm:"not null default '' comment('企业名(需与工商部门登记信息一致);如果是“无主体名称个体工商户”则填“个体户+法人姓名”,例如“个体户张三”') VARCHAR(255)"` + Code string `json:"code" xorm:"not null default '' comment('企业代码') VARCHAR(255)"` + CodeType int `json:"code_type" xorm:"not null default 3 comment('企业代码类型 1:统一社会信用代码(18 位) 2:组织机构代码(9 位 xxxxxxxx-x) 3:营业执照注册号(15 位)') TINYINT(3)"` + LegalPersonaWechat string `json:"legal_persona_wechat" xorm:"not null default '' comment('法人微信号') VARCHAR(255)"` + LegalPersonaName string `json:"legal_persona_name" xorm:"not null default '' comment('法人姓名(绑定银行卡)') VARCHAR(255)"` + State int `json:"state" xorm:"not null default 0 comment('创建状态(0:创建中 1:创建成功 2:创建失败)') TINYINT(3)"` + Ext string `json:"ext" xorm:"comment('拓展字段') TEXT"` + UniqueIdentifier string `json:"unique_identifier" xorm:"not null default '' comment('唯一标识符(企业名称、企业代码、法人微信、法人姓名四个字段作为每次任务的唯一标示,来区别每次任务。)') VARCHAR(255)"` + AppId string `json:"app_id" xorm:"default '' comment('小程序appId') VARCHAR(255)"` + OriginalAppId string `json:"original_app_id" xorm:"default '' comment('原始ID') VARCHAR(255)"` + AuthorizerToken string `json:"authorizer_token" xorm:"default '' comment('授权token') VARCHAR(255)"` + AuthorizerRefreshToken string `json:"authorizer_refresh_token" xorm:"default '' comment('授权更新token') VARCHAR(255)"` + AuditVersionState int `json:"audit_version_state" xorm:"not null default 0 comment('线上版本号') TINYINT(3)"` + PublishVersionNum string `json:"publish_version_num" xorm:"comment('审核状态(0:暂无审核;1:审核中;2:审核通过;3:审核驳回)') VARCHAR(255)"` + AppletName string `json:"applet_name" xorm:"default '' comment('小程序名字') VARCHAR(255)"` + AppletSignature string `json:"applet_signature" xorm:"default '' comment('小程序简介') VARCHAR(255)"` + AppletLogo string `json:"applet_logo" xorm:"default '' comment('小程序logo') VARCHAR(255)"` + SetAppletNameInfo string `json:"set_applet_name_info" xorm:"default '' comment('小程序改名证件url') VARCHAR(255)"` + SetAppletNameInfoType int `json:"set_applet_name_info_type" xorm:"default 1 comment('小程序改名证件类型(1:个人号 2:组织号)') TINYINT(3)"` + SetAppletNameState int `json:"set_applet_name_state" xorm:"default 0 comment('小程序改名状态(0:未进行 1:进行中 2:改名成功 3:改名失败)') TINYINT(3)"` + SetAppletNameAuditId string `json:"set_applet_name_audit_id" xorm:"default '' comment('小程序改名的审核单id') VARCHAR(255)"` + CreateAt time.Time `json:"create_at" xorm:"not null default 'CURRENT_TIMESTAMP' TIMESTAMP"` + UpdateAt time.Time `json:"update_at" xorm:"not null default 'CURRENT_TIMESTAMP' TIMESTAMP"` + IsFilterTaobao int `json:"is_filter_taobao" xorm:"default 0 comment('是否过滤淘宝商品 0否 1是') INT(1)"` + CateId string `json:"cate_id" xorm:"default '' comment('主营类目id') VARCHAR(50)"` + BottomNavCssId int `json:"bottom_nav_css_id" xorm:"default 0 comment('底部导航样式id') INT(11)"` + AuthType string `json:"auth_type" xorm:"default 'reg' comment('授权方式 直接授权old_auth 注册授权reg') VARCHAR(100)"` + MpAuditVersion string `json:"mp_audit_version" xorm:"default '' comment('审核版本') VARCHAR(100)"` + MpAuditCssId int `json:"mp_audit_css_id" xorm:"default 0 comment('审核版本底部样式ID') INT(11)"` + AppletBgColor string `json:"applet_bg_color" xorm:"default '' comment('导航栏/状态栏背景色') VARCHAR(100)"` + AppletNavColor string `json:"applet_nav_color" xorm:"default '' comment('导航栏/状态栏字体色') VARCHAR(100)"` +} diff --git a/super_cloud_issuance/db/official/db_super_cloud_issuance_baisc.go b/super_cloud_issuance/db/official/db_super_cloud_issuance_baisc.go new file mode 100644 index 0000000..39c2f98 --- /dev/null +++ b/super_cloud_issuance/db/official/db_super_cloud_issuance_baisc.go @@ -0,0 +1,15 @@ +package db + +import ( + "applet/app/db" + "applet/app/utils/logx" + "applet/super_cloud_issuance/db/official/model" +) + +func GetSuperCloudIssuanceBasic() (*model.SuperCloudIssuanceBasic, error) { + var m model.SuperCloudIssuanceBasic + if has, err := db.Db.Where("id >=1").Get(&m); err != nil || has == false { + return nil, logx.Error(err) + } + return &m, nil +} diff --git a/super_cloud_issuance/db/official/db_super_cloud_issuance_master.go b/super_cloud_issuance/db/official/db_super_cloud_issuance_master.go new file mode 100644 index 0000000..8d75512 --- /dev/null +++ b/super_cloud_issuance/db/official/db_super_cloud_issuance_master.go @@ -0,0 +1,117 @@ +package db + +import ( + "applet/app/db" + "applet/app/utils" + "applet/app/utils/logx" + "applet/super_cloud_issuance/db/official/model" + "errors" + "fmt" + "reflect" +) + +// BatchSelectSuperCloudIssuanceMaster 批量查询数据 TODO::和下面的方法重复了,建议采用下面的 `SuperCloudIssuanceMasterFindByParams` 方法 +func BatchSelectSuperCloudIssuanceMaster(params map[string]interface{}) (*[]model.SuperCloudIssuanceMaster, error) { + var SuperCloudIssuanceMasterData []model.SuperCloudIssuanceMaster + if err := db.Db.In(utils.AnyToString(params["key"]), params["value"]). + Find(&SuperCloudIssuanceMasterData); err != nil { + return nil, logx.Warn(err) + } + return &SuperCloudIssuanceMasterData, nil +} + +// SuperCloudIssuanceMasterInsert 插入单条数据 +func SuperCloudIssuanceMasterInsert(SuperCloudIssuanceMaster *model.SuperCloudIssuanceMaster) (int, error) { + _, err := db.Db.InsertOne(SuperCloudIssuanceMaster) + if err != nil { + return 0, err + } + return SuperCloudIssuanceMaster.Id, nil +} + +// BatchAddSuperCloudIssuanceMaster 批量新增数据 +func BatchAddSuperCloudIssuanceMaster(SuperCloudIssuanceMasterData []*model.SuperCloudIssuanceMaster) (int64, error) { + affected, err := db.Db.Insert(SuperCloudIssuanceMasterData) + if err != nil { + return 0, err + } + return affected, nil +} + +func GetSuperCloudIssuanceMasterCount() int { + var SuperCloudIssuanceMaster model.SuperCloudIssuanceMaster + session := db.Db.Where("") + count, err := session.Count(&SuperCloudIssuanceMaster) + if err != nil { + return 0 + } + return int(count) +} + +// SuperCloudIssuanceMasterDelete 删除记录 +func SuperCloudIssuanceMasterDelete(id interface{}) (int64, error) { + if reflect.TypeOf(id).Kind() == reflect.Slice { + return db.Db.In("id", id).Delete(model.SuperCloudIssuanceMaster{}) + } else { + return db.Db.Where("id = ?", id).Delete(model.SuperCloudIssuanceMaster{}) + } +} + +// SuperCloudIssuanceMasterUpdate 更新记录 +func SuperCloudIssuanceMasterUpdate(id interface{}, SuperCloudIssuanceMaster *model.SuperCloudIssuanceMaster, forceColums ...string) (int64, error) { + var ( + affected int64 + err error + ) + if forceColums != nil { + affected, err = db.Db.Where("id=?", id).Cols(forceColums...).Update(SuperCloudIssuanceMaster) + } else { + affected, err = db.Db.Where("id=?", id).Update(SuperCloudIssuanceMaster) + } + if err != nil { + return 0, err + } + return affected, nil +} + +// SuperCloudIssuanceMasterGetOneByParams 通过传入的参数查询数据(单条) +func SuperCloudIssuanceMasterGetOneByParams(params map[string]interface{}) (*model.SuperCloudIssuanceMaster, error) { + var m model.SuperCloudIssuanceMaster + var query = fmt.Sprintf("%s =?", params["key"]) + if has, err := db.Db.Where(query, params["value"]).Get(&m); err != nil || has == false { + return nil, logx.Error(err) + } + return &m, nil +} + +// SuperCloudIssuanceMasterFindByParams 通过传入的参数查询数据(多条) +func SuperCloudIssuanceMasterFindByParams(params map[string]interface{}) (*[]model.SuperCloudIssuanceMaster, error) { + var m []model.SuperCloudIssuanceMaster + if params["value"] == nil { + return nil, errors.New("参数有误") + } + if params["key"] == nil { + //查询全部数据 + err := db.Db.Find(&m) + if err != nil { + return nil, logx.Error(err) + } + return &m, nil + } else { + if reflect.TypeOf(params["value"]).Kind() == reflect.Slice { + //指定In查询 + if err := db.Db.In(utils.AnyToString(params["key"]), params["value"]).Find(&m); err != nil { + return nil, logx.Warn(err) + } + return &m, nil + } else { + var query = fmt.Sprintf("%s =?", params["key"]) + err := db.Db.Where(query, params["value"]).Find(&m) + if err != nil { + return nil, logx.Error(err) + } + return &m, nil + } + + } +} diff --git a/super_cloud_issuance/db/official/db_super_cloud_issuance_master_buy_ord.go b/super_cloud_issuance/db/official/db_super_cloud_issuance_master_buy_ord.go new file mode 100644 index 0000000..4339702 --- /dev/null +++ b/super_cloud_issuance/db/official/db_super_cloud_issuance_master_buy_ord.go @@ -0,0 +1,117 @@ +package db + +import ( + "applet/app/db" + "applet/app/utils" + "applet/app/utils/logx" + "applet/super_cloud_issuance/db/official/model" + "errors" + "fmt" + "reflect" +) + +// BatchSelectCloudIssuanceMasterBuyOrd 批量查询数据 TODO::和下面的方法重复了,建议采用下面的 `CloudIssuanceMasterBuyOrdFindByParams` 方法 +func BatchSelectCloudIssuanceMasterBuyOrd(params map[string]interface{}) (*[]model.SuperCloudIssuanceMasterBuyOrd, error) { + var CloudIssuanceMasterBuyOrdData []model.SuperCloudIssuanceMasterBuyOrd + if err := db.Db.In(utils.AnyToString(params["key"]), params["value"]). + Find(&CloudIssuanceMasterBuyOrdData); err != nil { + return nil, logx.Warn(err) + } + return &CloudIssuanceMasterBuyOrdData, nil +} + +// CloudIssuanceMasterBuyOrdInsert 插入单条数据 +func CloudIssuanceMasterBuyOrdInsert(CloudIssuanceMasterBuyOrd *model.SuperCloudIssuanceMasterBuyOrd) (int, error) { + _, err := db.Db.InsertOne(CloudIssuanceMasterBuyOrd) + if err != nil { + return 0, err + } + return CloudIssuanceMasterBuyOrd.Id, nil +} + +// BatchAddCloudIssuanceMasterBuyOrd 批量新增数据 +func BatchAddCloudIssuanceMasterBuyOrd(CloudIssuanceMasterBuyOrdData []*model.SuperCloudIssuanceMasterBuyOrd) (int64, error) { + affected, err := db.Db.Insert(CloudIssuanceMasterBuyOrdData) + if err != nil { + return 0, err + } + return affected, nil +} + +func GetCloudIssuanceMasterBuyOrdCount() int { + var CloudIssuanceMasterBuyOrd model.SuperCloudIssuanceMasterBuyOrd + session := db.Db.Where("") + count, err := session.Count(&CloudIssuanceMasterBuyOrd) + if err != nil { + return 0 + } + return int(count) +} + +// CloudIssuanceMasterBuyOrdDelete 删除记录 +func CloudIssuanceMasterBuyOrdDelete(id interface{}) (int64, error) { + if reflect.TypeOf(id).Kind() == reflect.Slice { + return db.Db.In("id", id).Delete(model.SuperCloudIssuanceMasterBuyOrd{}) + } else { + return db.Db.Where("id = ?", id).Delete(model.SuperCloudIssuanceMasterBuyOrd{}) + } +} + +// CloudIssuanceMasterBuyOrdUpdate 更新记录 +func CloudIssuanceMasterBuyOrdUpdate(id interface{}, CloudIssuanceMasterBuyOrd *model.SuperCloudIssuanceMasterBuyOrd, forceColums ...string) (int64, error) { + var ( + affected int64 + err error + ) + if forceColums != nil { + affected, err = db.Db.Where("id=?", id).Cols(forceColums...).Update(CloudIssuanceMasterBuyOrd) + } else { + affected, err = db.Db.Where("id=?", id).Update(CloudIssuanceMasterBuyOrd) + } + if err != nil { + return 0, err + } + return affected, nil +} + +// CloudIssuanceMasterBuyOrdGetOneByParams 通过传入的参数查询数据(单条) +func CloudIssuanceMasterBuyOrdGetOneByParams(params map[string]interface{}) (*model.SuperCloudIssuanceMasterBuyOrd, error) { + var m model.SuperCloudIssuanceMasterBuyOrd + var query = fmt.Sprintf("%s =?", params["key"]) + if has, err := db.Db.Where(query, params["value"]).Get(&m); err != nil || has == false { + return nil, logx.Error(err) + } + return &m, nil +} + +// CloudIssuanceMasterBuyOrdFindByParams 通过传入的参数查询数据(多条) +func CloudIssuanceMasterBuyOrdFindByParams(params map[string]interface{}) (*[]model.SuperCloudIssuanceMasterBuyOrd, error) { + var m []model.SuperCloudIssuanceMasterBuyOrd + if params["value"] == nil { + return nil, errors.New("参数有误") + } + if params["key"] == nil { + //查询全部数据 + err := db.Db.Find(&m) + if err != nil { + return nil, logx.Error(err) + } + return &m, nil + } else { + if reflect.TypeOf(params["value"]).Kind() == reflect.Slice { + //指定In查询 + if err := db.Db.In(utils.AnyToString(params["key"]), params["value"]).Find(&m); err != nil { + return nil, logx.Warn(err) + } + return &m, nil + } else { + var query = fmt.Sprintf("%s =?", params["key"]) + err := db.Db.Where(query, params["value"]).Find(&m) + if err != nil { + return nil, logx.Error(err) + } + return &m, nil + } + + } +} diff --git a/super_cloud_issuance/db/official/db_super_cloud_issuance_robot_records.go b/super_cloud_issuance/db/official/db_super_cloud_issuance_robot_records.go new file mode 100644 index 0000000..14a67fd --- /dev/null +++ b/super_cloud_issuance/db/official/db_super_cloud_issuance_robot_records.go @@ -0,0 +1,62 @@ +package db + +import ( + "applet/app/db" + "applet/app/utils" + "applet/app/utils/logx" + "applet/super_cloud_issuance/db/official/model" + "errors" + "fmt" + "reflect" +) + +// SuperCloudIssuanceRobotRecordsInsert 插入单条数据 +func SuperCloudIssuanceRobotRecordsInsert(SuperCloudIssuanceRobotRecords *model.SuperCloudIssuanceRobotRecords) (int, error) { + _, err := db.Db.InsertOne(SuperCloudIssuanceRobotRecords) + if err != nil { + return 0, err + } + return SuperCloudIssuanceRobotRecords.Id, nil +} + +// SuperCloudIssuanceRobotRecordsGetOneByParams 通过传入的参数查询数据(单条) +func SuperCloudIssuanceRobotRecordsGetOneByParams(params map[string]interface{}) (*model.SuperCloudIssuanceRobotRecords, error) { + var m model.SuperCloudIssuanceRobotRecords + var query = fmt.Sprintf("%s =?", params["key"]) + if has, err := db.Db.Where(query, params["value"]).Get(&m); err != nil || has == false { + return nil, logx.Error(err) + } + return &m, nil +} + +// SuperCloudIssuanceRobotRecordsFindByParams 通过传入的参数查询数据(多条) +func SuperCloudIssuanceRobotRecordsFindByParams(params map[string]interface{}) (*[]model.SuperCloudIssuanceRobotRecords, error) { + var m []model.SuperCloudIssuanceRobotRecords + if params["value"] == nil { + return nil, errors.New("参数有误") + } + if params["key"] == nil { + //查询全部数据 + err := db.Db.Find(&m) + if err != nil { + return nil, logx.Error(err) + } + return &m, nil + } else { + if reflect.TypeOf(params["value"]).Kind() == reflect.Slice { + //指定In查询 + if err := db.Db.In(utils.AnyToString(params["key"]), params["value"]).Find(&m); err != nil { + return nil, logx.Warn(err) + } + return &m, nil + } else { + var query = fmt.Sprintf("%s =?", params["key"]) + err := db.Db.Where(query, params["value"]).Find(&m) + if err != nil { + return nil, logx.Error(err) + } + return &m, nil + } + + } +} diff --git a/super_cloud_issuance/db/official/model/super_cloud_issuance_basic.go b/super_cloud_issuance/db/official/model/super_cloud_issuance_basic.go new file mode 100644 index 0000000..55fe03c --- /dev/null +++ b/super_cloud_issuance/db/official/model/super_cloud_issuance_basic.go @@ -0,0 +1,15 @@ +package model + +import "time" + +type SuperCloudIssuanceBasic struct { + Id int `json:"id"` + ImageNumsLimitIssuanceOnCircleOfFriends int `json:"image_nums_limit_issuance_on_circle_of_friends"` + ImageNumsLimitIssuanceOnGroups int `json:"image_nums_limit_issuance_on_groups"` + BindNums int `json:"bind_nums"` + FollowGroupUserNums int `json:"follow_group_user_nums"` + FollowGroupBindNums int `json:"follow_group_bind_nums"` + FollowGroupRelayNums int `json:"follow_group_relay_nums"` + CreateAt time.Time `json:"create_at" xorm:"not null default CURRENT_TIMESTAMP comment('创建时间') TIMESTAMP"` + UpdateAt time.Time `json:"update_at" xorm:"not null default CURRENT_TIMESTAMP comment('更新时间') TIMESTAMP"` +} diff --git a/super_cloud_issuance/db/official/model/super_cloud_issuance_master.go b/super_cloud_issuance/db/official/model/super_cloud_issuance_master.go new file mode 100644 index 0000000..5d964c2 --- /dev/null +++ b/super_cloud_issuance/db/official/model/super_cloud_issuance_master.go @@ -0,0 +1,14 @@ +package model + +import "time" + +type SuperCloudIssuanceMaster struct { + Id int `json:"id"` + MasterId int `json:"master_id"` + Amount string `json:"amount"` + CreditAmount string `json:"credit_amount"` + Memo string `json:"memo"` + State int `json:"state"` + CreateAt time.Time `json:"create_at" xorm:"not null default CURRENT_TIMESTAMP comment('创建时间') TIMESTAMP"` + UpdateAt time.Time `json:"update_at" xorm:"not null default CURRENT_TIMESTAMP comment('更新时间') TIMESTAMP"` +} diff --git a/super_cloud_issuance/db/official/model/super_cloud_issuance_master_buy_ord.go b/super_cloud_issuance/db/official/model/super_cloud_issuance_master_buy_ord.go new file mode 100644 index 0000000..52f77bb --- /dev/null +++ b/super_cloud_issuance/db/official/model/super_cloud_issuance_master_buy_ord.go @@ -0,0 +1,22 @@ +package model + +import "time" + +type SuperCloudIssuanceMasterBuyOrd struct { + Id int `json:"id"` + OrdId string `json:"ord_id"` + MasterId int `json:"master_id"` + Nickname string `json:"nickname"` + Phone int64 `json:"phone"` + Uid int `json:"uid"` + UserPhone string `json:"user_phone"` + RobotId int `json:"robot_id"` + Month int `json:"month"` + CostPrice string `json:"cost_price"` + BeforeBalance string `json:"before_balance"` + Balance string `json:"balance"` + Memo string `json:"memo"` + State int `json:"state"` + CreateAt time.Time `json:"create_at" xorm:"not null default CURRENT_TIMESTAMP comment('创建时间') TIMESTAMP"` + UpdateAt time.Time `json:"update_at" xorm:"not null default CURRENT_TIMESTAMP comment('更新时间') TIMESTAMP"` +} diff --git a/super_cloud_issuance/db/official/model/super_cloud_issuance_robot.go b/super_cloud_issuance/db/official/model/super_cloud_issuance_robot.go new file mode 100644 index 0000000..b65ad8c --- /dev/null +++ b/super_cloud_issuance/db/official/model/super_cloud_issuance_robot.go @@ -0,0 +1,15 @@ +package model + +import "time" + +type SuperCloudIssuanceRobot struct { + Id int `json:"id"` + Name string `json:"name"` + Price string `json:"price"` + Type int32 `json:"type"` + State int32 `json:"state"` + Sort int `json:"sort"` + Memo string `json:"memo"` + CreateAt time.Time `json:"create_at" xorm:"not null default CURRENT_TIMESTAMP comment('创建时间') TIMESTAMP"` + UpdateAt time.Time `json:"update_at" xorm:"not null default CURRENT_TIMESTAMP comment('更新时间') TIMESTAMP"` +} diff --git a/super_cloud_issuance/db/official/model/super_cloud_issuance_robot_records.go b/super_cloud_issuance/db/official/model/super_cloud_issuance_robot_records.go new file mode 100644 index 0000000..7b2dd44 --- /dev/null +++ b/super_cloud_issuance/db/official/model/super_cloud_issuance_robot_records.go @@ -0,0 +1,8 @@ +package model + +type SuperCloudIssuanceRobotRecords struct { + Id int `json:"id"` + MasterId string `json:"master_id"` + RobotId string `json:"robot_id"` + Uid int `json:"uid"` +} diff --git a/super_cloud_issuance/db/official/model/user_app_list.go b/super_cloud_issuance/db/official/model/user_app_list.go new file mode 100644 index 0000000..5d23804 --- /dev/null +++ b/super_cloud_issuance/db/official/model/user_app_list.go @@ -0,0 +1,8 @@ +package model + +type UserAppList struct { + Id int `json:"id" xorm:"int(11) NOT NULL "` + Uuid int64 `json:"uuid" xorm:"int(10) NOT NULL "` + AppId int64 `json:"app_id" xorm:"int(10) NOT NULL "` + Name string `json:"name" xorm:"varchar(255) DEFAULT '' "` +} diff --git a/super_cloud_issuance/db/official/model/user_app_member.go b/super_cloud_issuance/db/official/model/user_app_member.go new file mode 100644 index 0000000..9a07379 --- /dev/null +++ b/super_cloud_issuance/db/official/model/user_app_member.go @@ -0,0 +1,8 @@ +package model + +type UserAppMember struct { + Id int `json:"id" xorm:"int(11) NOT NULL "` + Uuid int64 `json:"uuid" xorm:"int(10) NOT NULL "` + Uid int64 `json:"uid" xorm:"int(10) NOT NULL "` + Phone int64 `json:"phone" xorm:"int(10) NOT NULL "` +} diff --git a/super_cloud_issuance/db/zhimeng_db.go b/super_cloud_issuance/db/zhimeng_db.go new file mode 100644 index 0000000..fe62545 --- /dev/null +++ b/super_cloud_issuance/db/zhimeng_db.go @@ -0,0 +1,41 @@ +package db + +import ( + "applet/app/cfg" + db2 "applet/app/db" + "fmt" + _ "github.com/go-sql-driver/mysql" + "os" + "xorm.io/xorm" + "xorm.io/xorm/log" +) + +var ZhimengDb *xorm.Engine + +func InitZhimengDB(c *cfg.DBCfg) error { + var err error + if ZhimengDb, err = xorm.NewEngine("mysql", fmt.Sprintf("%s:%s@tcp(%s)/%s?charset=utf8mb4", c.User, c.Psw, c.Host, c.Name)); err != nil { + return err + } + ZhimengDb.SetConnMaxLifetime(c.MaxLifetime) + ZhimengDb.SetMaxOpenConns(c.MaxOpenConns) + ZhimengDb.SetMaxIdleConns(c.MaxIdleConns) + if err = db2.Db.Ping(); err != nil { + return err + } + if c.ShowLog { + ZhimengDb.ShowSQL(true) + ZhimengDb.Logger().SetLevel(0) + f, err := os.OpenFile(c.Path, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0777) + if err != nil { + os.RemoveAll(c.Path) + if f, err = os.OpenFile(c.Path, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0777); err != nil { + return err + } + } + logger := log.NewSimpleLogger(f) + logger.ShowSQL(true) + ZhimengDb.SetLogger(logger) + } + return nil +} diff --git a/super_cloud_issuance/enum/enum_api.go b/super_cloud_issuance/enum/enum_api.go new file mode 100644 index 0000000..e0c1a72 --- /dev/null +++ b/super_cloud_issuance/enum/enum_api.go @@ -0,0 +1,88 @@ +package enum + +type CloudIssuanceMethodName string + +const ( + RobotCreateMethodName = "itaoke.robot.create.get" + QrcodeMacLoginMethodName = "itaoke.robot.qrcode.maclogin" + RobotAsyncMacLoginMethodName = "itaoke.robot.async.mlogin" + RobotForceOfflineMethodName = "itaoke.robot.force.offline" + RobotSecondLoginMethodName = "itaoke.robot.second.login" + RobotChangeMethodName = "itaoke.robot.change.get" + RobotResetMethodName = "itaoke.robot.reset.get" + RobotRoomListMethodName = "itaoke.robot.room.list" + RobotGroupListMethodName = "itaoke.robot.group.list" + RobotRoomDetailMethodName = "itaoke.robot.room.detail" + RobotMacGetChatRoomMemberMethodName = "itaoke.robot.macget.chatroommember" + RobotMacSendCardMethodName = "itaoke.robot.macsend.card" + RobotMacSendUriMethodName = "itaoke.robot.macsend.image" + RobotMacSendTextMethodName = "itaoke.robot.macsend.text" + RobotMacSendRecvImageMethodName = "itaoke.robot.macsend.recvimage" + RobotMacSendRecvViedoMethodName = "itaoke.robot.macsend.recvviedo" + RobotMacRepeatCircleMethodName = "itaoke.robot.macrepeat.circle" + RobotMacSendAppMethodName = "itaoke.robot.macsend.app" + RobotMacSendCircleMethodName = "itaoke.robot.macsend.circle" +) + +func (gt CloudIssuanceMethodName) String() string { + switch gt { + case RobotCreateMethodName: + return "云发单添加机器人" + case QrcodeMacLoginMethodName: + return "获取登录二维码" + case RobotAsyncMacLoginMethodName: + return "循环是否登陆" + case RobotForceOfflineMethodName: + return "强制下线" + case RobotSecondLoginMethodName: + return "二次登录(阻塞式)" + case RobotChangeMethodName: + return "机器人修改/续费" + case RobotResetMethodName: + return "重置机器人" + case RobotRoomListMethodName: + return "获取群列表" + case RobotGroupListMethodName: + return "获取群列表(优惠狗端)" + case RobotRoomDetailMethodName: + return "获取群详情" + case RobotMacGetChatRoomMemberMethodName: + return "获取群成员" + case RobotMacSendCardMethodName: + return "发链接消息" + case RobotMacSendUriMethodName: + return "根据url发图" + case RobotMacSendTextMethodName: + return "发文本消息" + case RobotMacSendRecvImageMethodName: + return "转发图片(xml版)" + case RobotMacSendRecvViedoMethodName: + return "转发视频(xml版)" + case RobotMacRepeatCircleMethodName: + return "朋友圈转发" + case RobotMacSendAppMethodName: + return "转发小程序等XML" + case RobotMacSendCircleMethodName: + return "发送朋友圈" + default: + return "未知" + } +} + +type CloudIssuanceLoginStatus int + +const ( + NotLogin = 0 + AlreadyLogin = 1 +) + +func (gt CloudIssuanceLoginStatus) String() string { + switch gt { + case NotLogin: + return "未登录" + case AlreadyLogin: + return "已登录" + default: + return "未知" + } +} diff --git a/super_cloud_issuance/enum/enum_goods_category.go b/super_cloud_issuance/enum/enum_goods_category.go new file mode 100644 index 0000000..1d55ad9 --- /dev/null +++ b/super_cloud_issuance/enum/enum_goods_category.go @@ -0,0 +1,31 @@ +package enum + +type CloudIssuanceGoodsProvider string + +const ( + ProviderForJd = "jd" + ProviderForTaoBao = "taobao" + ProviderForSuNing = "suning" + ProviderForPdd = "pdd" + ProviderForKaoLa = "kaola" + ProviderForVip = "vip" +) + +func (gt CloudIssuanceGoodsProvider) String() string { + switch gt { + case ProviderForJd: + return "京东" + case ProviderForTaoBao: + return "淘宝" + case ProviderForSuNing: + return "苏宁" + case ProviderForPdd: + return "拼多多" + case ProviderForKaoLa: + return "考拉" + case ProviderForVip: + return "唯品会" + default: + return "未知" + } +} diff --git a/super_cloud_issuance/enum/enum_super_cloud_issuance_add_group_welcome_message.go b/super_cloud_issuance/enum/enum_super_cloud_issuance_add_group_welcome_message.go new file mode 100644 index 0000000..3a0c851 --- /dev/null +++ b/super_cloud_issuance/enum/enum_super_cloud_issuance_add_group_welcome_message.go @@ -0,0 +1,19 @@ +package enum + +type SuperCloudIssuanceAddGroupWelcomeMessageState int + +const ( + SuperCloudIssuanceAddGroupWelcomeMessageStateForSuspend = 0 + SuperCloudIssuanceAddGroupWelcomeMessageStateForNormal = 1 +) + +func (gt SuperCloudIssuanceAddGroupWelcomeMessageState) String() string { + switch gt { + case SuperCloudIssuanceAddGroupWelcomeMessageStateForNormal: + return "正常" + case SuperCloudIssuanceAddGroupWelcomeMessageStateForSuspend: + return "暂停" + default: + return "未知" + } +} diff --git a/super_cloud_issuance/enum/enum_super_cloud_issuance_keyword_reply_with_activate_group.go b/super_cloud_issuance/enum/enum_super_cloud_issuance_keyword_reply_with_activate_group.go new file mode 100644 index 0000000..fcc2788 --- /dev/null +++ b/super_cloud_issuance/enum/enum_super_cloud_issuance_keyword_reply_with_activate_group.go @@ -0,0 +1,55 @@ +package enum + +type SuperCloudIssuanceKeywordReplyWithActivateGroupState int + +const ( + SuperCloudIssuanceKeywordReplyWithActivateGroupStateForNormal = 1 + SuperCloudIssuanceKeywordReplyWithActivateGroupStateForSuspend = 0 +) + +func (gt SuperCloudIssuanceKeywordReplyWithActivateGroupState) String() string { + switch gt { + case SuperCloudIssuanceKeywordReplyWithActivateGroupStateForNormal: + return "正常" + case SuperCloudIssuanceKeywordReplyWithActivateGroupStateForSuspend: + return "暂停" + default: + return "未知" + } +} + +type SuperCloudIssuanceKeywordReplyWithActivateGroupIsFollowOfficial int + +const ( + SuperCloudIssuanceKeywordReplyWithActivateGroupIsFollowOfficialForYes = 1 + SuperCloudIssuanceKeywordReplyWithActivateGroupIsFollowOfficialForNo = 0 +) + +func (gt SuperCloudIssuanceKeywordReplyWithActivateGroupIsFollowOfficial) String() string { + switch gt { + case SuperCloudIssuanceKeywordReplyWithActivateGroupIsFollowOfficialForYes: + return "跟随官方" + case SuperCloudIssuanceKeywordReplyWithActivateGroupIsFollowOfficialForNo: + return "不跟随官方" + default: + return "未知" + } +} + +type SuperCloudIssuanceKeywordReplyWithActivateGroupListKind int + +const ( + SuperCloudIssuanceKeywordReplyWithActivateGroupListKindForWriting = 1 + SuperCloudIssuanceKeywordReplyWithActivateGroupListKindForPicture = 2 +) + +func (gt SuperCloudIssuanceKeywordReplyWithActivateGroupListKind) String() string { + switch gt { + case SuperCloudIssuanceKeywordReplyWithActivateGroupListKindForWriting: + return "文字" + case SuperCloudIssuanceKeywordReplyWithActivateGroupListKindForPicture: + return "图片" + default: + return "未知" + } +} diff --git a/super_cloud_issuance/enum/enum_super_cloud_issuance_user_group_manage.go b/super_cloud_issuance/enum/enum_super_cloud_issuance_user_group_manage.go new file mode 100644 index 0000000..2094f9a --- /dev/null +++ b/super_cloud_issuance/enum/enum_super_cloud_issuance_user_group_manage.go @@ -0,0 +1,109 @@ +package enum + +type SuperCloudIssuanceUserGroupManageIsOpenOut int + +const ( + SuperCloudIssuanceUserGroupManageIsOpenOutForNo SuperCloudIssuanceUserGroupManageIsOpenOut = iota + SuperCloudIssuanceUserGroupManageIsOpenOutForYes +) + +func (gt SuperCloudIssuanceUserGroupManageIsOpenOut) String() string { + switch gt { + case SuperCloudIssuanceUserGroupManageIsOpenOutForNo: + return "关闭" + case SuperCloudIssuanceUserGroupManageIsOpenOutForYes: + return "开启" + default: + return "未知" + } +} + +type SuperCloudIssuanceUserGroupManageOutSendFile int + +const ( + SuperCloudIssuanceUserGroupManageOutSendFileForNo SuperCloudIssuanceUserGroupManageOutSendFile = iota + SuperCloudIssuanceUserGroupManageOutSendFileForYes +) + +func (gt SuperCloudIssuanceUserGroupManageOutSendFile) String() string { + switch gt { + case SuperCloudIssuanceUserGroupManageOutSendFileForNo: + return "踢发文件-关闭" + case SuperCloudIssuanceUserGroupManageOutSendFileForYes: + return "踢发文件-开启" + default: + return "未知" + } +} + +type SuperCloudIssuanceUserGroupManageOutSendCard int + +const ( + SuperCloudIssuanceUserGroupManageOutSendCardForNo SuperCloudIssuanceUserGroupManageOutSendCard = iota + SuperCloudIssuanceUserGroupManageOutSendCardForYes +) + +func (gt SuperCloudIssuanceUserGroupManageOutSendCard) String() string { + switch gt { + case SuperCloudIssuanceUserGroupManageOutSendCardForNo: + return "踢发名片-关闭" + case SuperCloudIssuanceUserGroupManageOutSendCardForYes: + return "踢发名片-开启" + default: + return "未知" + } +} + +type SuperCloudIssuanceUserGroupManageOutSendLink int + +const ( + SuperCloudIssuanceUserGroupManageOutSendLinkForNo SuperCloudIssuanceUserGroupManageOutSendLink = iota + SuperCloudIssuanceUserGroupManageOutSendLinkForYes +) + +func (gt SuperCloudIssuanceUserGroupManageOutSendLink) String() string { + switch gt { + case SuperCloudIssuanceUserGroupManageOutSendLinkForNo: + return "踢发链接-关闭" + case SuperCloudIssuanceUserGroupManageOutSendLinkForYes: + return "踢发链接-开启" + default: + return "未知" + } +} + +type SuperCloudIssuanceUserGroupManageOutSendApplet int + +const ( + SuperCloudIssuanceUserGroupManageOutSendAppletForNo SuperCloudIssuanceUserGroupManageOutSendApplet = iota + SuperCloudIssuanceUserGroupManageOutSendAppletForYes +) + +func (gt SuperCloudIssuanceUserGroupManageOutSendApplet) String() string { + switch gt { + case SuperCloudIssuanceUserGroupManageOutSendAppletForNo: + return "踢发小程序-关闭" + case SuperCloudIssuanceUserGroupManageOutSendAppletForYes: + return "踢发小程序-开启" + default: + return "未知" + } +} + +type SuperCloudIssuanceUserGroupManageOutAutoAddBlackList int + +const ( + SuperCloudIssuanceUserGroupManageOutAutoAddBlackListForNo SuperCloudIssuanceUserGroupManageOutAutoAddBlackList = iota + SuperCloudIssuanceUserGroupManageOutAutoAddBlackListForYes +) + +func (gt SuperCloudIssuanceUserGroupManageOutAutoAddBlackList) String() string { + switch gt { + case SuperCloudIssuanceUserGroupManageOutAutoAddBlackListForNo: + return "踢人时自动加入黑名单-关闭" + case SuperCloudIssuanceUserGroupManageOutAutoAddBlackListForYes: + return "踢人时自动加入黑名单-开启" + default: + return "未知" + } +} diff --git a/super_cloud_issuance/enum/enum_super_cloud_issuance_user_robot_kind.go b/super_cloud_issuance/enum/enum_super_cloud_issuance_user_robot_kind.go new file mode 100644 index 0000000..2b5bd43 --- /dev/null +++ b/super_cloud_issuance/enum/enum_super_cloud_issuance_user_robot_kind.go @@ -0,0 +1,19 @@ +package enum + +type CloudIssuanceUserRobotKind int + +const ( + ExclusiveRobot = 1 + ShareRobot = 2 +) + +func (gt CloudIssuanceUserRobotKind) String() string { + switch gt { + case ExclusiveRobot: + return "独享机器人" + case ShareRobot: + return "共享机器人" + default: + return "未知" + } +} diff --git a/super_cloud_issuance/enum/enum_super_cloud_issuance_user_robot_type.go b/super_cloud_issuance/enum/enum_super_cloud_issuance_user_robot_type.go new file mode 100644 index 0000000..565079a --- /dev/null +++ b/super_cloud_issuance/enum/enum_super_cloud_issuance_user_robot_type.go @@ -0,0 +1,31 @@ +package enum + +type CloudIssuanceUserRobotType int + +const ( + IssuingRobot = 1 + ForwardRobot = 2 + RebateRobot = 3 + AllAroundRobot = 4 + SmallRobot = 5 + SendToMomentsRobot = 6 +) + +func (gt CloudIssuanceUserRobotType) String() string { + switch gt { + case IssuingRobot: + return "发单机器人" + case ForwardRobot: + return "转发机器人" + case RebateRobot: + return "返利机器人" + case AllAroundRobot: + return "全能机器人" + case SmallRobot: + return "小型机器人" + case SendToMomentsRobot: + return "发圈机器人" + default: + return "未知" + } +} diff --git a/super_cloud_issuance/enum/enum_super_cloud_issuance_user_robot_with_activate_group.go b/super_cloud_issuance/enum/enum_super_cloud_issuance_user_robot_with_activate_group.go new file mode 100644 index 0000000..fd3be1f --- /dev/null +++ b/super_cloud_issuance/enum/enum_super_cloud_issuance_user_robot_with_activate_group.go @@ -0,0 +1,19 @@ +package enum + +type SuperCloudIssuanceUserRobotWithActivateGroupState int + +const ( + SuperCloudIssuanceUserRobotWithActivateGroupStateForNormal = 1 + SuperCloudIssuanceUserRobotWithActivateGroupStateForSuspend = 2 +) + +func (gt SuperCloudIssuanceUserRobotWithActivateGroupState) String() string { + switch gt { + case SuperCloudIssuanceUserRobotWithActivateGroupStateForNormal: + return "正常" + case SuperCloudIssuanceUserRobotWithActivateGroupStateForSuspend: + return "暂停" + default: + return "未知" + } +} diff --git a/super_cloud_issuance/lib/auth/base.go b/super_cloud_issuance/lib/auth/base.go new file mode 100644 index 0000000..dfdc165 --- /dev/null +++ b/super_cloud_issuance/lib/auth/base.go @@ -0,0 +1,23 @@ +package auth + +import ( + "time" + + "github.com/dgrijalva/jwt-go" +) + +// TokenExpireDuration is jwt 过期时间 +const TokenExpireDuration = time.Hour * 4380 + +var Secret = []byte("zyos") + +// JWTUser 如果想要保存更多信息,都可以添加到这个结构体中 +type JWTUser struct { + UID int `json:"uid"` + Username string `json:"username"` + Phone string `json:"phone"` + AppName string `json:"app_name"` + MiniOpenID string `json:"mini_open_id"` // 小程序的open_id + MiniSK string `json:"mini_session_key"` // 小程序的session_key + jwt.StandardClaims +} diff --git a/super_cloud_issuance/lib/baidu/shorten_url.go b/super_cloud_issuance/lib/baidu/shorten_url.go new file mode 100644 index 0000000..b405ce6 --- /dev/null +++ b/super_cloud_issuance/lib/baidu/shorten_url.go @@ -0,0 +1,40 @@ +package baidu + +import ( + "applet/app/utils" + "applet/app/utils/logx" + "encoding/json" +) + +var DWZ_TOKEN = "eecdf4b18f416b0cf26fef98f7e1f4ff" + +func ShortenUrl(url string) (string, error) { + host := "https://dwz.cn/admin/v2/create" + args := map[string]string{ + "Url": url, + "TermOfValidity": "1-year", + } + + resp, err := utils.CurlPost(host, utils.Serialize(args), map[string]string{ + "Content-Type": "application/json", + "Token": DWZ_TOKEN, + }) + // {"Code":0,"IsNew":true,"ShortUrl":"https://dwz.cn/4kSgiKVl","LongUrl":"https://open.taobao.com/search.htm?q=taobao.tbk.sc.material","ErrMsg":""} + if err != nil { + return "", logx.Warn(err) + } + var tmp struct { + Code int `json:"Code"` + IsNew bool `json:"IsNew"` + ShortURL string `json:"ShortUrl"` + LongURL string `json:"LongUrl"` + ErrMsg string `json:"ErrMsg"` + } + if err = json.Unmarshal(resp, &tmp); err != nil { + return url, logx.Warn("resp: " + string(resp) + ", err:" + err.Error()) + } + if tmp.ShortURL == "" { + tmp.ShortURL = url + } + return tmp.ShortURL, nil +} diff --git a/super_cloud_issuance/lib/qiniu/bucket_create.go b/super_cloud_issuance/lib/qiniu/bucket_create.go new file mode 100644 index 0000000..28d8106 --- /dev/null +++ b/super_cloud_issuance/lib/qiniu/bucket_create.go @@ -0,0 +1,16 @@ +package qiniu + +import ( + "github.com/qiniu/api.v7/v7/auth" + "github.com/qiniu/api.v7/v7/storage" +) + +func BucketCreate() error { + mac := auth.New(AK, SK) + cfg := storage.Config{ + // 是否使用https域名进行资源管理 + UseHTTPS: false, + } + bucketManager := storage.NewBucketManager(mac, &cfg) + return bucketManager.CreateBucket("", storage.RIDHuanan) +} diff --git a/super_cloud_issuance/lib/qiniu/bucket_delete.go b/super_cloud_issuance/lib/qiniu/bucket_delete.go new file mode 100644 index 0000000..6d41521 --- /dev/null +++ b/super_cloud_issuance/lib/qiniu/bucket_delete.go @@ -0,0 +1,18 @@ +package qiniu + +import ( + "github.com/qiniu/api.v7/v7/auth" + "github.com/qiniu/api.v7/v7/storage" +) + +func BucketDelete(bucketName string) error { + mac := auth.New(AK, SK) + + cfg := storage.Config{ + // 是否使用https域名进行资源管理 + UseHTTPS: false, + } + + bucketManager := storage.NewBucketManager(mac, &cfg) + return bucketManager.DropBucket(bucketName) +} diff --git a/super_cloud_issuance/lib/qiniu/bucket_get_domain.go b/super_cloud_issuance/lib/qiniu/bucket_get_domain.go new file mode 100644 index 0000000..f4cee3a --- /dev/null +++ b/super_cloud_issuance/lib/qiniu/bucket_get_domain.go @@ -0,0 +1,18 @@ +package qiniu + +import ( + "github.com/qiniu/api.v7/v7/auth" + "github.com/qiniu/api.v7/v7/storage" +) + +func BucketGetDomain(bucketName string) (string, error) { + mac := auth.New(AK, SK) + + cfg := storage.Config{UseHTTPS: false} + bucketManager := storage.NewBucketManager(mac, &cfg) + b, err := bucketManager.ListBucketDomains(bucketName) + if err != nil { + return "", err + } + return b[0].Domain, nil +} diff --git a/super_cloud_issuance/lib/qiniu/init.go b/super_cloud_issuance/lib/qiniu/init.go new file mode 100644 index 0000000..1d4346a --- /dev/null +++ b/super_cloud_issuance/lib/qiniu/init.go @@ -0,0 +1,22 @@ +package qiniu + +import ( + "applet/app/utils" +) + +var ( + AK = "MmxNdai23egjNUHjdzEVaTPdPCIbWzENz9BQuak3" + SK = "mElaFlM9O16rXp-ihoQdJ9KOH56naKm3MoyQBA59" + BUCKET = "dev-fnuoos" // 桶子名称 + BUCKET_SCHEME = "http" + BUCKET_REGION = "up-z2.qiniup.com" + Expires uint64 = 3600 +) + +func Init(ak, sk, bucket, region, scheme string) { + AK, SK, BUCKET, BUCKET_REGION, BUCKET_SCHEME = ak, sk, bucket, region, scheme +} + +func Sign(t string) string { + return utils.Md5(AK + SK + t) +} diff --git a/super_cloud_issuance/lib/qiniu/req_img_upload.go b/super_cloud_issuance/lib/qiniu/req_img_upload.go new file mode 100644 index 0000000..aad4d9d --- /dev/null +++ b/super_cloud_issuance/lib/qiniu/req_img_upload.go @@ -0,0 +1,54 @@ +package qiniu + +import ( + "applet/app/md" + "applet/app/utils" + "time" + + "github.com/qiniu/api.v7/v7/auth/qbox" + _ "github.com/qiniu/api.v7/v7/conf" + "github.com/qiniu/api.v7/v7/storage" +) + +// 请求图片上传地址信息 +func ReqImgUpload(f *md.FileCallback, callbackUrl string) interface{} { + if ext := utils.FileExt(f.FileName); ext == "png" || ext == "jpg" || ext == "jpeg" || ext == "gif" || ext == "bmp" || ext == "webp" { + f.Width = "$(imageInfo.width)" + f.Height = "$(imageInfo.height)" + } + f.Provider = "qiniu" + f.FileSize = "$(fsize)" + f.Hash = "$(etag)" + f.Bucket = "$(bucket)" + f.Mime = "$(mimeType)" + f.Time = utils.Int64ToStr(time.Now().Unix()) + f.Sign = Sign(f.Time) + putPolicy := storage.PutPolicy{ + Scope: BUCKET + ":" + f.FileName, // 使用覆盖方式时候必须请求里面有key,否则报错 + Expires: Expires, + ForceSaveKey: true, + SaveKey: f.FileName, + MimeLimit: "image/*", // 只允许上传图片 + CallbackURL: callbackUrl, + CallbackBody: utils.SerializeStr(f), + CallbackBodyType: "application/json", + } + return &struct { + Method string `json:"method"` + Key string `json:"key"` + Host string `json:"host"` + Token string `json:"token"` + }{Key: f.FileName, Method: "POST", Host: BUCKET_SCHEME + "://" + BUCKET_REGION, Token: putPolicy.UploadToken(qbox.NewMac(AK, SK))} +} + +/* +form表单上传 +地址 : http://upload-z2.qiniup.com +header + - Content-Type : multipart/form-data + +body : + - key : 文件名 + - token : 生成token + - file : 待上传文件 +*/ diff --git a/super_cloud_issuance/lib/zhimeng/api.go b/super_cloud_issuance/lib/zhimeng/api.go new file mode 100644 index 0000000..b797a56 --- /dev/null +++ b/super_cloud_issuance/lib/zhimeng/api.go @@ -0,0 +1,66 @@ +package zhimeng + +import ( + "applet/app/utils" + "fmt" + "sort" + "strconv" + "time" +) + +var StatusSuc int = 1 + +type ZM struct { + AK string + SK string + SMS_AK string + SMS_SK string +} + +// 智盟接口, 可以调取京东, 拼多多等 +const ZM_HOST = "http://www.izhim.com/" + +var ( + ZM_BASE_URL = ZM_HOST + "?mod=api&act=%s&ctrl=%s" + APP_KEY = "300000001" + SECRET_KEY = "95c347002b2750dbd4b6a03bd4196c18" + SMS_APP_KEY = "300000175" + SMS_SECRET_KEY = "6cf1dcd1820a576ff2cbecbe00d31df2" +) + +func Send(act, op string, args map[string]interface{}) ([]byte, error) { + router := fmt.Sprintf(ZM_BASE_URL, act, op) + // args["appkey"] = APP_KEY + args["time"] = strconv.Itoa(int(time.Now().Unix())) + args["sign"] = sign(args, args["secret_key"].(string)) + // b, _ := json.Marshal(args) + // fmt.Println(string(b)) + return utils.CurlPost(router, args, nil) +} + +// SMSend is 发送短信用的key 和签名 +func SMSend(act, op, key, secret string, args map[string]interface{}) ([]byte, error) { + router := fmt.Sprintf(ZM_BASE_URL, act, op) + + args["appkey"] = key + args["time"] = strconv.Itoa(int(time.Now().Unix())) + args["sign"] = sign(args, secret) + + return utils.CurlPost(router, args, nil) +} + +func sign(m map[string]interface{}, SK string) string { + // key sort + keys := make([]string, 0, len(m)) + for k := range m { + keys = append(keys, k) + } + sort.Strings(keys) + str := "" + for _, k := range keys { + str += k + utils.AnyToString(m[k]) + } + // merge string + str = SK + str + SK + "方诺科技" + return utils.Md5(str) +} diff --git a/super_cloud_issuance/lib/zhimeng/sdk.go b/super_cloud_issuance/lib/zhimeng/sdk.go new file mode 100644 index 0000000..09de264 --- /dev/null +++ b/super_cloud_issuance/lib/zhimeng/sdk.go @@ -0,0 +1,162 @@ +package zhimeng + +import ( + "applet/app/utils/logx" + "encoding/json" + "errors" + "fmt" + "strings" + + "github.com/shopspring/decimal" + "github.com/tidwall/gjson" +) + +// SDK is zhimeng sdk +type SDK struct { + Action string + operation string + response []byte + SmsKey string + SmsSecret string + data interface{} + err error +} + +// Init is init action +// In some condition, such as send Sms, need pass sms key and secret after 'action' +func (sdk *SDK) Init(action string, keys ...string) { + sdk.Action = action + //if keys[0] == "" || keys[1] == "" { + // sdk.err = errors.New("智盟短信未配置") + //} + if len(keys) > 1 { + sdk.SmsKey = keys[0] + sdk.SmsSecret = keys[1] + } + +} + +// SelectFunction is select api with operation +func (sdk *SDK) SelectFunction(operation string) *SDK { + sdk.operation = operation + return sdk +} + +// WithSMSArgs is SMS +func (sdk *SDK) WithSMSArgs(args map[string]interface{}) *SDK { + res, err := SMSend(sdk.Action, sdk.operation, sdk.SmsKey, sdk.SmsSecret, args) + if err != nil { + logx.Error(err) + } + sdk.response = res + return sdk +} + +// WithArgs is post data to api +func (sdk *SDK) WithArgs(args map[string]interface{}) *SDK { + // args["appkey"] = svc.SysCfgGet(c, md.KEY_CFG_ZM_AK) + // args["secret_key"] = svc.SysCfgGet(c, md.KEY_CFG_ZM_SK) + + res, err := Send(sdk.Action, sdk.operation, args) + if err != nil { + logx.Error(err) + } + // for k, v := range args { + // fmt.Printf("%s:%v \n", k, v) + // } + // fmt.Println(string(res)) + sdk.response = res + return sdk +} + +// Result is response data from api , return interface{} +func (sdk *SDK) Result() (*SDK, error) { + if sdk.err != nil { + return nil, sdk.err + } + tmp := struct { + Msg string `json:"msg"` + Success int `json:"success"` + Data interface{} `json:"data"` + }{} + if err := json.Unmarshal(sdk.response, &tmp); err != nil { + return nil, logx.Error("【Resp】" + string(sdk.response) + ", 【Error】" + err.Error()) + } + if tmp.Success != StatusSuc { + return nil, logx.Error(string(sdk.response)) + } + + if gjson.GetBytes(sdk.response, "data").String() == "[]" { + return nil, errors.New("no result") + } + + sdk.data = tmp.Data + return sdk, nil +} + +// ToObject is the interface is Slice and get the first item +func (sdk *SDK) ToObject() *SDK { + s, ok := sdk.ToInterface().([]interface{}) + if !ok { + logx.Errorf("\nToOject cantnot convert to []interface{}, 【Data】: %#v\n", sdk.data) + return sdk + } + sdk.data = s[len(s)-len(s)] + return sdk +} + +// ToInterface is data to Interface +func (sdk *SDK) ToInterface() interface{} { + return sdk.data +} + +// ToMapStringInterface is data to map[string]string +func (sdk *SDK) ToMapStringInterface(item interface{}) map[string]interface{} { + data, err := json.Marshal(item) + if err != nil { + logx.Error("ToMapStringString marshal error : " + err.Error()) + + } + m := make(map[string]interface{}) + if err = json.Unmarshal(data, &m); err != nil { + logx.Error("ToMapStringString unmarshal error : " + err.Error()) + + } + for key, v := range m { + switch v.(type) { + case int: + t, ok := v.(string) + if !ok { + logx.Warn("int convert error") + } + m[key] = t + case int32: + t, ok := v.(string) + if !ok { + logx.Warn("int32 convert error") + } + m[key] = t + case int64: + t, ok := v.(string) + if !ok { + logx.Warn("int64 convert error") + } + m[key] = t + case float64: + vstr := fmt.Sprintf("%v", v) + if strings.Contains(vstr, "e+") { + decimalNum, err := decimal.NewFromString(vstr) + if err != nil { + panic(logx.Errorf("decimal.NewFromString error, vstr:%s, err:%v", vstr, err)) + } + vstr = decimalNum.String() + } + m[key] = vstr + case nil: + m[key] = v + default: + m[key] = v + } + } + return m +} diff --git a/super_cloud_issuance/md/alipay.go b/super_cloud_issuance/md/alipay.go new file mode 100644 index 0000000..9916e75 --- /dev/null +++ b/super_cloud_issuance/md/alipay.go @@ -0,0 +1,64 @@ +package md + +// AliPayCallback 支付宝的回调结构体 +type AliPayCallback struct { + AppID string `json:"app_id"` + AuthAppID string `json:"auth_app_id"` + BuyerID string `json:"buyer_id"` + BuyerLogonID string `json:"buyer_logon_id"` + BuyerPayAmount string `json:"buyer_pay_amount"` + Charset string `json:"charset"` + FundBillList string `json:"fund_bill_list"` + GmtCreate string `json:"gmt_create"` + GmtPayment string `json:"gmt_payment"` + InvoiceAmount string `json:"invoice_amount"` + OrderType string `json:"order_type"` + MasterID string `json:"master_id"` + NotifyID string `json:"notify_id"` + NotifyTime string `json:"notify_time"` + NotifyType string `json:"notify_type"` + OutTradeNo string `json:"out_trade_no"` + PassbackParams string `json:"passback_params"` + PointAmount string `json:"point_amount"` + ReceiptAmount string `json:"receipt_amount"` + SellerEmail string `json:"seller_email"` + SellerID string `json:"seller_id"` + Sign string `json:"sign"` + SignType string `json:"sign_type"` + Subject string `json:"subject"` + TotalAmount string `json:"total_amount"` + TradeNo string `json:"trade_no"` + TradeStatus string `json:"trade_status"` + Version string `json:"version"` + PayMethod string `json:"pay_method"` +} + +type AliPayPayParams struct { + Subject string `json:"subject" binding:"required"` + Amount string `json:"amount" binding:"required"` + OrderType string `json:"order_type" binding:"required"` + OrdId string `json:"ord_id"` + Phone string `json:"phone"` +} +type PayData struct { + PayAppCertSn string `json:"pay_app_cert_sn"` + PayAlipayRootCertSn string `json:"pay_alipay_root_cert_sn"` + PayAlipayrsaPublicKey string `json:"pay_alipayrsa_public_key"` + PayAliUseType string `json:"pay_ali_use_type"` + PriKey string `json:"pay_ali_new_private_key"` +} +type UserCertifyParams struct { + RealName string `json:"real_name" ` + IdentityNum string `json:"identity_num" ` + OrdId string `json:"ord_id"` + CertifyId string `json:"certify_id"` + Uid string `json:"uid"` +} + +type UserCertifyRequest struct { + OrderId string `json:"order_id"` //支付订单 + RealName string `json:"real_name" ` + IdentityNum string `json:"identity_num" ` + CertifyId string `json:"certify_id"` + Uid string `json:"uid"` +} diff --git a/super_cloud_issuance/md/app_redis_key.go b/super_cloud_issuance/md/app_redis_key.go new file mode 100644 index 0000000..03f35ff --- /dev/null +++ b/super_cloud_issuance/md/app_redis_key.go @@ -0,0 +1,11 @@ +package md + +// 缓存key统一管理, %s格式化为masterId +const ( + AppCfgCacheKey = "%s:cfg_cache:%s" // 占位符: masterId, key的第一个字母 + VirtualCoinCfgCacheKey = "%s:virtual_coin_cfg" + + UserFinValidUpdateLock = "%s:user_fin_valid_update_lock:%s" // 用户余额更新锁(能拿到锁才能更新余额) + + CfgCacheTime = 86400 +) diff --git a/super_cloud_issuance/md/cfg_key.go b/super_cloud_issuance/md/cfg_key.go new file mode 100644 index 0000000..7d009cc --- /dev/null +++ b/super_cloud_issuance/md/cfg_key.go @@ -0,0 +1,19 @@ +package md + +// 获取用户的缓存key +const ( + KEY_SYS_CFG_CACHE = "sys_cfg_cache" + + // 文件缓存的key + KEY_CFG_FILE_PVD = "file_provider" // 文件供应商 + KEY_CFG_FILE_BUCKET = "file_bucket" + KEY_CFG_FILE_REGION = "file_bucket_region" + KEY_CFG_FILE_HOST = "file_bucket_host" + KEY_CFG_FILE_SCHEME = "file_bucket_scheme" + KEY_CFG_FILE_AK = "file_access_key" + KEY_CFG_FILE_SK = "file_secret_key" + KEY_CFG_FILE_MAX_SIZE = "file_user_upload_max_size" + KEY_CFG_FILE_EXT = "file_ext" + KEY_CFG_FILE_AVATAR_THUMBNAIL = "file_avatar_thumbnail" // 默认头像缩略图参数,宽高120px,格式webp. + +) diff --git a/super_cloud_issuance/md/file.go b/super_cloud_issuance/md/file.go new file mode 100644 index 0000000..db52eea --- /dev/null +++ b/super_cloud_issuance/md/file.go @@ -0,0 +1,54 @@ +package md + +// 用户拥有上传权限的目录, 目录ID + +const ( + FILE_DIR_FEEDBACK = "feedback" + FILE_DIR_AVATAR = "avatar" + FILE_DIR_QRCODE = "qrcode" + FILE_DIR_STYLE = "style" +) + +var ( + FileUserDir = map[string]string{ + FILE_DIR_FEEDBACK: "4", // 用户反馈 + FILE_DIR_AVATAR: "5", // 用户头像 + FILE_DIR_QRCODE: "6", // 用户微信二维码 + FILE_DIR_STYLE: "7", // 用户样式 + } +) + +// 文件回调信息 +type FileCallback struct { + Uid string `json:"uid"` + DirId string `json:"dir_id"` + Provider string `json:"provider"` // 供应商 + FileName string `json:"fname"` // 原文件名 + FileSize string `json:"fsize"` + Hash string `json:"hash"` + Bucket string `json:"bucket"` + Mime string `json:"mime"` + Width string `json:"w,omitempty"` + Height string `json:"h,omitempty"` + Time string `json:"time"` // 默认一个小时内要上传完毕,否则超时 + Sign string `json:"sign"` // 签名 +} + +type FileList struct { + Path string `json:"path"` + DirId int `json:"dir_id"` + FileName string `json:"f_name"` // 显示名称 + StgName string `json:"stg_name"` // 存储名字 + Ext string `json:"ext"` // 后缀名, png,jpg等 + FileSize string `json:"f_size"` + Provider string `json:"provider"` // 存储供应商 + Hash string `json:"hash"` + Bucket string `json:"bucket"` + Width int `json:"w"` + Height int `json:"h"` + Mime string `json:"mime"` + IsAdm bool `json:"is_adm"` //是否管理后台上传 + IsDir bool `json:"is_dir"` //是否文件夹 + CreateAt int `json:"create_at"` + Url string `json:"url"` +} diff --git a/super_cloud_issuance/md/md_api.go b/super_cloud_issuance/md/md_api.go new file mode 100644 index 0000000..409461d --- /dev/null +++ b/super_cloud_issuance/md/md_api.go @@ -0,0 +1,183 @@ +package md + +type CurlResponse struct { + Status string `json:"status"` + Data interface{} `json:"data"` + Msg string `json:"msg"` +} + +type CurlResponseForCircle struct { //朋友圈相关接口响应 + Code string `json:"code"` + Data interface{} `json:"data"` + Message string `json:"message"` +} + +type RobotCreateRequest struct { + Month int `json:"month"` //新增月份,默认1 + RobotType string `json:"robot_type"` //机器人类型 1 发单机器人 2转发机器人 3 返利机器人 4全能机器人 5小型机器人 6发圈机器人 + WechatRobot string `json:"wechatrobot"` //微信号 + Remark string `json:"remark"` //备注 +} +type RobotCreateResponse struct { + Id float64 `json:"id"` + Uid float64 `json:"uid"` + WechatRobot string `json:"wechatrobot"` + //NickName string `json:"nickname"` + LoginStatus float64 `json:"login_status"` + EndTime int64 `json:"end_time"` //到期时间 + Remark string `json:"remark"` + WcId string `json:"wc_id"` //微信实例id + IsEnabled float64 `json:"is_enabled"` //0 正常 1暂停 2已过期 +} + +type RobotQrcodeMacLoginRequest struct { + RobotId int `json:"robot_id"` //机器人id +} +type RobotQrcodeMacLoginResponse struct { + WId string `json:"wId"` //实例id + QrCodeUrl string `json:"qrCodeUrl"` +} + +type RobotAsyncMacLoginRequest struct { + WId string `json:"wId"` //实例id + RobotId int `json:"robot_id"` //机器人id +} +type RobotAsyncMacLoginResponse struct { + WId string `json:"wId"` //实例id + WcId string `json:"wcId"` //微信id + NickName string `json:"nickName"` //微信昵称 + HeadUrl string `json:"headUrl"` //微信头像 +} + +type RobotForceOfflineRequest struct { + RobotId int `json:"robot_id"` //机器人id +} + +type RobotSecondLoginRequest struct { + RobotId int `json:"robot_id"` //机器人id +} +type RobotSecondLoginResponse struct { + WId string `json:"wId"` //实例id + WcId string `json:"wcId"` //微信id + NickName string `json:"nickName"` //微信昵称 + HeadUrl string `json:"headUrl"` //微信头像 +} + +type RobotChangeRequest struct { + RobotId int `json:"robot_id"` //机器人id + Month int `json:"month"` //续费月数 + //WechatRobot int `json:"wechatrobot"` //微信号 更换号的时候传 (TODO::暂时用不到) +} +type RobotChangeResponse struct { + Uid float64 `json:"uid"` + WechatRobot string `json:"wechatrobot"` + LoginStatus float64 `json:"login_status"` + EndTime int64 `json:"end_time"` //到期时间 + Remark string `json:"remark"` + WcId string `json:"wc_id"` //微信实例id + IsEnabled float64 `json:"is_enabled"` //0 正常 1暂停 2已过期 +} + +type RobotResetRequest struct { + RobotId int `json:"robot_id"` //机器人id +} + +type RobotRoomListRequest struct { + RobotId int `json:"robot_id"` //机器人id + //RoomContactSeq int `json:"room_contact_seq"` // 首次传0, 后面接口返回, 不传默认全部 + //WxContactSeq int `json:"wx_contact_seq"` // 首次传0, 后面接口返回, 不传默认全部 +} +type RobotRoomListResponse []string + +type RobotRoomDetailRequest struct { + RobotId int `json:"robot_id"` //机器人id + RoomId string `json:"room_id"` // 群的id ,多个用逗号隔开 +} +type RobotRoomDetailResponse struct { + ChatRoomId string `json:"chatRoomId"` + NickName string `json:"nickName"` + ChatRoomOwner string `json:"chatRoomOwner"` + BigHeadImgUrl string `json:"bigHeadImgUrl"` + SmallHeadImgUrl string `json:"smallHeadImgUrl"` + V1 string `json:"v1"` + MemberCount string `json:"memberCount"` + ChatRoomMembers []ChatRoomMember `json:"chatRoomMembers"` +} +type ChatRoomMember struct { + UserName string `json:"userName"` + NikeName string `json:"nikeName"` + InviterUserName string `json:"inviterUserName"` +} + +type RobotMacSendCardRequest struct { + RobotId int `json:"robot_id"` //机器人id + WxId string `json:"wx_id"` //发送微信好友/群id。一般wxid_开头 + Title string `json:"title"` //标题 + Url string `json:"url"` //链接 + Description string `json:"description"` //描述 + ThumbUrl string `json:"thumbUrl"` //图片 +} + +type RobotMacSendUriRequest struct { + RobotId int `json:"robot_id"` //机器人id + WxId string `json:"toWxId"` //发送微信好友/群id。一般wxid_开头 + PicUrl string `json:"pic_url"` //图片地址 +} + +type RobotMacSendTextRequest struct { + RobotId int `json:"robot_id"` //机器人id + WxId string `json:"toWxId"` //发送微信好友/群id。一般wxid_开头 + Content string `json:"content"` //内容 +} + +type RobotMacSendRecvImageRequest struct { + RobotId int `json:"robot_id"` //机器人id + WxId string `json:"wx_id"` //发送微信好友/群id。一般wxid_开头 + Content string `json:"content"` //消息xml内容 +} + +type RobotMacSendRecvVideoRequest struct { + RobotId int `json:"robot_id"` //机器人id + WxId string `json:"wx_id"` //发送微信好友/群id。一般wxid_开头 + Content string `json:"content"` //消息xml内容 +} + +type RobotMacSendCircleRequest struct { + RobotId int `json:"robot_id"` //机器人id + PicUrl string `json:"pic_url"` //图片url,多个请用;分隔 + Content string `json:"content"` //文案 +} + +type GetUserInfoResponse struct { + User interface{} `json:"user"` + State int `json:"state"` //状态(0:未开通 1:未绑定 2:未登录 3:已登录) + EndTime string `json:"end_time"` //到期时间 + OpenTime string `json:"open_time"` //开通时间 + BalanceDay int `json:"balance_day"` //剩余天数 + WcNickname string `json:"wc_nickname"` //微信昵称 + WcHeadUrl string `json:"wc_head_url"` //微信头像 + GroupNum int `json:"group_num"` //最大群数 + AlreadyBindGroupNum int `json:"already_bind_group_num"` //已绑定群数 +} + +type RobotMacGetChatRoomMemberRequest struct { + RobotId int `json:"robot_id"` //机器人id + RoomId string `json:"room_id"` // 群的id +} + +type RobotMacGetChatRoomMemberResponseV1 struct { + UserName string `json:"userName"` //微信号 + NickName string `json:"nickName"` //昵称 + DisplayName string `json:"displayName"` //群昵称 + BigHeadImgUrl string `json:"bigHeadImgUrl"` //头像 + SmallHeadImgUrl string `json:"smallHeadImgUrl"` //头像(缩略图) + InviteUser string `json:"inviteUser"` //邀请人微信号 +} +type RobotMacGetChatRoomMemberResponse struct { + UserName string `json:"user_name"` //微信号 + NickName string `json:"nick_name"` //昵称 + DisplayName string `json:"display_name"` //群昵称 + BigHeadImgUrl string `json:"big_head_img_url"` //头像 + SmallHeadImgUrl string `json:"small_head_img_url"` //头像(缩略图) + InviteUser string `json:"invite_user"` //邀请人微信号 +} diff --git a/super_cloud_issuance/md/md_call_back.go b/super_cloud_issuance/md/md_call_back.go new file mode 100644 index 0000000..02c635c --- /dev/null +++ b/super_cloud_issuance/md/md_call_back.go @@ -0,0 +1,18 @@ +package md + +type CallbackRequest struct { + Account string `json:"account"` //账号 + MessageType int `json:"messageType"` //消息类型(0:好友请求 1:群邀请 2: 群名片 3:个人名片 4:下线 5:私聊文本消息 6:私聊图片消息 7:聊视频消息 8:私聊语音消息 9:群聊文本消息 10:群聊图片消息 11:群聊视频消息 12:群语音消息 13:私其他类型消息 4:群聊其他类型消) + RobotId int `json:"robotId"` //机器人id + WcId string `json:"wcId"` //微信号 + Data struct { + Content string `json:"content"` //消息体 + FromGroup string `json:"fromGroup"` //发送群号 + FromUser string `json:"fromUser"` //发送微信号 + ToUser string `json:"toUser"` //接收微信号 + MsgId string `json:"msgId"` //消息id + MsgType string `json:"msgType"` //其他消息具体类型(47:表示动图 ) + IsGroup bool `json:"isGroup"` //是否为群组消息 + Timestamp string `json:"timestamp"` //时间 + } `json:"data"` +} diff --git a/super_cloud_issuance/md/mod.go b/super_cloud_issuance/md/mod.go new file mode 100644 index 0000000..85b7d38 --- /dev/null +++ b/super_cloud_issuance/md/mod.go @@ -0,0 +1,143 @@ +package md + +type MultiNav struct { + CateName string `json:"cate_name"` + CateTag string `json:"cate_tag"` + Data CommModData `json:"data"` + ID string `json:"id"` + Img string `json:"img"` + ImgURL string `json:"img_url"` + Index int64 `json:"index"` + IsEnd string `json:"is_end"` + IsJump string `json:"is_jump"` + Name string `json:"name"` + RequiredLogin string `json:"required_login"` + RequiredTaobaoAuth string `json:"required_taobao_auth"` + RightIcon string `json:"right_icon"` + RightIconURL string `json:"right_icon_url"` + SkipIdentifier string `json:"skip_identifier"` + SkipName string `json:"skip_name"` + SubTitle string `json:"sub_title"` + Title string `json:"title"` + TypeListKey string `json:"type_list_key"` + URL string `json:"url"` +} + +// 公共data数据 +type CommModData struct { + AdvInfo string `json:"adv_info"` + AlipayUrl string `json:"alipay_url"` + AlipayAppid string `json:"alipay_appid"` + AdvType string `json:"adv_type"` + IsCanBuy string `json:"is_can_buy"` + IsShowCouponList string `json:"is_show_coupon_list"` + UserCouponAmount string `json:"user_coupon_amount"` + Coupon string `json:"coupon"` + Url string `json:"url"` + AppId string `json:"app_id"` + ActivityId string `json:"activity_id"` + Id string `json:"id"` + AdName string `json:"ad_name"` + AndroidAdID string `json:"android_ad_id"` + AndroidMediaID string `json:"android_media_id"` + AutoClickAd string `json:"auto_click_ad"` + Autoplay string `json:"autoplay"` + BrandID string `json:"brand_id"` + Conditions string `json:"conditions"` + CreateAt string `json:"create_at"` + EndTime string `json:"end_time"` + Img string `json:"img"` + IosAdID string `json:"ios_ad_id"` + IosMediaID string `json:"ios_media_id"` + IsRecommend interface{} `json:"is_recommend"` + LevelLimitID string `json:"level_limit_id"` + LevelLimitName string `json:"level_limit_name"` + LevelWeight string `json:"level_weight"` + NeedLocation int64 `json:"need_location"` + SdkType string `json:"sdk_type"` + Type string `json:"type"` + SourceType string `json:"source_type"` + StartTime string `json:"start_time"` + UpdateAt string `json:"update_at"` + VisitCount string `json:"visit_count"` + CountingDown string `json:"counting_down" ` + FunctionSkipType string `json:"function_skip_type"` + OpenType string `json:"open_type" ` //app 应用内打开 browser 系统浏览器打开 + GoodsId string `json:"goods_id"` + GoodsType string `json:"goods_type"` + SecondAdvList AdvCommModData `json:"second_adv_list"` + ThirdAdvList AdvCommModData `json:"third_adv_list"` + LevelType string `json:"level_type"` + //IsShowConditionPop string `json:"is_show_condition_pop"` + //ShowConditionStr string `json:"show_condition_str"` + //ShowConditionSkip SkipData `json:"show_condition_skip"` +} + +// 公共data数据 +type AdvCommModData struct { + Id string `json:"id"` + AdName string `json:"ad_name"` + AndroidAdID string `json:"android_ad_id"` + AndroidMediaID string `json:"android_media_id"` + AutoClickAd string `json:"auto_click_ad"` + Autoplay string `json:"autoplay"` + IosAdID string `json:"ios_ad_id"` + IosMediaID string `json:"ios_media_id"` + SdkType string `json:"sdk_type"` + AdvType string `json:"adv_type"` +} +type ShowCondition struct { + IsShowConditionPop string `json:"is_show_condition_pop"` + ShowConditionStr string `json:"show_condition_str"` + ShowConditionSkip SkipData `json:"show_condition_skip"` +} +type NextCommModData struct { + Url string `json:"url"` + AppId string `json:"app_id"` + AlipayUrl string `json:"alipay_url"` + AlipayAppid string `json:"alipay_appid"` + ActivityId string `json:"activity_id"` + Id string `json:"id"` + AdName string `json:"ad_name"` + AndroidAdID string `json:"android_ad_id"` + AndroidMediaID string `json:"android_media_id"` + AutoClickAd string `json:"auto_click_ad"` + Autoplay string `json:"autoplay"` + BrandID string `json:"brand_id"` + Conditions string `json:"conditions"` + CreateAt string `json:"create_at"` + EndTime string `json:"end_time"` + Img string `json:"img"` + IosAdID string `json:"ios_ad_id"` + IosMediaID string `json:"ios_media_id"` + IsRecommend interface{} `json:"is_recommend"` + LevelLimitID string `json:"level_limit_id"` + LevelLimitName string `json:"level_limit_name"` + LevelWeight string `json:"level_weight"` + NeedLocation int64 `json:"need_location"` + SdkType string `json:"sdk_type"` + SourceType string `json:"source_type"` + StartTime string `json:"start_time"` + UpdateAt string `json:"update_at"` + VisitCount string `json:"visit_count"` + CountingDown string `json:"counting_down" ` + LevelType string `json:"level_type"` + OpenType string `json:"open_type" ` //app 应用内打开 browser 系统浏览器打开 +} +type SkipData struct { + SkipName string `json:"skip_name"` + SkipIdentifier string `json:"skip_identifier"` + RequiredLogin string `json:"required_login"` + RequiredTaobaoAuth string `json:"required_taobao_auth"` + IsJump string `json:"is_jump"` + Data NextCommModData `json:"data"` +} + +type NewSelectList struct { + Key string `json:"key"` + Name string `json:"name"` +} +type NewValList struct { + Val string `json:"val"` + Name string `json:"name"` +} diff --git a/super_cloud_issuance/md/mq.go b/super_cloud_issuance/md/mq.go new file mode 100644 index 0000000..86e32a8 --- /dev/null +++ b/super_cloud_issuance/md/mq.go @@ -0,0 +1,14 @@ +package md + +const RobotQrcodeMacLoginQueue = "super_cloud_issuance_async_mlogin" +const SuperCloudIssuanceMsgCallBackQueue = "super_cloud_issuance_msg_call_back" //超级云发单消息回调 + +type SuperCloudIssuanceAsyncMLogin struct { + UserId string `json:"user_id"` //用户id + MasterId string `json:"master_id"` //站长id + WId string `json:"wId"` //实例id + RobotId int `json:"robot_id"` //机器人id + QrCodeUrl string `json:"qrCodeUrl"` +} + +const SuperCloudIssuanceMsgCallBackExchange = "zhios.super.cloud.issuance.msg.callback.exchange" diff --git a/super_cloud_issuance/md/pay.go b/super_cloud_issuance/md/pay.go new file mode 100644 index 0000000..28336ba --- /dev/null +++ b/super_cloud_issuance/md/pay.go @@ -0,0 +1,49 @@ +package md + +const ( + BALANCE_PAY = "balance_pay" + ALIPAY = "alipay" + WX_PAY = "wxpay" + FB_PAY_ALI = "fb_pay_ali" + FB_PAY_WX = "fb_pay_wx" + FB_PAY_WX_SUB = "fb_pay_wx_sub" + SuperCloudIssuancePackage = "super_cloud_issuance_package" + ONE_CALLBACK_URL = "%s/api/v1/superCloudIssuance/pay/callback?master_id=%s&order_type=%s&pay_method=%s" +) + +var NeedPayPart = map[string]string{ + SuperCloudIssuancePackage: "云发单套餐", +} + +var PayMethodIDToName = map[int]string{ + 1: "余额支付", + 2: "支付宝支付", + 3: "微信支付", + 18: "乐刷支付宝支付", + 19: "乐刷微信支付", +} +var PayStateToName = map[int]string{ + 0: "未支付", + 1: "已支付", + 2: "支付失败", +} + +// PayMethodIDs 支付方式ID +var PayMethodIDs = map[string]int{ + BALANCE_PAY: 1, + ALIPAY: 2, + WX_PAY: 3, + FB_PAY_ALI: 18, + FB_PAY_WX: 19, + FB_PAY_WX_SUB: 19, +} + +type BuyPackageReq struct { + PackageId int `json:"package_id"` //套餐id +} + +type PayRechargeResp struct { + MainOrdId string + Total string + Uid string +} diff --git a/super_cloud_issuance/md/platform.go b/super_cloud_issuance/md/platform.go new file mode 100644 index 0000000..d71a113 --- /dev/null +++ b/super_cloud_issuance/md/platform.go @@ -0,0 +1,38 @@ +package md + +const ( + /*********** DEVICE ***********/ + PLATFORM_WX_APPLET = "wx_applet" // 小程序 + PLATFORM_TOUTIAO_APPLET = "toutiao_applet" + PLATFORM_TIKTOK_APPLET = "tiktok_applet" + PLATFORM_BAIDU_APPLET = "baidu_applet" + PLATFORM_ALIPAY_APPLET = "alipay_applet" + PLATFORM_WAP = "wap" //h5 + PLATFORM_ANDROID = "android" + PLATFORM_IOS = "ios" + PLATFORM_JSAPI = "jsapi" // 公众号 +) + +const WX_PAY_BROWSER = "wx_pay_browser" // 用于判断显示支付方式 + +var PlatformList = map[string]struct{}{ + PLATFORM_WX_APPLET: {}, + PLATFORM_TOUTIAO_APPLET: {}, + PLATFORM_TIKTOK_APPLET: {}, + PLATFORM_BAIDU_APPLET: {}, + PLATFORM_ALIPAY_APPLET: {}, + PLATFORM_WAP: {}, + PLATFORM_ANDROID: {}, + PLATFORM_IOS: {}, +} + +var PlatformMap = map[string]string{ + "android": "2", + "ios": "2", + "wap": "4", // 和小程序公用模板 + "wx_applet": "4", //微信小程序 + "tiktok_applet": "4", + "baidu_applet": "4", + "alipay_applet": "4", + "toutiao_applet": "4", +} diff --git a/super_cloud_issuance/md/split_db.go b/super_cloud_issuance/md/split_db.go new file mode 100644 index 0000000..f60d962 --- /dev/null +++ b/super_cloud_issuance/md/split_db.go @@ -0,0 +1,42 @@ +package md + +import ( + "regexp" + + "xorm.io/xorm" +) + +type DbInfo struct { + User string + Psw string + Name string + Host string +} + +func SplitDbInfo(eg *xorm.Engine) *DbInfo { + if eg == nil { + return &DbInfo{ + User: "nil", + Psw: "nil", + Host: "nil", + Name: "nil", + } + } + pattern := `(\w+):(.*)@tcp\(([\w\.\-\:\_]+)\)\/(\w+)` + reg := regexp.MustCompile(pattern).FindStringSubmatch(eg.DataSourceName()) + + if len(reg) < 5 { + return &DbInfo{ + User: "unknown", + Psw: "unknown", + Host: "unknown", + Name: "unknown", + } + } + return &DbInfo{ + User: reg[1], + Psw: reg[2], + Host: reg[3], + Name: reg[4], + } +} diff --git a/super_cloud_issuance/md/user_info.go b/super_cloud_issuance/md/user_info.go new file mode 100644 index 0000000..72103ea --- /dev/null +++ b/super_cloud_issuance/md/user_info.go @@ -0,0 +1,39 @@ +package md + +import ( + "applet/app/db/model" +) + +type UserInfoResponse struct { + Avatar string `json:"avatar"` + NickName string `json:"nickname"` + Gender string `json:"gender"` + Birthday string `json:"birthday"` + RegisterTime string `json:"register_time"` + FileBucketURL string `json:"file_bucket_url"` + FileFormat string `json:"file_format"` + IsNoChange string `json:"is_no_change"` + IsUpLoadWx string `json:"is_upload_wx"` +} + +type User struct { + Info *model.User + Profile *model.UserProfile + Level *model.UserLevel + Tags []string +} + +type UserRelation struct { + Uid int + CurUid int + Diff int // 与当前用户级别差 + Level int // 用户当前等级 + OldDiff int // 旧的级别 +} + +type UserTree struct { + Uid int `json:"uid"` + Nickname string `json:"nickname"` + Phone string `json:"phone"` + Children []*UserTree `json:"children"` +} diff --git a/super_cloud_issuance/md/wxpay.go b/super_cloud_issuance/md/wxpay.go new file mode 100644 index 0000000..88a9f8d --- /dev/null +++ b/super_cloud_issuance/md/wxpay.go @@ -0,0 +1,30 @@ +package md + +type WxPayParams struct { + Subject string `json:"subject" binding:"required"` + Amount string `json:"amount" binding:"required"` + OrderType string `json:"order_type" binding:"required"` + OrdId string `json:"ord_id"` +} + +type WxPayCallback struct { + AppId string `json:"appid"` + BankType string `json:"bank_type"` + CashFee string `json:"cash_fee"` + FeeType string `json:"fee_type"` + IsSubscribe string `json:"is_subscribe"` + MasterID string `json:"master_id"` + MchID string `json:"mch_id"` + NonceStr string `json:"nonce_str"` + Openid string `json:"openid"` + OrderType string `json:"order_type"` + OutTradeNo string `json:"out_trade_no"` + PayMethod string `json:"pay_method"` + ResultCode string `json:"result_code"` + ReturnCode string `json:"return_code"` + Sign string `json:"sign"` + TimeEnd string `json:"time_end"` + TotalFee string `json:"total_fee"` + TradeType string `json:"trade_type"` + TransactionID string `json:"transaction_id"` +} diff --git a/super_cloud_issuance/svc/copy_writing.go b/super_cloud_issuance/svc/copy_writing.go new file mode 100644 index 0000000..2168fbb --- /dev/null +++ b/super_cloud_issuance/svc/copy_writing.go @@ -0,0 +1,89 @@ +package svc + +import ( + "applet/app/utils" + "applet/super_cloud_issuance/lib/baidu" + "applet/super_cloud_issuance/lib/zhimeng" + "github.com/gin-gonic/gin" + "github.com/tidwall/gjson" + "math/rand" + "strings" +) + +func GetContent(c *gin.Context, content string, ProductCopy, ProductTitle, + ProductOriginalPrice, ProductCouponPrice, ProductCoupon, taokou, shorturl, goodsContent string) string { + inviteLink := InviteLinks(c) + user := GetUser(c) + content = strings.Replace(content, "{商品文案}", ProductCopy, 1) + content = strings.Replace(content, "{商品标题}", ProductTitle, 1) + content = strings.Replace(content, "{原价}", ProductOriginalPrice, 1) + content = strings.Replace(content, "{现价}", ProductCouponPrice, 1) + content = strings.Replace(content, "{优惠券}", ProductCoupon, 1) + content = strings.Replace(content, "{文案}", goodsContent, 1) + if user.Profile.CustomInviteCode != "" { + content = strings.Replace(content, "{邀请码}", user.Profile.CustomInviteCode, 1) + } else { + content = strings.Replace(content, "{邀请码}", user.Profile.InviteCode, 1) + } + content = strings.Replace(content, "{邀请注册链接}", inviteLink, 1) + content = strings.Replace(content, "{下载链接}", ImageFormat(c, SysCfgGet(c, "app_android_download_url")), 1) + content = strings.Replace(content, "{应用宝下载链接}", SysCfgGet(c, "app_treasure_url"), 1) + content = strings.Replace(content, "{口令}", taokou, 1) + content = strings.Replace(content, "{商品链接}", shorturl, 1) + + if taokou != "" { + content = utils.IntToStr(rand.Intn(9)) + content + } + return content +} + +func InviteLinks(c *gin.Context) string { + user := GetUser(c) + //downLoadRoute := "/#/zy-landing-page/pages/lading-page-download/lading-page-download?invited_code=" + registerRoute := "/#/zy-landing-page/pages/landing-page-login/landing-page-login?invited_code=" + h5Domain := GetWebSiteDomainInfo(c, "wap") + var inviteLink = "" + //if user.Profile.CustomInviteCode != "" { + // inviteLink = h5Domain + downLoadRoute + user.Profile.CustomInviteCode + //} else { + // inviteLink = h5Domain + downLoadRoute + user.Profile.InviteCode + //} + //urlType := gjson.Get(mdata, "url_type").String() + if user.Profile.CustomInviteCode != "" { + inviteLink = h5Domain + registerRoute + user.Profile.CustomInviteCode + } else { + inviteLink = h5Domain + registerRoute + user.Profile.InviteCode + } + //判断生成短链 + inviteLink = CommShareShorUrl(c, inviteLink) + return inviteLink +} + +// 公共处理链接转换短链 +func CommShareShorUrl(c *gin.Context, shareUrl string) string { + val := SysCfgFind(c, "share_link_type") + if val["share_link_type"] == "1" { //百度短链 + shareUrl, _ = baidu.ShortenUrl(shareUrl) + } else if val["share_link_type"] == "2" { //快站短链 + shareUrl = KuaiZhanShortURL(c, shareUrl) + } + return shareUrl +} + +// KuaiZhanShortURL is 快站短链 +func KuaiZhanShortURL(c *gin.Context, url string) string { + args := map[string]interface{}{ + "appkey": SysCfgGet(c, "third_zm_app_key"), + "secret_key": SysCfgGet(c, "third_zm_app_key"), + "url": utils.Base64StdEncode(url), + } + resp, err := zhimeng.Send("kuaizhan", "short_url", args) + if err != nil { + return "" + } + kurl := gjson.GetBytes(resp, "data.shortUrl").String() + if kurl == "" { + kurl = url + } + return kurl +} diff --git a/super_cloud_issuance/svc/svc_auth.go b/super_cloud_issuance/svc/svc_auth.go new file mode 100644 index 0000000..8897d46 --- /dev/null +++ b/super_cloud_issuance/svc/svc_auth.go @@ -0,0 +1,14 @@ +package svc + +import ( + "applet/super_cloud_issuance/md" + "github.com/gin-gonic/gin" +) + +func GetUser(c *gin.Context) *md.User { + user, _ := c.Get("user") + if user == nil { + return nil + } + return user.(*md.User) +} diff --git a/super_cloud_issuance/svc/svc_cloud_issuance.go b/super_cloud_issuance/svc/svc_cloud_issuance.go new file mode 100644 index 0000000..3c4a3e0 --- /dev/null +++ b/super_cloud_issuance/svc/svc_cloud_issuance.go @@ -0,0 +1,369 @@ +package svc + +import ( + "applet/app/cfg" + "applet/app/db" + "applet/cloud_issuance/enum" + "applet/mall/utils" + "applet/super_cloud_issuance/md" + "applet/super_cloud_issuance/tool/super_cloud_issuance" + "code.fnuoos.com/go_rely_warehouse/zyos_model.git/src/implement" + "encoding/json" + "github.com/gin-gonic/gin" + "strconv" + "strings" +) + +type CloudIssuanceService struct { + Context *gin.Context `json:"context"` + RequestMethodName string `json:"request_method_name"` + RequestClientIp string `json:"request_client_ip"` +} + +func (svcCloudIssuance *CloudIssuanceService) Set(c *gin.Context, methodName, clientIp string) { // set方法 + svcCloudIssuance.Context = c + svcCloudIssuance.RequestMethodName = methodName + svcCloudIssuance.RequestClientIp = clientIp +} + +func (svcCloudIssuance *CloudIssuanceService) RobotCreate(args md.RobotCreateRequest) (err error, result md.RobotCreateResponse) { // 添加机器人 + if !cfg.Prd { + //TODO::测试环境不用买 + return + } + url := super_cloud_issuance.HttpBuild(svcCloudIssuance.RequestMethodName, svcCloudIssuance.RequestClientIp, map[string]string{ + "month": strconv.Itoa(args.Month), + "robot_type": args.RobotType, + "wechatrobot": args.WechatRobot, + "remark": args.Remark, + }) + data, err := svcCloudIssuance.SendPost(url, args) + if err != nil { + return + } + resByte, err := json.Marshal(data.Data) + if err != nil { + return + } + err = json.Unmarshal(resByte, &result) + if err != nil { + return + } + + //result, ok := data.Data.(md.RobotCreateResponse) + //if !ok { + // err = errors.New("返回的结果 can not convert") + //} + return +} + +func (svcCloudIssuance *CloudIssuanceService) QrcodeMacLogin(args md.RobotQrcodeMacLoginRequest) (err error, result md.RobotQrcodeMacLoginResponse) { // 获取登录二维码 + url := super_cloud_issuance.HttpBuild(svcCloudIssuance.RequestMethodName, svcCloudIssuance.RequestClientIp, map[string]string{ + "robot_id": strconv.Itoa(args.RobotId), + }) + data, err := svcCloudIssuance.SendPost(url, args) + if err != nil { + return + } + resByte, err := json.Marshal(data.Data) + if err != nil { + return + } + err = json.Unmarshal(resByte, &result) + if err != nil { + return + } + return +} + +func (svcCloudIssuance *CloudIssuanceService) RobotAsyncMacLogin(args md.RobotAsyncMacLoginRequest) (err error, result md.RobotAsyncMacLoginResponse) { // 同步登录状态 + url := super_cloud_issuance.HttpBuild(svcCloudIssuance.RequestMethodName, svcCloudIssuance.RequestClientIp, map[string]string{ + "robot_id": strconv.Itoa(args.RobotId), + "wId": args.WId, + }) + data, err := svcCloudIssuance.SendPost(url, args) + if err != nil { + return + } + resByte, err := json.Marshal(data.Data) + if err != nil { + return + } + err = json.Unmarshal(resByte, &result) + if err != nil { + return + } + return +} + +func (svcCloudIssuance *CloudIssuanceService) RobotForceOffline(args md.RobotForceOfflineRequest) (err error) { // 下线机器人 + url := super_cloud_issuance.HttpBuild(svcCloudIssuance.RequestMethodName, svcCloudIssuance.RequestClientIp, map[string]string{ + "robot_id": strconv.Itoa(args.RobotId), + }) + _, err = svcCloudIssuance.SendPost(url, args) + return +} + +func (svcCloudIssuance *CloudIssuanceService) RobotSecondLogin(args md.RobotSecondLoginRequest) (err error, result md.RobotSecondLoginResponse) { // 二次登录 + url := super_cloud_issuance.HttpBuild(svcCloudIssuance.RequestMethodName, svcCloudIssuance.RequestClientIp, map[string]string{ + "robot_id": strconv.Itoa(args.RobotId), + }) + data, err := svcCloudIssuance.SendPost(url, args) + if err != nil { + return + } + resByte, err := json.Marshal(data.Data) + if err != nil { + return + } + err = json.Unmarshal(resByte, &result) + if err != nil { + return + } + return +} + +func (svcCloudIssuance *CloudIssuanceService) RobotChange(args md.RobotChangeRequest) (err error, result md.RobotChangeResponse) { // 机器人修改/续费 + if !cfg.Prd { + //TODO::测试环境不用买 + return + } + url := super_cloud_issuance.HttpBuild(svcCloudIssuance.RequestMethodName, svcCloudIssuance.RequestClientIp, map[string]string{ + "robot_id": strconv.Itoa(args.RobotId), + "month": strconv.Itoa(args.Month), + }) + data, err := svcCloudIssuance.SendPost(url, args) + if err != nil { + return + } + resByte, err := json.Marshal(data.Data) + if err != nil { + return + } + err = json.Unmarshal(resByte, &result) + if err != nil { + return + } + return +} + +func (svcCloudIssuance *CloudIssuanceService) RobotReset(args md.RobotResetRequest) (err error) { // 重置机器人 + url := super_cloud_issuance.HttpBuild(svcCloudIssuance.RequestMethodName, svcCloudIssuance.RequestClientIp, map[string]string{ + "robot_id": strconv.Itoa(args.RobotId), + }) + _, err = svcCloudIssuance.SendPost(url, args) + return +} + +func (svcCloudIssuance *CloudIssuanceService) RobotRoomListV1(args md.RobotRoomListRequest) (err error, result []md.RobotRoomDetailResponse) { // 群组列表 + url := super_cloud_issuance.HttpBuild(svcCloudIssuance.RequestMethodName, svcCloudIssuance.RequestClientIp, map[string]string{ + "robot_id": strconv.Itoa(args.RobotId), + }) + data, err := svcCloudIssuance.SendPost(url, args) + if err != nil { + return + } + utils.FilePutContents("RobotRoomListV1", utils.SerializeStr(map[string]interface{}{ + "args": args, + "resp": data, + })) + + return +} + +func (svcCloudIssuance *CloudIssuanceService) RobotRoomList(args md.RobotRoomListRequest) (err error, result []md.RobotRoomDetailResponse) { // 群组列表 + url := super_cloud_issuance.HttpBuild(svcCloudIssuance.RequestMethodName, svcCloudIssuance.RequestClientIp, map[string]string{ + "robot_id": strconv.Itoa(args.RobotId), + }) + data, err := svcCloudIssuance.SendPost(url, args) + if err != nil { + return + } + utils.FilePutContents("RobotRoomList", utils.SerializeStr(map[string]interface{}{ + "args": args, + "resp": data, + })) + resByte, err := json.Marshal(data.Data) + if err != nil { + return + } + var list = md.RobotRoomListResponse{} + err = json.Unmarshal(resByte, &list) + if err != nil { + return + } + + //TODO::每次最多5个 调用"群组详情"接口 + i := 0 + var tmpList = md.RobotRoomListResponse{} + var tmpResult []md.RobotRoomDetailResponse + for i < len(list) { + tmpList = append(tmpList, list[i]) + i++ + if len(tmpList) == 1 { + roomId := strings.Join(tmpList, ",") + requestUrl := super_cloud_issuance.HttpBuild(enum.RobotRoomDetailMethodName, svcCloudIssuance.RequestClientIp, map[string]string{ + "robot_id": strconv.Itoa(args.RobotId), + "room_id": roomId, + }) + data, err = svcCloudIssuance.SendPost(requestUrl, md.RobotRoomDetailRequest{ + RobotId: args.RobotId, + RoomId: roomId, + }) + resByte, err = json.Marshal(data.Data) + if err != nil { + return + } + err = json.Unmarshal(resByte, &tmpResult) + if err != nil { + return + } + result = append(result, tmpResult...) + tmpList = md.RobotRoomListResponse{} + } + } + + if len(tmpList) > 0 { + roomId := strings.Join(list, ",") + requestUrl := super_cloud_issuance.HttpBuild(enum.RobotRoomDetailMethodName, svcCloudIssuance.RequestClientIp, map[string]string{ + "robot_id": strconv.Itoa(args.RobotId), + "room_id": roomId, + }) + data, err = svcCloudIssuance.SendPost(requestUrl, md.RobotRoomDetailRequest{ + RobotId: args.RobotId, + RoomId: roomId, + }) + resByte, err = json.Marshal(data.Data) + if err != nil { + return + } + err = json.Unmarshal(resByte, &tmpResult) + if err != nil { + return + } + result = append(result, tmpResult...) + tmpList = md.RobotRoomListResponse{} + } + + return +} + +func (svcCloudIssuance *CloudIssuanceService) RobotMacGetChatRoomMember(args md.RobotMacGetChatRoomMemberRequest) (err error, result []md.RobotMacGetChatRoomMemberResponseV1) { // 获取群成员 + url := super_cloud_issuance.HttpBuild(svcCloudIssuance.RequestMethodName, svcCloudIssuance.RequestClientIp, map[string]string{ + "robot_id": strconv.Itoa(args.RobotId), + "room_id": args.RoomId, + }) + data, err := svcCloudIssuance.SendPost(url, args) + if err != nil { + return + } + resByte, err := json.Marshal(data.Data) + if err != nil { + return + } + err = json.Unmarshal(resByte, &result) + if err != nil { + return + } + return +} + +func (svcCloudIssuance *CloudIssuanceService) RobotMacSendCard(args md.RobotMacSendCardRequest) (err error) { // 发送链接消息 + url := super_cloud_issuance.HttpBuild(svcCloudIssuance.RequestMethodName, svcCloudIssuance.RequestClientIp, map[string]string{ + "robot_id": strconv.Itoa(args.RobotId), + "wx_id": args.WxId, + "title": args.Title, + "url": args.Url, + "description": args.Description, + "thumbUrl": args.ThumbUrl, + }) + _, err = svcCloudIssuance.SendPost(url, args) + return +} + +func (svcCloudIssuance *CloudIssuanceService) RobotMacSendUri(args md.RobotMacSendUriRequest) (err error) { // 发送uri图片消息 + url := super_cloud_issuance.HttpBuild(svcCloudIssuance.RequestMethodName, svcCloudIssuance.RequestClientIp, map[string]string{ + "robot_id": strconv.Itoa(args.RobotId), + "toWxId": args.WxId, + "pic_url": args.PicUrl, + }) + _, err = svcCloudIssuance.SendPost(url, args) + return +} + +func (svcCloudIssuance *CloudIssuanceService) RobotMacSendText(args md.RobotMacSendTextRequest) (err error) { // 发送文本消息 + url := super_cloud_issuance.HttpBuild(svcCloudIssuance.RequestMethodName, svcCloudIssuance.RequestClientIp, map[string]string{ + "robot_id": strconv.Itoa(args.RobotId), + "toWxId": args.WxId, + "content": args.Content, + }) + resp, err := svcCloudIssuance.SendPost(url, args) + if args.RobotId == 487259 { + utils.FilePutContents("RobotMacSendText_487259", utils.SerializeStr(resp)) + } + return +} + +func (svcCloudIssuance *CloudIssuanceService) RobotMacSendRecvImage(args md.RobotMacSendRecvImageRequest) (err error) { // 发送文本消息 + url := super_cloud_issuance.HttpBuild(svcCloudIssuance.RequestMethodName, svcCloudIssuance.RequestClientIp, map[string]string{ + "robot_id": strconv.Itoa(args.RobotId), + "wx_id": args.WxId, + "content": args.Content, + }) + _, err = svcCloudIssuance.SendPost(url, args) + return +} + +func (svcCloudIssuance *CloudIssuanceService) RobotMacSendRecvVideo(args md.RobotMacSendRecvVideoRequest) (err error) { // 发送文本消息 + url := super_cloud_issuance.HttpBuild(svcCloudIssuance.RequestMethodName, svcCloudIssuance.RequestClientIp, map[string]string{ + "robot_id": strconv.Itoa(args.RobotId), + "wx_id": args.WxId, + "content": args.Content, + }) + _, err = svcCloudIssuance.SendPost(url, args) + return +} + +func (svcCloudIssuance *CloudIssuanceService) RobotMacSendCircle(args md.RobotMacSendCircleRequest) (err error) { // 下线机器人 + url := super_cloud_issuance.HttpBuild(svcCloudIssuance.RequestMethodName, svcCloudIssuance.RequestClientIp, map[string]string{ + "robot_id": strconv.Itoa(args.RobotId), + "pic_url": args.PicUrl, + "content": args.Content, + }) + _, err = svcCloudIssuance.SendPostForCircle(url, args) + return +} + +func (svcCloudIssuance *CloudIssuanceService) SendPost(url string, args interface{}) (data md.CurlResponse, err error) { + data, err = super_cloud_issuance.SendPost(url, args) + if data.Status == "1123" && data.Msg == "当前机器人不在线" && svcCloudIssuance.Context != nil { + masterId := svcCloudIssuance.Context.GetString("mid") + engine := db.DBs[masterId] + user := GetUser(svcCloudIssuance.Context) + superCloudIssuanceUserRobotDb := implement.NewSuperCloudIssuanceUserRobotDb(engine, user.Info.Uid, masterId) + robot, err := superCloudIssuanceUserRobotDb.GetSuperCloudIssuanceUserRobot() + if err != nil { + panic(err) + } + robot.LoginStatus = enum.NotLogin + superCloudIssuanceUserRobotDb.SaveSuperCloudIssuanceUserRobot(robot.Id, robot, "login_status") + } + return +} + +func (svcCloudIssuance *CloudIssuanceService) SendPostForCircle(url string, args interface{}) (data md.CurlResponseForCircle, err error) { + data, err = super_cloud_issuance.SendPostForCircle(url, args) + if data.Code == "1123" && data.Message == "当前机器人不在线" && svcCloudIssuance.Context != nil { + masterId := svcCloudIssuance.Context.GetString("mid") + engine := db.DBs[masterId] + user := GetUser(svcCloudIssuance.Context) + superCloudIssuanceUserRobotDb := implement.NewSuperCloudIssuanceUserRobotDb(engine, user.Info.Uid, masterId) + robot, err := superCloudIssuanceUserRobotDb.GetSuperCloudIssuanceUserRobot() + if err != nil { + panic(err) + } + robot.LoginStatus = enum.NotLogin + superCloudIssuanceUserRobotDb.SaveSuperCloudIssuanceUserRobot(robot.Id, robot, "login_status") + } + return +} diff --git a/super_cloud_issuance/svc/svc_db.go b/super_cloud_issuance/svc/svc_db.go new file mode 100644 index 0000000..99b1e0d --- /dev/null +++ b/super_cloud_issuance/svc/svc_db.go @@ -0,0 +1,11 @@ +package svc + +import ( + "applet/app/db" + "github.com/gin-gonic/gin" + "xorm.io/xorm" +) + +func MasterDb(c *gin.Context) *xorm.Engine { + return db.DBs[c.GetString("mid")] +} diff --git a/super_cloud_issuance/svc/svc_deal_call_back.go b/super_cloud_issuance/svc/svc_deal_call_back.go new file mode 100644 index 0000000..40a80fa --- /dev/null +++ b/super_cloud_issuance/svc/svc_deal_call_back.go @@ -0,0 +1,210 @@ +package svc + +import ( + "applet/app/cfg" + "applet/app/db" + "applet/app/utils/cache" + "applet/mall/utils" + db2 "applet/super_cloud_issuance/db" + "applet/super_cloud_issuance/enum" + "applet/super_cloud_issuance/md" + "code.fnuoos.com/go_rely_warehouse/zyos_go_third_party_api.git/chain_transfer" + "code.fnuoos.com/go_rely_warehouse/zyos_model.git/src/implement" + "code.fnuoos.com/go_rely_warehouse/zyos_model.git/src/models" + "fmt" + "github.com/gin-gonic/gin" + "time" +) + +type DealSuperCloudIssuanceCallBackService struct { + Context *gin.Context `json:"context"` +} + +func (dealSuperCloudIssuanceCallBackService *DealSuperCloudIssuanceCallBackService) Set(c *gin.Context) { // set方法 + dealSuperCloudIssuanceCallBackService.Context = c +} + +func (dealSuperCloudIssuanceCallBackService *DealSuperCloudIssuanceCallBackService) DealCallBack(c *gin.Context, req md.CallbackRequest) { + //1、初始化云发单类 + cloudIssuanceService := CloudIssuanceService{} + engine := db.DBs[dealSuperCloudIssuanceCallBackService.Context.GetString("mid")] + + //2、判断是否为群组消息 + if req.Data.IsGroup { + //2、判断消息类型 + switch req.MessageType { + case 9: + dealSuperCloudIssuanceCallBackService.DealSourceGroupMessage(req.Data.FromGroup, req) + + //群聊文本消息 + bindId := dealSuperCloudIssuanceCallBackService.IsNeedDealGroupMessage(req.Data.FromGroup, req.Data.FromUser, req.RobotId) + if bindId == 0 { + return + } + //3、查询需转发的群 + superCloudIssuanceUserRobotBindFollowGroupDb := implement.NewSuperCloudIssuanceUserRobotBindFollowGroupDb(engine) + cloudIssuanceUserRobotBindFollowGroups, err := superCloudIssuanceUserRobotBindFollowGroupDb.GetCloudIssuanceUserRobotBindFollowGroupByBindId(bindId) + if err != nil { + fmt.Println("DealCallBack_err::::", err.Error()) + return + } + cache.NewRedis(cfg.RedisAddr) + cloudIssuanceUserRobotBindFollowDb := implement.NewSuperCloudIssuanceUserRobotBindFollowDb(engine) + cloudIssuanceUserRobotBindFollow, err := cloudIssuanceUserRobotBindFollowDb.GetCloudIssuanceUserRobotBindFollow(bindId) + for _, cloudIssuanceUserRobotBindFollowGroup := range cloudIssuanceUserRobotBindFollowGroups { + fmt.Println(cloudIssuanceUserRobotBindFollowGroup) + cloudIssuanceService.Set(nil, enum.RobotMacSendTextMethodName, "127.0.0.1") + //转链 + if cloudIssuanceUserRobotBindFollow.Uid > 0 { + args := map[string]string{ + "uid": utils.IntToStr(cloudIssuanceUserRobotBindFollow.Uid), + "platform": "", + "master_id": c.GetString("mid"), + "content": req.Data.Content, + } + utils.FilePutContents("cloud", utils.SerializeStr(args)) + chain := chain_transfer.TurnChain(MasterDb(c), db.Db, db2.ZhimengDb, args) + utils.FilePutContents("cloud", utils.SerializeStr(chain)) + if chain.Count != "" { + req.Data.Content = chain.Count + } + } + utils.FilePutContents("cloud", req.Data.Content) + err = cloudIssuanceService.RobotMacSendText(md.RobotMacSendTextRequest{ + RobotId: req.RobotId, + WxId: cloudIssuanceUserRobotBindFollowGroup.FollowChatRoomId, + Content: req.Data.Content, + }) + if err != nil { + fmt.Println("DealCallBack_err::::", err.Error()) + return + } + } + break + case 10: + dealSuperCloudIssuanceCallBackService.DealSourceGroupMessage(req.Data.FromGroup, req) + + //群聊图片消息 + bindId := dealSuperCloudIssuanceCallBackService.IsNeedDealGroupMessage(req.Data.FromGroup, req.Data.FromUser, req.RobotId) + if bindId == 0 { + return + } + //3、查询需转发的群 + superCloudIssuanceUserRobotBindFollowGroupDb := implement.NewSuperCloudIssuanceUserRobotBindFollowGroupDb(engine) + cloudIssuanceUserRobotBindFollowGroups, err := superCloudIssuanceUserRobotBindFollowGroupDb.GetCloudIssuanceUserRobotBindFollowGroupByBindId(bindId) + if err != nil { + fmt.Println("DealCallBack_err::::", err.Error()) + return + } + for _, cloudIssuanceUserRobotBindFollowGroup := range cloudIssuanceUserRobotBindFollowGroups { + cloudIssuanceService.Set(nil, enum.RobotMacSendRecvImageMethodName, "127.0.0.1") + err = cloudIssuanceService.RobotMacSendRecvImage(md.RobotMacSendRecvImageRequest{ + RobotId: req.RobotId, + WxId: cloudIssuanceUserRobotBindFollowGroup.FollowChatRoomId, + Content: req.Data.Content, + }) + if err != nil { + fmt.Println("DealCallBack_err::::", err.Error()) + return + } + } + break + case 11: + dealSuperCloudIssuanceCallBackService.DealSourceGroupMessage(req.Data.FromGroup, req) + + //群聊视屏消息 + bindId := dealSuperCloudIssuanceCallBackService.IsNeedDealGroupMessage(req.Data.FromGroup, req.Data.FromUser, req.RobotId) + if bindId == 0 { + return + } + //3、查询需转发的群 + superCloudIssuanceUserRobotBindFollowGroupDb := implement.NewSuperCloudIssuanceUserRobotBindFollowGroupDb(engine) + cloudIssuanceUserRobotBindFollowGroups, err := superCloudIssuanceUserRobotBindFollowGroupDb.GetCloudIssuanceUserRobotBindFollowGroupByBindId(bindId) + if err != nil { + fmt.Println("DealCallBack_err::::", err.Error()) + return + } + for _, cloudIssuanceUserRobotBindFollowGroup := range cloudIssuanceUserRobotBindFollowGroups { + cloudIssuanceService.Set(nil, enum.RobotMacSendRecvViedoMethodName, "127.0.0.1") + err = cloudIssuanceService.RobotMacSendRecvVideo(md.RobotMacSendRecvVideoRequest{ + RobotId: req.RobotId, + WxId: cloudIssuanceUserRobotBindFollowGroup.FollowChatRoomId, + Content: req.Data.Content, + }) + if err != nil { + fmt.Println("DealCallBack_err::::", err.Error()) + return + } + } + break + } + } +} + +func (dealSuperCloudIssuanceCallBackService *DealSuperCloudIssuanceCallBackService) IsNeedDealGroupMessage(fromGroup, fromUser string, robotId int) (bindId int) { + //查询 "发送群号" 是否被监听 + superCloudIssuanceUserRobotBindFollowDb := implement.NewSuperCloudIssuanceUserRobotBindFollowDb(db.DBs[dealSuperCloudIssuanceCallBackService.Context.GetString("mid")]) + cloudIssuanceUserRobotBindFollow, err := superCloudIssuanceUserRobotBindFollowDb.GetCloudIssuanceUserRobotBindFollowByChatRoomId(fromGroup, robotId) + if err != nil { + fmt.Println("IsNeedDealGroupMessage_Err:::::", err.Error()) + return + } + if cloudIssuanceUserRobotBindFollow == nil { + return + } + + //查询 "发送微信号" 是否被监听 + superCloudIssuanceUserRobotBindFollowUserDb := implement.NewSuperCloudIssuanceUserRobotBindFollowUserDb(db.DBs[dealSuperCloudIssuanceCallBackService.Context.GetString("mid")]) + cloudIssuanceUserRobotBindFollowUser, err := superCloudIssuanceUserRobotBindFollowUserDb.GetCloudIssuanceUserRobotBindFollowUserByWxId(fromUser) + if err != nil { + fmt.Println("IsNeedDealGroupMessage_Err:::::", err.Error()) + return + } + if cloudIssuanceUserRobotBindFollowUser == nil { + return + } + + bindId = cloudIssuanceUserRobotBindFollow.ActivateGroupId + return +} + +func (dealSuperCloudIssuanceCallBackService *DealSuperCloudIssuanceCallBackService) DealSourceGroupMessage(fromGroup string, req md.CallbackRequest) (err error) { + engine := db.DBs[dealSuperCloudIssuanceCallBackService.Context.GetString("mid")] + //查询 "发送群号" 是否为源头群 + superCloudIssuanceUserRobotWithActivateGroupDb := implement.NewSuperCloudIssuanceUserRobotWithActivateGroupDb(engine) + superCloudIssuanceUserRobotWithActivateGroup, err := superCloudIssuanceUserRobotWithActivateGroupDb.GetSuperCloudIssuanceUserRobotWithActivateGroupByChatRoomId(fromGroup, req.RobotId) + if err != nil { + fmt.Println("DealSourceGroupMessage_Err:::::", err.Error()) + return + } + if superCloudIssuanceUserRobotWithActivateGroup == nil { + return + } + activateGroupId := superCloudIssuanceUserRobotWithActivateGroup.Id + + superCloudIssuanceUserRobotBindSourceDb := implement.NewSuperCloudIssuanceUserRobotBindSourceDb(engine) + superCloudIssuanceUserRobotBindSource, err := superCloudIssuanceUserRobotBindSourceDb.GetSuperCloudIssuanceUserRobotBindSource(activateGroupId) + if err != nil { + fmt.Println("DealSourceGroupMessage_Err:::::", err.Error()) + return + } + if superCloudIssuanceUserRobotBindSource != nil { + superCloudIssuanceUserRobotBindSourceMessageLog := models.SuperCloudIssuanceUserRobotBindSourceMessageLog{ + ActivateGroupId: superCloudIssuanceUserRobotBindSource.ActivateGroupId, + MessageType: req.MessageType, + Timestamp: utils.StrToInt64(req.Data.Timestamp), + Content: req.Data.Content, + CreateAt: time.Now().Format("2006-01-02 15:04:05"), + UpdateAt: time.Now().Format("2006-01-02 15:04:05"), + } + + superCloudIssuanceUserRobotBindSourceMessageLogDb := implement.NewSuperCloudIssuanceUserRobotBindSourceMessageLogDb(engine) + _, err = superCloudIssuanceUserRobotBindSourceMessageLogDb.InsertSuperCloudIssuanceUserRobotBindSourceMessageLog(&superCloudIssuanceUserRobotBindSourceMessageLog) + if err != nil { + fmt.Println("DealSourceGroupMessage_Err:::::", err.Error()) + return err + } + } + + return +} diff --git a/super_cloud_issuance/svc/svc_domain_info.go b/super_cloud_issuance/svc/svc_domain_info.go new file mode 100644 index 0000000..a27bc2a --- /dev/null +++ b/super_cloud_issuance/svc/svc_domain_info.go @@ -0,0 +1,58 @@ +package svc + +import ( + "applet/app/db" + "applet/app/db/model" + "applet/app/utils" + "applet/app/utils/logx" + "github.com/gin-gonic/gin" + "github.com/tidwall/gjson" + "strings" +) + +// 获取指定类型的域名:admin、wap、api +func GetWebSiteDomainInfo(c *gin.Context, domainType string) string { + if domainType == "" { + domainType = "wap" + } + + domainSetting := SysCfgGet(c, "domain_setting") + + domainTypePath := domainType + ".type" + domainSslPath := domainType + ".isOpenHttps" + domainPath := domainType + ".domain" + + domainTypeValue := gjson.Get(domainSetting, domainTypePath).String() + domainSslValue := gjson.Get(domainSetting, domainSslPath).String() + domain := gjson.Get(domainSetting, domainPath).String() + + scheme := "http://" + if domainSslValue == "1" { + scheme = "https://" + } + + // 有自定义域名 返回自定义的 + if domainTypeValue == "own" && domain != "" { + return scheme + domain + } + // 否则返回官方的 + official, err := db.GetOfficialDomainInfoByType(db.Db, c.GetString("mid"), domainType) + if err != nil { + _ = logx.Errorf("Get Official Domain Fail! %s", err) + return "" + } + if strings.Contains(official, "http") { + return official + } + return scheme + official +} + +// 获取指定类型的域名对应的masterId:admin、wap、api +func GetWebSiteDomainMasterId(domainType string, host string) string { + obj := new(model.UserAppDomain) + has, err := db.Db.Where("domain=? and type=?", host, domainType).Get(obj) + if err != nil || !has { + return "" + } + return utils.AnyToString(obj.Uuid) +} diff --git a/super_cloud_issuance/svc/svc_file_img_format.go b/super_cloud_issuance/svc/svc_file_img_format.go new file mode 100644 index 0000000..c14f066 --- /dev/null +++ b/super_cloud_issuance/svc/svc_file_img_format.go @@ -0,0 +1,71 @@ +package svc + +import ( + "applet/app/utils" + "fmt" + "strings" + + "github.com/gin-gonic/gin" +) + +//ImageFormat is 格式化 图片 +func ImageFormat(c *gin.Context, name string) string { + if strings.Contains(name, "https:") || strings.Contains(name, "http:") { + return name + } + scheme := SysCfgGet(c, "file_bucket_scheme") + domain := SysCfgGet(c, "file_bucket_host") + return fmt.Sprintf("%s://%s/%s", scheme, domain, name) +} + +//OffImageFormat is 格式化官方 图片 +func OffImageFormat(c *gin.Context, name string) string { + if strings.Contains(name, "https:") || strings.Contains(name, "http:") { + return name + } + return fmt.Sprintf("%s://%s/%s", "http", "ossq.izhyin.cn", name) +} + +// ImageBucket is 获取域名 +func ImageBucket(c *gin.Context) (string, string) { + return SysCfgGet(c, "file_bucket_scheme"), SysCfgGet(c, "file_bucket_host") +} + +// ImageBucketNew is 获取域名 +func ImageBucketNew(c *gin.Context) (string, string, string, map[string]string) { + var list = make(map[string]string, 0) + for i := 1; i < 10; i++ { + keys := "file_bucket_sub_host" + utils.IntToStr(i) + list[keys] = SysCfgGet(c, keys) + } + return SysCfgGet(c, "file_bucket_scheme"), SysCfgGet(c, "file_bucket_host"), SysCfgGet(c, "file_bucket_sub_host"), list +} + +// ImageFormatWithBucket is 格式化成oss 域名 +func ImageFormatWithBucket(scheme, domain, name string) string { + if strings.Contains(name, "http") { + return name + } + return fmt.Sprintf("%s://%s/%s", scheme, domain, name) +} + +// ImageFormatWithBucket is 格式化成oss 域名 +func ImageFormatWithBucketNew(scheme, domain, subDomain string, moreSubDomain map[string]string, name string) string { + if strings.Contains(name, "http") { + return name + } + if strings.Contains(name, "{{subhost}}") && subDomain != "" { //读副域名 有可能是其他平台的 + domain = subDomain + } + //为了兼容一些客户自营商城导到不同系统 并且七牛云不一样 + for i := 1; i < 10; i++ { + keys := "file_bucket_sub_host" + utils.IntToStr(i) + if strings.Contains(name, "{{subhost"+utils.IntToStr(i)+"}}") && moreSubDomain[keys] != "" { + domain = moreSubDomain[keys] + } + name = strings.ReplaceAll(name, "{{subhost"+utils.IntToStr(i)+"}}", "") + } + name = strings.ReplaceAll(name, "{{host}}", "") + name = strings.ReplaceAll(name, "{{subhost}}", "") + return fmt.Sprintf("%s://%s/%s", scheme, domain, name) +} diff --git a/super_cloud_issuance/svc/svc_file_img_upload.go b/super_cloud_issuance/svc/svc_file_img_upload.go new file mode 100644 index 0000000..384ad74 --- /dev/null +++ b/super_cloud_issuance/svc/svc_file_img_upload.go @@ -0,0 +1,103 @@ +package svc + +import ( + "applet/app/e" + "applet/app/utils" + "applet/super_cloud_issuance/lib/qiniu" + "applet/super_cloud_issuance/md" + "applet/super_cloud_issuance/utils/logx" + "fmt" + "strings" + + "github.com/gin-gonic/gin" +) + +// 请求文件上传 +func ImgReqUpload(c *gin.Context, uid, dirName, fname, callbackUrl string, fsize int64) (interface{}, error) { + ext := utils.FileExt(fname) + if err := initStg(c, fsize, ext); err != nil { + return nil, err + } + // logx.Warn(uid) + newName := dirName + "_" + fmt.Sprintf("%010s", uid) + + // if dirName == md.FILE_DIR_FEEDBACK || dirName == md.FILE_DIR_STYLE { + // newName += "_" + utils.FormatNanoUnix() + utils.RandString(4, "0123456789") + // } + // 默认都加时间戳 + newName += "_" + utils.FormatNanoUnix() + utils.RandString(4, "0123456789") + newName += ".png" // 因为可能存在多种图像格式,这里统一后缀为png + + f := &md.FileCallback{ + Uid: uid, + DirId: md.FileUserDir[dirName], + FileName: newName, + } + // logx.Warn(f.Uid) + return qiniu.ReqImgUpload(f, callbackUrl), nil +} + +func initStg(c *gin.Context, fsize int64, ext string) error { + // 获取上传配置 + stgInfo := SysCfgFind( + c, + md.KEY_CFG_FILE_BUCKET, + md.KEY_CFG_FILE_HOST, + md.KEY_CFG_FILE_AK, + md.KEY_CFG_FILE_SK, + md.KEY_CFG_FILE_PVD, + md.KEY_CFG_FILE_REGION, + md.KEY_CFG_FILE_MAX_SIZE, + md.KEY_CFG_FILE_EXT, + md.KEY_CFG_FILE_SCHEME, + md.KEY_CFG_FILE_AVATAR_THUMBNAIL, + ) + //?imageView2/1/w/120/h/120/format/webp/interlace/1 + if stgInfo == nil { + return e.NewErrCode(e.ERR_CFG) + } + // todo 目前仅支持七牛 + if v, ok := stgInfo[md.KEY_CFG_FILE_PVD]; !ok || v != "qiniu" { + return e.NewErrCode(e.ERR_CFG) + } + if v, ok := stgInfo[md.KEY_CFG_FILE_REGION]; !ok || v == "" { + return e.NewErrCode(e.ERR_CFG) + } + if v, ok := stgInfo[md.KEY_CFG_FILE_AK]; !ok || v == "" { + return e.NewErrCode(e.ERR_CFG) + } + if v, ok := stgInfo[md.KEY_CFG_FILE_SK]; !ok || v == "" { + return e.NewErrCode(e.ERR_CFG) + } + if v, ok := stgInfo[md.KEY_CFG_FILE_BUCKET]; !ok || v == "" { + return e.NewErrCode(e.ERR_CFG) + } + if v, ok := stgInfo[md.KEY_CFG_FILE_SCHEME]; !ok || v == "" { + stgInfo[md.KEY_CFG_FILE_SCHEME] = "http" + SysCfgSet(c, md.KEY_CFG_FILE_SCHEME, stgInfo[md.KEY_CFG_FILE_SCHEME], "文件域名HTTP协议") + } + qiniu.Init(stgInfo[md.KEY_CFG_FILE_AK], stgInfo[md.KEY_CFG_FILE_SK], stgInfo[md.KEY_CFG_FILE_BUCKET], stgInfo[md.KEY_CFG_FILE_REGION], stgInfo[md.KEY_CFG_FILE_SCHEME]) + if v, ok := stgInfo[md.KEY_CFG_FILE_HOST]; !ok || v == "" { + var err error + stgInfo[md.KEY_CFG_FILE_HOST], err = qiniu.BucketGetDomain(stgInfo[md.KEY_CFG_FILE_BUCKET]) + if err != nil { + logx.Error(err) + return e.NewErrCode(e.ERR_CFG) + } + SysCfgSet(c, md.KEY_CFG_FILE_HOST, stgInfo[md.KEY_CFG_FILE_HOST], "文件域名地址") + } + // 头像缩略图参数 + if v, ok := stgInfo[md.KEY_CFG_FILE_AVATAR_THUMBNAIL]; !ok || v == "" { + SysCfgSet(c, md.KEY_CFG_FILE_AVATAR_THUMBNAIL, "?imageView2/1/w/200/h/200/format/png", "文件用户头像缩略图参数") + } + + // 检查文件大小限制 + if v, ok := stgInfo[md.KEY_CFG_FILE_MAX_SIZE]; ok && v != "" && utils.StrToInt64(v) < fsize { + return e.NewErrCode(e.ERR_FILE_MAX_SIZE) + } + // 检查文件后缀 + if v, ok := stgInfo[md.KEY_CFG_FILE_EXT]; ok && v != "" && !strings.Contains(v, ext) { + return e.NewErrCode(e.ERR_FILE_EXT) + } + return nil +} diff --git a/super_cloud_issuance/svc/svc_fin_user_flow.go b/super_cloud_issuance/svc/svc_fin_user_flow.go new file mode 100644 index 0000000..9d33051 --- /dev/null +++ b/super_cloud_issuance/svc/svc_fin_user_flow.go @@ -0,0 +1,68 @@ +package svc + +import ( + "applet/app/db" + "applet/app/db/model" + "applet/app/utils" + "applet/app/utils/logx" + "time" + "xorm.io/xorm" +) + +// 开始写入流水 +func FlowInsert(eg *xorm.Engine, uid int, paidPrice string, orderAction int, ordId int64, id int64, goodsId int, ItemTitle string, ordType string, types int, beforeAmount string, afterAmount string) { + session := eg.NewSession() + + now := time.Now() + if err := db.FinUserFlowInsertOneWithSession( + session, + &model.FinUserFlow{ + Type: types, + Uid: uid, + Amount: paidPrice, + BeforeAmount: beforeAmount, + AfterAmount: afterAmount, + OrdType: ordType, + OrdId: utils.Int64ToStr(ordId), + OrdAction: orderAction, + OrdDetail: utils.IntToStr(goodsId), + State: 2, + OtherId: id, + OrdTitle: ItemTitle, + OrdTime: int(now.Unix()), + CreateAt: now, + UpdateAt: now, + }); err != nil { + _ = session.Rollback() + _ = logx.Warn(err) + return + } +} + +// 开始写入流水 +func SessionFlowInsert(session *xorm.Session, uid int, paidPrice string, orderAction int, ordId int64, id int64, goodsId int, ItemTitle string, ordType string, types int, beforeAmount string, afterAmount string) { + now := time.Now() + if err := db.FinUserFlowInsertOneWithSession( + session, + &model.FinUserFlow{ + Type: types, + Uid: uid, + Amount: paidPrice, + BeforeAmount: beforeAmount, + AfterAmount: afterAmount, + OrdType: ordType, + OrdId: utils.Int64ToStr(ordId), + OrdAction: orderAction, + OrdDetail: utils.IntToStr(goodsId), + State: 2, + OtherId: id, + OrdTitle: ItemTitle, + OrdTime: int(now.Unix()), + CreateAt: now, + UpdateAt: now, + }); err != nil { + _ = session.Rollback() + _ = logx.Warn(err) + return + } +} diff --git a/super_cloud_issuance/svc/svc_redis_mutex_lock.go b/super_cloud_issuance/svc/svc_redis_mutex_lock.go new file mode 100644 index 0000000..396e15c --- /dev/null +++ b/super_cloud_issuance/svc/svc_redis_mutex_lock.go @@ -0,0 +1,85 @@ +package svc + +import ( + "applet/app/md" + "applet/app/utils" + "applet/app/utils/cache" + "errors" + "fmt" + "math/rand" + "reflect" + "time" +) + +const redisMutexLockExpTime = 15 + +// TryGetDistributedLock 分布式锁获取 +// requestId 用于标识请求客户端,可以是随机字符串,需确保唯一 +func TryGetDistributedLock(lockKey, requestId string, isNegative bool) bool { + if isNegative { // 多次尝试获取 + retry := 1 + for { + ok, err := cache.Do("SET", lockKey, requestId, "EX", redisMutexLockExpTime, "NX") + // 获取锁成功 + if err == nil && ok == "OK" { + return true + } + // 尝试多次没获取成功 + if retry > 10 { + return false + } + time.Sleep(time.Millisecond * time.Duration(rand.Intn(1000))) + retry += 1 + } + } else { // 只尝试一次 + ok, err := cache.Do("SET", lockKey, requestId, "EX", redisMutexLockExpTime, "NX") + // 获取锁成功 + if err == nil && ok == "OK" { + return true + } + + return false + } +} + +// ReleaseDistributedLock 释放锁,通过比较requestId,用于确保客户端只释放自己的锁,使用lua脚本保证操作的原子型 +func ReleaseDistributedLock(lockKey, requestId string) (bool, error) { + luaScript := ` + if redis.call("get",KEYS[1]) == ARGV[1] + then + return redis.call("del",KEYS[1]) + else + return 0 + end` + + do, err := cache.Do("eval", luaScript, 1, lockKey, requestId) + fmt.Println(reflect.TypeOf(do)) + fmt.Println(do) + + if utils.AnyToInt64(do) == 1 { + return true, err + } else { + return false, err + } +} + +func GetDistributedLockRequestId(prefix string) string { + return prefix + utils.IntToStr(rand.Intn(100000000)) +} + +// HandleBalanceDistributedLock 处理余额更新时获取锁和释放锁 如果加锁成功,使用语句 ` defer cb() ` 释放锁 +func HandleBalanceDistributedLock(masterId, uid, requestIdPrefix string) (cb func(), err error) { + // 获取余额更新锁 + balanceLockKey := fmt.Sprintf(md.UserFinValidUpdateLock, masterId, uid) + requestId := GetDistributedLockRequestId(requestIdPrefix) + balanceLockOk := TryGetDistributedLock(balanceLockKey, requestId, true) + if !balanceLockOk { + return nil, errors.New("系统繁忙,请稍后再试") + } + + cb = func() { + _, _ = ReleaseDistributedLock(balanceLockKey, requestId) + } + + return cb, nil +} diff --git a/super_cloud_issuance/svc/svc_sys_cfg_get.go b/super_cloud_issuance/svc/svc_sys_cfg_get.go new file mode 100644 index 0000000..46e8264 --- /dev/null +++ b/super_cloud_issuance/svc/svc_sys_cfg_get.go @@ -0,0 +1,137 @@ +package svc + +import ( + "applet/app/db" + "applet/app/utils/cache" + "applet/super_cloud_issuance/md" + "errors" + "fmt" + "github.com/gin-gonic/gin" + "strings" + "xorm.io/xorm" +) + +// 单挑记录获取 +func SysCfgGet(c *gin.Context, key string) string { + mid := c.GetString("mid") + eg := db.DBs[mid] + return db.SysCfgGetWithDb(eg, mid, key) +} + +// 多条记录获取 +func SysCfgFind(c *gin.Context, keys ...string) map[string]string { + e := db.DBs[c.GetString("mid")] + res := map[string]string{} + cacheKey := fmt.Sprintf(md.AppCfgCacheKey, c.GetString("mid")) + err := cache.GetJson(cacheKey, &res) + if err != nil || len(res) == 0 { + cfgList, _ := db.SysCfgGetAll(e) + if cfgList == nil { + return nil + } + for _, v := range *cfgList { + res[v.Key] = v.Val + } + // 先不设置缓存 + cache.SetJson(cacheKey, res, md.CfgCacheTime) + } + if len(keys) == 0 { + return res + } + tmp := map[string]string{} + for _, v := range keys { + if val, ok := res[v]; ok { + tmp[v] = val + } else { + tmp[v] = "" + } + } + return tmp +} + +// 多条记录获取 +func EgSysCfgFind(keys ...string) map[string]string { + var e *xorm.Engine + res := map[string]string{} + if len(res) == 0 { + cfgList, _ := db.SysCfgGetAll(e) + if cfgList == nil { + return nil + } + for _, v := range *cfgList { + res[v.Key] = v.Val + } + // 先不设置缓存 + // cache.SetJson(md.KEY_SYS_CFG_CACHE, res, 60) + } + if len(keys) == 0 { + return res + } + tmp := map[string]string{} + for _, v := range keys { + if val, ok := res[v]; ok { + tmp[v] = val + } else { + tmp[v] = "" + } + } + return tmp +} + +// 清理系统配置信息 +func SysCfgCleanCache() { + cache.Del(md.KEY_SYS_CFG_CACHE) +} + +// 写入系统设置 +func SysCfgSet(c *gin.Context, key, val, memo string) bool { + cfg, err := db.SysCfgGetOne(db.DBs[c.GetString("mid")], key) + if err != nil || cfg == nil { + return db.SysCfgInsert(db.DBs[c.GetString("mid")], key, val, memo) + } + if memo != "" && cfg.Memo != memo { + cfg.Memo = memo + } + SysCfgCleanCache() + return db.SysCfgUpdate(db.DBs[c.GetString("mid")], key, val, cfg.Memo) +} + +// 支付配置 +func SysCfgFindPayment(c *gin.Context) ([]map[string]string, error) { + platform := c.GetHeader("platform") + payCfg := SysCfgFind(c, "pay_wx_pay_img", "pay_ali_pay_img", "pay_balance_img", "pay_type") + if payCfg["pay_wx_pay_img"] == "" || payCfg["pay_ali_pay_img"] == "" || payCfg["pay_balance_img"] == "" || payCfg["pay_type"] == "" { + return nil, errors.New("lack of payment config") + } + payCfg["pay_wx_pay_img"] = ImageFormat(c, payCfg["pay_wx_pay_img"]) + payCfg["pay_ali_pay_img"] = ImageFormat(c, payCfg["pay_ali_pay_img"]) + payCfg["pay_balance_img"] = ImageFormat(c, payCfg["pay_balance_img"]) + + var result []map[string]string + + if strings.Contains(payCfg["pay_type"], "aliPay") && platform != md.PLATFORM_WX_APPLET { + item := make(map[string]string) + item["pay_channel"] = "alipay" + item["img"] = payCfg["pay_ali_pay_img"] + item["name"] = "支付宝支付" + result = append(result, item) + } + + if strings.Contains(payCfg["pay_type"], "wxPay") { + item := make(map[string]string) + item["pay_channel"] = "wx" + item["img"] = payCfg["pay_wx_pay_img"] + item["name"] = "微信支付" + result = append(result, item) + } + + if strings.Contains(payCfg["pay_type"], "walletPay") { + item := make(map[string]string) + item["pay_channel"] = "fin" + item["img"] = payCfg["pay_balance_img"] + item["name"] = "余额支付" + result = append(result, item) + } + + return result, nil +} diff --git a/super_cloud_issuance/svc/svc_validate_common.go b/super_cloud_issuance/svc/svc_validate_common.go new file mode 100644 index 0000000..08e1e9d --- /dev/null +++ b/super_cloud_issuance/svc/svc_validate_common.go @@ -0,0 +1,26 @@ +package svc + +import ( + "applet/app/e" + "applet/app/utils" + "applet/app/utils/logx" + "encoding/json" + "fmt" + "github.com/go-playground/validator/v10" +) + +// HandleValidateErr 通用请求参数错误处理 +func HandleValidateErr(err error) error { + switch err.(type) { + case *json.UnmarshalTypeError: + return e.NewErr(e.ERR_UNMARSHAL, "参数格式错误") + case validator.ValidationErrors: + errs := err.(validator.ValidationErrors) + transMsgMap := errs.Translate(utils.ValidatorTrans) + transMsgOne := transMsgMap[utils.GetOneKeyOfMapString(transMsgMap)] + return e.NewErr(e.ERR_INVALID_ARGS, transMsgOne) + default: + _ = logx.Error(err) + return e.NewErr(e.ERR, fmt.Sprintf("validate request params, err:%v\n", err)) + } +} diff --git a/super_cloud_issuance/tool/super_cloud_issuance/api.go b/super_cloud_issuance/tool/super_cloud_issuance/api.go new file mode 100644 index 0000000..edf2cba --- /dev/null +++ b/super_cloud_issuance/tool/super_cloud_issuance/api.go @@ -0,0 +1,101 @@ +package super_cloud_issuance + +import ( + "applet/app/md" + "applet/app/utils" + "encoding/json" + "errors" + "fmt" + "sort" + "time" +) + +const ( + RequestUrl = "http://router.itaokecms.com/api?app_key=%s&v=1.0&format=json&sign_method=md5&method=%s×tamp=%s&domain=%s&client=%s&partner_id=%s&sign=%s" + AppKey = "1091808433" + AppSecret = "bed35c10-ecf1-2d06-477b-f821c227198b" + Domain = "hairuyi.com" + PartnerId = "top-sdk-php-20190618" +) + +func SendPost(url string, args interface{}) (data md.CurlResponse, err error) { + post, err := utils.CurlPost(url, utils.Serialize(args), map[string]string{}) + err = json.Unmarshal(post, &data) + utils.FilePutContents("cloud_issuance_send_resp", utils.SerializeStr(map[string]interface{}{ + "time": time.Now().Format("2006-01-02 15:04:05.000"), + "url": url, + "args": args, + "resp": data, + })) + if err != nil { + return + } + if data.Status != "0000" { + err = errors.New(data.Msg) + return + } + return data, err +} + +func SendPostForCircle(url string, args interface{}) (data md.CurlResponseForCircle, err error) { + post, err := utils.CurlPost(url, utils.Serialize(args), map[string]string{}) + err = json.Unmarshal(post, &data) + utils.FilePutContents("cloud_issuance_send_resp_for_circle", utils.SerializeStr(map[string]interface{}{ + "time": time.Now().Format("2006-01-02 15:04:05.000"), + "url": url, + "args": args, + "resp": data, + })) + if err != nil { + return + } + if data.Code != "1000" { + err = errors.New(data.Message) + return + } + return data, err +} + +func HttpBuild(methodName, clientIP string, params map[string]string) (httpUrl string) { + timestamp := utils.AnyToString(time.Now().Unix()) + params["app_key"] = AppKey + params["v"] = "1.0" + params["format"] = "json" + params["sign_method"] = "md5" + params["method"] = methodName + params["timestamp"] = timestamp + params["domain"] = Domain + params["client"] = clientIP + params["partner_id"] = PartnerId + sign := httpBuildQuery(params, true) + sign = AppSecret + httpBuildQuery(params, true) + AppSecret + sign = utils.MD5ToUpper32(sign) + httpUrl = fmt.Sprintf(RequestUrl, AppKey, methodName, timestamp, Domain, clientIP, PartnerId, sign) + return +} + +func httpBuildQuery(args map[string]string, sortAsc ...bool) string { + str := "" + if len(args) == 0 { + return str + } + if len(sortAsc) > 0 { + keys := make([]string, 0, len(args)) + for k := range args { + keys = append(keys, k) + } + if sortAsc[0] { + sort.Strings(keys) + } else { + sort.Sort(sort.Reverse(sort.StringSlice(keys))) + } + for _, k := range keys { + str += k + args[k] + } + } else { + for k, v := range args { + str += k + v + } + } + return str +} diff --git a/super_cloud_issuance/utils/aes.go b/super_cloud_issuance/utils/aes.go new file mode 100644 index 0000000..8f5aaac --- /dev/null +++ b/super_cloud_issuance/utils/aes.go @@ -0,0 +1,123 @@ +package utils + +import ( + "bytes" + "crypto/aes" + "crypto/cipher" + "fmt" +) + +func AesEncrypt(rawData, key []byte) ([]byte, error) { + block, err := aes.NewCipher(key) + if err != nil { + return nil, err + } + blockSize := block.BlockSize() + rawData = PKCS5Padding(rawData, blockSize) + // rawData = ZeroPadding(rawData, block.BlockSize()) + blockMode := cipher.NewCBCEncrypter(block, key[:blockSize]) + encrypted := make([]byte, len(rawData)) + // 根据CryptBlocks方法的说明,如下方式初始化encrypted也可以 + // encrypted := rawData + blockMode.CryptBlocks(encrypted, rawData) + return encrypted, nil +} + +func AesDecrypt(encrypted, key []byte) ([]byte, error) { + block, err := aes.NewCipher(key) + if err != nil { + return nil, err + } + blockSize := block.BlockSize() + blockMode := cipher.NewCBCDecrypter(block, key[:blockSize]) + rawData := make([]byte, len(encrypted)) + // rawData := encrypted + blockMode.CryptBlocks(rawData, encrypted) + rawData = PKCS5UnPadding(rawData) + // rawData = ZeroUnPadding(rawData) + return rawData, nil +} + +func ZeroPadding(cipherText []byte, blockSize int) []byte { + padding := blockSize - len(cipherText)%blockSize + padText := bytes.Repeat([]byte{0}, padding) + return append(cipherText, padText...) +} + +func ZeroUnPadding(rawData []byte) []byte { + length := len(rawData) + unPadding := int(rawData[length-1]) + return rawData[:(length - unPadding)] +} + +func PKCS5Padding(cipherText []byte, blockSize int) []byte { + padding := blockSize - len(cipherText)%blockSize + padText := bytes.Repeat([]byte{byte(padding)}, padding) + return append(cipherText, padText...) +} + +func PKCS5UnPadding(rawData []byte) []byte { + length := len(rawData) + // 去掉最后一个字节 unPadding 次 + unPadding := int(rawData[length-1]) + return rawData[:(length - unPadding)] +} + +// 填充0 +func zeroFill(key *string) { + l := len(*key) + if l != 16 && l != 24 && l != 32 { + if l < 16 { + *key = *key + fmt.Sprintf("%0*d", 16-l, 0) + } else if l < 24 { + *key = *key + fmt.Sprintf("%0*d", 24-l, 0) + } else if l < 32 { + *key = *key + fmt.Sprintf("%0*d", 32-l, 0) + } else { + *key = string([]byte(*key)[:32]) + } + } +} + +type AesCrypt struct { + Key []byte + Iv []byte +} + +func (a *AesCrypt) Encrypt(data []byte) ([]byte, error) { + aesBlockEncrypt, err := aes.NewCipher(a.Key) + if err != nil { + println(err.Error()) + return nil, err + } + + content := pKCS5Padding(data, aesBlockEncrypt.BlockSize()) + cipherBytes := make([]byte, len(content)) + aesEncrypt := cipher.NewCBCEncrypter(aesBlockEncrypt, a.Iv) + aesEncrypt.CryptBlocks(cipherBytes, content) + return cipherBytes, nil +} + +func (a *AesCrypt) Decrypt(src []byte) (data []byte, err error) { + decrypted := make([]byte, len(src)) + var aesBlockDecrypt cipher.Block + aesBlockDecrypt, err = aes.NewCipher(a.Key) + if err != nil { + println(err.Error()) + return nil, err + } + aesDecrypt := cipher.NewCBCDecrypter(aesBlockDecrypt, a.Iv) + aesDecrypt.CryptBlocks(decrypted, src) + return pKCS5Trimming(decrypted), nil +} + +func pKCS5Padding(cipherText []byte, blockSize int) []byte { + padding := blockSize - len(cipherText)%blockSize + padText := bytes.Repeat([]byte{byte(padding)}, padding) + return append(cipherText, padText...) +} + +func pKCS5Trimming(encrypt []byte) []byte { + padding := encrypt[len(encrypt)-1] + return encrypt[:len(encrypt)-int(padding)] +} diff --git a/super_cloud_issuance/utils/auth.go b/super_cloud_issuance/utils/auth.go new file mode 100644 index 0000000..d7bd9ae --- /dev/null +++ b/super_cloud_issuance/utils/auth.go @@ -0,0 +1,46 @@ +package utils + +import ( + "errors" + "time" + + "applet/app/lib/auth" + + "github.com/dgrijalva/jwt-go" +) + +// GenToken 生成JWT +func GenToken(uid int, username, phone, appname, MiniOpenID, MiniSK string) (string, error) { + // 创建一个我们自己的声明 + c := auth.JWTUser{ + uid, + username, + phone, + appname, + MiniOpenID, + MiniSK, + jwt.StandardClaims{ + ExpiresAt: time.Now().Add(auth.TokenExpireDuration).Unix(), // 过期时间 + Issuer: "zyos", // 签发人 + }, + } + // 使用指定的签名方法创建签名对象 + token := jwt.NewWithClaims(jwt.SigningMethodHS256, c) + // 使用指定的secret签名并获得完整的编码后的字符串token + return token.SignedString(auth.Secret) +} + +// ParseToken 解析JWT +func ParseToken(tokenString string) (*auth.JWTUser, error) { + // 解析token + token, err := jwt.ParseWithClaims(tokenString, &auth.JWTUser{}, func(token *jwt.Token) (i interface{}, err error) { + return auth.Secret, nil + }) + if err != nil { + return nil, err + } + if claims, ok := token.Claims.(*auth.JWTUser); ok && token.Valid { // 校验token + return claims, nil + } + return nil, errors.New("invalid token") +} diff --git a/super_cloud_issuance/utils/base64.go b/super_cloud_issuance/utils/base64.go new file mode 100644 index 0000000..ee16553 --- /dev/null +++ b/super_cloud_issuance/utils/base64.go @@ -0,0 +1,95 @@ +package utils + +import ( + "encoding/base64" + "fmt" +) + +const ( + Base64Std = iota + Base64Url + Base64RawStd + Base64RawUrl +) + +func Base64StdEncode(str interface{}) string { + return Base64Encode(str, Base64Std) +} + +func Base64StdDecode(str interface{}) string { + return Base64Decode(str, Base64Std) +} + +func Base64UrlEncode(str interface{}) string { + return Base64Encode(str, Base64Url) +} + +func Base64UrlDecode(str interface{}) string { + return Base64Decode(str, Base64Url) +} + +func Base64RawStdEncode(str interface{}) string { + return Base64Encode(str, Base64RawStd) +} + +func Base64RawStdDecode(str interface{}) string { + return Base64Decode(str, Base64RawStd) +} + +func Base64RawUrlEncode(str interface{}) string { + return Base64Encode(str, Base64RawUrl) +} + +func Base64RawUrlDecode(str interface{}) string { + return Base64Decode(str, Base64RawUrl) +} + +func Base64Encode(str interface{}, encode int) string { + newEncode := base64Encode(encode) + if newEncode == nil { + return "" + } + switch v := str.(type) { + case string: + return newEncode.EncodeToString([]byte(v)) + case []byte: + return newEncode.EncodeToString(v) + } + return newEncode.EncodeToString([]byte(fmt.Sprint(str))) +} + +func Base64Decode(str interface{}, encode int) string { + var err error + var b []byte + newEncode := base64Encode(encode) + if newEncode == nil { + return "" + } + switch v := str.(type) { + case string: + b, err = newEncode.DecodeString(v) + case []byte: + b, err = newEncode.DecodeString(string(v)) + default: + return "" + } + if err != nil { + return "" + } + return string(b) +} + +func base64Encode(encode int) *base64.Encoding { + switch encode { + case Base64Std: + return base64.StdEncoding + case Base64Url: + return base64.URLEncoding + case Base64RawStd: + return base64.RawStdEncoding + case Base64RawUrl: + return base64.RawURLEncoding + default: + return nil + } +} diff --git a/super_cloud_issuance/utils/boolean.go b/super_cloud_issuance/utils/boolean.go new file mode 100644 index 0000000..fdfd986 --- /dev/null +++ b/super_cloud_issuance/utils/boolean.go @@ -0,0 +1,26 @@ +package utils + +import "reflect" + +// 检验一个值是否为空 +func Empty(val interface{}) bool { + v := reflect.ValueOf(val) + switch v.Kind() { + case reflect.String, reflect.Array: + return v.Len() == 0 + case reflect.Map, reflect.Slice: + return v.Len() == 0 || v.IsNil() + case reflect.Bool: + return !v.Bool() + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return v.Int() == 0 + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + return v.Uint() == 0 + case reflect.Float32, reflect.Float64: + return v.Float() == 0 + case reflect.Interface, reflect.Ptr: + return v.IsNil() + } + + return reflect.DeepEqual(val, reflect.Zero(v.Type()).Interface()) +} diff --git a/super_cloud_issuance/utils/cache/base.go b/super_cloud_issuance/utils/cache/base.go new file mode 100644 index 0000000..64648dd --- /dev/null +++ b/super_cloud_issuance/utils/cache/base.go @@ -0,0 +1,421 @@ +package cache + +import ( + "errors" + "fmt" + "strconv" + "time" +) + +const ( + redisDialTTL = 10 * time.Second + redisReadTTL = 3 * time.Second + redisWriteTTL = 3 * time.Second + redisIdleTTL = 10 * time.Second + redisPoolTTL = 10 * time.Second + redisPoolSize int = 512 + redisMaxIdleConn int = 64 + redisMaxActive int = 512 +) + +var ( + ErrNil = errors.New("nil return") + ErrWrongArgsNum = errors.New("args num error") + ErrNegativeInt = errors.New("redis cluster: unexpected value for Uint64") +) + +// 以下为提供类型转换 + +func Int(reply interface{}, err error) (int, error) { + if err != nil { + return 0, err + } + switch reply := reply.(type) { + case int: + return reply, nil + case int8: + return int(reply), nil + case int16: + return int(reply), nil + case int32: + return int(reply), nil + case int64: + x := int(reply) + if int64(x) != reply { + return 0, strconv.ErrRange + } + return x, nil + case uint: + n := int(reply) + if n < 0 { + return 0, strconv.ErrRange + } + return n, nil + case uint8: + return int(reply), nil + case uint16: + return int(reply), nil + case uint32: + n := int(reply) + if n < 0 { + return 0, strconv.ErrRange + } + return n, nil + case uint64: + n := int(reply) + if n < 0 { + return 0, strconv.ErrRange + } + return n, nil + case []byte: + data := string(reply) + if len(data) == 0 { + return 0, ErrNil + } + + n, err := strconv.ParseInt(data, 10, 0) + return int(n), err + case string: + if len(reply) == 0 { + return 0, ErrNil + } + + n, err := strconv.ParseInt(reply, 10, 0) + return int(n), err + case nil: + return 0, ErrNil + case error: + return 0, reply + } + return 0, fmt.Errorf("redis cluster: unexpected type for Int, got type %T", reply) +} + +func Int64(reply interface{}, err error) (int64, error) { + if err != nil { + return 0, err + } + switch reply := reply.(type) { + case int: + return int64(reply), nil + case int8: + return int64(reply), nil + case int16: + return int64(reply), nil + case int32: + return int64(reply), nil + case int64: + return reply, nil + case uint: + n := int64(reply) + if n < 0 { + return 0, strconv.ErrRange + } + return n, nil + case uint8: + return int64(reply), nil + case uint16: + return int64(reply), nil + case uint32: + return int64(reply), nil + case uint64: + n := int64(reply) + if n < 0 { + return 0, strconv.ErrRange + } + return n, nil + case []byte: + data := string(reply) + if len(data) == 0 { + return 0, ErrNil + } + + n, err := strconv.ParseInt(data, 10, 64) + return n, err + case string: + if len(reply) == 0 { + return 0, ErrNil + } + + n, err := strconv.ParseInt(reply, 10, 64) + return n, err + case nil: + return 0, ErrNil + case error: + return 0, reply + } + return 0, fmt.Errorf("redis cluster: unexpected type for Int64, got type %T", reply) +} + +func Uint64(reply interface{}, err error) (uint64, error) { + if err != nil { + return 0, err + } + switch reply := reply.(type) { + case uint: + return uint64(reply), nil + case uint8: + return uint64(reply), nil + case uint16: + return uint64(reply), nil + case uint32: + return uint64(reply), nil + case uint64: + return reply, nil + case int: + if reply < 0 { + return 0, ErrNegativeInt + } + return uint64(reply), nil + case int8: + if reply < 0 { + return 0, ErrNegativeInt + } + return uint64(reply), nil + case int16: + if reply < 0 { + return 0, ErrNegativeInt + } + return uint64(reply), nil + case int32: + if reply < 0 { + return 0, ErrNegativeInt + } + return uint64(reply), nil + case int64: + if reply < 0 { + return 0, ErrNegativeInt + } + return uint64(reply), nil + case []byte: + data := string(reply) + if len(data) == 0 { + return 0, ErrNil + } + + n, err := strconv.ParseUint(data, 10, 64) + return n, err + case string: + if len(reply) == 0 { + return 0, ErrNil + } + + n, err := strconv.ParseUint(reply, 10, 64) + return n, err + case nil: + return 0, ErrNil + case error: + return 0, reply + } + return 0, fmt.Errorf("redis cluster: unexpected type for Uint64, got type %T", reply) +} + +func Float64(reply interface{}, err error) (float64, error) { + if err != nil { + return 0, err + } + + var value float64 + err = nil + switch v := reply.(type) { + case float32: + value = float64(v) + case float64: + value = v + case int: + value = float64(v) + case int8: + value = float64(v) + case int16: + value = float64(v) + case int32: + value = float64(v) + case int64: + value = float64(v) + case uint: + value = float64(v) + case uint8: + value = float64(v) + case uint16: + value = float64(v) + case uint32: + value = float64(v) + case uint64: + value = float64(v) + case []byte: + data := string(v) + if len(data) == 0 { + return 0, ErrNil + } + value, err = strconv.ParseFloat(string(v), 64) + case string: + if len(v) == 0 { + return 0, ErrNil + } + value, err = strconv.ParseFloat(v, 64) + case nil: + err = ErrNil + case error: + err = v + default: + err = fmt.Errorf("redis cluster: unexpected type for Float64, got type %T", v) + } + + return value, err +} + +func Bool(reply interface{}, err error) (bool, error) { + if err != nil { + return false, err + } + switch reply := reply.(type) { + case bool: + return reply, nil + case int64: + return reply != 0, nil + case []byte: + data := string(reply) + if len(data) == 0 { + return false, ErrNil + } + + return strconv.ParseBool(data) + case string: + if len(reply) == 0 { + return false, ErrNil + } + + return strconv.ParseBool(reply) + case nil: + return false, ErrNil + case error: + return false, reply + } + return false, fmt.Errorf("redis cluster: unexpected type for Bool, got type %T", reply) +} + +func Bytes(reply interface{}, err error) ([]byte, error) { + if err != nil { + return nil, err + } + switch reply := reply.(type) { + case []byte: + if len(reply) == 0 { + return nil, ErrNil + } + return reply, nil + case string: + data := []byte(reply) + if len(data) == 0 { + return nil, ErrNil + } + return data, nil + case nil: + return nil, ErrNil + case error: + return nil, reply + } + return nil, fmt.Errorf("redis cluster: unexpected type for Bytes, got type %T", reply) +} + +func String(reply interface{}, err error) (string, error) { + if err != nil { + return "", err + } + + value := "" + err = nil + switch v := reply.(type) { + case string: + if len(v) == 0 { + return "", ErrNil + } + + value = v + case []byte: + if len(v) == 0 { + return "", ErrNil + } + + value = string(v) + case int: + value = strconv.FormatInt(int64(v), 10) + case int8: + value = strconv.FormatInt(int64(v), 10) + case int16: + value = strconv.FormatInt(int64(v), 10) + case int32: + value = strconv.FormatInt(int64(v), 10) + case int64: + value = strconv.FormatInt(v, 10) + case uint: + value = strconv.FormatUint(uint64(v), 10) + case uint8: + value = strconv.FormatUint(uint64(v), 10) + case uint16: + value = strconv.FormatUint(uint64(v), 10) + case uint32: + value = strconv.FormatUint(uint64(v), 10) + case uint64: + value = strconv.FormatUint(v, 10) + case float32: + value = strconv.FormatFloat(float64(v), 'f', -1, 32) + case float64: + value = strconv.FormatFloat(v, 'f', -1, 64) + case bool: + value = strconv.FormatBool(v) + case nil: + err = ErrNil + case error: + err = v + default: + err = fmt.Errorf("redis cluster: unexpected type for String, got type %T", v) + } + + return value, err +} + +func Strings(reply interface{}, err error) ([]string, error) { + if err != nil { + return nil, err + } + switch reply := reply.(type) { + case []interface{}: + result := make([]string, len(reply)) + for i := range reply { + if reply[i] == nil { + continue + } + switch subReply := reply[i].(type) { + case string: + result[i] = subReply + case []byte: + result[i] = string(subReply) + default: + return nil, fmt.Errorf("redis cluster: unexpected element type for String, got type %T", reply[i]) + } + } + return result, nil + case []string: + return reply, nil + case nil: + return nil, ErrNil + case error: + return nil, reply + } + return nil, fmt.Errorf("redis cluster: unexpected type for Strings, got type %T", reply) +} + +func Values(reply interface{}, err error) ([]interface{}, error) { + if err != nil { + return nil, err + } + switch reply := reply.(type) { + case []interface{}: + return reply, nil + case nil: + return nil, ErrNil + case error: + return nil, reply + } + return nil, fmt.Errorf("redis cluster: unexpected type for Values, got type %T", reply) +} diff --git a/super_cloud_issuance/utils/cache/cache/cache.go b/super_cloud_issuance/utils/cache/cache/cache.go new file mode 100644 index 0000000..e43c5f0 --- /dev/null +++ b/super_cloud_issuance/utils/cache/cache/cache.go @@ -0,0 +1,107 @@ +package cache + +import ( + "fmt" + "time" +) + +var c Cache + +type Cache interface { + // get cached value by key. + Get(key string) interface{} + // GetMulti is a batch version of Get. + GetMulti(keys []string) []interface{} + // set cached value with key and expire time. + Put(key string, val interface{}, timeout time.Duration) error + // delete cached value by key. + Delete(key string) error + // increase cached int value by key, as a counter. + Incr(key string) error + // decrease cached int value by key, as a counter. + Decr(key string) error + // check if cached value exists or not. + IsExist(key string) bool + // clear all cache. + ClearAll() error + // start gc routine based on config string settings. + StartAndGC(config string) error +} + +// Instance is a function create a new Cache Instance +type Instance func() Cache + +var adapters = make(map[string]Instance) + +// Register makes a cache adapter available by the adapter name. +// If Register is called twice with the same name or if driver is nil, +// it panics. +func Register(name string, adapter Instance) { + if adapter == nil { + panic("cache: Register adapter is nil") + } + if _, ok := adapters[name]; ok { + panic("cache: Register called twice for adapter " + name) + } + adapters[name] = adapter +} + +// NewCache Create a new cache driver by adapter name and config string. +// config need to be correct JSON as string: {"interval":360}. +// it will start gc automatically. +func NewCache(adapterName, config string) (adapter Cache, err error) { + instanceFunc, ok := adapters[adapterName] + if !ok { + err = fmt.Errorf("cache: unknown adapter name %q (forgot to import?)", adapterName) + return + } + adapter = instanceFunc() + err = adapter.StartAndGC(config) + if err != nil { + adapter = nil + } + return +} + +func InitCache(adapterName, config string) (err error) { + instanceFunc, ok := adapters[adapterName] + if !ok { + err = fmt.Errorf("cache: unknown adapter name %q (forgot to import?)", adapterName) + return + } + c = instanceFunc() + err = c.StartAndGC(config) + if err != nil { + c = nil + } + return +} + +func Get(key string) interface{} { + return c.Get(key) +} + +func GetMulti(keys []string) []interface{} { + return c.GetMulti(keys) +} +func Put(key string, val interface{}, ttl time.Duration) error { + return c.Put(key, val, ttl) +} +func Delete(key string) error { + return c.Delete(key) +} +func Incr(key string) error { + return c.Incr(key) +} +func Decr(key string) error { + return c.Decr(key) +} +func IsExist(key string) bool { + return c.IsExist(key) +} +func ClearAll() error { + return c.ClearAll() +} +func StartAndGC(cfg string) error { + return c.StartAndGC(cfg) +} diff --git a/super_cloud_issuance/utils/cache/cache/conv.go b/super_cloud_issuance/utils/cache/cache/conv.go new file mode 100644 index 0000000..6b700ae --- /dev/null +++ b/super_cloud_issuance/utils/cache/cache/conv.go @@ -0,0 +1,86 @@ +package cache + +import ( + "fmt" + "strconv" +) + +// GetString convert interface to string. +func GetString(v interface{}) string { + switch result := v.(type) { + case string: + return result + case []byte: + return string(result) + default: + if v != nil { + return fmt.Sprint(result) + } + } + return "" +} + +// GetInt convert interface to int. +func GetInt(v interface{}) int { + switch result := v.(type) { + case int: + return result + case int32: + return int(result) + case int64: + return int(result) + default: + if d := GetString(v); d != "" { + value, _ := strconv.Atoi(d) + return value + } + } + return 0 +} + +// GetInt64 convert interface to int64. +func GetInt64(v interface{}) int64 { + switch result := v.(type) { + case int: + return int64(result) + case int32: + return int64(result) + case int64: + return result + default: + + if d := GetString(v); d != "" { + value, _ := strconv.ParseInt(d, 10, 64) + return value + } + } + return 0 +} + +// GetFloat64 convert interface to float64. +func GetFloat64(v interface{}) float64 { + switch result := v.(type) { + case float64: + return result + default: + if d := GetString(v); d != "" { + value, _ := strconv.ParseFloat(d, 64) + return value + } + } + return 0 +} + +// GetBool convert interface to bool. +func GetBool(v interface{}) bool { + switch result := v.(type) { + case bool: + return result + default: + if d := GetString(v); d != "" { + value, _ := strconv.ParseBool(d) + return value + } + } + return false +} diff --git a/super_cloud_issuance/utils/cache/cache/file.go b/super_cloud_issuance/utils/cache/cache/file.go new file mode 100644 index 0000000..5c4e366 --- /dev/null +++ b/super_cloud_issuance/utils/cache/cache/file.go @@ -0,0 +1,241 @@ +package cache + +import ( + "bytes" + "crypto/md5" + "encoding/gob" + "encoding/hex" + "encoding/json" + "fmt" + "io" + "io/ioutil" + "os" + "path/filepath" + "reflect" + "strconv" + "time" +) + +// FileCacheItem is basic unit of file cache adapter. +// it contains data and expire time. +type FileCacheItem struct { + Data interface{} + LastAccess time.Time + Expired time.Time +} + +// FileCache Config +var ( + FileCachePath = "cache" // cache directory + FileCacheFileSuffix = ".bin" // cache file suffix + FileCacheDirectoryLevel = 2 // cache file deep level if auto generated cache files. + FileCacheEmbedExpiry time.Duration // cache expire time, default is no expire forever. +) + +// FileCache is cache adapter for file storage. +type FileCache struct { + CachePath string + FileSuffix string + DirectoryLevel int + EmbedExpiry int +} + +// NewFileCache Create new file cache with no config. +// the level and expiry need set in method StartAndGC as config string. +func NewFileCache() Cache { + // return &FileCache{CachePath:FileCachePath, FileSuffix:FileCacheFileSuffix} + return &FileCache{} +} + +// StartAndGC will start and begin gc for file cache. +// the config need to be like {CachePath:"/cache","FileSuffix":".bin","DirectoryLevel":2,"EmbedExpiry":0} +func (fc *FileCache) StartAndGC(config string) error { + + var cfg map[string]string + json.Unmarshal([]byte(config), &cfg) + if _, ok := cfg["CachePath"]; !ok { + cfg["CachePath"] = FileCachePath + } + if _, ok := cfg["FileSuffix"]; !ok { + cfg["FileSuffix"] = FileCacheFileSuffix + } + if _, ok := cfg["DirectoryLevel"]; !ok { + cfg["DirectoryLevel"] = strconv.Itoa(FileCacheDirectoryLevel) + } + if _, ok := cfg["EmbedExpiry"]; !ok { + cfg["EmbedExpiry"] = strconv.FormatInt(int64(FileCacheEmbedExpiry.Seconds()), 10) + } + fc.CachePath = cfg["CachePath"] + fc.FileSuffix = cfg["FileSuffix"] + fc.DirectoryLevel, _ = strconv.Atoi(cfg["DirectoryLevel"]) + fc.EmbedExpiry, _ = strconv.Atoi(cfg["EmbedExpiry"]) + + fc.Init() + return nil +} + +// Init will make new dir for file cache if not exist. +func (fc *FileCache) Init() { + if ok, _ := exists(fc.CachePath); !ok { // todo : error handle + _ = os.MkdirAll(fc.CachePath, os.ModePerm) // todo : error handle + } +} + +// get cached file name. it's md5 encoded. +func (fc *FileCache) getCacheFileName(key string) string { + m := md5.New() + io.WriteString(m, key) + keyMd5 := hex.EncodeToString(m.Sum(nil)) + cachePath := fc.CachePath + switch fc.DirectoryLevel { + case 2: + cachePath = filepath.Join(cachePath, keyMd5[0:2], keyMd5[2:4]) + case 1: + cachePath = filepath.Join(cachePath, keyMd5[0:2]) + } + + if ok, _ := exists(cachePath); !ok { // todo : error handle + _ = os.MkdirAll(cachePath, os.ModePerm) // todo : error handle + } + + return filepath.Join(cachePath, fmt.Sprintf("%s%s", keyMd5, fc.FileSuffix)) +} + +// Get value from file cache. +// if non-exist or expired, return empty string. +func (fc *FileCache) Get(key string) interface{} { + fileData, err := FileGetContents(fc.getCacheFileName(key)) + if err != nil { + return "" + } + var to FileCacheItem + GobDecode(fileData, &to) + if to.Expired.Before(time.Now()) { + return "" + } + return to.Data +} + +// GetMulti gets values from file cache. +// if non-exist or expired, return empty string. +func (fc *FileCache) GetMulti(keys []string) []interface{} { + var rc []interface{} + for _, key := range keys { + rc = append(rc, fc.Get(key)) + } + return rc +} + +// Put value into file cache. +// timeout means how long to keep this file, unit of ms. +// if timeout equals FileCacheEmbedExpiry(default is 0), cache this item forever. +func (fc *FileCache) Put(key string, val interface{}, timeout time.Duration) error { + gob.Register(val) + + item := FileCacheItem{Data: val} + if timeout == FileCacheEmbedExpiry { + item.Expired = time.Now().Add((86400 * 365 * 10) * time.Second) // ten years + } else { + item.Expired = time.Now().Add(timeout) + } + item.LastAccess = time.Now() + data, err := GobEncode(item) + if err != nil { + return err + } + return FilePutContents(fc.getCacheFileName(key), data) +} + +// Delete file cache value. +func (fc *FileCache) Delete(key string) error { + filename := fc.getCacheFileName(key) + if ok, _ := exists(filename); ok { + return os.Remove(filename) + } + return nil +} + +// Incr will increase cached int value. +// fc value is saving forever unless Delete. +func (fc *FileCache) Incr(key string) error { + data := fc.Get(key) + var incr int + if reflect.TypeOf(data).Name() != "int" { + incr = 0 + } else { + incr = data.(int) + 1 + } + fc.Put(key, incr, FileCacheEmbedExpiry) + return nil +} + +// Decr will decrease cached int value. +func (fc *FileCache) Decr(key string) error { + data := fc.Get(key) + var decr int + if reflect.TypeOf(data).Name() != "int" || data.(int)-1 <= 0 { + decr = 0 + } else { + decr = data.(int) - 1 + } + fc.Put(key, decr, FileCacheEmbedExpiry) + return nil +} + +// IsExist check value is exist. +func (fc *FileCache) IsExist(key string) bool { + ret, _ := exists(fc.getCacheFileName(key)) + return ret +} + +// ClearAll will clean cached files. +// not implemented. +func (fc *FileCache) ClearAll() error { + return nil +} + +// check file exist. +func exists(path string) (bool, error) { + _, err := os.Stat(path) + if err == nil { + return true, nil + } + if os.IsNotExist(err) { + return false, nil + } + return false, err +} + +// FileGetContents Get bytes to file. +// if non-exist, create this file. +func FileGetContents(filename string) (data []byte, e error) { + return ioutil.ReadFile(filename) +} + +// FilePutContents Put bytes to file. +// if non-exist, create this file. +func FilePutContents(filename string, content []byte) error { + return ioutil.WriteFile(filename, content, os.ModePerm) +} + +// GobEncode Gob encodes file cache item. +func GobEncode(data interface{}) ([]byte, error) { + buf := bytes.NewBuffer(nil) + enc := gob.NewEncoder(buf) + err := enc.Encode(data) + if err != nil { + return nil, err + } + return buf.Bytes(), err +} + +// GobDecode Gob decodes file cache item. +func GobDecode(data []byte, to *FileCacheItem) error { + buf := bytes.NewBuffer(data) + dec := gob.NewDecoder(buf) + return dec.Decode(&to) +} + +func init() { + Register("file", NewFileCache) +} diff --git a/super_cloud_issuance/utils/cache/cache/memory.go b/super_cloud_issuance/utils/cache/cache/memory.go new file mode 100644 index 0000000..0cc5015 --- /dev/null +++ b/super_cloud_issuance/utils/cache/cache/memory.go @@ -0,0 +1,239 @@ +package cache + +import ( + "encoding/json" + "errors" + "sync" + "time" +) + +var ( + // DefaultEvery means the clock time of recycling the expired cache items in memory. + DefaultEvery = 60 // 1 minute +) + +// MemoryItem store memory cache item. +type MemoryItem struct { + val interface{} + createdTime time.Time + lifespan time.Duration +} + +func (mi *MemoryItem) isExpire() bool { + // 0 means forever + if mi.lifespan == 0 { + return false + } + return time.Now().Sub(mi.createdTime) > mi.lifespan +} + +// MemoryCache is Memory cache adapter. +// it contains a RW locker for safe map storage. +type MemoryCache struct { + sync.RWMutex + dur time.Duration + items map[string]*MemoryItem + Every int // run an expiration check Every clock time +} + +// NewMemoryCache returns a new MemoryCache. +func NewMemoryCache() Cache { + cache := MemoryCache{items: make(map[string]*MemoryItem)} + return &cache +} + +// Get cache from memory. +// if non-existed or expired, return nil. +func (bc *MemoryCache) Get(name string) interface{} { + bc.RLock() + defer bc.RUnlock() + if itm, ok := bc.items[name]; ok { + if itm.isExpire() { + return nil + } + return itm.val + } + return nil +} + +// GetMulti gets caches from memory. +// if non-existed or expired, return nil. +func (bc *MemoryCache) GetMulti(names []string) []interface{} { + var rc []interface{} + for _, name := range names { + rc = append(rc, bc.Get(name)) + } + return rc +} + +// Put cache to memory. +// if lifespan is 0, it will be forever till restart. +func (bc *MemoryCache) Put(name string, value interface{}, lifespan time.Duration) error { + bc.Lock() + defer bc.Unlock() + bc.items[name] = &MemoryItem{ + val: value, + createdTime: time.Now(), + lifespan: lifespan, + } + return nil +} + +// Delete cache in memory. +func (bc *MemoryCache) Delete(name string) error { + bc.Lock() + defer bc.Unlock() + if _, ok := bc.items[name]; !ok { + return errors.New("key not exist") + } + delete(bc.items, name) + if _, ok := bc.items[name]; ok { + return errors.New("delete key error") + } + return nil +} + +// Incr increase cache counter in memory. +// it supports int,int32,int64,uint,uint32,uint64. +func (bc *MemoryCache) Incr(key string) error { + bc.RLock() + defer bc.RUnlock() + itm, ok := bc.items[key] + if !ok { + return errors.New("key not exist") + } + switch itm.val.(type) { + case int: + itm.val = itm.val.(int) + 1 + case int32: + itm.val = itm.val.(int32) + 1 + case int64: + itm.val = itm.val.(int64) + 1 + case uint: + itm.val = itm.val.(uint) + 1 + case uint32: + itm.val = itm.val.(uint32) + 1 + case uint64: + itm.val = itm.val.(uint64) + 1 + default: + return errors.New("item val is not (u)int (u)int32 (u)int64") + } + return nil +} + +// Decr decrease counter in memory. +func (bc *MemoryCache) Decr(key string) error { + bc.RLock() + defer bc.RUnlock() + itm, ok := bc.items[key] + if !ok { + return errors.New("key not exist") + } + switch itm.val.(type) { + case int: + itm.val = itm.val.(int) - 1 + case int64: + itm.val = itm.val.(int64) - 1 + case int32: + itm.val = itm.val.(int32) - 1 + case uint: + if itm.val.(uint) > 0 { + itm.val = itm.val.(uint) - 1 + } else { + return errors.New("item val is less than 0") + } + case uint32: + if itm.val.(uint32) > 0 { + itm.val = itm.val.(uint32) - 1 + } else { + return errors.New("item val is less than 0") + } + case uint64: + if itm.val.(uint64) > 0 { + itm.val = itm.val.(uint64) - 1 + } else { + return errors.New("item val is less than 0") + } + default: + return errors.New("item val is not int int64 int32") + } + return nil +} + +// IsExist check cache exist in memory. +func (bc *MemoryCache) IsExist(name string) bool { + bc.RLock() + defer bc.RUnlock() + if v, ok := bc.items[name]; ok { + return !v.isExpire() + } + return false +} + +// ClearAll will delete all cache in memory. +func (bc *MemoryCache) ClearAll() error { + bc.Lock() + defer bc.Unlock() + bc.items = make(map[string]*MemoryItem) + return nil +} + +// StartAndGC start memory cache. it will check expiration in every clock time. +func (bc *MemoryCache) StartAndGC(config string) error { + var cf map[string]int + json.Unmarshal([]byte(config), &cf) + if _, ok := cf["interval"]; !ok { + cf = make(map[string]int) + cf["interval"] = DefaultEvery + } + dur := time.Duration(cf["interval"]) * time.Second + bc.Every = cf["interval"] + bc.dur = dur + go bc.vacuum() + return nil +} + +// check expiration. +func (bc *MemoryCache) vacuum() { + bc.RLock() + every := bc.Every + bc.RUnlock() + + if every < 1 { + return + } + for { + <-time.After(bc.dur) + if bc.items == nil { + return + } + if keys := bc.expiredKeys(); len(keys) != 0 { + bc.clearItems(keys) + } + } +} + +// expiredKeys returns key list which are expired. +func (bc *MemoryCache) expiredKeys() (keys []string) { + bc.RLock() + defer bc.RUnlock() + for key, itm := range bc.items { + if itm.isExpire() { + keys = append(keys, key) + } + } + return +} + +// clearItems removes all the items which key in keys. +func (bc *MemoryCache) clearItems(keys []string) { + bc.Lock() + defer bc.Unlock() + for _, key := range keys { + delete(bc.items, key) + } +} + +func init() { + Register("memory", NewMemoryCache) +} diff --git a/super_cloud_issuance/utils/cache/redis.go b/super_cloud_issuance/utils/cache/redis.go new file mode 100644 index 0000000..3c4b914 --- /dev/null +++ b/super_cloud_issuance/utils/cache/redis.go @@ -0,0 +1,408 @@ +package cache + +import ( + "encoding/json" + "errors" + "log" + "strings" + "time" + + redigo "github.com/gomodule/redigo/redis" +) + +// configuration +type Config struct { + Server string + Password string + MaxIdle int // Maximum number of idle connections in the pool. + + // Maximum number of connections allocated by the pool at a given time. + // When zero, there is no limit on the number of connections in the pool. + MaxActive int + + // Close connections after remaining idle for this duration. If the value + // is zero, then idle connections are not closed. Applications should set + // the timeout to a value less than the server's timeout. + IdleTimeout time.Duration + + // If Wait is true and the pool is at the MaxActive limit, then Get() waits + // for a connection to be returned to the pool before returning. + Wait bool + KeyPrefix string // prefix to all keys; example is "dev environment name" + KeyDelimiter string // delimiter to be used while appending keys; example is ":" + KeyPlaceholder string // placeholder to be parsed using given arguments to obtain a final key; example is "?" +} + +var pool *redigo.Pool +var conf *Config + +func NewRedis(addr string) { + if addr == "" { + panic("\nredis connect string cannot be empty\n") + } + pool = &redigo.Pool{ + MaxIdle: redisMaxIdleConn, + IdleTimeout: redisIdleTTL, + MaxActive: redisMaxActive, + // MaxConnLifetime: redisDialTTL, + Wait: true, + Dial: func() (redigo.Conn, error) { + c, err := redigo.Dial("tcp", addr, + redigo.DialConnectTimeout(redisDialTTL), + redigo.DialReadTimeout(redisReadTTL), + redigo.DialWriteTimeout(redisWriteTTL), + ) + if err != nil { + log.Println("Redis Dial failed: ", err) + return nil, err + } + return c, err + }, + TestOnBorrow: func(c redigo.Conn, t time.Time) error { + _, err := c.Do("PING") + if err != nil { + log.Println("Unable to ping to redis server:", err) + } + return err + }, + } + conn := pool.Get() + defer conn.Close() + if conn.Err() != nil { + println("\nredis connect " + addr + " error: " + conn.Err().Error()) + } else { + println("\nredis connect " + addr + " success!\n") + } +} + +func Do(cmd string, args ...interface{}) (reply interface{}, err error) { + conn := pool.Get() + defer conn.Close() + return conn.Do(cmd, args...) +} + +func GetPool() *redigo.Pool { + return pool +} + +func ParseKey(key string, vars []string) (string, error) { + arr := strings.Split(key, conf.KeyPlaceholder) + actualKey := "" + if len(arr) != len(vars)+1 { + return "", errors.New("redis/connection.go: Insufficient arguments to parse key") + } else { + for index, val := range arr { + if index == 0 { + actualKey = arr[index] + } else { + actualKey += vars[index-1] + val + } + } + } + return getPrefixedKey(actualKey), nil +} + +func getPrefixedKey(key string) string { + return conf.KeyPrefix + conf.KeyDelimiter + key +} +func StripEnvKey(key string) string { + return strings.TrimLeft(key, conf.KeyPrefix+conf.KeyDelimiter) +} +func SplitKey(key string) []string { + return strings.Split(key, conf.KeyDelimiter) +} +func Expire(key string, ttl int) (interface{}, error) { + return Do("EXPIRE", key, ttl) +} +func Persist(key string) (interface{}, error) { + return Do("PERSIST", key) +} + +func Del(key string) (interface{}, error) { + return Do("DEL", key) +} +func Set(key string, data interface{}) (interface{}, error) { + // set + return Do("SET", key, data) +} +func SetNX(key string, data interface{}) (interface{}, error) { + return Do("SETNX", key, data) +} +func SetEx(key string, data interface{}, ttl int) (interface{}, error) { + return Do("SETEX", key, ttl, data) +} + +func SetJson(key string, data interface{}, ttl int) bool { + c, err := json.Marshal(data) + if err != nil { + return false + } + if ttl < 1 { + _, err = Set(key, c) + } else { + _, err = SetEx(key, c, ttl) + } + if err != nil { + return false + } + return true +} + +func GetJson(key string, dst interface{}) error { + b, err := GetBytes(key) + if err != nil { + return err + } + if err = json.Unmarshal(b, dst); err != nil { + return err + } + return nil +} + +func Get(key string) (interface{}, error) { + // get + return Do("GET", key) +} +func GetTTL(key string) (time.Duration, error) { + ttl, err := redigo.Int64(Do("TTL", key)) + return time.Duration(ttl) * time.Second, err +} +func GetBytes(key string) ([]byte, error) { + return redigo.Bytes(Do("GET", key)) +} +func GetString(key string) (string, error) { + return redigo.String(Do("GET", key)) +} +func GetStringMap(key string) (map[string]string, error) { + return redigo.StringMap(Do("GET", key)) +} +func GetInt(key string) (int, error) { + return redigo.Int(Do("GET", key)) +} +func GetInt64(key string) (int64, error) { + return redigo.Int64(Do("GET", key)) +} +func GetStringLength(key string) (int, error) { + return redigo.Int(Do("STRLEN", key)) +} +func ZAdd(key string, score float64, data interface{}) (interface{}, error) { + return Do("ZADD", key, score, data) +} +func ZAddNX(key string, score float64, data interface{}) (interface{}, error) { + return Do("ZADD", key, "NX", score, data) +} +func ZRem(key string, data interface{}) (interface{}, error) { + return Do("ZREM", key, data) +} +func ZRange(key string, start int, end int, withScores bool) ([]interface{}, error) { + if withScores { + return redigo.Values(Do("ZRANGE", key, start, end, "WITHSCORES")) + } + return redigo.Values(Do("ZRANGE", key, start, end)) +} +func ZRemRangeByScore(key string, start int64, end int64) ([]interface{}, error) { + return redigo.Values(Do("ZREMRANGEBYSCORE", key, start, end)) +} +func ZCard(setName string) (int64, error) { + return redigo.Int64(Do("ZCARD", setName)) +} +func ZScan(setName string) (int64, error) { + return redigo.Int64(Do("ZCARD", setName)) +} +func SAdd(setName string, data interface{}) (interface{}, error) { + return Do("SADD", setName, data) +} +func SCard(setName string) (int64, error) { + return redigo.Int64(Do("SCARD", setName)) +} +func SIsMember(setName string, data interface{}) (bool, error) { + return redigo.Bool(Do("SISMEMBER", setName, data)) +} +func SMembers(setName string) ([]string, error) { + return redigo.Strings(Do("SMEMBERS", setName)) +} +func SRem(setName string, data interface{}) (interface{}, error) { + return Do("SREM", setName, data) +} +func HSet(key string, HKey string, data interface{}) (interface{}, error) { + return Do("HSET", key, HKey, data) +} + +func HGet(key string, HKey string) (interface{}, error) { + return Do("HGET", key, HKey) +} + +func HMGet(key string, hashKeys ...string) ([]interface{}, error) { + ret, err := Do("HMGET", key, hashKeys) + if err != nil { + return nil, err + } + reta, ok := ret.([]interface{}) + if !ok { + return nil, errors.New("result not an array") + } + return reta, nil +} + +func HMSet(key string, hashKeys []string, vals []interface{}) (interface{}, error) { + if len(hashKeys) == 0 || len(hashKeys) != len(vals) { + var ret interface{} + return ret, errors.New("bad length") + } + input := []interface{}{key} + for i, v := range hashKeys { + input = append(input, v, vals[i]) + } + return Do("HMSET", input...) +} + +func HGetString(key string, HKey string) (string, error) { + return redigo.String(Do("HGET", key, HKey)) +} +func HGetFloat(key string, HKey string) (float64, error) { + f, err := redigo.Float64(Do("HGET", key, HKey)) + return f, err +} +func HGetInt(key string, HKey string) (int, error) { + return redigo.Int(Do("HGET", key, HKey)) +} +func HGetInt64(key string, HKey string) (int64, error) { + return redigo.Int64(Do("HGET", key, HKey)) +} +func HGetBool(key string, HKey string) (bool, error) { + return redigo.Bool(Do("HGET", key, HKey)) +} +func HDel(key string, HKey string) (interface{}, error) { + return Do("HDEL", key, HKey) +} + +func HGetAll(key string) (map[string]interface{}, error) { + vals, err := redigo.Values(Do("HGETALL", key)) + if err != nil { + return nil, err + } + num := len(vals) / 2 + result := make(map[string]interface{}, num) + for i := 0; i < num; i++ { + key, _ := redigo.String(vals[2*i], nil) + result[key] = vals[2*i+1] + } + return result, nil +} + +func FlushAll() bool { + res, _ := redigo.String(Do("FLUSHALL")) + if res == "" { + return false + } + return true +} + +// NOTE: Use this in production environment with extreme care. +// Read more here:https://redigo.io/commands/keys +func Keys(pattern string) ([]string, error) { + return redigo.Strings(Do("KEYS", pattern)) +} + +func HKeys(key string) ([]string, error) { + return redigo.Strings(Do("HKEYS", key)) +} + +func Exists(key string) bool { + count, err := redigo.Int(Do("EXISTS", key)) + if count == 0 || err != nil { + return false + } + return true +} + +func Incr(key string) (int64, error) { + return redigo.Int64(Do("INCR", key)) +} + +func Decr(key string) (int64, error) { + return redigo.Int64(Do("DECR", key)) +} + +func IncrBy(key string, incBy int64) (int64, error) { + return redigo.Int64(Do("INCRBY", key, incBy)) +} + +func DecrBy(key string, decrBy int64) (int64, error) { + return redigo.Int64(Do("DECRBY", key)) +} + +func IncrByFloat(key string, incBy float64) (float64, error) { + return redigo.Float64(Do("INCRBYFLOAT", key, incBy)) +} + +func DecrByFloat(key string, decrBy float64) (float64, error) { + return redigo.Float64(Do("DECRBYFLOAT", key, decrBy)) +} + +// use for message queue +func LPush(key string, data interface{}) (interface{}, error) { + // set + return Do("LPUSH", key, data) +} + +func LPop(key string) (interface{}, error) { + return Do("LPOP", key) +} + +func LPopString(key string) (string, error) { + return redigo.String(Do("LPOP", key)) +} +func LPopFloat(key string) (float64, error) { + f, err := redigo.Float64(Do("LPOP", key)) + return f, err +} +func LPopInt(key string) (int, error) { + return redigo.Int(Do("LPOP", key)) +} +func LPopInt64(key string) (int64, error) { + return redigo.Int64(Do("LPOP", key)) +} + +func RPush(key string, data interface{}) (interface{}, error) { + // set + return Do("RPUSH", key, data) +} + +func RPop(key string) (interface{}, error) { + return Do("RPOP", key) +} + +func RPopString(key string) (string, error) { + return redigo.String(Do("RPOP", key)) +} +func RPopFloat(key string) (float64, error) { + f, err := redigo.Float64(Do("RPOP", key)) + return f, err +} +func RPopInt(key string) (int, error) { + return redigo.Int(Do("RPOP", key)) +} +func RPopInt64(key string) (int64, error) { + return redigo.Int64(Do("RPOP", key)) +} + +func Scan(cursor int64, pattern string, count int64) (int64, []string, error) { + var items []string + var newCursor int64 + + values, err := redigo.Values(Do("SCAN", cursor, "MATCH", pattern, "COUNT", count)) + if err != nil { + return 0, nil, err + } + values, err = redigo.Scan(values, &newCursor, &items) + if err != nil { + return 0, nil, err + } + return newCursor, items, nil +} + +func LPushMax(key string, data ...interface{}) (interface{}, error) { + // set + return Do("LPUSH", key, data) +} diff --git a/super_cloud_issuance/utils/cache/redis_cluster.go b/super_cloud_issuance/utils/cache/redis_cluster.go new file mode 100644 index 0000000..901f30c --- /dev/null +++ b/super_cloud_issuance/utils/cache/redis_cluster.go @@ -0,0 +1,622 @@ +package cache + +import ( + "strconv" + "time" + + "github.com/go-redis/redis" +) + +var pools *redis.ClusterClient + +func NewRedisCluster(addrs []string) error { + opt := &redis.ClusterOptions{ + Addrs: addrs, + PoolSize: redisPoolSize, + PoolTimeout: redisPoolTTL, + IdleTimeout: redisIdleTTL, + DialTimeout: redisDialTTL, + ReadTimeout: redisReadTTL, + WriteTimeout: redisWriteTTL, + } + pools = redis.NewClusterClient(opt) + if err := pools.Ping().Err(); err != nil { + return err + } + return nil +} + +func RCGet(key string) (interface{}, error) { + res, err := pools.Get(key).Result() + if err != nil { + return nil, convertError(err) + } + return []byte(res), nil +} +func RCSet(key string, value interface{}) error { + err := pools.Set(key, value, 0).Err() + return convertError(err) +} +func RCGetSet(key string, value interface{}) (interface{}, error) { + res, err := pools.GetSet(key, value).Result() + if err != nil { + return nil, convertError(err) + } + return []byte(res), nil +} +func RCSetNx(key string, value interface{}) (int64, error) { + res, err := pools.SetNX(key, value, 0).Result() + if err != nil { + return 0, convertError(err) + } + if res { + return 1, nil + } + return 0, nil +} +func RCSetEx(key string, value interface{}, timeout int64) error { + _, err := pools.Set(key, value, time.Duration(timeout)*time.Second).Result() + if err != nil { + return convertError(err) + } + return nil +} + +// nil表示成功,ErrNil表示数据库内已经存在这个key,其他表示数据库发生错误 +func RCSetNxEx(key string, value interface{}, timeout int64) error { + res, err := pools.SetNX(key, value, time.Duration(timeout)*time.Second).Result() + if err != nil { + return convertError(err) + } + if res { + return nil + } + return ErrNil +} +func RCMGet(keys ...string) ([]interface{}, error) { + res, err := pools.MGet(keys...).Result() + return res, convertError(err) +} + +// 为确保多个key映射到同一个slot,每个key最好加上hash tag,如:{test} +func RCMSet(kvs map[string]interface{}) error { + pairs := make([]string, 0, len(kvs)*2) + for k, v := range kvs { + val, err := String(v, nil) + if err != nil { + return err + } + pairs = append(pairs, k, val) + } + return convertError(pools.MSet(pairs).Err()) +} + +// 为确保多个key映射到同一个slot,每个key最好加上hash tag,如:{test} +func RCMSetNX(kvs map[string]interface{}) (bool, error) { + pairs := make([]string, 0, len(kvs)*2) + for k, v := range kvs { + val, err := String(v, nil) + if err != nil { + return false, err + } + pairs = append(pairs, k, val) + } + res, err := pools.MSetNX(pairs).Result() + return res, convertError(err) +} +func RCExpireAt(key string, timestamp int64) (int64, error) { + res, err := pools.ExpireAt(key, time.Unix(timestamp, 0)).Result() + if err != nil { + return 0, convertError(err) + } + if res { + return 1, nil + } + return 0, nil +} +func RCDel(keys ...string) (int64, error) { + args := make([]interface{}, 0, len(keys)) + for _, key := range keys { + args = append(args, key) + } + res, err := pools.Del(keys...).Result() + if err != nil { + return res, convertError(err) + } + return res, nil +} +func RCIncr(key string) (int64, error) { + res, err := pools.Incr(key).Result() + if err != nil { + return res, convertError(err) + } + return res, nil +} +func RCIncrBy(key string, delta int64) (int64, error) { + res, err := pools.IncrBy(key, delta).Result() + if err != nil { + return res, convertError(err) + } + return res, nil +} +func RCExpire(key string, duration int64) (int64, error) { + res, err := pools.Expire(key, time.Duration(duration)*time.Second).Result() + if err != nil { + return 0, convertError(err) + } + if res { + return 1, nil + } + return 0, nil +} +func RCExists(key string) (bool, error) { + res, err := pools.Exists(key).Result() + if err != nil { + return false, convertError(err) + } + if res > 0 { + return true, nil + } + return false, nil +} +func RCHGet(key string, field string) (interface{}, error) { + res, err := pools.HGet(key, field).Result() + if err != nil { + return nil, convertError(err) + } + return []byte(res), nil +} +func RCHLen(key string) (int64, error) { + res, err := pools.HLen(key).Result() + if err != nil { + return res, convertError(err) + } + return res, nil +} +func RCHSet(key string, field string, val interface{}) error { + value, err := String(val, nil) + if err != nil && err != ErrNil { + return err + } + _, err = pools.HSet(key, field, value).Result() + if err != nil { + return convertError(err) + } + return nil +} +func RCHDel(key string, fields ...string) (int64, error) { + args := make([]interface{}, 0, len(fields)+1) + args = append(args, key) + for _, field := range fields { + args = append(args, field) + } + res, err := pools.HDel(key, fields...).Result() + if err != nil { + return 0, convertError(err) + } + return res, nil +} + +func RCHMGet(key string, fields ...string) (interface{}, error) { + args := make([]interface{}, 0, len(fields)+1) + args = append(args, key) + for _, field := range fields { + args = append(args, field) + } + if len(fields) == 0 { + return nil, ErrNil + } + res, err := pools.HMGet(key, fields...).Result() + if err != nil { + return nil, convertError(err) + } + return res, nil +} +func RCHMSet(key string, kvs ...interface{}) error { + if len(kvs) == 0 { + return nil + } + if len(kvs)%2 != 0 { + return ErrWrongArgsNum + } + var err error + v := map[string]interface{}{} // todo change + v["field"], err = String(kvs[0], nil) + if err != nil && err != ErrNil { + return err + } + v["value"], err = String(kvs[1], nil) + if err != nil && err != ErrNil { + return err + } + pairs := make([]string, 0, len(kvs)-2) + if len(kvs) > 2 { + for _, kv := range kvs[2:] { + kvString, err := String(kv, nil) + if err != nil && err != ErrNil { + return err + } + pairs = append(pairs, kvString) + } + } + v["paris"] = pairs + _, err = pools.HMSet(key, v).Result() + if err != nil { + return convertError(err) + } + return nil +} + +func RCHKeys(key string) ([]string, error) { + res, err := pools.HKeys(key).Result() + if err != nil { + return res, convertError(err) + } + return res, nil +} +func RCHVals(key string) ([]interface{}, error) { + res, err := pools.HVals(key).Result() + if err != nil { + return nil, convertError(err) + } + rs := make([]interface{}, 0, len(res)) + for _, res := range res { + rs = append(rs, res) + } + return rs, nil +} +func RCHGetAll(key string) (map[string]string, error) { + vals, err := pools.HGetAll(key).Result() + if err != nil { + return nil, convertError(err) + } + return vals, nil +} +func RCHIncrBy(key, field string, delta int64) (int64, error) { + res, err := pools.HIncrBy(key, field, delta).Result() + if err != nil { + return res, convertError(err) + } + return res, nil +} +func RCZAdd(key string, kvs ...interface{}) (int64, error) { + args := make([]interface{}, 0, len(kvs)+1) + args = append(args, key) + args = append(args, kvs...) + if len(kvs) == 0 { + return 0, nil + } + if len(kvs)%2 != 0 { + return 0, ErrWrongArgsNum + } + zs := make([]redis.Z, len(kvs)/2) + for i := 0; i < len(kvs); i += 2 { + idx := i / 2 + score, err := Float64(kvs[i], nil) + if err != nil && err != ErrNil { + return 0, err + } + zs[idx].Score = score + zs[idx].Member = kvs[i+1] + } + res, err := pools.ZAdd(key, zs...).Result() + if err != nil { + return res, convertError(err) + } + return res, nil +} +func RCZRem(key string, members ...string) (int64, error) { + args := make([]interface{}, 0, len(members)) + args = append(args, key) + for _, member := range members { + args = append(args, member) + } + res, err := pools.ZRem(key, members).Result() + if err != nil { + return res, convertError(err) + } + return res, err +} + +func RCZRange(key string, min, max int64, withScores bool) (interface{}, error) { + res := make([]interface{}, 0) + if withScores { + zs, err := pools.ZRangeWithScores(key, min, max).Result() + if err != nil { + return nil, convertError(err) + } + for _, z := range zs { + res = append(res, z.Member, strconv.FormatFloat(z.Score, 'f', -1, 64)) + } + } else { + ms, err := pools.ZRange(key, min, max).Result() + if err != nil { + return nil, convertError(err) + } + for _, m := range ms { + res = append(res, m) + } + } + return res, nil +} +func RCZRangeByScoreWithScore(key string, min, max int64) (map[string]int64, error) { + opt := new(redis.ZRangeBy) + opt.Min = strconv.FormatInt(int64(min), 10) + opt.Max = strconv.FormatInt(int64(max), 10) + opt.Count = -1 + opt.Offset = 0 + vals, err := pools.ZRangeByScoreWithScores(key, *opt).Result() + if err != nil { + return nil, convertError(err) + } + res := make(map[string]int64, len(vals)) + for _, val := range vals { + key, err := String(val.Member, nil) + if err != nil && err != ErrNil { + return nil, err + } + res[key] = int64(val.Score) + } + return res, nil +} +func RCLRange(key string, start, stop int64) (interface{}, error) { + res, err := pools.LRange(key, start, stop).Result() + if err != nil { + return nil, convertError(err) + } + return res, nil +} +func RCLSet(key string, index int, value interface{}) error { + err := pools.LSet(key, int64(index), value).Err() + return convertError(err) +} +func RCLLen(key string) (int64, error) { + res, err := pools.LLen(key).Result() + if err != nil { + return res, convertError(err) + } + return res, nil +} +func RCLRem(key string, count int, value interface{}) (int, error) { + val, _ := value.(string) + res, err := pools.LRem(key, int64(count), val).Result() + if err != nil { + return int(res), convertError(err) + } + return int(res), nil +} +func RCTTl(key string) (int64, error) { + duration, err := pools.TTL(key).Result() + if err != nil { + return int64(duration.Seconds()), convertError(err) + } + return int64(duration.Seconds()), nil +} +func RCLPop(key string) (interface{}, error) { + res, err := pools.LPop(key).Result() + if err != nil { + return nil, convertError(err) + } + return res, nil +} +func RCRPop(key string) (interface{}, error) { + res, err := pools.RPop(key).Result() + if err != nil { + return nil, convertError(err) + } + return res, nil +} +func RCBLPop(key string, timeout int) (interface{}, error) { + res, err := pools.BLPop(time.Duration(timeout)*time.Second, key).Result() + if err != nil { + // 兼容redis 2.x + if err == redis.Nil { + return nil, ErrNil + } + return nil, err + } + return res[1], nil +} +func RCBRPop(key string, timeout int) (interface{}, error) { + res, err := pools.BRPop(time.Duration(timeout)*time.Second, key).Result() + if err != nil { + // 兼容redis 2.x + if err == redis.Nil { + return nil, ErrNil + } + return nil, convertError(err) + } + return res[1], nil +} +func RCLPush(key string, value ...interface{}) error { + args := make([]interface{}, 0, len(value)+1) + args = append(args, key) + args = append(args, value...) + vals := make([]string, 0, len(value)) + for _, v := range value { + val, err := String(v, nil) + if err != nil && err != ErrNil { + return err + } + vals = append(vals, val) + } + _, err := pools.LPush(key, vals).Result() // todo ... + if err != nil { + return convertError(err) + } + return nil +} +func RCRPush(key string, value ...interface{}) error { + args := make([]interface{}, 0, len(value)+1) + args = append(args, key) + args = append(args, value...) + vals := make([]string, 0, len(value)) + for _, v := range value { + val, err := String(v, nil) + if err != nil && err != ErrNil { + if err == ErrNil { + continue + } + return err + } + if val == "" { + continue + } + vals = append(vals, val) + } + _, err := pools.RPush(key, vals).Result() // todo ... + if err != nil { + return convertError(err) + } + return nil +} + +// 为确保srcKey跟destKey映射到同一个slot,srcKey和destKey需要加上hash tag,如:{test} +func RCBRPopLPush(srcKey string, destKey string, timeout int) (interface{}, error) { + res, err := pools.BRPopLPush(srcKey, destKey, time.Duration(timeout)*time.Second).Result() + if err != nil { + return nil, convertError(err) + } + return res, nil +} + +// 为确保srcKey跟destKey映射到同一个slot,srcKey和destKey需要加上hash tag,如:{test} +func RCRPopLPush(srcKey string, destKey string) (interface{}, error) { + res, err := pools.RPopLPush(srcKey, destKey).Result() + if err != nil { + return nil, convertError(err) + } + return res, nil +} +func RCSAdd(key string, members ...interface{}) (int64, error) { + args := make([]interface{}, 0, len(members)+1) + args = append(args, key) + args = append(args, members...) + ms := make([]string, 0, len(members)) + for _, member := range members { + m, err := String(member, nil) + if err != nil && err != ErrNil { + return 0, err + } + ms = append(ms, m) + } + res, err := pools.SAdd(key, ms).Result() // todo ... + if err != nil { + return res, convertError(err) + } + return res, nil +} +func RCSPop(key string) ([]byte, error) { + res, err := pools.SPop(key).Result() + if err != nil { + return nil, convertError(err) + } + return []byte(res), nil +} +func RCSIsMember(key string, member interface{}) (bool, error) { + m, _ := member.(string) + res, err := pools.SIsMember(key, m).Result() + if err != nil { + return res, convertError(err) + } + return res, nil +} +func RCSRem(key string, members ...interface{}) (int64, error) { + args := make([]interface{}, 0, len(members)+1) + args = append(args, key) + args = append(args, members...) + ms := make([]string, 0, len(members)) + for _, member := range members { + m, err := String(member, nil) + if err != nil && err != ErrNil { + return 0, err + } + ms = append(ms, m) + } + res, err := pools.SRem(key, ms).Result() // todo ... + if err != nil { + return res, convertError(err) + } + return res, nil +} +func RCSMembers(key string) ([]string, error) { + res, err := pools.SMembers(key).Result() + if err != nil { + return nil, convertError(err) + } + return res, nil +} +func RCScriptLoad(luaScript string) (interface{}, error) { + res, err := pools.ScriptLoad(luaScript).Result() + if err != nil { + return nil, convertError(err) + } + return res, nil +} +func RCEvalSha(sha1 string, numberKeys int, keysArgs ...interface{}) (interface{}, error) { + vals := make([]interface{}, 0, len(keysArgs)+2) + vals = append(vals, sha1, numberKeys) + vals = append(vals, keysArgs...) + keys := make([]string, 0, numberKeys) + args := make([]string, 0, len(keysArgs)-numberKeys) + for i, value := range keysArgs { + val, err := String(value, nil) + if err != nil && err != ErrNil { + return nil, err + } + if i < numberKeys { + keys = append(keys, val) + } else { + args = append(args, val) + } + } + res, err := pools.EvalSha(sha1, keys, args).Result() + if err != nil { + return nil, convertError(err) + } + return res, nil +} +func RCEval(luaScript string, numberKeys int, keysArgs ...interface{}) (interface{}, error) { + vals := make([]interface{}, 0, len(keysArgs)+2) + vals = append(vals, luaScript, numberKeys) + vals = append(vals, keysArgs...) + keys := make([]string, 0, numberKeys) + args := make([]string, 0, len(keysArgs)-numberKeys) + for i, value := range keysArgs { + val, err := String(value, nil) + if err != nil && err != ErrNil { + return nil, err + } + if i < numberKeys { + keys = append(keys, val) + } else { + args = append(args, val) + } + } + res, err := pools.Eval(luaScript, keys, args).Result() + if err != nil { + return nil, convertError(err) + } + return res, nil +} +func RCGetBit(key string, offset int64) (int64, error) { + res, err := pools.GetBit(key, offset).Result() + if err != nil { + return res, convertError(err) + } + return res, nil +} +func RCSetBit(key string, offset uint32, value int) (int, error) { + res, err := pools.SetBit(key, int64(offset), value).Result() + return int(res), convertError(err) +} +func RCGetClient() *redis.ClusterClient { + return pools +} +func convertError(err error) error { + if err == redis.Nil { + // 为了兼容redis 2.x,这里不返回 ErrNil,ErrNil在调用redis_cluster_reply函数时才返回 + return nil + } + return err +} diff --git a/super_cloud_issuance/utils/cache/redis_pool.go b/super_cloud_issuance/utils/cache/redis_pool.go new file mode 100644 index 0000000..ca38b3f --- /dev/null +++ b/super_cloud_issuance/utils/cache/redis_pool.go @@ -0,0 +1,324 @@ +package cache + +import ( + "errors" + "log" + "strings" + "time" + + redigo "github.com/gomodule/redigo/redis" +) + +type RedisPool struct { + *redigo.Pool +} + +func NewRedisPool(cfg *Config) *RedisPool { + return &RedisPool{&redigo.Pool{ + MaxIdle: cfg.MaxIdle, + IdleTimeout: cfg.IdleTimeout, + MaxActive: cfg.MaxActive, + Wait: cfg.Wait, + Dial: func() (redigo.Conn, error) { + c, err := redigo.Dial("tcp", cfg.Server) + if err != nil { + log.Println("Redis Dial failed: ", err) + return nil, err + } + if cfg.Password != "" { + if _, err := c.Do("AUTH", cfg.Password); err != nil { + c.Close() + log.Println("Redis AUTH failed: ", err) + return nil, err + } + } + return c, err + }, + TestOnBorrow: func(c redigo.Conn, t time.Time) error { + _, err := c.Do("PING") + if err != nil { + log.Println("Unable to ping to redis server:", err) + } + return err + }, + }} +} + +func (p *RedisPool) Do(cmd string, args ...interface{}) (reply interface{}, err error) { + conn := pool.Get() + defer conn.Close() + return conn.Do(cmd, args...) +} + +func (p *RedisPool) GetPool() *redigo.Pool { + return pool +} + +func (p *RedisPool) ParseKey(key string, vars []string) (string, error) { + arr := strings.Split(key, conf.KeyPlaceholder) + actualKey := "" + if len(arr) != len(vars)+1 { + return "", errors.New("redis/connection.go: Insufficient arguments to parse key") + } else { + for index, val := range arr { + if index == 0 { + actualKey = arr[index] + } else { + actualKey += vars[index-1] + val + } + } + } + return getPrefixedKey(actualKey), nil +} + +func (p *RedisPool) getPrefixedKey(key string) string { + return conf.KeyPrefix + conf.KeyDelimiter + key +} +func (p *RedisPool) StripEnvKey(key string) string { + return strings.TrimLeft(key, conf.KeyPrefix+conf.KeyDelimiter) +} +func (p *RedisPool) SplitKey(key string) []string { + return strings.Split(key, conf.KeyDelimiter) +} +func (p *RedisPool) Expire(key string, ttl int) (interface{}, error) { + return Do("EXPIRE", key, ttl) +} +func (p *RedisPool) Persist(key string) (interface{}, error) { + return Do("PERSIST", key) +} + +func (p *RedisPool) Del(key string) (interface{}, error) { + return Do("DEL", key) +} +func (p *RedisPool) Set(key string, data interface{}) (interface{}, error) { + // set + return Do("SET", key, data) +} +func (p *RedisPool) SetNX(key string, data interface{}) (interface{}, error) { + return Do("SETNX", key, data) +} +func (p *RedisPool) SetEx(key string, data interface{}, ttl int) (interface{}, error) { + return Do("SETEX", key, ttl, data) +} +func (p *RedisPool) Get(key string) (interface{}, error) { + // get + return Do("GET", key) +} +func (p *RedisPool) GetStringMap(key string) (map[string]string, error) { + // get + return redigo.StringMap(Do("GET", key)) +} + +func (p *RedisPool) GetTTL(key string) (time.Duration, error) { + ttl, err := redigo.Int64(Do("TTL", key)) + return time.Duration(ttl) * time.Second, err +} +func (p *RedisPool) GetBytes(key string) ([]byte, error) { + return redigo.Bytes(Do("GET", key)) +} +func (p *RedisPool) GetString(key string) (string, error) { + return redigo.String(Do("GET", key)) +} +func (p *RedisPool) GetInt(key string) (int, error) { + return redigo.Int(Do("GET", key)) +} +func (p *RedisPool) GetStringLength(key string) (int, error) { + return redigo.Int(Do("STRLEN", key)) +} +func (p *RedisPool) ZAdd(key string, score float64, data interface{}) (interface{}, error) { + return Do("ZADD", key, score, data) +} +func (p *RedisPool) ZRem(key string, data interface{}) (interface{}, error) { + return Do("ZREM", key, data) +} +func (p *RedisPool) ZRange(key string, start int, end int, withScores bool) ([]interface{}, error) { + if withScores { + return redigo.Values(Do("ZRANGE", key, start, end, "WITHSCORES")) + } + return redigo.Values(Do("ZRANGE", key, start, end)) +} +func (p *RedisPool) SAdd(setName string, data interface{}) (interface{}, error) { + return Do("SADD", setName, data) +} +func (p *RedisPool) SCard(setName string) (int64, error) { + return redigo.Int64(Do("SCARD", setName)) +} +func (p *RedisPool) SIsMember(setName string, data interface{}) (bool, error) { + return redigo.Bool(Do("SISMEMBER", setName, data)) +} +func (p *RedisPool) SMembers(setName string) ([]string, error) { + return redigo.Strings(Do("SMEMBERS", setName)) +} +func (p *RedisPool) SRem(setName string, data interface{}) (interface{}, error) { + return Do("SREM", setName, data) +} +func (p *RedisPool) HSet(key string, HKey string, data interface{}) (interface{}, error) { + return Do("HSET", key, HKey, data) +} + +func (p *RedisPool) HGet(key string, HKey string) (interface{}, error) { + return Do("HGET", key, HKey) +} + +func (p *RedisPool) HMGet(key string, hashKeys ...string) ([]interface{}, error) { + ret, err := Do("HMGET", key, hashKeys) + if err != nil { + return nil, err + } + reta, ok := ret.([]interface{}) + if !ok { + return nil, errors.New("result not an array") + } + return reta, nil +} + +func (p *RedisPool) HMSet(key string, hashKeys []string, vals []interface{}) (interface{}, error) { + if len(hashKeys) == 0 || len(hashKeys) != len(vals) { + var ret interface{} + return ret, errors.New("bad length") + } + input := []interface{}{key} + for i, v := range hashKeys { + input = append(input, v, vals[i]) + } + return Do("HMSET", input...) +} + +func (p *RedisPool) HGetString(key string, HKey string) (string, error) { + return redigo.String(Do("HGET", key, HKey)) +} +func (p *RedisPool) HGetFloat(key string, HKey string) (float64, error) { + f, err := redigo.Float64(Do("HGET", key, HKey)) + return float64(f), err +} +func (p *RedisPool) HGetInt(key string, HKey string) (int, error) { + return redigo.Int(Do("HGET", key, HKey)) +} +func (p *RedisPool) HGetInt64(key string, HKey string) (int64, error) { + return redigo.Int64(Do("HGET", key, HKey)) +} +func (p *RedisPool) HGetBool(key string, HKey string) (bool, error) { + return redigo.Bool(Do("HGET", key, HKey)) +} +func (p *RedisPool) HDel(key string, HKey string) (interface{}, error) { + return Do("HDEL", key, HKey) +} +func (p *RedisPool) HGetAll(key string) (map[string]interface{}, error) { + vals, err := redigo.Values(Do("HGETALL", key)) + if err != nil { + return nil, err + } + num := len(vals) / 2 + result := make(map[string]interface{}, num) + for i := 0; i < num; i++ { + key, _ := redigo.String(vals[2*i], nil) + result[key] = vals[2*i+1] + } + return result, nil +} + +// NOTE: Use this in production environment with extreme care. +// Read more here:https://redigo.io/commands/keys +func (p *RedisPool) Keys(pattern string) ([]string, error) { + return redigo.Strings(Do("KEYS", pattern)) +} + +func (p *RedisPool) HKeys(key string) ([]string, error) { + return redigo.Strings(Do("HKEYS", key)) +} + +func (p *RedisPool) Exists(key string) (bool, error) { + count, err := redigo.Int(Do("EXISTS", key)) + if count == 0 { + return false, err + } else { + return true, err + } +} + +func (p *RedisPool) Incr(key string) (int64, error) { + return redigo.Int64(Do("INCR", key)) +} + +func (p *RedisPool) Decr(key string) (int64, error) { + return redigo.Int64(Do("DECR", key)) +} + +func (p *RedisPool) IncrBy(key string, incBy int64) (int64, error) { + return redigo.Int64(Do("INCRBY", key, incBy)) +} + +func (p *RedisPool) DecrBy(key string, decrBy int64) (int64, error) { + return redigo.Int64(Do("DECRBY", key)) +} + +func (p *RedisPool) IncrByFloat(key string, incBy float64) (float64, error) { + return redigo.Float64(Do("INCRBYFLOAT", key, incBy)) +} + +func (p *RedisPool) DecrByFloat(key string, decrBy float64) (float64, error) { + return redigo.Float64(Do("DECRBYFLOAT", key, decrBy)) +} + +// use for message queue +func (p *RedisPool) LPush(key string, data interface{}) (interface{}, error) { + // set + return Do("LPUSH", key, data) +} + +func (p *RedisPool) LPop(key string) (interface{}, error) { + return Do("LPOP", key) +} + +func (p *RedisPool) LPopString(key string) (string, error) { + return redigo.String(Do("LPOP", key)) +} +func (p *RedisPool) LPopFloat(key string) (float64, error) { + f, err := redigo.Float64(Do("LPOP", key)) + return float64(f), err +} +func (p *RedisPool) LPopInt(key string) (int, error) { + return redigo.Int(Do("LPOP", key)) +} +func (p *RedisPool) LPopInt64(key string) (int64, error) { + return redigo.Int64(Do("LPOP", key)) +} + +func (p *RedisPool) RPush(key string, data interface{}) (interface{}, error) { + // set + return Do("RPUSH", key, data) +} + +func (p *RedisPool) RPop(key string) (interface{}, error) { + return Do("RPOP", key) +} + +func (p *RedisPool) RPopString(key string) (string, error) { + return redigo.String(Do("RPOP", key)) +} +func (p *RedisPool) RPopFloat(key string) (float64, error) { + f, err := redigo.Float64(Do("RPOP", key)) + return float64(f), err +} +func (p *RedisPool) RPopInt(key string) (int, error) { + return redigo.Int(Do("RPOP", key)) +} +func (p *RedisPool) RPopInt64(key string) (int64, error) { + return redigo.Int64(Do("RPOP", key)) +} + +func (p *RedisPool) Scan(cursor int64, pattern string, count int64) (int64, []string, error) { + var items []string + var newCursor int64 + + values, err := redigo.Values(Do("SCAN", cursor, "MATCH", pattern, "COUNT", count)) + if err != nil { + return 0, nil, err + } + values, err = redigo.Scan(values, &newCursor, &items) + if err != nil { + return 0, nil, err + } + + return newCursor, items, nil +} diff --git a/super_cloud_issuance/utils/cache/redis_pool_cluster.go b/super_cloud_issuance/utils/cache/redis_pool_cluster.go new file mode 100644 index 0000000..cd1911b --- /dev/null +++ b/super_cloud_issuance/utils/cache/redis_pool_cluster.go @@ -0,0 +1,617 @@ +package cache + +import ( + "strconv" + "time" + + "github.com/go-redis/redis" +) + +type RedisClusterPool struct { + client *redis.ClusterClient +} + +func NewRedisClusterPool(addrs []string) (*RedisClusterPool, error) { + opt := &redis.ClusterOptions{ + Addrs: addrs, + PoolSize: 512, + PoolTimeout: 10 * time.Second, + IdleTimeout: 10 * time.Second, + DialTimeout: 10 * time.Second, + ReadTimeout: 3 * time.Second, + WriteTimeout: 3 * time.Second, + } + c := redis.NewClusterClient(opt) + if err := c.Ping().Err(); err != nil { + return nil, err + } + return &RedisClusterPool{client: c}, nil +} + +func (p *RedisClusterPool) Get(key string) (interface{}, error) { + res, err := p.client.Get(key).Result() + if err != nil { + return nil, convertError(err) + } + return []byte(res), nil +} +func (p *RedisClusterPool) Set(key string, value interface{}) error { + err := p.client.Set(key, value, 0).Err() + return convertError(err) +} +func (p *RedisClusterPool) GetSet(key string, value interface{}) (interface{}, error) { + res, err := p.client.GetSet(key, value).Result() + if err != nil { + return nil, convertError(err) + } + return []byte(res), nil +} +func (p *RedisClusterPool) SetNx(key string, value interface{}) (int64, error) { + res, err := p.client.SetNX(key, value, 0).Result() + if err != nil { + return 0, convertError(err) + } + if res { + return 1, nil + } + return 0, nil +} +func (p *RedisClusterPool) SetEx(key string, value interface{}, timeout int64) error { + _, err := p.client.Set(key, value, time.Duration(timeout)*time.Second).Result() + if err != nil { + return convertError(err) + } + return nil +} + +// nil表示成功,ErrNil表示数据库内已经存在这个key,其他表示数据库发生错误 +func (p *RedisClusterPool) SetNxEx(key string, value interface{}, timeout int64) error { + res, err := p.client.SetNX(key, value, time.Duration(timeout)*time.Second).Result() + if err != nil { + return convertError(err) + } + if res { + return nil + } + return ErrNil +} +func (p *RedisClusterPool) MGet(keys ...string) ([]interface{}, error) { + res, err := p.client.MGet(keys...).Result() + return res, convertError(err) +} + +// 为确保多个key映射到同一个slot,每个key最好加上hash tag,如:{test} +func (p *RedisClusterPool) MSet(kvs map[string]interface{}) error { + pairs := make([]string, 0, len(kvs)*2) + for k, v := range kvs { + val, err := String(v, nil) + if err != nil { + return err + } + pairs = append(pairs, k, val) + } + return convertError(p.client.MSet(pairs).Err()) +} + +// 为确保多个key映射到同一个slot,每个key最好加上hash tag,如:{test} +func (p *RedisClusterPool) MSetNX(kvs map[string]interface{}) (bool, error) { + pairs := make([]string, 0, len(kvs)*2) + for k, v := range kvs { + val, err := String(v, nil) + if err != nil { + return false, err + } + pairs = append(pairs, k, val) + } + res, err := p.client.MSetNX(pairs).Result() + return res, convertError(err) +} +func (p *RedisClusterPool) ExpireAt(key string, timestamp int64) (int64, error) { + res, err := p.client.ExpireAt(key, time.Unix(timestamp, 0)).Result() + if err != nil { + return 0, convertError(err) + } + if res { + return 1, nil + } + return 0, nil +} +func (p *RedisClusterPool) Del(keys ...string) (int64, error) { + args := make([]interface{}, 0, len(keys)) + for _, key := range keys { + args = append(args, key) + } + res, err := p.client.Del(keys...).Result() + if err != nil { + return res, convertError(err) + } + return res, nil +} +func (p *RedisClusterPool) Incr(key string) (int64, error) { + res, err := p.client.Incr(key).Result() + if err != nil { + return res, convertError(err) + } + return res, nil +} +func (p *RedisClusterPool) IncrBy(key string, delta int64) (int64, error) { + res, err := p.client.IncrBy(key, delta).Result() + if err != nil { + return res, convertError(err) + } + return res, nil +} +func (p *RedisClusterPool) Expire(key string, duration int64) (int64, error) { + res, err := p.client.Expire(key, time.Duration(duration)*time.Second).Result() + if err != nil { + return 0, convertError(err) + } + if res { + return 1, nil + } + return 0, nil +} +func (p *RedisClusterPool) Exists(key string) (bool, error) { // todo (bool, error) + res, err := p.client.Exists(key).Result() + if err != nil { + return false, convertError(err) + } + if res > 0 { + return true, nil + } + return false, nil +} +func (p *RedisClusterPool) HGet(key string, field string) (interface{}, error) { + res, err := p.client.HGet(key, field).Result() + if err != nil { + return nil, convertError(err) + } + return []byte(res), nil +} +func (p *RedisClusterPool) HLen(key string) (int64, error) { + res, err := p.client.HLen(key).Result() + if err != nil { + return res, convertError(err) + } + return res, nil +} +func (p *RedisClusterPool) HSet(key string, field string, val interface{}) error { + value, err := String(val, nil) + if err != nil && err != ErrNil { + return err + } + _, err = p.client.HSet(key, field, value).Result() + if err != nil { + return convertError(err) + } + return nil +} +func (p *RedisClusterPool) HDel(key string, fields ...string) (int64, error) { + args := make([]interface{}, 0, len(fields)+1) + args = append(args, key) + for _, field := range fields { + args = append(args, field) + } + res, err := p.client.HDel(key, fields...).Result() + if err != nil { + return 0, convertError(err) + } + return res, nil +} + +func (p *RedisClusterPool) HMGet(key string, fields ...string) (interface{}, error) { + args := make([]interface{}, 0, len(fields)+1) + args = append(args, key) + for _, field := range fields { + args = append(args, field) + } + if len(fields) == 0 { + return nil, ErrNil + } + res, err := p.client.HMGet(key, fields...).Result() + if err != nil { + return nil, convertError(err) + } + return res, nil +} +func (p *RedisClusterPool) HMSet(key string, kvs ...interface{}) error { + if len(kvs) == 0 { + return nil + } + if len(kvs)%2 != 0 { + return ErrWrongArgsNum + } + var err error + v := map[string]interface{}{} // todo change + v["field"], err = String(kvs[0], nil) + if err != nil && err != ErrNil { + return err + } + v["value"], err = String(kvs[1], nil) + if err != nil && err != ErrNil { + return err + } + pairs := make([]string, 0, len(kvs)-2) + if len(kvs) > 2 { + for _, kv := range kvs[2:] { + kvString, err := String(kv, nil) + if err != nil && err != ErrNil { + return err + } + pairs = append(pairs, kvString) + } + } + v["paris"] = pairs + _, err = p.client.HMSet(key, v).Result() + if err != nil { + return convertError(err) + } + return nil +} + +func (p *RedisClusterPool) HKeys(key string) ([]string, error) { + res, err := p.client.HKeys(key).Result() + if err != nil { + return res, convertError(err) + } + return res, nil +} +func (p *RedisClusterPool) HVals(key string) ([]interface{}, error) { + res, err := p.client.HVals(key).Result() + if err != nil { + return nil, convertError(err) + } + rs := make([]interface{}, 0, len(res)) + for _, res := range res { + rs = append(rs, res) + } + return rs, nil +} +func (p *RedisClusterPool) HGetAll(key string) (map[string]string, error) { + vals, err := p.client.HGetAll(key).Result() + if err != nil { + return nil, convertError(err) + } + return vals, nil +} +func (p *RedisClusterPool) HIncrBy(key, field string, delta int64) (int64, error) { + res, err := p.client.HIncrBy(key, field, delta).Result() + if err != nil { + return res, convertError(err) + } + return res, nil +} +func (p *RedisClusterPool) ZAdd(key string, kvs ...interface{}) (int64, error) { + args := make([]interface{}, 0, len(kvs)+1) + args = append(args, key) + args = append(args, kvs...) + if len(kvs) == 0 { + return 0, nil + } + if len(kvs)%2 != 0 { + return 0, ErrWrongArgsNum + } + zs := make([]redis.Z, len(kvs)/2) + for i := 0; i < len(kvs); i += 2 { + idx := i / 2 + score, err := Float64(kvs[i], nil) + if err != nil && err != ErrNil { + return 0, err + } + zs[idx].Score = score + zs[idx].Member = kvs[i+1] + } + res, err := p.client.ZAdd(key, zs...).Result() + if err != nil { + return res, convertError(err) + } + return res, nil +} +func (p *RedisClusterPool) ZRem(key string, members ...string) (int64, error) { + args := make([]interface{}, 0, len(members)) + args = append(args, key) + for _, member := range members { + args = append(args, member) + } + res, err := p.client.ZRem(key, members).Result() + if err != nil { + return res, convertError(err) + } + return res, err +} + +func (p *RedisClusterPool) ZRange(key string, min, max int64, withScores bool) (interface{}, error) { + res := make([]interface{}, 0) + if withScores { + zs, err := p.client.ZRangeWithScores(key, min, max).Result() + if err != nil { + return nil, convertError(err) + } + for _, z := range zs { + res = append(res, z.Member, strconv.FormatFloat(z.Score, 'f', -1, 64)) + } + } else { + ms, err := p.client.ZRange(key, min, max).Result() + if err != nil { + return nil, convertError(err) + } + for _, m := range ms { + res = append(res, m) + } + } + return res, nil +} +func (p *RedisClusterPool) ZRangeByScoreWithScore(key string, min, max int64) (map[string]int64, error) { + opt := new(redis.ZRangeBy) + opt.Min = strconv.FormatInt(int64(min), 10) + opt.Max = strconv.FormatInt(int64(max), 10) + opt.Count = -1 + opt.Offset = 0 + vals, err := p.client.ZRangeByScoreWithScores(key, *opt).Result() + if err != nil { + return nil, convertError(err) + } + res := make(map[string]int64, len(vals)) + for _, val := range vals { + key, err := String(val.Member, nil) + if err != nil && err != ErrNil { + return nil, err + } + res[key] = int64(val.Score) + } + return res, nil +} +func (p *RedisClusterPool) LRange(key string, start, stop int64) (interface{}, error) { + res, err := p.client.LRange(key, start, stop).Result() + if err != nil { + return nil, convertError(err) + } + return res, nil +} +func (p *RedisClusterPool) LSet(key string, index int, value interface{}) error { + err := p.client.LSet(key, int64(index), value).Err() + return convertError(err) +} +func (p *RedisClusterPool) LLen(key string) (int64, error) { + res, err := p.client.LLen(key).Result() + if err != nil { + return res, convertError(err) + } + return res, nil +} +func (p *RedisClusterPool) LRem(key string, count int, value interface{}) (int, error) { + val, _ := value.(string) + res, err := p.client.LRem(key, int64(count), val).Result() + if err != nil { + return int(res), convertError(err) + } + return int(res), nil +} +func (p *RedisClusterPool) TTl(key string) (int64, error) { + duration, err := p.client.TTL(key).Result() + if err != nil { + return int64(duration.Seconds()), convertError(err) + } + return int64(duration.Seconds()), nil +} +func (p *RedisClusterPool) LPop(key string) (interface{}, error) { + res, err := p.client.LPop(key).Result() + if err != nil { + return nil, convertError(err) + } + return res, nil +} +func (p *RedisClusterPool) RPop(key string) (interface{}, error) { + res, err := p.client.RPop(key).Result() + if err != nil { + return nil, convertError(err) + } + return res, nil +} +func (p *RedisClusterPool) BLPop(key string, timeout int) (interface{}, error) { + res, err := p.client.BLPop(time.Duration(timeout)*time.Second, key).Result() + if err != nil { + // 兼容redis 2.x + if err == redis.Nil { + return nil, ErrNil + } + return nil, err + } + return res[1], nil +} +func (p *RedisClusterPool) BRPop(key string, timeout int) (interface{}, error) { + res, err := p.client.BRPop(time.Duration(timeout)*time.Second, key).Result() + if err != nil { + // 兼容redis 2.x + if err == redis.Nil { + return nil, ErrNil + } + return nil, convertError(err) + } + return res[1], nil +} +func (p *RedisClusterPool) LPush(key string, value ...interface{}) error { + args := make([]interface{}, 0, len(value)+1) + args = append(args, key) + args = append(args, value...) + vals := make([]string, 0, len(value)) + for _, v := range value { + val, err := String(v, nil) + if err != nil && err != ErrNil { + return err + } + vals = append(vals, val) + } + _, err := p.client.LPush(key, vals).Result() // todo ... + if err != nil { + return convertError(err) + } + return nil +} +func (p *RedisClusterPool) RPush(key string, value ...interface{}) error { + args := make([]interface{}, 0, len(value)+1) + args = append(args, key) + args = append(args, value...) + vals := make([]string, 0, len(value)) + for _, v := range value { + val, err := String(v, nil) + if err != nil && err != ErrNil { + if err == ErrNil { + continue + } + return err + } + if val == "" { + continue + } + vals = append(vals, val) + } + _, err := p.client.RPush(key, vals).Result() // todo ... + if err != nil { + return convertError(err) + } + return nil +} + +// 为确保srcKey跟destKey映射到同一个slot,srcKey和destKey需要加上hash tag,如:{test} +func (p *RedisClusterPool) BRPopLPush(srcKey string, destKey string, timeout int) (interface{}, error) { + res, err := p.client.BRPopLPush(srcKey, destKey, time.Duration(timeout)*time.Second).Result() + if err != nil { + return nil, convertError(err) + } + return res, nil +} + +// 为确保srcKey跟destKey映射到同一个slot,srcKey和destKey需要加上hash tag,如:{test} +func (p *RedisClusterPool) RPopLPush(srcKey string, destKey string) (interface{}, error) { + res, err := p.client.RPopLPush(srcKey, destKey).Result() + if err != nil { + return nil, convertError(err) + } + return res, nil +} +func (p *RedisClusterPool) SAdd(key string, members ...interface{}) (int64, error) { + args := make([]interface{}, 0, len(members)+1) + args = append(args, key) + args = append(args, members...) + ms := make([]string, 0, len(members)) + for _, member := range members { + m, err := String(member, nil) + if err != nil && err != ErrNil { + return 0, err + } + ms = append(ms, m) + } + res, err := p.client.SAdd(key, ms).Result() // todo ... + if err != nil { + return res, convertError(err) + } + return res, nil +} +func (p *RedisClusterPool) SPop(key string) ([]byte, error) { + res, err := p.client.SPop(key).Result() + if err != nil { + return nil, convertError(err) + } + return []byte(res), nil +} +func (p *RedisClusterPool) SIsMember(key string, member interface{}) (bool, error) { + m, _ := member.(string) + res, err := p.client.SIsMember(key, m).Result() + if err != nil { + return res, convertError(err) + } + return res, nil +} +func (p *RedisClusterPool) SRem(key string, members ...interface{}) (int64, error) { + args := make([]interface{}, 0, len(members)+1) + args = append(args, key) + args = append(args, members...) + ms := make([]string, 0, len(members)) + for _, member := range members { + m, err := String(member, nil) + if err != nil && err != ErrNil { + return 0, err + } + ms = append(ms, m) + } + res, err := p.client.SRem(key, ms).Result() // todo ... + if err != nil { + return res, convertError(err) + } + return res, nil +} +func (p *RedisClusterPool) SMembers(key string) ([]string, error) { + res, err := p.client.SMembers(key).Result() + if err != nil { + return nil, convertError(err) + } + return res, nil +} +func (p *RedisClusterPool) ScriptLoad(luaScript string) (interface{}, error) { + res, err := p.client.ScriptLoad(luaScript).Result() + if err != nil { + return nil, convertError(err) + } + return res, nil +} +func (p *RedisClusterPool) EvalSha(sha1 string, numberKeys int, keysArgs ...interface{}) (interface{}, error) { + vals := make([]interface{}, 0, len(keysArgs)+2) + vals = append(vals, sha1, numberKeys) + vals = append(vals, keysArgs...) + keys := make([]string, 0, numberKeys) + args := make([]string, 0, len(keysArgs)-numberKeys) + for i, value := range keysArgs { + val, err := String(value, nil) + if err != nil && err != ErrNil { + return nil, err + } + if i < numberKeys { + keys = append(keys, val) + } else { + args = append(args, val) + } + } + res, err := p.client.EvalSha(sha1, keys, args).Result() + if err != nil { + return nil, convertError(err) + } + return res, nil +} +func (p *RedisClusterPool) Eval(luaScript string, numberKeys int, keysArgs ...interface{}) (interface{}, error) { + vals := make([]interface{}, 0, len(keysArgs)+2) + vals = append(vals, luaScript, numberKeys) + vals = append(vals, keysArgs...) + keys := make([]string, 0, numberKeys) + args := make([]string, 0, len(keysArgs)-numberKeys) + for i, value := range keysArgs { + val, err := String(value, nil) + if err != nil && err != ErrNil { + return nil, err + } + if i < numberKeys { + keys = append(keys, val) + } else { + args = append(args, val) + } + } + res, err := p.client.Eval(luaScript, keys, args).Result() + if err != nil { + return nil, convertError(err) + } + return res, nil +} +func (p *RedisClusterPool) GetBit(key string, offset int64) (int64, error) { + res, err := p.client.GetBit(key, offset).Result() + if err != nil { + return res, convertError(err) + } + return res, nil +} +func (p *RedisClusterPool) SetBit(key string, offset uint32, value int) (int, error) { + res, err := p.client.SetBit(key, int64(offset), value).Result() + return int(res), convertError(err) +} +func (p *RedisClusterPool) GetClient() *redis.ClusterClient { + return pools +} diff --git a/super_cloud_issuance/utils/commission.go b/super_cloud_issuance/utils/commission.go new file mode 100644 index 0000000..dfc4d98 --- /dev/null +++ b/super_cloud_issuance/utils/commission.go @@ -0,0 +1,89 @@ +package utils + +import ( + "fmt" + "github.com/gin-gonic/gin" + "strconv" + "strings" +) + +func GetIntegralPrec(c *gin.Context, sum string) string { + if sum == "" { + sum = "0" + } + commPrec := c.GetString("integral_prec") + sum = StrToFormat(c, sum, StrToInt(commPrec)) + ex := strings.Split(sum, ".") + if len(ex) == 2 && c.GetString("is_show_point") != "1" { + if StrToFloat64(ex[1]) == 0 { + sum = ex[0] + } else { + val := Float64ToStrByPrec(StrToFloat64(ex[1]), 0) + keyMax := 0 + for i := 0; i < len(val); i++ { + ch := string(val[i]) + fmt.Println(StrToInt(ch)) + if StrToInt(ch) > 0 { + keyMax = i + } + } + valNew := val[0 : keyMax+1] + sum = ex[0] + "." + strings.ReplaceAll(ex[1], val, valNew) + } + } + return sum +} + +func GetCommissionPrec(c *gin.Context, sum string) string { + if sum == "" { + sum = "0" + } + commPrec := c.GetString("commission_prec") + sum = StrToFormat(c, sum, StrToInt(commPrec)) + ex := strings.Split(sum, ".") + if len(ex) == 2 && c.GetString("is_show_point") != "1" { + if StrToFloat64(ex[1]) == 0 { + sum = ex[0] + } else { + val := Float64ToStrByPrec(StrToFloat64(ex[1]), 0) + keyMax := 0 + for i := 0; i < len(val); i++ { + ch := string(val[i]) + fmt.Println(StrToInt(ch)) + if StrToInt(ch) > 0 { + keyMax = i + } + } + valNew := val[0 : keyMax+1] + sum = ex[0] + "." + strings.ReplaceAll(ex[1], val, valNew) + } + } + return sum +} +func Float64ToStrByPrec(f float64, prec int) string { + return strconv.FormatFloat(f, 'f', prec, 64) +} +func StrToFormat(c *gin.Context, s string, prec int) string { + ex := strings.Split(s, ".") + if len(ex) == 2 { + if StrToFloat64(ex[1]) == 0 && c.GetString("is_show_point") != "1" { //小数点后面为空就是不要小数点了 + return ex[0] + } + //看取多少位 + str := ex[1] + str1 := str + if prec < len(str) { + str1 = str[0:prec] + } else { + for i := 0; i < prec-len(str); i++ { + str1 += "0" + } + } + if prec > 0 { + return ex[0] + "." + str1 + } else { + return ex[0] + } + } + return s +} diff --git a/super_cloud_issuance/utils/convert.go b/super_cloud_issuance/utils/convert.go new file mode 100644 index 0000000..f28eefd --- /dev/null +++ b/super_cloud_issuance/utils/convert.go @@ -0,0 +1,330 @@ +package utils + +import ( + "code.fnuoos.com/go_rely_warehouse/zyos_go_order_relate_rule.git/lib/comm_plan" + "encoding/binary" + "encoding/json" + "fmt" + "math" + "strconv" + "strings" +) + +func ToString(raw interface{}, e error) (res string) { + if e != nil { + return "" + } + return AnyToString(raw) +} + +func ToInt64(raw interface{}, e error) int64 { + if e != nil { + return 0 + } + return AnyToInt64(raw) +} + +func AnyToBool(raw interface{}) bool { + switch i := raw.(type) { + case float32, float64, int, int64, uint, uint8, uint16, uint32, uint64, int8, int16, int32: + return i != 0 + case []byte: + return i != nil + case string: + if i == "false" { + return false + } + return i != "" + case error: + return false + case nil: + return true + } + val := fmt.Sprint(raw) + val = strings.TrimLeft(val, "&") + if strings.TrimLeft(val, "{}") == "" { + return false + } + if strings.TrimLeft(val, "[]") == "" { + return false + } + // ptr type + b, err := json.Marshal(raw) + if err != nil { + return false + } + if strings.TrimLeft(string(b), "\"\"") == "" { + return false + } + if strings.TrimLeft(string(b), "{}") == "" { + return false + } + return true +} + +func AnyToInt64(raw interface{}) int64 { + switch i := raw.(type) { + case string: + res, _ := strconv.ParseInt(i, 10, 64) + return res + case []byte: + return BytesToInt64(i) + case int: + return int64(i) + case int64: + return i + case uint: + return int64(i) + case uint8: + return int64(i) + case uint16: + return int64(i) + case uint32: + return int64(i) + case uint64: + return int64(i) + case int8: + return int64(i) + case int16: + return int64(i) + case int32: + return int64(i) + case float32: + return int64(i) + case float64: + return int64(i) + case error: + return 0 + case bool: + if i { + return 1 + } + return 0 + } + return 0 +} + +func AnyToString(raw interface{}) string { + switch i := raw.(type) { + case []byte: + return string(i) + case int: + return strconv.FormatInt(int64(i), 10) + case int64: + return strconv.FormatInt(i, 10) + case float32: + return Float64ToStr(float64(i)) + case float64: + return Float64ToStr(i) + case uint: + return strconv.FormatInt(int64(i), 10) + case uint8: + return strconv.FormatInt(int64(i), 10) + case uint16: + return strconv.FormatInt(int64(i), 10) + case uint32: + return strconv.FormatInt(int64(i), 10) + case uint64: + return strconv.FormatInt(int64(i), 10) + case int8: + return strconv.FormatInt(int64(i), 10) + case int16: + return strconv.FormatInt(int64(i), 10) + case int32: + return strconv.FormatInt(int64(i), 10) + case string: + return i + case error: + return i.Error() + case bool: + return strconv.FormatBool(i) + } + return fmt.Sprintf("%#v", raw) +} + +func AnyToFloat64(raw interface{}) float64 { + switch i := raw.(type) { + case []byte: + f, _ := strconv.ParseFloat(string(i), 64) + return f + case int: + return float64(i) + case int64: + return float64(i) + case float32: + return float64(i) + case float64: + return i + case uint: + return float64(i) + case uint8: + return float64(i) + case uint16: + return float64(i) + case uint32: + return float64(i) + case uint64: + return float64(i) + case int8: + return float64(i) + case int16: + return float64(i) + case int32: + return float64(i) + case string: + f, _ := strconv.ParseFloat(i, 64) + return f + case bool: + if i { + return 1 + } + } + return 0 +} + +func ToByte(raw interface{}, e error) []byte { + if e != nil { + return []byte{} + } + switch i := raw.(type) { + case string: + return []byte(i) + case int: + return Int64ToBytes(int64(i)) + case int64: + return Int64ToBytes(i) + case float32: + return Float32ToByte(i) + case float64: + return Float64ToByte(i) + case uint: + return Int64ToBytes(int64(i)) + case uint8: + return Int64ToBytes(int64(i)) + case uint16: + return Int64ToBytes(int64(i)) + case uint32: + return Int64ToBytes(int64(i)) + case uint64: + return Int64ToBytes(int64(i)) + case int8: + return Int64ToBytes(int64(i)) + case int16: + return Int64ToBytes(int64(i)) + case int32: + return Int64ToBytes(int64(i)) + case []byte: + return i + case error: + return []byte(i.Error()) + case bool: + if i { + return []byte("true") + } + return []byte("false") + } + return []byte(fmt.Sprintf("%#v", raw)) +} + +func Int64ToBytes(i int64) []byte { + var buf = make([]byte, 8) + binary.BigEndian.PutUint64(buf, uint64(i)) + return buf +} + +func BytesToInt64(buf []byte) int64 { + return int64(binary.BigEndian.Uint64(buf)) +} + +func StrToInt(s string) int { + res, _ := strconv.Atoi(s) + return res +} + +func StrToInt64(s string) int64 { + res, _ := strconv.ParseInt(s, 10, 64) + return res +} + +func Float32ToByte(float float32) []byte { + bits := math.Float32bits(float) + bytes := make([]byte, 4) + binary.LittleEndian.PutUint32(bytes, bits) + + return bytes +} + +func ByteToFloat32(bytes []byte) float32 { + bits := binary.LittleEndian.Uint32(bytes) + return math.Float32frombits(bits) +} + +func Float64ToByte(float float64) []byte { + bits := math.Float64bits(float) + bytes := make([]byte, 8) + binary.LittleEndian.PutUint64(bytes, bits) + return bytes +} + +func ByteToFloat64(bytes []byte) float64 { + bits := binary.LittleEndian.Uint64(bytes) + return math.Float64frombits(bits) +} + +func Float64ToStr(f float64) string { + return strconv.FormatFloat(f, 'f', 2, 64) +} +func Float64ToStrPrec1(f float64) string { + return strconv.FormatFloat(f, 'f', 1, 64) +} + +func Float32ToStr(f float32) string { + return Float64ToStr(float64(f)) +} + +func StrToFloat64(s string) float64 { + res, err := strconv.ParseFloat(s, 64) + if err != nil { + return 0 + } + return res +} + +func StrToFloat32(s string) float32 { + res, err := strconv.ParseFloat(s, 32) + if err != nil { + return 0 + } + return float32(res) +} + +func StrToBool(s string) bool { + b, _ := strconv.ParseBool(s) + return b +} + +func BoolToStr(b bool) string { + if b { + return "true" + } + return "false" +} + +func FloatToInt64(f float64) int64 { + return int64(f) +} + +func IntToStr(i int) string { + return strconv.Itoa(i) +} + +func Int64ToStr(i int64) string { + return strconv.FormatInt(i, 10) +} +func ConvertList2Map(a []*comm_plan.VirtualCoinCommission) (b map[string]float64) { + b = make(map[string]float64) + for _, i := range a { + b[i.Cid] = i.Val + } + return b +} diff --git a/super_cloud_issuance/utils/crypto.go b/super_cloud_issuance/utils/crypto.go new file mode 100644 index 0000000..56289c5 --- /dev/null +++ b/super_cloud_issuance/utils/crypto.go @@ -0,0 +1,19 @@ +package utils + +import ( + "crypto/md5" + "encoding/base64" + "fmt" +) + +func GetMd5(raw []byte) string { + h := md5.New() + h.Write(raw) + return fmt.Sprintf("%x", h.Sum(nil)) +} + +func GetBase64Md5(raw []byte) string { + h := md5.New() + h.Write(raw) + return base64.StdEncoding.EncodeToString(h.Sum(nil)) +} diff --git a/super_cloud_issuance/utils/curl.go b/super_cloud_issuance/utils/curl.go new file mode 100644 index 0000000..0a45607 --- /dev/null +++ b/super_cloud_issuance/utils/curl.go @@ -0,0 +1,209 @@ +package utils + +import ( + "bytes" + "crypto/tls" + "fmt" + "io" + "io/ioutil" + "net/http" + "net/url" + "sort" + "strings" + "time" +) + +var CurlDebug bool + +func CurlGet(router string, header map[string]string) ([]byte, error) { + return curl(http.MethodGet, router, nil, header) +} +func CurlGetJson(router string, body interface{}, header map[string]string) ([]byte, error) { + return curl_new(http.MethodGet, router, body, header) +} + +// 只支持form 与json 提交, 请留意body的类型, 支持string, []byte, map[string]string +func CurlPost(router string, body interface{}, header map[string]string) ([]byte, error) { + return curl(http.MethodPost, router, body, header) +} + +func CurlPut(router string, body interface{}, header map[string]string) ([]byte, error) { + return curl(http.MethodPut, router, body, header) +} + +// 只支持form 与json 提交, 请留意body的类型, 支持string, []byte, map[string]string +func CurlPatch(router string, body interface{}, header map[string]string) ([]byte, error) { + return curl(http.MethodPatch, router, body, header) +} + +// CurlDelete is curl delete +func CurlDelete(router string, body interface{}, header map[string]string) ([]byte, error) { + return curl(http.MethodDelete, router, body, header) +} + +func curl(method, router string, body interface{}, header map[string]string) ([]byte, error) { + var reqBody io.Reader + contentType := "application/json" + switch v := body.(type) { + case string: + reqBody = strings.NewReader(v) + case []byte: + reqBody = bytes.NewReader(v) + case map[string]string: + val := url.Values{} + for k, v := range v { + val.Set(k, v) + } + reqBody = strings.NewReader(val.Encode()) + contentType = "application/x-www-form-urlencoded" + case map[string]interface{}: + val := url.Values{} + for k, v := range v { + val.Set(k, v.(string)) + } + reqBody = strings.NewReader(val.Encode()) + contentType = "application/x-www-form-urlencoded" + } + if header == nil { + header = map[string]string{"Content-Type": contentType} + } + if _, ok := header["Content-Type"]; !ok { + header["Content-Type"] = contentType + } + resp, er := CurlReq(method, router, reqBody, header) + if er != nil { + return nil, er + } + res, err := ioutil.ReadAll(resp.Body) + if CurlDebug { + blob := SerializeStr(body) + if contentType != "application/json" { + blob = HttpBuild(body) + } + fmt.Printf("\n\n=====================\n[url]: %s\n[time]: %s\n[method]: %s\n[content-type]: %v\n[req_header]: %s\n[req_body]: %#v\n[resp_err]: %v\n[resp_header]: %v\n[resp_body]: %v\n=====================\n\n", + router, + time.Now().Format("2006-01-02 15:04:05.000"), + method, + contentType, + HttpBuildQuery(header), + blob, + err, + SerializeStr(resp.Header), + string(res), + ) + } + resp.Body.Close() + return res, err +} + +func curl_new(method, router string, body interface{}, header map[string]string) ([]byte, error) { + var reqBody io.Reader + contentType := "application/json" + + if header == nil { + header = map[string]string{"Content-Type": contentType} + } + if _, ok := header["Content-Type"]; !ok { + header["Content-Type"] = contentType + } + resp, er := CurlReq(method, router, reqBody, header) + if er != nil { + return nil, er + } + res, err := ioutil.ReadAll(resp.Body) + if CurlDebug { + blob := SerializeStr(body) + if contentType != "application/json" { + blob = HttpBuild(body) + } + fmt.Printf("\n\n=====================\n[url]: %s\n[time]: %s\n[method]: %s\n[content-type]: %v\n[req_header]: %s\n[req_body]: %#v\n[resp_err]: %v\n[resp_header]: %v\n[resp_body]: %v\n=====================\n\n", + router, + time.Now().Format("2006-01-02 15:04:05.000"), + method, + contentType, + HttpBuildQuery(header), + blob, + err, + SerializeStr(resp.Header), + string(res), + ) + } + resp.Body.Close() + return res, err +} + +func CurlReq(method, router string, reqBody io.Reader, header map[string]string) (*http.Response, error) { + req, _ := http.NewRequest(method, router, reqBody) + if header != nil { + for k, v := range header { + req.Header.Set(k, v) + } + } + // 绕过github等可能因为特征码返回503问题 + // https://www.imwzk.com/posts/2021-03-14-why-i-always-get-503-with-golang/ + defaultCipherSuites := []uint16{0xc02f, 0xc030, 0xc02b, 0xc02c, 0xcca8, 0xcca9, 0xc013, 0xc009, + 0xc014, 0xc00a, 0x009c, 0x009d, 0x002f, 0x0035, 0xc012, 0x000a} + client := &http.Client{ + Transport: &http.Transport{ + TLSClientConfig: &tls.Config{ + InsecureSkipVerify: true, + CipherSuites: append(defaultCipherSuites[8:], defaultCipherSuites[:8]...), + }, + }, + // 获取301重定向 + CheckRedirect: func(req *http.Request, via []*http.Request) error { + return http.ErrUseLastResponse + }, + } + return client.Do(req) +} + +// 组建get请求参数,sortAsc true为小到大,false为大到小,nil不排序 a=123&b=321 +func HttpBuildQuery(args map[string]string, sortAsc ...bool) string { + str := "" + if len(args) == 0 { + return str + } + if len(sortAsc) > 0 { + keys := make([]string, 0, len(args)) + for k := range args { + keys = append(keys, k) + } + if sortAsc[0] { + sort.Strings(keys) + } else { + sort.Sort(sort.Reverse(sort.StringSlice(keys))) + } + for _, k := range keys { + str += "&" + k + "=" + args[k] + } + } else { + for k, v := range args { + str += "&" + k + "=" + v + } + } + return str[1:] +} + +func HttpBuild(body interface{}, sortAsc ...bool) string { + params := map[string]string{} + if args, ok := body.(map[string]interface{}); ok { + for k, v := range args { + params[k] = AnyToString(v) + } + return HttpBuildQuery(params, sortAsc...) + } + if args, ok := body.(map[string]string); ok { + for k, v := range args { + params[k] = AnyToString(v) + } + return HttpBuildQuery(params, sortAsc...) + } + if args, ok := body.(map[string]int); ok { + for k, v := range args { + params[k] = AnyToString(v) + } + return HttpBuildQuery(params, sortAsc...) + } + return AnyToString(body) +} diff --git a/super_cloud_issuance/utils/debug.go b/super_cloud_issuance/utils/debug.go new file mode 100644 index 0000000..bb2e9d3 --- /dev/null +++ b/super_cloud_issuance/utils/debug.go @@ -0,0 +1,25 @@ +package utils + +import ( + "fmt" + "os" + "strconv" + "time" +) + +func Debug(args ...interface{}) { + s := "" + l := len(args) + if l < 1 { + fmt.Println("please input some data") + os.Exit(0) + } + i := 1 + for _, v := range args { + s += fmt.Sprintf("【"+strconv.Itoa(i)+"】: %#v\n", v) + i++ + } + s = "******************** 【DEBUG - " + time.Now().Format("2006-01-02 15:04:05") + "】 ********************\n" + s + "******************** 【DEBUG - END】 ********************\n" + fmt.Println(s) + os.Exit(0) +} diff --git a/super_cloud_issuance/utils/duplicate.go b/super_cloud_issuance/utils/duplicate.go new file mode 100644 index 0000000..17cea88 --- /dev/null +++ b/super_cloud_issuance/utils/duplicate.go @@ -0,0 +1,37 @@ +package utils + +func RemoveDuplicateString(elms []string) []string { + res := make([]string, 0, len(elms)) + temp := map[string]struct{}{} + for _, item := range elms { + if _, ok := temp[item]; !ok { + temp[item] = struct{}{} + res = append(res, item) + } + } + return res +} + +func RemoveDuplicateInt(elms []int) []int { + res := make([]int, 0, len(elms)) + temp := map[int]struct{}{} + for _, item := range elms { + if _, ok := temp[item]; !ok { + temp[item] = struct{}{} + res = append(res, item) + } + } + return res +} + +func RemoveDuplicateInt64(elms []int64) []int64 { + res := make([]int64, 0, len(elms)) + temp := map[int64]struct{}{} + for _, item := range elms { + if _, ok := temp[item]; !ok { + temp[item] = struct{}{} + res = append(res, item) + } + } + return res +} diff --git a/super_cloud_issuance/utils/file.go b/super_cloud_issuance/utils/file.go new file mode 100644 index 0000000..93ed08f --- /dev/null +++ b/super_cloud_issuance/utils/file.go @@ -0,0 +1,22 @@ +package utils + +import ( + "os" + "path" + "strings" + "time" +) + +// 获取文件后缀 +func FileExt(fname string) string { + return strings.ToLower(strings.TrimLeft(path.Ext(fname), ".")) +} + +func FilePutContents(fileName string, content string) { + fd, _ := os.OpenFile("./tmp/"+fileName+".log", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0644) + fd_time := time.Now().Format("2006-01-02 15:04:05") + fd_content := strings.Join([]string{"[", fd_time, "] ", content, "\n"}, "") + buf := []byte(fd_content) + fd.Write(buf) + fd.Close() +} diff --git a/super_cloud_issuance/utils/file_and_dir.go b/super_cloud_issuance/utils/file_and_dir.go new file mode 100644 index 0000000..93141f9 --- /dev/null +++ b/super_cloud_issuance/utils/file_and_dir.go @@ -0,0 +1,29 @@ +package utils + +import "os" + +// 判断所给路径文件、文件夹是否存在 +func Exists(path string) bool { + _, err := os.Stat(path) //os.Stat获取文件信息 + if err != nil { + if os.IsExist(err) { + return true + } + return false + } + return true +} + +// 判断所给路径是否为文件夹 +func IsDir(path string) bool { + s, err := os.Stat(path) + if err != nil { + return false + } + return s.IsDir() +} + +// 判断所给路径是否为文件 +func IsFile(path string) bool { + return !IsDir(path) +} diff --git a/super_cloud_issuance/utils/format.go b/super_cloud_issuance/utils/format.go new file mode 100644 index 0000000..997fe80 --- /dev/null +++ b/super_cloud_issuance/utils/format.go @@ -0,0 +1,59 @@ +package utils + +import ( + "math" +) + +func CouponFormat(data string) string { + switch data { + case "0.00", "0", "": + return "" + default: + return Int64ToStr(FloatToInt64(StrToFloat64(data))) + } +} +func CommissionFormat(data string) string { + if StrToFloat64(data) > 0 { + return data + } + + return "" +} + +func HideString(src string, hLen int) string { + str := []rune(src) + if hLen == 0 { + hLen = 4 + } + hideStr := "" + for i := 0; i < hLen; i++ { + hideStr += "*" + } + hideLen := len(str) / 2 + showLen := len(str) - hideLen + if hideLen == 0 || showLen == 0 { + return hideStr + } + subLen := showLen / 2 + if subLen == 0 { + return string(str[:showLen]) + hideStr + } + s := string(str[:subLen]) + s += hideStr + s += string(str[len(str)-subLen:]) + return s +} + +//SaleCountFormat is 格式化销量 +func SaleCountFormat(s string) string { + return s + "已售" +} + +// 小数格式化 +func FloatFormat(f float64, i int) float64 { + if i > 14 { + return f + } + p := math.Pow10(i) + return float64(int64((f+0.000000000000009)*p)) / p +} diff --git a/super_cloud_issuance/utils/json.go b/super_cloud_issuance/utils/json.go new file mode 100644 index 0000000..0902b17 --- /dev/null +++ b/super_cloud_issuance/utils/json.go @@ -0,0 +1,38 @@ +package utils + +import ( + "bytes" + "encoding/json" + "regexp" +) + +func JsonMarshal(interface{}) { + +} + +// 不科学计数法 +func JsonDecode(data []byte, v interface{}) error { + d := json.NewDecoder(bytes.NewReader(data)) + d.UseNumber() + return d.Decode(v) +} + +// json字符串驼峰命名格式 转为 下划线命名格式 +// +// c :json字符串 +func MarshalJSONCamelCase2JsonSnakeCase(c string) []byte { + // Regexp definitions + var keyMatchRegex = regexp.MustCompile(`\"(\w+)\":`) + var wordBarrierRegex = regexp.MustCompile(`(\w)([A-Z])`) + marshalled := []byte(c) + converted := keyMatchRegex.ReplaceAllFunc( + marshalled, + func(match []byte) []byte { + return bytes.ToLower(wordBarrierRegex.ReplaceAll( + match, + []byte(`${1}_${2}`), + )) + }, + ) + return converted +} diff --git a/super_cloud_issuance/utils/logx/log.go b/super_cloud_issuance/utils/logx/log.go new file mode 100644 index 0000000..ca11223 --- /dev/null +++ b/super_cloud_issuance/utils/logx/log.go @@ -0,0 +1,245 @@ +package logx + +import ( + "os" + "strings" + "time" + + "go.uber.org/zap" + "go.uber.org/zap/zapcore" +) + +type LogConfig struct { + AppName string `yaml:"app_name" json:"app_name" toml:"app_name"` + Level string `yaml:"level" json:"level" toml:"level"` + StacktraceLevel string `yaml:"stacktrace_level" json:"stacktrace_level" toml:"stacktrace_level"` + IsStdOut bool `yaml:"is_stdout" json:"is_stdout" toml:"is_stdout"` + TimeFormat string `yaml:"time_format" json:"time_format" toml:"time_format"` // second, milli, nano, standard, iso, + Encoding string `yaml:"encoding" json:"encoding" toml:"encoding"` // console, json + Skip int `yaml:"skip" json:"skip" toml:"skip"` + + IsFileOut bool `yaml:"is_file_out" json:"is_file_out" toml:"is_file_out"` + FileDir string `yaml:"file_dir" json:"file_dir" toml:"file_dir"` + FileName string `yaml:"file_name" json:"file_name" toml:"file_name"` + FileMaxSize int `yaml:"file_max_size" json:"file_max_size" toml:"file_max_size"` + FileMaxAge int `yaml:"file_max_age" json:"file_max_age" toml:"file_max_age"` +} + +var ( + l *LogX = defaultLogger() + conf *LogConfig +) + +// default logger setting +func defaultLogger() *LogX { + conf = &LogConfig{ + Level: "debug", + StacktraceLevel: "error", + IsStdOut: true, + TimeFormat: "standard", + Encoding: "console", + Skip: 2, + } + writers := []zapcore.WriteSyncer{os.Stdout} + lg, lv := newZapLogger(setLogLevel(conf.Level), setLogLevel(conf.StacktraceLevel), conf.Encoding, conf.TimeFormat, conf.Skip, zapcore.NewMultiWriteSyncer(writers...)) + zap.RedirectStdLog(lg) + return &LogX{logger: lg, atomLevel: lv} +} + +// initial standard log, if you don't init, it will use default logger setting +func InitDefaultLogger(cfg *LogConfig) { + var writers []zapcore.WriteSyncer + if cfg.IsStdOut || (!cfg.IsStdOut && !cfg.IsFileOut) { + writers = append(writers, os.Stdout) + } + if cfg.IsFileOut { + writers = append(writers, NewRollingFile(cfg.FileDir, cfg.FileName, cfg.FileMaxSize, cfg.FileMaxAge)) + } + + lg, lv := newZapLogger(setLogLevel(cfg.Level), setLogLevel(cfg.StacktraceLevel), cfg.Encoding, cfg.TimeFormat, cfg.Skip, zapcore.NewMultiWriteSyncer(writers...)) + zap.RedirectStdLog(lg) + if cfg.AppName != "" { + lg = lg.With(zap.String("app", cfg.AppName)) // 加上应用名称 + } + l = &LogX{logger: lg, atomLevel: lv} +} + +// create a new logger +func NewLogger(cfg *LogConfig) *LogX { + var writers []zapcore.WriteSyncer + if cfg.IsStdOut || (!cfg.IsStdOut && !cfg.IsFileOut) { + writers = append(writers, os.Stdout) + } + if cfg.IsFileOut { + writers = append(writers, NewRollingFile(cfg.FileDir, cfg.FileName, cfg.FileMaxSize, cfg.FileMaxAge)) + } + + lg, lv := newZapLogger(setLogLevel(cfg.Level), setLogLevel(cfg.StacktraceLevel), cfg.Encoding, cfg.TimeFormat, cfg.Skip, zapcore.NewMultiWriteSyncer(writers...)) + zap.RedirectStdLog(lg) + if cfg.AppName != "" { + lg = lg.With(zap.String("app", cfg.AppName)) // 加上应用名称 + } + return &LogX{logger: lg, atomLevel: lv} +} + +// create a new zaplog logger +func newZapLogger(level, stacktrace zapcore.Level, encoding, timeType string, skip int, output zapcore.WriteSyncer) (*zap.Logger, *zap.AtomicLevel) { + encCfg := zapcore.EncoderConfig{ + TimeKey: "T", + LevelKey: "L", + NameKey: "N", + CallerKey: "C", + MessageKey: "M", + StacktraceKey: "S", + LineEnding: zapcore.DefaultLineEnding, + EncodeCaller: zapcore.ShortCallerEncoder, + EncodeDuration: zapcore.NanosDurationEncoder, + EncodeLevel: zapcore.LowercaseLevelEncoder, + } + setTimeFormat(timeType, &encCfg) // set time type + atmLvl := zap.NewAtomicLevel() // set level + atmLvl.SetLevel(level) + encoder := zapcore.NewJSONEncoder(encCfg) // 确定encoder格式 + if encoding == "console" { + encoder = zapcore.NewConsoleEncoder(encCfg) + } + return zap.New(zapcore.NewCore(encoder, output, atmLvl), zap.AddCaller(), zap.AddStacktrace(stacktrace), zap.AddCallerSkip(skip)), &atmLvl +} + +// set log level +func setLogLevel(lvl string) zapcore.Level { + switch strings.ToLower(lvl) { + case "panic": + return zapcore.PanicLevel + case "fatal": + return zapcore.FatalLevel + case "error": + return zapcore.ErrorLevel + case "warn", "warning": + return zapcore.WarnLevel + case "info": + return zapcore.InfoLevel + default: + return zapcore.DebugLevel + } +} + +// set time format +func setTimeFormat(timeType string, z *zapcore.EncoderConfig) { + switch strings.ToLower(timeType) { + case "iso": // iso8601 standard + z.EncodeTime = zapcore.ISO8601TimeEncoder + case "sec": // only for unix second, without millisecond + z.EncodeTime = func(t time.Time, enc zapcore.PrimitiveArrayEncoder) { + enc.AppendInt64(t.Unix()) + } + case "second": // unix second, with millisecond + z.EncodeTime = zapcore.EpochTimeEncoder + case "milli", "millisecond": // millisecond + z.EncodeTime = zapcore.EpochMillisTimeEncoder + case "nano", "nanosecond": // nanosecond + z.EncodeTime = zapcore.EpochNanosTimeEncoder + default: // standard format + z.EncodeTime = func(t time.Time, enc zapcore.PrimitiveArrayEncoder) { + enc.AppendString(t.Format("2006-01-02 15:04:05.000")) + } + } +} + +func GetLevel() string { + switch l.atomLevel.Level() { + case zapcore.PanicLevel: + return "panic" + case zapcore.FatalLevel: + return "fatal" + case zapcore.ErrorLevel: + return "error" + case zapcore.WarnLevel: + return "warn" + case zapcore.InfoLevel: + return "info" + default: + return "debug" + } +} + +func SetLevel(lvl string) { + l.atomLevel.SetLevel(setLogLevel(lvl)) +} + +// temporary add call skip +func AddCallerSkip(skip int) *LogX { + l.logger.WithOptions(zap.AddCallerSkip(skip)) + return l +} + +// permanent add call skip +func AddDepth(skip int) *LogX { + l.logger = l.logger.WithOptions(zap.AddCallerSkip(skip)) + return l +} + +// permanent add options +func AddOptions(opts ...zap.Option) *LogX { + l.logger = l.logger.WithOptions(opts...) + return l +} + +func AddField(k string, v interface{}) { + l.logger.With(zap.Any(k, v)) +} + +func AddFields(fields map[string]interface{}) *LogX { + for k, v := range fields { + l.logger.With(zap.Any(k, v)) + } + return l +} + +// Normal log +func Debug(e interface{}, args ...interface{}) error { + return l.Debug(e, args...) +} +func Info(e interface{}, args ...interface{}) error { + return l.Info(e, args...) +} +func Warn(e interface{}, args ...interface{}) error { + return l.Warn(e, args...) +} +func Error(e interface{}, args ...interface{}) error { + return l.Error(e, args...) +} +func Panic(e interface{}, args ...interface{}) error { + return l.Panic(e, args...) +} +func Fatal(e interface{}, args ...interface{}) error { + return l.Fatal(e, args...) +} + +// Format logs +func Debugf(format string, args ...interface{}) error { + return l.Debugf(format, args...) +} +func Infof(format string, args ...interface{}) error { + return l.Infof(format, args...) +} +func Warnf(format string, args ...interface{}) error { + return l.Warnf(format, args...) +} +func Errorf(format string, args ...interface{}) error { + return l.Errorf(format, args...) +} +func Panicf(format string, args ...interface{}) error { + return l.Panicf(format, args...) +} +func Fatalf(format string, args ...interface{}) error { + return l.Fatalf(format, args...) +} + +func formatFieldMap(m FieldMap) []Field { + var res []Field + for k, v := range m { + res = append(res, zap.Any(k, v)) + } + return res +} diff --git a/super_cloud_issuance/utils/logx/output.go b/super_cloud_issuance/utils/logx/output.go new file mode 100644 index 0000000..ef33f0b --- /dev/null +++ b/super_cloud_issuance/utils/logx/output.go @@ -0,0 +1,105 @@ +package logx + +import ( + "bytes" + "io" + "os" + "path/filepath" + "time" + + "gopkg.in/natefinch/lumberjack.v2" +) + +// output interface +type WriteSyncer interface { + io.Writer + Sync() error +} + +// split writer +func NewRollingFile(dir, filename string, maxSize, MaxAge int) WriteSyncer { + s, err := os.Stat(dir) + if err != nil || !s.IsDir() { + os.RemoveAll(dir) + if err := os.MkdirAll(dir, 0766); err != nil { + panic(err) + } + } + return newLumberjackWriteSyncer(&lumberjack.Logger{ + Filename: filepath.Join(dir, filename), + MaxSize: maxSize, // megabytes, MB + MaxAge: MaxAge, // days + LocalTime: true, + Compress: false, + }) +} + +type lumberjackWriteSyncer struct { + *lumberjack.Logger + buf *bytes.Buffer + logChan chan []byte + closeChan chan interface{} + maxSize int +} + +func newLumberjackWriteSyncer(l *lumberjack.Logger) *lumberjackWriteSyncer { + ws := &lumberjackWriteSyncer{ + Logger: l, + buf: bytes.NewBuffer([]byte{}), + logChan: make(chan []byte, 5000), + closeChan: make(chan interface{}), + maxSize: 1024, + } + go ws.run() + return ws +} + +func (l *lumberjackWriteSyncer) run() { + ticker := time.NewTicker(1 * time.Second) + + for { + select { + case <-ticker.C: + if l.buf.Len() > 0 { + l.sync() + } + case bs := <-l.logChan: + _, err := l.buf.Write(bs) + if err != nil { + continue + } + if l.buf.Len() > l.maxSize { + l.sync() + } + case <-l.closeChan: + l.sync() + return + } + } +} + +func (l *lumberjackWriteSyncer) Stop() { + close(l.closeChan) +} + +func (l *lumberjackWriteSyncer) Write(bs []byte) (int, error) { + b := make([]byte, len(bs)) + for i, c := range bs { + b[i] = c + } + l.logChan <- b + return 0, nil +} + +func (l *lumberjackWriteSyncer) Sync() error { + return nil +} + +func (l *lumberjackWriteSyncer) sync() error { + defer l.buf.Reset() + _, err := l.Logger.Write(l.buf.Bytes()) + if err != nil { + return err + } + return nil +} diff --git a/super_cloud_issuance/utils/logx/sugar.go b/super_cloud_issuance/utils/logx/sugar.go new file mode 100644 index 0000000..ab380fc --- /dev/null +++ b/super_cloud_issuance/utils/logx/sugar.go @@ -0,0 +1,192 @@ +package logx + +import ( + "errors" + "fmt" + "strconv" + + "go.uber.org/zap" +) + +type LogX struct { + logger *zap.Logger + atomLevel *zap.AtomicLevel +} + +type Field = zap.Field +type FieldMap map[string]interface{} + +// 判断其他类型--start +func getFields(msg string, format bool, args ...interface{}) (string, []Field) { + var str []interface{} + var fields []zap.Field + if len(args) > 0 { + for _, v := range args { + if f, ok := v.(Field); ok { + fields = append(fields, f) + } else if f, ok := v.(FieldMap); ok { + fields = append(fields, formatFieldMap(f)...) + } else { + str = append(str, AnyToString(v)) + } + } + if format { + return fmt.Sprintf(msg, str...), fields + } + str = append([]interface{}{msg}, str...) + return fmt.Sprintln(str...), fields + } + return msg, []Field{} +} + +func (l *LogX) Debug(s interface{}, args ...interface{}) error { + es, e := checkErr(s) + if es != "" { + msg, field := getFields(es, false, args...) + l.logger.Debug(msg, field...) + } + return e +} +func (l *LogX) Info(s interface{}, args ...interface{}) error { + es, e := checkErr(s) + if es != "" { + msg, field := getFields(es, false, args...) + l.logger.Info(msg, field...) + } + return e +} +func (l *LogX) Warn(s interface{}, args ...interface{}) error { + es, e := checkErr(s) + if es != "" { + msg, field := getFields(es, false, args...) + l.logger.Warn(msg, field...) + } + return e +} +func (l *LogX) Error(s interface{}, args ...interface{}) error { + es, e := checkErr(s) + if es != "" { + msg, field := getFields(es, false, args...) + l.logger.Error(msg, field...) + } + return e +} +func (l *LogX) DPanic(s interface{}, args ...interface{}) error { + es, e := checkErr(s) + if es != "" { + msg, field := getFields(es, false, args...) + l.logger.DPanic(msg, field...) + } + return e +} +func (l *LogX) Panic(s interface{}, args ...interface{}) error { + es, e := checkErr(s) + if es != "" { + msg, field := getFields(es, false, args...) + l.logger.Panic(msg, field...) + } + return e +} +func (l *LogX) Fatal(s interface{}, args ...interface{}) error { + es, e := checkErr(s) + if es != "" { + msg, field := getFields(es, false, args...) + l.logger.Fatal(msg, field...) + } + return e +} + +func checkErr(s interface{}) (string, error) { + switch e := s.(type) { + case error: + return e.Error(), e + case string: + return e, errors.New(e) + case []byte: + return string(e), nil + default: + return "", nil + } +} + +func (l *LogX) LogError(err error) error { + return l.Error(err.Error()) +} + +func (l *LogX) Debugf(msg string, args ...interface{}) error { + s, f := getFields(msg, true, args...) + l.logger.Debug(s, f...) + return errors.New(s) +} + +func (l *LogX) Infof(msg string, args ...interface{}) error { + s, f := getFields(msg, true, args...) + l.logger.Info(s, f...) + return errors.New(s) +} + +func (l *LogX) Warnf(msg string, args ...interface{}) error { + s, f := getFields(msg, true, args...) + l.logger.Warn(s, f...) + return errors.New(s) +} + +func (l *LogX) Errorf(msg string, args ...interface{}) error { + s, f := getFields(msg, true, args...) + l.logger.Error(s, f...) + return errors.New(s) +} + +func (l *LogX) DPanicf(msg string, args ...interface{}) error { + s, f := getFields(msg, true, args...) + l.logger.DPanic(s, f...) + return errors.New(s) +} + +func (l *LogX) Panicf(msg string, args ...interface{}) error { + s, f := getFields(msg, true, args...) + l.logger.Panic(s, f...) + return errors.New(s) +} + +func (l *LogX) Fatalf(msg string, args ...interface{}) error { + s, f := getFields(msg, true, args...) + l.logger.Fatal(s, f...) + return errors.New(s) +} + +func AnyToString(raw interface{}) string { + switch i := raw.(type) { + case []byte: + return string(i) + case int: + return strconv.FormatInt(int64(i), 10) + case int64: + return strconv.FormatInt(i, 10) + case float32: + return strconv.FormatFloat(float64(i), 'f', 2, 64) + case float64: + return strconv.FormatFloat(i, 'f', 2, 64) + case uint: + return strconv.FormatInt(int64(i), 10) + case uint8: + return strconv.FormatInt(int64(i), 10) + case uint16: + return strconv.FormatInt(int64(i), 10) + case uint32: + return strconv.FormatInt(int64(i), 10) + case uint64: + return strconv.FormatInt(int64(i), 10) + case int8: + return strconv.FormatInt(int64(i), 10) + case int16: + return strconv.FormatInt(int64(i), 10) + case int32: + return strconv.FormatInt(int64(i), 10) + case string: + return i + case error: + return i.Error() + } + return fmt.Sprintf("%#v", raw) +} diff --git a/super_cloud_issuance/utils/map.go b/super_cloud_issuance/utils/map.go new file mode 100644 index 0000000..d9f3b7a --- /dev/null +++ b/super_cloud_issuance/utils/map.go @@ -0,0 +1,9 @@ +package utils + +// GetOneKeyOfMapString 取出Map的一个key +func GetOneKeyOfMapString(collection map[string]string) string { + for k := range collection { + return k + } + return "" +} diff --git a/super_cloud_issuance/utils/map_and_struct.go b/super_cloud_issuance/utils/map_and_struct.go new file mode 100644 index 0000000..34904ce --- /dev/null +++ b/super_cloud_issuance/utils/map_and_struct.go @@ -0,0 +1,341 @@ +package utils + +import ( + "encoding/json" + "fmt" + "reflect" + "strconv" + "strings" +) + +func Map2Struct(vals map[string]interface{}, dst interface{}) (err error) { + return Map2StructByTag(vals, dst, "json") +} + +func Map2StructByTag(vals map[string]interface{}, dst interface{}, structTag string) (err error) { + defer func() { + e := recover() + if e != nil { + if v, ok := e.(error); ok { + err = fmt.Errorf("Panic: %v", v.Error()) + } else { + err = fmt.Errorf("Panic: %v", e) + } + } + }() + + pt := reflect.TypeOf(dst) + pv := reflect.ValueOf(dst) + + if pv.Kind() != reflect.Ptr || pv.Elem().Kind() != reflect.Struct { + return fmt.Errorf("not a pointer of struct") + } + + var f reflect.StructField + var ft reflect.Type + var fv reflect.Value + + for i := 0; i < pt.Elem().NumField(); i++ { + f = pt.Elem().Field(i) + fv = pv.Elem().Field(i) + ft = f.Type + + if f.Anonymous || !fv.CanSet() { + continue + } + + tag := f.Tag.Get(structTag) + + name, option := parseTag(tag) + + if name == "-" { + continue + } + + if name == "" { + name = strings.ToLower(f.Name) + } + val, ok := vals[name] + + if !ok { + if option == "required" { + return fmt.Errorf("'%v' not found", name) + } + if len(option) != 0 { + val = option // default value + } else { + //fv.Set(reflect.Zero(ft)) // TODO set zero value or just ignore it? + continue + } + } + + // convert or set value to field + vv := reflect.ValueOf(val) + vt := reflect.TypeOf(val) + + if vt.Kind() != reflect.String { + // try to assign and convert + if vt.AssignableTo(ft) { + fv.Set(vv) + continue + } + + if vt.ConvertibleTo(ft) { + fv.Set(vv.Convert(ft)) + continue + } + + return fmt.Errorf("value type not match: field=%v(%v) value=%v(%v)", f.Name, ft.Kind(), val, vt.Kind()) + } + s := strings.TrimSpace(vv.String()) + if len(s) == 0 && option == "required" { + return fmt.Errorf("value of required argument can't not be empty") + } + fk := ft.Kind() + + // convert string to value + if fk == reflect.Ptr && ft.Elem().Kind() == reflect.String { + fv.Set(reflect.ValueOf(&s)) + continue + } + if fk == reflect.Ptr || fk == reflect.Struct { + err = convertJsonValue(s, name, fv) + } else if fk == reflect.Slice { + err = convertSlice(s, f.Name, ft, fv) + } else { + err = convertValue(fk, s, f.Name, fv) + } + + if err != nil { + return err + } + continue + } + + return nil +} + +func Struct2Map(s interface{}) map[string]interface{} { + return Struct2MapByTag(s, "json") +} +func Struct2MapByTag(s interface{}, tagName string) map[string]interface{} { + t := reflect.TypeOf(s) + v := reflect.ValueOf(s) + + if v.Kind() == reflect.Ptr && v.Elem().Kind() == reflect.Struct { + t = t.Elem() + v = v.Elem() + } + + if v.Kind() != reflect.Struct { + return nil + } + + m := make(map[string]interface{}) + + for i := 0; i < t.NumField(); i++ { + fv := v.Field(i) + ft := t.Field(i) + + if !fv.CanInterface() { + continue + } + + if ft.PkgPath != "" { // unexported + continue + } + + var name string + var option string + tag := ft.Tag.Get(tagName) + if tag != "" { + ts := strings.Split(tag, ",") + if len(ts) == 1 { + name = ts[0] + } else if len(ts) > 1 { + name = ts[0] + option = ts[1] + } + if name == "-" { + continue // skip this field + } + if name == "" { + name = strings.ToLower(ft.Name) + } + if option == "omitempty" { + if isEmpty(&fv) { + continue // skip empty field + } + } + } else { + name = strings.ToLower(ft.Name) + } + + if ft.Anonymous && fv.Kind() == reflect.Ptr && fv.IsNil() { + continue + } + if (ft.Anonymous && fv.Kind() == reflect.Struct) || + (ft.Anonymous && fv.Kind() == reflect.Ptr && fv.Elem().Kind() == reflect.Struct) { + + // embedded struct + embedded := Struct2MapByTag(fv.Interface(), tagName) + for embName, embValue := range embedded { + m[embName] = embValue + } + } else if option == "string" { + kind := fv.Kind() + if kind == reflect.Int || kind == reflect.Int8 || kind == reflect.Int16 || kind == reflect.Int32 || kind == reflect.Int64 { + m[name] = strconv.FormatInt(fv.Int(), 10) + } else if kind == reflect.Uint || kind == reflect.Uint8 || kind == reflect.Uint16 || kind == reflect.Uint32 || kind == reflect.Uint64 { + m[name] = strconv.FormatUint(fv.Uint(), 10) + } else if kind == reflect.Float32 || kind == reflect.Float64 { + m[name] = strconv.FormatFloat(fv.Float(), 'f', 2, 64) + } else { + m[name] = fv.Interface() + } + } else { + m[name] = fv.Interface() + } + } + + return m +} + +func isEmpty(v *reflect.Value) bool { + k := v.Kind() + if k == reflect.Bool { + return v.Bool() == false + } else if reflect.Int < k && k < reflect.Int64 { + return v.Int() == 0 + } else if reflect.Uint < k && k < reflect.Uintptr { + return v.Uint() == 0 + } else if k == reflect.Float32 || k == reflect.Float64 { + return v.Float() == 0 + } else if k == reflect.Array || k == reflect.Map || k == reflect.Slice || k == reflect.String { + return v.Len() == 0 + } else if k == reflect.Interface || k == reflect.Ptr { + return v.IsNil() + } + return false +} + +func convertSlice(s string, name string, ft reflect.Type, fv reflect.Value) error { + var err error + et := ft.Elem() + + if et.Kind() == reflect.Ptr || et.Kind() == reflect.Struct { + return convertJsonValue(s, name, fv) + } + + ss := strings.Split(s, ",") + + if len(s) == 0 || len(ss) == 0 { + return nil + } + + fs := reflect.MakeSlice(ft, 0, len(ss)) + + for _, si := range ss { + ev := reflect.New(et).Elem() + + err = convertValue(et.Kind(), si, name, ev) + if err != nil { + return err + } + fs = reflect.Append(fs, ev) + } + + fv.Set(fs) + + return nil +} + +func convertJsonValue(s string, name string, fv reflect.Value) error { + var err error + d := StringToSlice(s) + + if fv.Kind() == reflect.Ptr { + if fv.IsNil() { + fv.Set(reflect.New(fv.Type().Elem())) + } + } else { + fv = fv.Addr() + } + + err = json.Unmarshal(d, fv.Interface()) + + if err != nil { + return fmt.Errorf("invalid json '%v': %v, %v", name, err.Error(), s) + } + + return nil +} + +func convertValue(kind reflect.Kind, s string, name string, fv reflect.Value) error { + if !fv.CanAddr() { + return fmt.Errorf("can not addr: %v", name) + } + + if kind == reflect.String { + fv.SetString(s) + return nil + } + + if kind == reflect.Bool { + switch s { + case "true": + fv.SetBool(true) + case "false": + fv.SetBool(false) + case "1": + fv.SetBool(true) + case "0": + fv.SetBool(false) + default: + return fmt.Errorf("invalid bool: %v value=%v", name, s) + } + return nil + } + + if reflect.Int <= kind && kind <= reflect.Int64 { + i, err := strconv.ParseInt(s, 10, 64) + if err != nil { + return fmt.Errorf("invalid int: %v value=%v", name, s) + } + fv.SetInt(i) + + } else if reflect.Uint <= kind && kind <= reflect.Uint64 { + i, err := strconv.ParseUint(s, 10, 64) + if err != nil { + return fmt.Errorf("invalid int: %v value=%v", name, s) + } + fv.SetUint(i) + + } else if reflect.Float32 == kind || kind == reflect.Float64 { + i, err := strconv.ParseFloat(s, 64) + + if err != nil { + return fmt.Errorf("invalid float: %v value=%v", name, s) + } + + fv.SetFloat(i) + } else { + // not support or just ignore it? + // return fmt.Errorf("type not support: field=%v(%v) value=%v(%v)", name, ft.Kind(), val, vt.Kind()) + } + return nil +} + +func parseTag(tag string) (string, string) { + tags := strings.Split(tag, ",") + + if len(tags) <= 0 { + return "", "" + } + + if len(tags) == 1 { + return tags[0], "" + } + + return tags[0], tags[1] +} diff --git a/super_cloud_issuance/utils/md5.go b/super_cloud_issuance/utils/md5.go new file mode 100644 index 0000000..1fd05db --- /dev/null +++ b/super_cloud_issuance/utils/md5.go @@ -0,0 +1,35 @@ +package utils + +import ( + "crypto/md5" + "encoding/hex" + "fmt" + "io" + "strings" +) + +func Md5(str string) string { + h := md5.New() + h.Write([]byte(str)) + return hex.EncodeToString(h.Sum(nil)) +} + +/* +MD5ToUpper32 将字符串,转为32位md5加密,返回大写字母 +*/ +func MD5ToUpper32(str string) string { + w := md5.New() + io.WriteString(w, str) //将str写入到w中 + md5Str := fmt.Sprintf("%x", w.Sum(nil)) //w.Sum(nil)将w的hash转成[]byte格式 + return strings.ToUpper(md5Str) +} + +/* +MD5ToLower32 将字符串,转为32位md5加密,返回小写字母 +*/ +func MD5ToLower32(str string) string { + w := md5.New() + io.WriteString(w, str) //将str写入到w中 + md5Str := fmt.Sprintf("%x", w.Sum(nil)) //w.Sum(nil)将w的hash转成[]byte格式 + return md5Str +} diff --git a/super_cloud_issuance/utils/qrcode/decodeFile.go b/super_cloud_issuance/utils/qrcode/decodeFile.go new file mode 100644 index 0000000..f50fb28 --- /dev/null +++ b/super_cloud_issuance/utils/qrcode/decodeFile.go @@ -0,0 +1,33 @@ +package qrcode + +import ( + "image" + _ "image/jpeg" + _ "image/png" + "os" + + "github.com/makiuchi-d/gozxing" + "github.com/makiuchi-d/gozxing/qrcode" +) + +func DecodeFile(fi string) (string, error) { + file, err := os.Open(fi) + if err != nil { + return "", err + } + img, _, err := image.Decode(file) + if err != nil { + return "", err + } + // prepare BinaryBitmap + bmp, err := gozxing.NewBinaryBitmapFromImage(img) + if err != nil { + return "", err + } + // decode image + result, err := qrcode.NewQRCodeReader().Decode(bmp, nil) + if err != nil { + return "", err + } + return result.String(), nil +} diff --git a/super_cloud_issuance/utils/qrcode/getBase64.go b/super_cloud_issuance/utils/qrcode/getBase64.go new file mode 100644 index 0000000..11d149c --- /dev/null +++ b/super_cloud_issuance/utils/qrcode/getBase64.go @@ -0,0 +1,43 @@ +package qrcode + +// 生成登录二维码图片, 方便在网页上显示 + +import ( + "bytes" + "encoding/base64" + "image/jpeg" + "image/png" + + "github.com/boombuler/barcode" + "github.com/boombuler/barcode/qr" +) + +func GetJPGBase64(content string, edges ...int) string { + edgeLen := 300 + if len(edges) > 0 && edges[0] > 100 && edges[0] < 2000 { + edgeLen = edges[0] + } + img, _ := qr.Encode(content, qr.L, qr.Unicode) + img, _ = barcode.Scale(img, edgeLen, edgeLen) + + emptyBuff := bytes.NewBuffer(nil) // 开辟一个新的空buff缓冲区 + jpeg.Encode(emptyBuff, img, nil) + dist := make([]byte, 50000) // 开辟存储空间 + base64.StdEncoding.Encode(dist, emptyBuff.Bytes()) // buff转成base64 + return "data:image/png;base64," + string(dist) // 输出图片base64(type = []byte) +} + +func GetPNGBase64(content string, edges ...int) string { + edgeLen := 300 + if len(edges) > 0 && edges[0] > 100 && edges[0] < 2000 { + edgeLen = edges[0] + } + img, _ := qr.Encode(content, qr.L, qr.Unicode) + img, _ = barcode.Scale(img, edgeLen, edgeLen) + + emptyBuff := bytes.NewBuffer(nil) // 开辟一个新的空buff缓冲区 + png.Encode(emptyBuff, img) + dist := make([]byte, 50000) // 开辟存储空间 + base64.StdEncoding.Encode(dist, emptyBuff.Bytes()) // buff转成base64 + return string(dist) // 输出图片base64(type = []byte) +} diff --git a/super_cloud_issuance/utils/qrcode/saveFile.go b/super_cloud_issuance/utils/qrcode/saveFile.go new file mode 100644 index 0000000..4854783 --- /dev/null +++ b/super_cloud_issuance/utils/qrcode/saveFile.go @@ -0,0 +1,85 @@ +package qrcode + +// 生成登录二维码图片 + +import ( + "errors" + "image" + "image/jpeg" + "image/png" + "os" + "path/filepath" + "strings" + + "github.com/boombuler/barcode" + "github.com/boombuler/barcode/qr" +) + +func SaveJpegFile(filePath, content string, edges ...int) error { + edgeLen := 300 + if len(edges) > 0 && edges[0] > 100 && edges[0] < 2000 { + edgeLen = edges[0] + } + img, _ := qr.Encode(content, qr.L, qr.Unicode) + img, _ = barcode.Scale(img, edgeLen, edgeLen) + + return writeFile(filePath, img, "jpg") +} + +func SavePngFile(filePath, content string, edges ...int) error { + edgeLen := 300 + if len(edges) > 0 && edges[0] > 100 && edges[0] < 2000 { + edgeLen = edges[0] + } + img, _ := qr.Encode(content, qr.L, qr.Unicode) + img, _ = barcode.Scale(img, edgeLen, edgeLen) + + return writeFile(filePath, img, "png") +} + +func writeFile(filePath string, img image.Image, format string) error { + if err := createDir(filePath); err != nil { + return err + } + file, err := os.Create(filePath) + defer file.Close() + if err != nil { + return err + } + switch strings.ToLower(format) { + case "png": + err = png.Encode(file, img) + break + case "jpg": + err = jpeg.Encode(file, img, nil) + default: + return errors.New("format not accept") + } + if err != nil { + return err + } + return nil +} + +func createDir(filePath string) error { + var err error + // filePath, _ = filepath.Abs(filePath) + dirPath := filepath.Dir(filePath) + dirInfo, err := os.Stat(dirPath) + if err != nil { + if !os.IsExist(err) { + err = os.MkdirAll(dirPath, 0777) + if err != nil { + return err + } + } else { + return err + } + } else { + if dirInfo.IsDir() { + return nil + } + return errors.New("directory is a file") + } + return nil +} diff --git a/super_cloud_issuance/utils/qrcode/writeWeb.go b/super_cloud_issuance/utils/qrcode/writeWeb.go new file mode 100644 index 0000000..57e1e92 --- /dev/null +++ b/super_cloud_issuance/utils/qrcode/writeWeb.go @@ -0,0 +1,39 @@ +package qrcode + +import ( + "bytes" + "image/jpeg" + "image/png" + "net/http" + + "github.com/boombuler/barcode" + "github.com/boombuler/barcode/qr" +) + +func WritePng(w http.ResponseWriter, content string, edges ...int) error { + edgeLen := 300 + if len(edges) > 0 && edges[0] > 100 && edges[0] < 2000 { + edgeLen = edges[0] + } + img, _ := qr.Encode(content, qr.L, qr.Unicode) + img, _ = barcode.Scale(img, edgeLen, edgeLen) + buff := bytes.NewBuffer(nil) + png.Encode(buff, img) + w.Header().Set("Content-Type", "image/png") + _, err := w.Write(buff.Bytes()) + return err +} + +func WriteJpg(w http.ResponseWriter, content string, edges ...int) error { + edgeLen := 300 + if len(edges) > 0 && edges[0] > 100 && edges[0] < 2000 { + edgeLen = edges[0] + } + img, _ := qr.Encode(content, qr.L, qr.Unicode) + img, _ = barcode.Scale(img, edgeLen, edgeLen) + buff := bytes.NewBuffer(nil) + jpeg.Encode(buff, img, nil) + w.Header().Set("Content-Type", "image/jpg") + _, err := w.Write(buff.Bytes()) + return err +} diff --git a/super_cloud_issuance/utils/rand.go b/super_cloud_issuance/utils/rand.go new file mode 100644 index 0000000..f0c8a97 --- /dev/null +++ b/super_cloud_issuance/utils/rand.go @@ -0,0 +1,40 @@ +package utils + +import ( + crand "crypto/rand" + "fmt" + "math/big" + "math/rand" + "time" +) + +func RandString(l int, c ...string) string { + var ( + chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" + str string + num *big.Int + ) + if len(c) > 0 { + chars = c[0] + } + chrLen := int64(len(chars)) + for len(str) < l { + num, _ = crand.Int(crand.Reader, big.NewInt(chrLen)) + str += string(chars[num.Int64()]) + } + return str +} + +func RandNum() string { + seed := time.Now().UnixNano() + rand.Int63() + return fmt.Sprintf("%05v", rand.New(rand.NewSource(seed)).Int31n(1000000)) +} +func RandInt(min, max int) int { + if min >= max || min == 0 || max == 0 { + if max == 0 { + max = min + } + return max + } + return rand.Intn(max-min) + min +} diff --git a/super_cloud_issuance/utils/rsa.go b/super_cloud_issuance/utils/rsa.go new file mode 100644 index 0000000..fb8274a --- /dev/null +++ b/super_cloud_issuance/utils/rsa.go @@ -0,0 +1,170 @@ +package utils + +import ( + "bytes" + "crypto/rand" + "crypto/rsa" + "crypto/x509" + "encoding/pem" + "errors" + "fmt" + "io/ioutil" + "log" + "os" +) + +// 生成私钥文件 TODO 未指定路径 +func RsaKeyGen(bits int) error { + privateKey, err := rsa.GenerateKey(rand.Reader, bits) + if err != nil { + return err + } + derStream := x509.MarshalPKCS1PrivateKey(privateKey) + block := &pem.Block{ + Type: "RSA PRIVATE KEY", + Bytes: derStream, + } + priFile, err := os.Create("private.pem") + if err != nil { + return err + } + err = pem.Encode(priFile, block) + priFile.Close() + if err != nil { + return err + } + // 生成公钥文件 + publicKey := &privateKey.PublicKey + derPkix, err := x509.MarshalPKIXPublicKey(publicKey) + if err != nil { + return err + } + block = &pem.Block{ + Type: "PUBLIC KEY", + Bytes: derPkix, + } + pubFile, err := os.Create("public.pem") + if err != nil { + return err + } + err = pem.Encode(pubFile, block) + pubFile.Close() + if err != nil { + return err + } + return nil +} + +// 生成私钥文件, 返回 privateKey , publicKey, error +func RsaKeyGenText(bits int) (string, string, error) { // bits 字节位 1024/2048 + privateKey, err := rsa.GenerateKey(rand.Reader, bits) + if err != nil { + return "", "", err + } + derStream := x509.MarshalPKCS1PrivateKey(privateKey) + block := &pem.Block{ + Type: "RSA PRIVATE KEY", + Bytes: derStream, + } + priBuff := bytes.NewBuffer(nil) + err = pem.Encode(priBuff, block) + if err != nil { + return "", "", err + } + // 生成公钥文件 + publicKey := &privateKey.PublicKey + derPkix, err := x509.MarshalPKIXPublicKey(publicKey) + if err != nil { + return "", "", err + } + block = &pem.Block{ + Type: "PUBLIC KEY", + Bytes: derPkix, + } + pubBuff := bytes.NewBuffer(nil) + err = pem.Encode(pubBuff, block) + if err != nil { + return "", "", err + } + return priBuff.String(), pubBuff.String(), nil +} + +// 加密 +func RsaEncrypt(rawData, publicKey []byte) ([]byte, error) { + block, _ := pem.Decode(publicKey) + if block == nil { + return nil, errors.New("public key error") + } + pubInterface, err := x509.ParsePKIXPublicKey(block.Bytes) + if err != nil { + return nil, err + } + pub := pubInterface.(*rsa.PublicKey) + return rsa.EncryptPKCS1v15(rand.Reader, pub, rawData) +} + +// 公钥加密 +func RsaEncrypts(data, keyBytes []byte) []byte { + //解密pem格式的公钥 + block, _ := pem.Decode(keyBytes) + if block == nil { + panic(errors.New("public key error")) + } + // 解析公钥 + pubInterface, err := x509.ParsePKIXPublicKey(block.Bytes) + if err != nil { + panic(err) + } + // 类型断言 + pub := pubInterface.(*rsa.PublicKey) + //加密 + ciphertext, err := rsa.EncryptPKCS1v15(rand.Reader, pub, data) + if err != nil { + panic(err) + } + return ciphertext +} + +// 解密 +func RsaDecrypt(cipherText, privateKey []byte) ([]byte, error) { + block, _ := pem.Decode(privateKey) + if block == nil { + return nil, errors.New("private key error") + } + priv, err := x509.ParsePKCS1PrivateKey(block.Bytes) + if err != nil { + return nil, err + } + return rsa.DecryptPKCS1v15(rand.Reader, priv, cipherText) +} + +// 从证书获取公钥 +func OpensslPemGetPublic(pathOrString string) (interface{}, error) { + var certPem []byte + var err error + if IsFile(pathOrString) && Exists(pathOrString) { + certPem, err = ioutil.ReadFile(pathOrString) + if err != nil { + return nil, err + } + if string(certPem) == "" { + return nil, errors.New("empty pem file") + } + } else { + if pathOrString == "" { + return nil, errors.New("empty pem string") + } + certPem = StringToSlice(pathOrString) + } + block, rest := pem.Decode(certPem) + if block == nil || block.Type != "PUBLIC KEY" { + //log.Fatal("failed to decode PEM block containing public key") + return nil, errors.New("failed to decode PEM block containing public key") + } + pub, err := x509.ParsePKIXPublicKey(block.Bytes) + if err != nil { + log.Fatal(err) + } + fmt.Printf("Got a %T, with remaining data: %q", pub, rest) + return pub, nil +} diff --git a/super_cloud_issuance/utils/serialize.go b/super_cloud_issuance/utils/serialize.go new file mode 100644 index 0000000..1ac4d80 --- /dev/null +++ b/super_cloud_issuance/utils/serialize.go @@ -0,0 +1,23 @@ +package utils + +import ( + "encoding/json" +) + +func Serialize(data interface{}) []byte { + res, err := json.Marshal(data) + if err != nil { + return []byte{} + } + return res +} + +func Unserialize(b []byte, dst interface{}) { + if err := json.Unmarshal(b, dst); err != nil { + dst = nil + } +} + +func SerializeStr(data interface{}, arg ...interface{}) string { + return string(Serialize(data)) +} diff --git a/super_cloud_issuance/utils/shuffle.go b/super_cloud_issuance/utils/shuffle.go new file mode 100644 index 0000000..2c845a8 --- /dev/null +++ b/super_cloud_issuance/utils/shuffle.go @@ -0,0 +1,48 @@ +package utils + +import ( + "math/rand" + "time" +) + +// 打乱随机字符串 +func ShuffleString(s *string) { + if len(*s) > 1 { + b := []byte(*s) + rand.Seed(time.Now().UnixNano()) + rand.Shuffle(len(b), func(x, y int) { + b[x], b[y] = b[y], b[x] + }) + *s = string(b) + } +} + +// 打乱随机slice +func ShuffleSliceBytes(b []byte) { + if len(b) > 1 { + rand.Seed(time.Now().UnixNano()) + rand.Shuffle(len(b), func(x, y int) { + b[x], b[y] = b[y], b[x] + }) + } +} + +// 打乱slice int +func ShuffleSliceInt(i []int) { + if len(i) > 1 { + rand.Seed(time.Now().UnixNano()) + rand.Shuffle(len(i), func(x, y int) { + i[x], i[y] = i[y], i[x] + }) + } +} + +// 打乱slice interface +func ShuffleSliceInterface(i []interface{}) { + if len(i) > 1 { + rand.Seed(time.Now().UnixNano()) + rand.Shuffle(len(i), func(x, y int) { + i[x], i[y] = i[y], i[x] + }) + } +} diff --git a/super_cloud_issuance/utils/sign_check.go b/super_cloud_issuance/utils/sign_check.go new file mode 100644 index 0000000..798f63d --- /dev/null +++ b/super_cloud_issuance/utils/sign_check.go @@ -0,0 +1,125 @@ +package utils + +import ( + "applet/app/utils/logx" + "fmt" + "github.com/forgoer/openssl" + "github.com/gin-gonic/gin" + "github.com/syyongx/php2go" + "strings" +) + +var publicKey = []byte(`-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCFQD7RL2tDNuwdg0jTfV0zjAzh +WoCWfGrcNiucy2XUHZZU2oGhHv1N10qu3XayTDD4pu4sJ73biKwqR6ZN7IS4Sfon +vrzaXGvrTG4kmdo3XrbrkzmyBHDLTsJvv6pyS2HPl9QPSvKDN0iJ66+KN8QjBpw1 +FNIGe7xbDaJPY733/QIDAQAB +-----END PUBLIC KEY-----`) + +var privateKey = []byte(`-----BEGIN RSA PRIVATE KEY----- +MIICXAIBAAKBgQCFQD7RL2tDNuwdg0jTfV0zjAzhWoCWfGrcNiucy2XUHZZU2oGh +Hv1N10qu3XayTDD4pu4sJ73biKwqR6ZN7IS4SfonvrzaXGvrTG4kmdo3Xrbrkzmy +BHDLTsJvv6pyS2HPl9QPSvKDN0iJ66+KN8QjBpw1FNIGe7xbDaJPY733/QIDAQAB +AoGADi14wY8XDY7Bbp5yWDZFfV+QW0Xi2qAgSo/k8gjeK8R+I0cgdcEzWF3oz1Q2 +9d+PclVokAAmfj47e0AmXLImqMCSEzi1jDBUFIRoJk9WE1YstE94mrCgV0FW+N/u ++L6OgZcjmF+9dHKprnpaUGQuUV5fF8j0qp8S2Jfs3Sw+dOECQQCQnHALzFjmXXIR +Ez3VSK4ZoYgDIrrpzNst5Hh6AMDNZcG3CrCxlQrgqjgTzBSr3ZSavvkfYRj42STk +TqyX1tQFAkEA6+O6UENoUTk2lG7iO/ta7cdIULnkTGwQqvkgLIUjk6w8E3sBTIfw +rerTEmquw5F42HHE+FMrRat06ZN57lENmQJAYgUHlZevcoZIePZ35Qfcqpbo4Gc8 +Fpm6vwKr/tZf2Vlt0qo2VkhWFS6L0C92m4AX6EQmDHT+Pj7BWNdS+aCuGQJBAOkq +NKPZvWdr8jNOV3mKvxqB/U0uMigIOYGGtvLKt5vkh42J7ILFbHW8w95UbWMKjDUG +X/hF3WQEUo//Imsa2yECQHSZIpJxiTRueoDiyRt0LH+jdbYFUu/6D0UIYXhFvP/p +EZX+hfCfUnNYX59UVpRjSZ66g0CbCjuBPOhmOD+hDeQ= +-----END RSA PRIVATE KEY-----`) + +func GetApiVersion(c *gin.Context) int { + var apiVersion = c.GetHeader("apiVersion") + if StrToInt(apiVersion) == 0 { //没有版本号先不校验 + apiVersion = c.GetHeader("Apiversion") + } + if StrToInt(apiVersion) == 0 { //没有版本号先不校验 + apiVersion = c.GetHeader("api_version") + } + return StrToInt(apiVersion) +} + +//签名校验 +func SignCheck(c *gin.Context) bool { + var apiVersion = GetApiVersion(c) + if apiVersion == 0 { //没有版本号先不校验 + return true + } + //1.通过rsa 解析出 aes + var key = c.GetHeader("key") + + //拼接对应参数 + var uri = c.Request.RequestURI + var query = GetQueryParam(uri) + fmt.Println(query) + query["timestamp"] = c.GetHeader("timestamp") + query["nonce"] = c.GetHeader("nonce") + query["key"] = key + token := c.GetHeader("Authorization") + if token != "" { + // 按空格分割 + parts := strings.SplitN(token, " ", 2) + if len(parts) == 2 && parts[0] == "Bearer" { + token = parts[1] + } + } + query["token"] = token + //2.query参数按照 ASCII 码从小到大排序 + str := JoinStringsInASCII(query, "&", false, false, "") + //3.拼上密钥 + secret := "" + if InArr(c.GetHeader("platform"), []string{"android", "ios"}) { + secret = c.GetString("app_api_secret_key") + } else if c.GetHeader("platform") == "wap" { + secret = c.GetString("h5_api_secret_key") + } else { + secret = c.GetString("applet_api_secret_key") + } + str = fmt.Sprintf("%s&secret=%s", str, secret) + fmt.Println(str) + //4.md5加密 转小写 + sign := strings.ToLower(Md5(str)) + //5.判断跟前端传来的sign是否一致 + if sign != c.GetHeader("sign") { + return false + } + return true +} + +func ResultAes(c *gin.Context, raw []byte) string { + var key = c.GetHeader("key") + base, _ := php2go.Base64Decode(key) + aes, err := RsaDecrypt([]byte(base), privateKey) + if err != nil { + logx.Info(err) + return "" + } + + str, _ := openssl.AesECBEncrypt(raw, aes, openssl.PKCS7_PADDING) + value := php2go.Base64Encode(string(str)) + fmt.Println(value) + + return value +} + +func ResultAesDecrypt(c *gin.Context, raw string) string { + var key = c.GetHeader("key") + base, _ := php2go.Base64Decode(key) + aes, err := RsaDecrypt([]byte(base), privateKey) + if err != nil { + logx.Info(err) + return "" + } + fmt.Println(raw) + value1, _ := php2go.Base64Decode(raw) + if value1 == "" { + return "" + } + str1, _ := openssl.AesECBDecrypt([]byte(value1), aes, openssl.PKCS7_PADDING) + + return string(str1) +} diff --git a/super_cloud_issuance/utils/slice.go b/super_cloud_issuance/utils/slice.go new file mode 100644 index 0000000..30bd4ee --- /dev/null +++ b/super_cloud_issuance/utils/slice.go @@ -0,0 +1,26 @@ +package utils + +// ContainsString is 字符串是否包含在字符串切片里 +func ContainsString(array []string, val string) (index int) { + index = -1 + for i := 0; i < len(array); i++ { + if array[i] == val { + index = i + return + } + } + return +} + +func PaginateSliceInt64(x []int64, skip int, size int) []int64 { + if skip > len(x) { + skip = len(x) + } + + end := skip + size + if end > len(x) { + end = len(x) + } + + return x[skip:end] +} diff --git a/super_cloud_issuance/utils/slice_and_string.go b/super_cloud_issuance/utils/slice_and_string.go new file mode 100644 index 0000000..3ae6946 --- /dev/null +++ b/super_cloud_issuance/utils/slice_and_string.go @@ -0,0 +1,47 @@ +package utils + +import ( + "fmt" + "reflect" + "strings" + "unsafe" +) + +// string与slice互转,零copy省内存 + +// zero copy to change slice to string +func Slice2String(b []byte) (s string) { + pBytes := (*reflect.SliceHeader)(unsafe.Pointer(&b)) + pString := (*reflect.StringHeader)(unsafe.Pointer(&s)) + pString.Data = pBytes.Data + pString.Len = pBytes.Len + return +} + +// no copy to change string to slice +func StringToSlice(s string) (b []byte) { + pBytes := (*reflect.SliceHeader)(unsafe.Pointer(&b)) + pString := (*reflect.StringHeader)(unsafe.Pointer(&s)) + pBytes.Data = pString.Data + pBytes.Len = pString.Len + pBytes.Cap = pString.Len + return +} + +// 任意slice合并 +func SliceJoin(sep string, elems ...interface{}) string { + l := len(elems) + if l == 0 { + return "" + } + if l == 1 { + s := fmt.Sprint(elems[0]) + sLen := len(s) - 1 + if s[0] == '[' && s[sLen] == ']' { + return strings.Replace(s[1:sLen], " ", sep, -1) + } + return s + } + sep = strings.Replace(fmt.Sprint(elems), " ", sep, -1) + return sep[1 : len(sep)-1] +} diff --git a/super_cloud_issuance/utils/string.go b/super_cloud_issuance/utils/string.go new file mode 100644 index 0000000..e7142ef --- /dev/null +++ b/super_cloud_issuance/utils/string.go @@ -0,0 +1,155 @@ +package utils + +import ( + "fmt" + "github.com/syyongx/php2go" + "reflect" + "sort" + "strings" +) + +func Implode(glue string, args ...interface{}) string { + data := make([]string, len(args)) + for i, s := range args { + data[i] = fmt.Sprint(s) + } + return strings.Join(data, glue) +} + +//字符串是否在数组里 +func InArr(target string, str_array []string) bool { + for _, element := range str_array { + if target == element { + return true + } + } + return false +} + +//把数组的值放到key里 +func ArrayColumn(array interface{}, key string) (result map[string]interface{}, err error) { + result = make(map[string]interface{}) + t := reflect.TypeOf(array) + v := reflect.ValueOf(array) + if t.Kind() != reflect.Slice { + return nil, nil + } + if v.Len() == 0 { + return nil, nil + } + for i := 0; i < v.Len(); i++ { + indexv := v.Index(i) + if indexv.Type().Kind() != reflect.Struct { + return nil, nil + } + mapKeyInterface := indexv.FieldByName(key) + if mapKeyInterface.Kind() == reflect.Invalid { + return nil, nil + } + mapKeyString, err := InterfaceToString(mapKeyInterface.Interface()) + if err != nil { + return nil, err + } + result[mapKeyString] = indexv.Interface() + } + return result, err +} + +//转string +func InterfaceToString(v interface{}) (result string, err error) { + switch reflect.TypeOf(v).Kind() { + case reflect.Int64, reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32: + result = fmt.Sprintf("%v", v) + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + result = fmt.Sprintf("%v", v) + case reflect.String: + result = v.(string) + default: + err = nil + } + return result, err +} + +func HideTrueName(name string) string { + res := "**" + if name != "" { + runs := []rune(name) + leng := len(runs) + if leng <= 3 { + res = string(runs[0:1]) + res + } else if leng < 5 { + res = string(runs[0:2]) + res + } else if leng < 10 { + res = string(runs[0:2]) + "***" + string(runs[leng-2:leng]) + } else if leng < 16 { + res = string(runs[0:3]) + "****" + string(runs[leng-3:leng]) + } else { + res = string(runs[0:4]) + "*****" + string(runs[leng-4:leng]) + } + } + return res +} +func GetQueryParam(uri string) map[string]string { + //根据问号分割路由还是query参数 + uriList := strings.Split(uri, "?") + var query = make(map[string]string, 0) + //有参数才处理 + if len(uriList) == 2 { + //分割query参数 + var queryList = strings.Split(uriList[1], "&") + if len(queryList) > 0 { + //key value 分别赋值 + for _, v := range queryList { + var valueList = strings.Split(v, "=") + if len(valueList) == 2 { + value, _ := php2go.URLDecode(valueList[1]) + if value == "" { + value = valueList[1] + } + query[valueList[0]] = value + } + } + } + } + return query +} + +//JoinStringsInASCII 按照规则,参数名ASCII码从小到大排序后拼接 +//data 待拼接的数据 +//sep 连接符 +//onlyValues 是否只包含参数值,true则不包含参数名,否则参数名和参数值均有 +//includeEmpty 是否包含空值,true则包含空值,否则不包含,注意此参数不影响参数名的存在 +//exceptKeys 被排除的参数名,不参与排序及拼接 +func JoinStringsInASCII(data map[string]string, sep string, onlyValues, includeEmpty bool, exceptKeys ...string) string { + var list []string + var keyList []string + m := make(map[string]int) + if len(exceptKeys) > 0 { + for _, except := range exceptKeys { + m[except] = 1 + } + } + for k := range data { + if _, ok := m[k]; ok { + continue + } + value := data[k] + if !includeEmpty && value == "" { + continue + } + if onlyValues { + keyList = append(keyList, k) + } else { + list = append(list, fmt.Sprintf("%s=%s", k, value)) + } + } + if onlyValues { + sort.Strings(keyList) + for _, v := range keyList { + list = append(list, AnyToString(data[v])) + } + } else { + sort.Strings(list) + } + return strings.Join(list, sep) +} diff --git a/super_cloud_issuance/utils/time.go b/super_cloud_issuance/utils/time.go new file mode 100644 index 0000000..523eed6 --- /dev/null +++ b/super_cloud_issuance/utils/time.go @@ -0,0 +1,234 @@ +package utils + +import ( + "errors" + "fmt" + "strconv" + "strings" + "time" +) + +func StrToTime(s string) (int64, error) { + // delete all not int characters + if s == "" { + return time.Now().Unix(), nil + } + r := make([]rune, 14) + l := 0 + // 过滤除数字以外的字符 + for _, v := range s { + if '0' <= v && v <= '9' { + r[l] = v + l++ + if l == 14 { + break + } + } + } + for l < 14 { + r[l] = '0' // 补0 + l++ + } + t, err := time.Parse("20060102150405", string(r)) + if err != nil { + return 0, err + } + return t.Unix(), nil +} + +func TimeToStr(unixSecTime interface{}, layout ...string) string { + i := AnyToInt64(unixSecTime) + if i == 0 { + return "" + } + f := "2006-01-02 15:04:05" + if len(layout) > 0 { + f = layout[0] + } + return time.Unix(i, 0).Format(f) +} +func Time2String(date time.Time, format string) string { + if format == "" { + format = "2006-01-02 15:04:05" + } + timeS := date.Format(format) + if timeS == "0001-01-01 00:00:00" { + return "" + } + return timeS +} + +func FormatNanoUnix() string { + return strings.Replace(time.Now().Format("20060102150405.0000000"), ".", "", 1) +} + +func TimeParse(format, src string) (time.Time, error) { + return time.ParseInLocation(format, src, time.Local) +} + +func TimeParseStd(src string) time.Time { + t, _ := TimeParse("2006-01-02 15:04:05", src) + return t +} + +func TimeStdParseUnix(src string) int64 { + t, err := TimeParse("2006-01-02 15:04:05", src) + if err != nil { + return 0 + } + return t.Unix() +} + +// 获取一个当前时间 时间间隔 时间戳 +func GetTimeInterval(unit string, amount int) (startTime, endTime int64) { + t := time.Now() + nowTime := t.Unix() + tmpTime := int64(0) + switch unit { + case "years": + tmpTime = time.Date(t.Year()+amount, t.Month(), t.Day(), t.Hour(), 0, 0, 0, t.Location()).Unix() + case "months": + tmpTime = time.Date(t.Year(), t.Month()+time.Month(amount), t.Day(), t.Hour(), 0, 0, 0, t.Location()).Unix() + case "days": + tmpTime = time.Date(t.Year(), t.Month(), t.Day()+amount, t.Hour(), 0, 0, 0, t.Location()).Unix() + case "hours": + tmpTime = time.Date(t.Year(), t.Month(), t.Day(), t.Hour()+amount, 0, 0, 0, t.Location()).Unix() + } + if amount > 0 { + startTime = nowTime + endTime = tmpTime + } else { + startTime = tmpTime + endTime = nowTime + } + return +} + +// 几天前 +func TimeInterval(newTime int) string { + now := time.Now().Unix() + newTime64 := AnyToInt64(newTime) + if newTime64 >= now { + return "刚刚" + } + interval := now - newTime64 + switch { + case interval < 60: + return AnyToString(interval) + "秒前" + case interval < 60*60: + return AnyToString(interval/60) + "分前" + case interval < 60*60*24: + return AnyToString(interval/60/60) + "小时前" + case interval < 60*60*24*30: + return AnyToString(interval/60/60/24) + "天前" + case interval < 60*60*24*30*12: + return AnyToString(interval/60/60/24/30) + "月前" + default: + return AnyToString(interval/60/60/24/30/12) + "年前" + } +} + +// 时分秒字符串转时间戳,传入示例:8:40 or 8:40:10 +func HmsToUnix(str string) (int64, error) { + t := time.Now() + arr := strings.Split(str, ":") + if len(arr) < 2 { + return 0, errors.New("Time format error") + } + h, _ := strconv.Atoi(arr[0]) + m, _ := strconv.Atoi(arr[1]) + s := 0 + if len(arr) == 3 { + s, _ = strconv.Atoi(arr[3]) + } + formatted1 := fmt.Sprintf("%d%02d%02d%02d%02d%02d", t.Year(), t.Month(), t.Day(), h, m, s) + res, err := time.ParseInLocation("20060102150405", formatted1, time.Local) + if err != nil { + return 0, err + } else { + return res.Unix(), nil + } +} + +// 获取特定时间范围 +func GetTimeRange(s string) map[string]int64 { + t := time.Now() + var stime, etime time.Time + + switch s { + case "today": + stime = time.Date(t.Year(), t.Month(), t.Day(), 0, 0, 0, 0, t.Location()) + etime = time.Date(t.Year(), t.Month(), t.Day()+1, 0, 0, 0, 0, t.Location()) + case "yesterday": + stime = time.Date(t.Year(), t.Month(), t.Day()-1, 0, 0, 0, 0, t.Location()) + etime = time.Date(t.Year(), t.Month(), t.Day(), 0, 0, 0, 0, t.Location()) + case "within_seven_days": + // 前6天0点 + stime = time.Date(t.Year(), t.Month(), t.Day()-6, 0, 0, 0, 0, t.Location()) + // 明天 0点 + etime = time.Date(t.Year(), t.Month(), t.Day()+1, 0, 0, 0, 0, t.Location()) + case "current_month": + stime = time.Date(t.Year(), t.Month(), 0, 0, 0, 0, 0, t.Location()) + etime = time.Date(t.Year(), t.Month()+1, 0, 0, 0, 0, 0, t.Location()) + case "last_month": + stime = time.Date(t.Year(), t.Month()-1, 0, 0, 0, 0, 0, t.Location()) + etime = time.Date(t.Year(), t.Month(), 0, 0, 0, 0, 0, t.Location()) + } + + return map[string]int64{ + "start": stime.Unix(), + "end": etime.Unix(), + } +} + +// 获取特定时间范围 +func GetDateTimeRangeStr(s string) (string, string) { + t := time.Now() + var stime, etime time.Time + + switch s { + case "today": + stime = time.Date(t.Year(), t.Month(), t.Day(), 0, 0, 0, 0, t.Location()) + etime = time.Date(t.Year(), t.Month(), t.Day()+1, 0, 0, 0, 0, t.Location()) + case "yesterday": + stime = time.Date(t.Year(), t.Month(), t.Day()-1, 0, 0, 0, 0, t.Location()) + etime = time.Date(t.Year(), t.Month(), t.Day(), 0, 0, 0, 0, t.Location()) + case "within_seven_days": + // 前6天0点 + stime = time.Date(t.Year(), t.Month(), t.Day()-6, 0, 0, 0, 0, t.Location()) + // 明天 0点 + etime = time.Date(t.Year(), t.Month(), t.Day()+1, 0, 0, 0, 0, t.Location()) + case "current_month": + stime = time.Date(t.Year(), t.Month(), 0, 0, 0, 0, 0, t.Location()) + etime = time.Date(t.Year(), t.Month()+1, 0, 0, 0, 0, 0, t.Location()) + case "last_month": + stime = time.Date(t.Year(), t.Month()-1, 0, 0, 0, 0, 0, t.Location()) + etime = time.Date(t.Year(), t.Month(), 0, 0, 0, 0, 0, t.Location()) + } + + return stime.Format("2006-01-02 15:04:05"), etime.Format("2006-01-02 15:04:05") +} + +// 获取传入的时间所在月份的第一天,即某月第一天的0点。如传入time.Now(), 返回当前月份的第一天0点时间。 +func GetFirstDateOfMonth(d time.Time) time.Time { + d = d.AddDate(0, 0, -d.Day()+1) + return GetZeroTime(d) +} + +// 获取传入的时间所在月份的最后一天,即某月最后一天的0点。如传入time.Now(), 返回当前月份的最后一天0点时间。 +func GetLastDateOfMonth(d time.Time) time.Time { + return GetFirstDateOfMonth(d).AddDate(0, 1, -1) +} + +// 获取某一天的0点时间 +func GetZeroTime(d time.Time) time.Time { + return time.Date(d.Year(), d.Month(), d.Day(), 0, 0, 0, 0, d.Location()) +} + +// 获取两个时间相差的天数,0表同一天,正数表t1>t2,负数表t1 2 || kind < 0 + rand.Seed(time.Now().UnixNano()) + for i := 0; i < size; i++ { + if isAll { // random ikind + ikind = rand.Intn(3) + } + scope, base := kinds[ikind][0], kinds[ikind][1] + result[i] = uint8(base + rand.Intn(scope)) + } + return result +} + +// OrderUUID is only num for uuid +func OrderUUID(uid int) string { + ustr := IntToStr(uid) + tstr := Int64ToStr(time.Now().Unix()) + ulen := len(ustr) + tlen := len(tstr) + rlen := 18 - ulen - tlen + krb := Krand(rlen, KC_RAND_KIND_NUM) + return ustr + tstr + string(krb) +} + +var flake *sonyflake.Sonyflake + +func GenId() int64 { + + id, err := flake.NextID() + if err != nil { + _ = logx.Errorf("flake.NextID() failed with %s\n", err) + panic(err) + } + return int64(id) +} diff --git a/super_cloud_issuance/utils/validator_err_trans.go b/super_cloud_issuance/utils/validator_err_trans.go new file mode 100644 index 0000000..29d97bf --- /dev/null +++ b/super_cloud_issuance/utils/validator_err_trans.go @@ -0,0 +1,55 @@ +package utils + +import ( + "fmt" + "github.com/gin-gonic/gin/binding" + "github.com/go-playground/locales/en" + "github.com/go-playground/locales/zh" + ut "github.com/go-playground/universal-translator" + "github.com/go-playground/validator/v10" + enTranslations "github.com/go-playground/validator/v10/translations/en" + chTranslations "github.com/go-playground/validator/v10/translations/zh" + "reflect" +) + +var ValidatorTrans ut.Translator + +// ValidatorTransInit 验证器错误信息翻译初始化 +// local 通常取决于 http 请求头的 'Accept-Language' +func ValidatorTransInit(local string) (err error) { + if v, ok := binding.Validator.Engine().(*validator.Validate); ok { + zhT := zh.New() //chinese + enT := en.New() //english + uni := ut.New(enT, zhT, enT) + + var o bool + ValidatorTrans, o = uni.GetTranslator(local) + if !o { + return fmt.Errorf("uni.GetTranslator(%s) failed", local) + } + // 注册一个方法,从自定义标签label中获取值(用在把字段名映射为中文) + v.RegisterTagNameFunc(func(field reflect.StructField) string { + label := field.Tag.Get("label") + if label == "" { + return field.Name + } + return label + }) + // 注册翻译器 + switch local { + case "en": + err = enTranslations.RegisterDefaultTranslations(v, ValidatorTrans) + case "zh": + err = chTranslations.RegisterDefaultTranslations(v, ValidatorTrans) + default: + err = enTranslations.RegisterDefaultTranslations(v, ValidatorTrans) + } + return + } + return +} + +// ValidatorTransInitZh 验证器错误信息翻译为中文初始化 +func ValidatorTransInitZh() (err error) { + return ValidatorTransInit("zh") +} From bb78641039e3a4794f8589dfc063bff083be7b5b Mon Sep 17 00:00:00 2001 From: dengbiao Date: Mon, 1 Jul 2024 16:07:38 +0800 Subject: [PATCH 2/2] update --- consume/init.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/consume/init.go b/consume/init.go index b9c7ce5..d3ae98f 100644 --- a/consume/init.go +++ b/consume/init.go @@ -99,7 +99,7 @@ func initConsumes() { jobs[consumeMd.InstallmentPaymentAutoRepaidConsumeFunName] = InstallmentPaymentAutoRepaidConsume //分期付 - 自动扣款 ////////////////////////////////////// SuperCloudIssuance ///////////////////////////////////////////////////// - jobs[consumeMd.SuperCloudIssuanceMsgCallBackFunName] = SuperCloudIssuanceMsgCallBackConsume + //jobs[consumeMd.SuperCloudIssuanceMsgCallBackFunName] = SuperCloudIssuanceMsgCallBackConsume } func Run() {