package application import ( "encoding/json" "finclip-app-manager/domain/entity" "finclip-app-manager/domain/entity/proto" "finclip-app-manager/domain/entity/proto/apiproto" "finclip-app-manager/domain/service" "finclip-app-manager/infrastructure/config" "finclip-app-manager/infrastructure/logger" "finclip-app-manager/infrastructure/utility" "finclip-app-manager/infrastructure/utils" "fmt" "net/http" "net/url" "path" "strconv" "strings" "time" "github.com/gin-gonic/gin" uuid "github.com/satori/go.uuid" "gitlab.finogeeks.club/finclip-backend/apm" ) /** * @api {POST} * @apiGroup Finclip App Manager * @apiParam (RequestBody) {string} appId 小程序Id * @apiParam (RequestBody) {string} sequence 小程序序列号 * @apiParam (RequestBody) {string} apiServer 小程序apiServer * @apiParam (RequestBody) {string} type * @apiParam (RequestBody) {string} codeId 标识某个编译版本的id * @apiParam (RequestBody) {string} startParams 小程序启动参数 * @apiParamExample {json} Request-Example: * { * "appId": "5fd17becec413300012b1911", * "sequence": 0, * "apiServer": "https://finchat-mop-b.finogeeks.club", * "type": "trial", * "codeId": "c1218720c7a34e5f43b3b6d3", * "startParams": { * "path": "", * "query": "" * } * } * @apiSuccessExample {json} Success Status: * HTTP/1.1 200 OK * { * "data": { * "url": "https://finchat-mop-b.finogeeks.club/api/v1/mop/runtime/applet/-f-NDhiNThiOGIwYjJlNDdmZg--" * }, * "errcode": "OK", * "error": "" * } * @apiErrorExample Error Status: * HTTP/1.1 !=200 服务端异常 */ func GenQrcodeHand(c *gin.Context) { traceCtx := apm.ApmClient().TraceContextFromGin(c) req := proto.GenQrcodeReq{} if err := c.BindJSON(&req); err != nil { log.Errorf("GenQrcodeHand bind err:%s", err.Error()) utility.MakeLocRsp(c, http.StatusInternalServerError, utility.FS_PARAM_ERR, gin.H{}) return } log.Infof("GenQrcodeHand req:%+v", req) svr := service.NewQrCodeInfoService() info, err := svr.GenQrcodeInfo(traceCtx, req) if err != nil { log.Errorf("GenQrcodeHand GenQrcodeInfo err:%s", err.Error()) utility.MakeLocRsp(c, http.StatusInternalServerError, utility.FS_DB_ERR, gin.H{}) return } log.Debugf("get qrcode type:%s info:%+v", info.Type, info) rspInfo := gin.H{} if info.Type == entity.QrCodeTypeTemporary || info.Type == entity.QrCodeTypeRomoteDebug || info.Type == entity.QrCodeTypeReview { rspInfo["expireTime"] = info.ExpireTime } server, err := parseServer(req.ApiServer) if err != nil { log.Errorf("gen url err:%s", err.Error()) utility.MakeLocRsp(c, http.StatusBadRequest, utility.FS_PARAM_ERR, gin.H{}) return } var serverUrl string if req.Limit != "" { serverUrl = config.GetConfig().QRcodeUriV2 } else { serverUrl = config.GetConfig().QRcodeUri } resultUrl := server + path.Join(serverUrl, req.Limit, "/", info.Uuid) rspInfo["url"] = resultUrl log.Debugf("qrcode type:%s result info:%+v", info.Type, rspInfo) utility.MakeLocRsp(c, http.StatusOK, utility.OK, rspInfo) return } //对原有的二维码逻辑进行重新处理 //文档见:https://wiki.finogeeks.club/pages/viewpage.action?pageId=161317118 func joinUrl(server string, uri, uuid string) (string, error) { u, err := url.Parse(server) if err != nil { return "", err } u.Path = path.Join(u.Path, uri, uuid) return u.String(), nil } func parseServer(server string) (string, error) { u, err := url.Parse(server) if err != nil { return "", err } return u.String(), nil } type appQRcodeInfoReq struct { AppID string `json:"appId"` Sequence int `json:"sequence"` ApiServer string `json:"apiServer"` CodeId string `json:"codeId"` Type string `json:"type"` StartParams appQRcodeInfoStartParams `json:"startParams"` } type appQRcodeInfoStartParams struct { Path string `json:"path"` Query string `json:"query"` } type EncryptInfo struct { AppID string `json:"appId"` Sequence int `json:"sequence"` ApiServer string `json:"apiServer"` CodeId string `json:"codeId"` Type string `json:"type"` StartParams appQRcodeInfoStartParams `json:"startParams"` ExpireTime int64 `json:"expireTime"` Uuid string `json:"uuid"` } type appQRcodeInfoRsp struct { QRData string `json:"qrData"` ExpireTime int `json:"expireTime"` } /** * @api {GET} * @apiGroup Finclip App Manager * @apiSuccessExample {json} Success Status: * HTTP/1.1 200 OK * { * "errcode": "OK", * "error": "成功", * "data":{ * * } * } * @apiErrorExample Error Status: * HTTP/1.1 !=200 服务端异常 */ func QRCodeRefresh(c *gin.Context) { req := appQRcodeInfoReq{} if err := c.ShouldBindJSON(&req); err != nil { log.Errorf("appInfo bind err:%s", err.Error()) utility.MakeLocRsp(c, http.StatusBadRequest, utility.FS_BAD_JSON, nil) return } log.Infof("QRCodeRefresh req:%+v", req) addSecond, _ := time.ParseDuration(strconv.Itoa(config.GetConfig().QRcodeExpireTime) + "s") encryptData := EncryptInfo{} encryptData.AppID = req.AppID encryptData.Sequence = req.Sequence encryptData.ApiServer = req.ApiServer encryptData.CodeId = req.CodeId encryptData.Type = req.Type if config.GetConfig().ApiServer != "" { encryptData.ApiServer = config.GetConfig().ApiServer } encryptData.StartParams.Path = req.StartParams.Path encryptData.StartParams.Query = req.StartParams.Query //过期时间 encryptData.ExpireTime = -1 encryptData.Uuid = uuid.NewV4().String() if req.Type == "temporary" { encryptData.ExpireTime = time.Now().Add(addSecond).UnixNano() / 1e6 } jsonByte, _ := json.Marshal(encryptData) logger.GetLogger().Debugf("jsonByte:%s", string(jsonByte)) encodeStr := utils.EncodeAESContent(string(jsonByte)) //if req.Type == "temporary" { // /*err := cache.NewAppCache(req.AppID).SetAppInfoQRcode(traceCtx, encodeStr, jsonByte, config.Cfg.QRcodeExpireTime) // if err != nil { // logger.GetLogger().Errorf("redis set data error:", err.Error()) // MakeRsp(c, http.StatusBadRequest, utility.FS_REDIS_ERR, nil) // return // }*/ // encryptData.ExpireTime = time.Now().Add(addSecond).UnixNano() / 1e6 //} rsp := appQRcodeInfoRsp{} rsp.QRData = encodeStr rsp.ExpireTime = config.GetConfig().QRcodeExpireTime utility.MakeLocRsp(c, http.StatusOK, utility.OK, rsp) return } /** * @api {GET} * @apiGroup Finclip App Manager * @apiSuccessExample {json} Success Status: * HTTP/1.1 200 OK * { * "errcode": "OK", * "error": "成功", * "data":{ * * } * } * @apiErrorExample Error Status: * HTTP/1.1 !=200 服务端异常 */ func InternalGetQRcodeAppVerInfo(c *gin.Context) { //traceCtx := apm.ApmClient().TraceContextFromGin(c) SDKKey := c.GetHeader(entity.SDKKEY_HEADER_KEY) redisKey := c.GetHeader("redisKey") log.Infof("InternalGetAppVerInfo req appId:%s,seq:%s,sdk-key:%s,sdk-ver:%s", SDKKey, redisKey) rspErr := make(map[string]interface{}) if redisKey == "" { log.Errorf("InternalGetAppVerInfo redisKey empty!!!") utility.MakeLocRsp(c, http.StatusBadRequest, utility.FS_LACK_OF_APPID, rspErr) return } if SDKKey == "" { log.Errorf("InternalGetAppVerInfo sdk-key empty!!!") utility.MakeLocRsp(c, http.StatusBadRequest, utility.FS_LACK_OF_SDKKEY, rspErr) return } //sdkKey白名单的校验 if !utils.InArry(SDKKey, config.WhiteSDKArry) { log.Errorf("RuntimeGetAppVersionInfo sdk not in white sdk arry,sdk-key:%s", SDKKey) utility.MakeLocRsp(c, http.StatusForbidden, utility.FS_COOPERATION_TERMINATED, rspErr) return } /* appVerSvr := service.NewAppVerService() data, httpCode, errcode := appVerSvr.OpenApiGetAppVerInfo(traceCtx, appId, sequence, sdkVer) if data == nil { MakeRsp(c, httpCode, errcode, rspErr) return } MakeRsp(c, httpCode, errcode, data)*/ rspInfo := InternalGetAppVerInfoRsp{} // 临时注释 //dataBytes, err := cache.NewQRcodeAppCache().GetQRcodeAppInfo(c, redisKey) //fmt.Println("dataBytes------------", dataBytes) //if err != nil { // if len(dataBytes) == 0 { // log.Debugln("qrcode is refresh:") // utility.MakeLocRsp(c, http.StatusOK, utility.FS_QRCODE_HAS_EXPIRE, rspInfo) // return // } else { // log.Errorf("redis error:", err.Error()) // utility.MakeLocRsp(c, http.StatusBadRequest, utility.FS_DB_ERR, rspInfo) // return // } //} //err = json.Unmarshal(dataBytes, &rspInfo) //if err != nil { // log.Errorf("json unmarshal error:", err.Error()) // utility.MakeLocRsp(c, http.StatusBadRequest, utility.FS_BAD_JSON, rspInfo) // return //} utility.MakeLocRsp(c, http.StatusOK, utility.OK, rspInfo) return } /** * @api {GET} * @apiGroup Finclip App Manager * @apiSuccessExample {json} Success Status: * HTTP/1.1 200 OK * { * "errcode": "OK", * "error": "成功", * "data":{ * * } * } * @apiErrorExample Error Status: * HTTP/1.1 !=200 服务端异常 */ func DeleteWechatQrcode(c *gin.Context) { traceCtx := apm.ApmClient().TraceContextFromGin(c) req := apiproto.DeleteWechatInfoReq{} if err := c.ShouldBindJSON(&req); err != nil { log.Errorf("UpdateWechatInfo err:%s", err.Error()) utility.MakeLocRsp(c, http.StatusBadRequest, utility.FS_BAD_JSON, nil) return } svr := service.NewQrCodeInfoService() if err := svr.DeleteWechatQrcode(traceCtx, req); err != nil { log.Errorf("DeleteWechatQrcode err:%s", err.Error()) utility.MakeLocRsp(c, http.StatusBadRequest, utility.FS_DB_ERR, nil) return } utility.MakeLocRsp(c, http.StatusOK, utility.OK, nil) return } /** * @api {GET} * @apiGroup Finclip App Manager * @apiSuccessExample {json} Success Status: * HTTP/1.1 200 OK * { * "errcode": "OK", * "error": "成功", * "data":{ * * } * } * @apiErrorExample Error Status: * HTTP/1.1 !=200 服务端异常 */ func GetQrcodeInfo(c *gin.Context) { traceCtx := apm.ApmClient().TraceContextFromGin(c) uuid := c.Param("uuid") log.Infof("GetQrcodeInfo req uuid:%v", uuid) svr := service.NewQrCodeInfoService() info, err := svr.GetQrcodeInfo(traceCtx, uuid) log.Errorf(utility.InterfaceToJsonString(info)) if err != nil { log.Errorf("GetQrcodeInfo err:%s", err.Error()) if err == entity.NotFoundErr { utility.MakeLocRsp(c, http.StatusNotFound, utility.FS_NOT_FOUND, gin.H{}) return } utility.MakeLocRsp(c, http.StatusInternalServerError, utility.FS_DB_ERR, gin.H{}) return } now := time.Now().UnixNano() / 1e6 if info.Type == entity.QrCodeTypeReview && now >= info.ExpireTime { utility.MakeLocRsp(c, http.StatusBadRequest, utility.FS_QR_CODE_EXPIRED, gin.H{}) return } //uat多域名兼容 if utils.InArry(info.ApiServer, config.GetConfig().UatDomainList) { info.ApiServer = "https://api.finclip.com" } //if info.ApiServer == "https://www.finclip.com" || info.ApiServer == "https://www.finclip.com/" { // info.ApiServer = "https://api.finclip.com" //} resultInfo := make(map[string]interface{}) resultInfo["apiServer"] = info.ApiServer resultInfo["type"] = info.Type switch info.Type { case entity.QrCodeTypeReview: resultInfo["appId"] = info.AppId resultInfo["sequence"] = info.Sequence resultInfo["expireTime"] = info.ExpireTime case entity.QrCodeTypeRelease: resultInfo["appId"] = info.AppId case entity.APP_BUILD_SOURCE_TRIAL: resultInfo["codeId"] = info.CodeId //这里的返回做一个转换 StartParamsMap := map[string]string{ "path": "", "query": "", } paramList := strings.Split(info.StartParams.PathAndQuery, "?") if len(paramList) > 0 { StartParamsMap["path"] = paramList[0] } if len(paramList) > 1 { StartParamsMap["query"] = paramList[1] } resultInfo["startParams"] = StartParamsMap case entity.QrCodeTypeTemporary: resultInfo["appId"] = info.AppId resultInfo["codeId"] = info.AppId resultInfo["sequence"] = info.Sequence resultInfo["expireTime"] = info.ExpireTime StartParamsMap := map[string]string{ "path": "", "query": "", } paramList := strings.Split(info.StartParams.PathAndQuery, "?") if len(paramList) > 0 { StartParamsMap["path"] = paramList[0] } if len(paramList) > 1 { StartParamsMap["query"] = paramList[1] } resultInfo["startParams"] = StartParamsMap case entity.QrCodeTypeRomoteDebug: resultInfo["appId"] = info.AppId resultInfo["codeId"] = info.AppId resultInfo["sequence"] = info.Sequence resultInfo["expireTime"] = info.ExpireTime resultInfo["debugInfo"] = info.DebugInfo } log.Infof("GetQrcodeInfo rsp:%+v", resultInfo) infoByte, _ := json.Marshal(resultInfo) infoStr := utils.EncodeAESContent(string(infoByte)) log.Infof("info.ApiServer:%v", info.ApiServer) link := info.ApiServer + "/mop/scattered-page/#/sdktip" resultUrl := fmt.Sprintf("%s?info=%s&type=scanOpen&codeType=%s", link, infoStr, info.Type) //resultUrl := fmt.Sprintf("%s/mop/scattered-page/#/sdktip?info=%s&type=scanOpen&codeType=%s", info.ApiServer, infoStr, info.Type) //c.Redirect(http.StatusMovedPermanently, resultUrl) utility.MakeLocRsp(c, http.StatusOK, utility.OK, gin.H{"url": resultUrl}) return } const ( QRCodeMinWidth = 280 QRCodeMaxWidth = 1280 QRCodeDefaultWidth = 430 ) func GetQRCode(c *gin.Context) { //traceCtx := apm.ApmClient().TraceContextFromGin(c) //appID := c.Param("path1") //widthStr := c.Query("width") //width := QRCodeDefaultWidth //if widthStr != "" { // var err error // width, err = strconv.Atoi(c.Query("width")) // if err != nil { // //msg := "Invalid width format: should be integer" // utility.MakeLocRsp(c, http.StatusBadRequest, utility.FS_BAD_JSON, nil) // return // } //} //if width < QRCodeMinWidth || width > QRCodeMaxWidth { // //msg := "Invalid width" // utility.MakeLocRsp(c, http.StatusBadRequest, utility.FS_BAD_JSON, nil) // return //} //if appID == "" { // //msg := "Lack of appId" // utility.MakeLocRsp(c, http.StatusBadRequest, utility.FS_BAD_JSON, nil) // return //} //qr := model.QRCode{} //if err := qr.GetOne(traceCtx, bson.M{"appId": appID}); err != nil { // if err.Error() == model.ErrorNotFound { // msg := fmt.Sprintf("QR Code info with appId %s not found", appID) // LogAndSetErrResp(c, http.StatusNotFound, FS_NOT_FOUND, nil, msg, nil) // return // } //} //app := model.App{} //if err := app.GetOne(traceCtx, bson.M{"appId": appID}); err != nil { // if err.Error() == model.ErrorNotFound { // msg := fmt.Sprintf("App with appId %s not found", appID) // LogAndSetErrResp(c, http.StatusBadRequest, FS_BAD_JSON, nil, msg, nil) // } else { // LogAndSetErrResp(c, http.StatusInternalServerError, FS_SYSTEM_CALL, err, "Failed to get app", nil) // } // return //} ////qrCodeStr := fmt.Sprintf("%s://applet/appid/%s?path=%s", qr.Scheme, appID, qr.Path) //qrCodeStr := fmt.Sprintf("%s://applet/appid/%s", qr.Scheme, appID) //if qr.Path != "" { // qrCodeStr = qrCodeStr + "?path=" + qr.Path //} //bytes, err := createQRCode(traceCtx, qrCodeStr, app.Logo, width) //if err != nil { // LogAndSetErrResp(c, http.StatusInternalServerError, FS_SYSTEM_CALL, err, "Failed create QR Code", nil) // return //} //c.Data(http.StatusOK, "image/png", bytes) } func GetQRCodeInfo(c *gin.Context) { }