Parcourir la source

添加tile处理

liwei il y a 2 ans
Parent
commit
28569e0f63

+ 43 - 427
3dshow-supplier/api/asset.go

@@ -1,36 +1,20 @@
 package api
 
 import (
-	"3dshow-supplier/conf"
+	"3dshow-supplier/bus"
 	"3dshow-supplier/db/model"
 	"3dshow-supplier/db/repo"
-	"3dshow-supplier/log"
-	"bytes"
-	"context"
-	"crypto/tls"
-	"errors"
-	"fmt"
-	"image"
-	"io"
-	"io/ioutil"
-	"net/http"
-	"os"
-	"os/exec"
-	"path"
-	"strings"
+	"3dshow-supplier/funcgraph"
 	"time"
 
 	_ "image/jpeg"
 	_ "image/png"
 
 	"github.com/gin-gonic/gin"
-	"github.com/huaweicloud/huaweicloud-sdk-go-obs/obs"
 	"go.mongodb.org/mongo-driver/bson"
 	"go.mongodb.org/mongo-driver/bson/primitive"
 )
 
-var ffmpegExe = ""
-
 func regAssetApi(r *GinRouter) {
 
 	// 添加管理端接口
@@ -43,6 +27,15 @@ func regAssetApi(r *GinRouter) {
 			entity.SupplyId, _ = primitive.ObjectIDFromHex(apictx.User.Parent)
 			entity.CreateTime = time.Now()
 
+			if entity.Groups != nil {
+				for _, g := range entity.Groups {
+					if len(g.ImagesPath) < 1 {
+						g.State = model.GROUPSTATE_UNSET
+					} else {
+						g.State = model.GROUPSTATE_ADDED
+					}
+				}
+			}
 			return entity, nil
 		},
 
@@ -58,419 +51,42 @@ func regAssetApi(r *GinRouter) {
 		},
 		JWT:           true,
 		SearchProject: []string{"name", "createTime", "type", "unit", "price", "cover", "status"},
-	})
-
-	r.POST("/assets/conv/:id/:groupId", AssetsConv)
-}
-
-func AssetsConv(c *gin.Context, apictx *ApiSession) (interface{}, error) {
-
-	params := c.Params
-	id, ok := params.Get("id")
-	if !ok {
-		return nil, errors.New("id不能为空")
-	}
-	groupId, ok := params.Get("groupId")
-	if !ok {
-		return nil, errors.New("groupId不能为空")
-	}
-
-	startTime := time.Now()
-	dir, _ := os.Getwd()
-	ffmpegExe = fmt.Sprintf("%s/ffmpeg", dir)
-	wPath := fmt.Sprintf("%s/%s/%s/spin_360", "assets", id, groupId)
-	oPath := fmt.Sprintf("%s/%s/%s/spin_360", "images", id, groupId)
-
-	// todo下载图片到oPth
-	currAsset := &model.Asset360Fake3d{}
-	ok, _ = repo.RepoSeachDoc(apictx.CreateRepoCtx(), &repo.DocSearchOptions{
-		CollectName: repo.CollectionAssets,
-		Query:       repo.Map{"_id": id},
-	}, currAsset)
-	if !ok {
-		return nil, fmt.Errorf("当前资产不存在")
-	}
-
-	groupPath := ""
-	for _, item := range currAsset.Groups {
-		if item.Id == groupId {
-			groupPath = item.ImagesPath
-			break
-		}
-	}
-	if len(groupPath) < 1 {
-		return nil, fmt.Errorf("当前素材才尚未上传")
-	}
-
-	_getImageIndex := func(i int) string {
-		if i < 10 {
-			return fmt.Sprintf("00_0%d.png", i)
-		}
-
-		return fmt.Sprintf("00_%d.png", i)
-	}
-
-	index := 0
-	for {
-		name := _getImageIndex(index)
-		remoteUrl := fmt.Sprintf("%s/%s", groupPath, name)
-
-		//下载文件
-		err := DownLoadFile(remoteUrl, fmt.Sprintf("%s/%s", oPath, name))
-		if err != nil {
-			return nil, fmt.Errorf("文件下载失败!")
-		}
-	}
-
-	// 获取图片
-	files, _ := os.ReadDir(oPath)
-	levels := map[int]int{4: 10, 2: 11, 1: 12}
-
-	// 递归创建
-	os.MkdirAll(wPath, os.ModePerm)
-
-	for _, f := range files {
-		fi, _ := os.Open(fmt.Sprintf("./%s/%s", oPath, f.Name()))
-
-		imageInfo, _, _ := image.DecodeConfig(fi)
-		defer fi.Close()
-
-		filePrefix := getFilePrefix(f.Name())
-		// 生成每个文件目录 00_00_files
-		preFileDir := fmt.Sprintf("%s/%s%s", wPath, filePrefix, "_files")
-		os.Mkdir(preFileDir, os.ModePerm)
-
-		// 生成cover 384/512
-		// asset/spin_360/00_00_cover.png
-		orignFile := fmt.Sprintf("%s/%s", oPath, f.Name())
-		coverFile := fmt.Sprintf("%s/%s_cover%s", wPath, filePrefix, path.Ext(f.Name()))
-		scaleImage(384, 512, orignFile, coverFile)
-
-		// 生成json文件 asset/spin_360/00_00.json
-		jsonContent := fmt.Sprintf("{\"tileSource\": \"%s\",\"tileSize\": 510,\"width\": 1944,\"height\": 2592,\"sceneType\": \"spin\",\"scaleType\": \"inside\",\"minLevel\": 10,\"coverWidth\": 384,\"coverHeight\": 512,\"dziFile\": \"%s.dzi\",\"coverImage\":\"%s\"}", fmt.Sprintf("%s%s", filePrefix, "_files"), filePrefix, fmt.Sprintf("%s_cover%s", filePrefix, path.Ext(f.Name())))
-		jsonFileName := fmt.Sprintf("%s/%s.json", wPath, filePrefix)
-		setJsonFile(jsonFileName, jsonContent)
-
-		// 文件目录下level目录 00_00_files/10 11 23
-		for scale, level := range levels {
-			preLevelDir := fmt.Sprintf("%s/%s%s/%d", wPath, filePrefix, "_files", level)
-			os.Mkdir(preLevelDir, os.ModePerm)
-
-			// 生成缩略图
-			levelW := imageInfo.Width / scale
-			levelH := imageInfo.Height / scale
-
-			levelDest := fmt.Sprintf("%s/%s%s/%d", wPath, filePrefix, "_files", level)
-			levelScaleImage := fmt.Sprintf("%s/%s_scale%s", levelDest, filePrefix, path.Ext(f.Name()))
-			scaleImage(levelW, levelH, orignFile, levelScaleImage)
-
-			// 裁剪缩略图
-			createLevel(levelW, levelH, levelScaleImage, levelDest)
-			os.Remove(levelScaleImage)
-		}
-	}
-	// 删除图片文件
-	// os.Remove(oPath)
-	// os.Remove(wPath)
-
-	fmt.Println(time.Since(startTime).Seconds())
-
-	key := wPath
-	_url, _ := serviceObsUploadPolicy(key, apictx.Svc.Conf)
-
-	url := fmt.Sprintf("%s%s", "https://www.3dqueen.cloud/asset360/index.html?apath=", _url)
-
-	result, err := repo.RepoDocArrayOneUpdate(apictx.CreateRepoCtx(), &repo.ArrayOneUpdateOption{
-		CollectName: repo.CollectionAssets,
-		Id:          id,
-		Query:       repo.Map{"groups.id": groupId},
-		Set:         repo.Map{"groups.$.url": url},
-	})
-
-	return result, err
-
-}
-
-func createLevel(w, h int, source, dest string) {
-
-	xIndex := 0
-	yIndex := 0
-	step := 510
-	for {
-
-		offsetX := xIndex * step
-		cropX := offsetX - 1
-		cropW := 512
-		if xIndex == 0 {
-			cropW = 511
-			cropX = 0
-		}
-		isOver := false
-		if w < 511 {
-			cropW = w
-			isOver = true
-		}
-		if (offsetX - 1 + cropW) >= w {
-			cropW = w - offsetX + 1
-			isOver = true
-		}
-
-		for {
-
-			offsetY := yIndex * step
-			cropY := offsetY - 1
-			cropH := 512
-			if yIndex == 0 {
-				cropH = 511
-				cropY = 0
+		OnUpdate: func(c *gin.Context, apictx *ApiSession, entity interface{}, id primitive.ObjectID) {
+			asset := entity.(*model.Asset360Fake3d)
+			if asset == nil {
+				return
 			}
-			isYOver := false
-			if (offsetY - 1 + cropH) >= h {
-				cropH = h - offsetY + 1
-				isYOver = true
+			natsUrl := ""
+			if asset.Groups == nil {
+				return
 			}
 
-			//开始按参数裁剪
-			cropImage(cropX, cropY, cropW, cropH, xIndex, yIndex, source, dest)
-			fmt.Println("x:", cropX)
-			fmt.Println("y:", cropY)
-			fmt.Println("w:", cropW)
-			fmt.Println("h:", cropH)
-			fmt.Println("yIndex:", yIndex)
-
-			yIndex = yIndex + 1
-
-			if isYOver {
-				break
+			for _, g := range asset.Groups {
+				if len(g.ImagesPath) < 1 {
+					g.State = model.GROUPSTATE_UNSET
+				} else {
+					if len(g.State) < 1 {
+						g.State = model.GROUPSTATE_ADDED
+					}
+				}
+
+				if g.State == model.GROUPSTATE_ADDED && len(g.ImagesPath) > 1 {
+					if len(natsUrl) < 1 {
+						url, err := bus.NatsCenter.RequestConfig("bus-network")
+						if err != nil {
+							g.State = model.GROUPSTATE_FAIL
+							return
+						}
+						natsUrl = url
+					}
+					err := funcgraph.Tile360onvRequest(id.Hex(), g.Id, g.ImagesPath, natsUrl)
+					if err != nil {
+						g.State = model.GROUPSTATE_FAIL
+					} else {
+						g.State = model.GROUPSTATE_CROPING
+					}
+				}
 			}
-		}
-
-		yIndex = 0
-		xIndex = xIndex + 1
-		if isOver {
-			break
-		}
-	}
-}
-
-// asset/spin_360/00_00.json
-func setJsonFile(fileName string, content string) {
-	f, err := os.Create(fileName)
-	if err != nil {
-		return
-	}
-	f.WriteString(content)
-	defer f.Close()
-}
-
-// 获取不带后缀文件名
-func getFilePrefix(fileName string) string {
-	fileSilce := strings.Split(fileName, ".")
-	return fileSilce[0]
-}
-
-// asset/spin_360_scene/00_00_files/10/00_00_scale.png asset/spin_360_scene/00_00_files/10
-func cropImage(x, y, w, h int, xIndex, yIndex int, source, dest string) {
-	ctx, cancel := context.WithTimeout(context.Background(), time.Duration(50000)*time.Millisecond)
-	cmd := exec.CommandContext(ctx, ffmpegExe,
-		"-i", source,
-		"-vf", fmt.Sprintf("crop=%d:%d:%d:%d", w, h, x, y),
-		fmt.Sprintf("%s/%d_%d%s", dest, xIndex, yIndex, path.Ext(source)),
-	)
-	defer cancel()
-
-	err := cmd.Run()
-	if err != nil {
-		errImage := fmt.Sprintf("%s/%d_%d%s", dest, xIndex, yIndex, path.Ext(source))
-		fmt.Println("err image:", errImage)
-		fmt.Println("crop err", err)
-	}
-}
-
-func scaleImage(w, h int, source, dest string) {
-	ctx, cancel := context.WithTimeout(context.Background(), time.Duration(50000)*time.Millisecond)
-	// ffmpeg -i image_source -vf scale=width:height out_source
-	cmd := exec.CommandContext(ctx, ffmpegExe,
-		"-i", source,
-		"-vf", fmt.Sprintf("scale=%d:%d", w, h),
-		dest,
-	)
-	defer cancel()
-
-	err := cmd.Run()
-	if err != nil {
-		fmt.Println("scale err", err)
-	}
-}
-
-func serviceObsUploadPolicy(key string, conf *conf.AppConf) (interface{}, error) {
-
-	client, err := CreateObsClient()
-	if err != nil {
-		return nil, NewError("创建ObsClient 失败!")
-	}
-	defer func() {
-		client.Close()
-	}()
-	bucketName := conf.Obs.Bucket
-	_, err = client.CreateBrowserBasedSignature(&obs.CreateBrowserBasedSignatureInput{
-		Bucket:  bucketName,
-		Key:     key,
-		Expires: 600,
-		FormParams: map[string]string{
-			"x-obs-acl": "public-read",
 		},
 	})
-
-	if err != nil {
-		return nil, NewLogWithError(err)
-	}
-	obsConf := conf.Obs
-	// out := map[string]interface{}{
-	// 	"accessKeyId":  obsConf.AccessKeyId,
-	// 	"originPolicy": result.OriginPolicy,
-	// 	"policy":       result.Policy,
-	// 	"signature":    result.Signature,
-	// 	"host":         fmt.Sprintf("https://%s.%s", bucketName, obsConf.Endpoint),
-	// 	"key":          key,
-	// 	"saveType":     conf.SaveType,
-	// }
-	url := fmt.Sprintf("%s/%s", fmt.Sprintf("https://%s.%s", bucketName, obsConf.Endpoint), key)
-	return url, nil
-}
-
-func CreateObsClient() (*obs.ObsClient, error) {
-	obsConf := conf.AppConfig.Obs
-	return obs.New(obsConf.AccessKeyId, obsConf.SecrateKey, obsConf.Endpoint)
-}
-
-func uploadImage(fpath string, obsDir string) (string, error) {
-	client, err := CreateObsClient()
-	if err != nil {
-		return "", err
-	}
-	obsConf := conf.AppConfig.Obs
-
-	return UploadFile(client, obsConf.Bucket, fpath, obsDir)
-}
-
-func UploadFile(obsClient *obs.ObsClient, bucketName string, fpath string, obsDir string) (string, error) {
-	_, obsname := path.Split(fpath)
-	keyFormat := "%s/%s"
-	if strings.HasSuffix(obsDir, "/") {
-		keyFormat = "%s%s"
-	}
-	obsKey := fmt.Sprintf(keyFormat, obsDir, obsname)
-
-	input := &obs.PutFileInput{}
-	input.Bucket = bucketName
-	input.Key = obsKey
-	input.SourceFile = fpath
-
-	fpathExt := path.Ext(fpath)
-	isGzFile := fpathExt == ".gz"
-	if isGzFile {
-		input.ContentType = "text/plain"
-		input.Metadata = map[string]string{"Content-Encoding": "gzip"}
-	}
-	result, err := obsClient.PutFile(input)
-
-	isUploadOk := true
-
-	if err != nil {
-		log.Errorf("upload obs fail %s", fpath)
-		log.Error(err)
-		isUploadOk = false
-	}
-
-	if result.StatusCode != 200 {
-		isUploadOk = false
-	}
-
-	if !isUploadOk {
-		result, err = obsClient.PutFile(input)
-
-		if err != nil {
-			log.Errorf("upload obs fail2 %s", fpath)
-			log.Error(err)
-			return "", err
-		}
-		if result.StatusCode != 200 {
-			return "", fmt.Errorf("上传失败!")
-		}
-	}
-
-	if isGzFile {
-		metaRet, err := obsClient.SetObjectMetadata(&obs.SetObjectMetadataInput{
-			Bucket:          bucketName,
-			Key:             obsKey,
-			ContentEncoding: "gzip",
-			ContentType:     "text/plain",
-		})
-		fmt.Println(metaRet, err)
-
-		if err != nil {
-			metaRet, err = obsClient.SetObjectMetadata(&obs.SetObjectMetadataInput{
-				Bucket:          bucketName,
-				Key:             obsKey,
-				ContentEncoding: "gzip",
-				ContentType:     "text/plain",
-			})
-			fmt.Println(metaRet, err)
-		}
-	}
-	obsConf := conf.AppConfig.Obs
-
-	return fmt.Sprintf("//%s.%s/%s", bucketName, obsConf.Endpoint, obsKey), nil
-}
-
-func DownLoadFile(src string, target string) error {
-	out, err := os.Create(target)
-	if err != nil {
-		return err
-	}
-
-	if strings.HasPrefix(src, "//") {
-		src = fmt.Sprintf("http:%s", src)
-	}
-
-	timeout := time.Duration(180 * time.Second)
-	client := &http.Client{
-		Timeout: timeout,
-		Transport: &http.Transport{
-			TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
-		},
-	}
-	resp, err := client.Get(src)
-	if err != nil {
-		return err
-	}
-	defer resp.Body.Close()
-
-	pix, err := ioutil.ReadAll(resp.Body)
-	if err != nil {
-		return err
-	}
-	_, err = io.Copy(out, bytes.NewReader(pix))
-	if err != nil {
-		return err
-	}
-	out.Close()
-
-	return nil
-}
-
-func isExist(path string) bool {
-	_, err := os.Stat(path)
-	if err != nil {
-		if os.IsExist(err) {
-			return true
-		}
-		if os.IsNotExist(err) {
-			return false
-		}
-		fmt.Println(err)
-		return false
-	}
-	return true
 }

+ 10 - 3
3dshow-supplier/api/service.go

@@ -18,6 +18,7 @@ type SearchFilterFn func(c *gin.Context, apictx *ApiSession, query map[string]in
 type Update func(c *gin.Context, apictx *ApiSession, entity interface{})
 type SearchPostFn func(page *repo.PageResult, c *gin.Context, apictx *ApiSession, query map[string]interface{}) (interface{}, error)
 type RemoveFn func(c *gin.Context, apictx *ApiSession, id string) (interface{}, error)
+type UpdatePost func(c *gin.Context, apictx *ApiSession, entity interface{}, id primitive.ObjectID)
 
 type CRUDOption struct {
 	Collection        string
@@ -30,8 +31,10 @@ type CRUDOption struct {
 	JWT               bool
 	SearchProject     []string
 	DetailProject     []string
-	OnUpdate          Update
-	noUpdate          bool
+	OnUpdate          UpdatePost
+	OnPostUpdate      UpdatePost
+
+	noUpdate bool
 }
 
 func CreateCRUD(router *GinRouter, prefix string, option *CRUDOption) {
@@ -79,9 +82,10 @@ func CreateCRUD(router *GinRouter, prefix string, option *CRUDOption) {
 			for i := 0; i < 12; i++ {
 				mid.Index(i).SetUint(0)
 			}
+			oid, _ := primitive.ObjectIDFromHex(objId)
 
 			if option.OnUpdate != nil {
-				option.OnUpdate(c, apictx, m)
+				option.OnUpdate(c, apictx, m, oid)
 			}
 
 			out, err := repo.RepoUpdateSetDoc(apictx.CreateRepoCtx(), option.Collection, objId, m)
@@ -94,6 +98,9 @@ func CreateCRUD(router *GinRouter, prefix string, option *CRUDOption) {
 				return nil, NewError("文件不存在!")
 			}
 
+			if option.OnPostUpdate != nil {
+				option.OnPostUpdate(c, apictx, m, oid)
+			}
 			return out, nil
 		})
 	}

+ 1 - 0
3dshow-supplier/app.yaml

@@ -22,6 +22,7 @@ nats:
   # url: nats://127.0.0.1:14301
   maxReconnect: 1000
   reconnDelaySecond: 5
+  tileConvStreamTopic: convtile360-result-stream#convtile360.result#convtile360-result-queue
 
 obs:
   bucket: show3d

+ 3 - 1
3dshow-supplier/bus/main.go

@@ -12,7 +12,9 @@ func NewNatsBus(app *conf.AppConf) *comm.NatsBus {
 
 	bus, _ := comm.NewNatsBus2(app.Nats.Url, app.Nats.MaxReconnect,
 		app.Nats.ReconnDelaySecond,
-		[]*comm.NatsStreamWather{},
+		[]*comm.NatsStreamWather{
+			CreateTileConvResultWather(app),
+		},
 		[]*comm.NatsMsgReplyer{})
 	NatsCenter = bus
 	return NatsCenter

+ 87 - 0
3dshow-supplier/bus/tileResult.go

@@ -0,0 +1,87 @@
+package bus
+
+import (
+	"3dshow-supplier/conf"
+	"3dshow-supplier/db"
+	"3dshow-supplier/db/model"
+	"3dshow-supplier/db/repo"
+	"context"
+	"fmt"
+	"strings"
+
+	"github.com/nats-io/nats.go"
+	"infish.cn/comm"
+)
+
+type TileConvertorResult struct {
+	AssetId    string `json:"assetId"`
+	GroupId    string `json:"groupId"`
+	SourcePath string `json:"sourcePath"`
+	TilePath   string `json:"tilePath"`
+}
+
+func CreateTileConvResultWather(app *conf.AppConf) *comm.NatsStreamWather {
+
+	topics := strings.Split(app.Nats.TileConvStreamTopic, "#")
+
+	return &comm.NatsStreamWather{
+		Stream: topics[0],
+		Topic:  topics[1],
+		Queue:  topics[2],
+		Entity: func() interface{} { return &TileConvertorResult{} },
+		Cb: func(msg *nats.Msg, entity interface{}) {
+			result := entity.(*TileConvertorResult)
+
+			if len(result.TilePath) < 1 || len(result.AssetId) < 1 || len(result.GroupId) < 1 {
+				msg.AckSync()
+				return
+			}
+
+			err := RepoTileConvResult(result)
+			if err != nil {
+				msg.Nak()
+				return
+			}
+			msg.AckSync()
+
+		},
+	}
+}
+
+func CreateRepoCtx() *repo.RepoSession {
+	return &repo.RepoSession{
+		Client: db.MongoClient,
+		Ctx:    context.Background(),
+	}
+}
+
+func RepoTileConvResult(data *TileConvertorResult) error {
+
+	fmt.Println("RepoTileConvResult", data.AssetId, data.GroupId, data.TilePath)
+
+	asset := &model.Asset360Fake3d{}
+	ok, _ := repo.RepoSeachDoc(CreateRepoCtx(), &repo.DocSearchOptions{
+		CollectName: repo.CollectionAssets,
+		Query:       repo.Map{"_id": data.AssetId},
+	}, asset)
+
+	if !ok {
+		fmt.Println("RepoTileConvResult will be loss no asset find")
+		return nil
+	}
+
+	if asset.Groups != nil {
+		for _, g := range asset.Groups {
+			if g.Id == data.GroupId {
+				host := "https://www.3dqueen.cloud/asset360/index.html?apath="
+				g.Url = fmt.Sprintf("%s%s", host, data.TilePath)
+				g.State = model.GROUPSTATE_SUCC
+			}
+		}
+	}
+	ret, err := repo.RepoUpdateSetDoc(CreateRepoCtx(), repo.CollectionAssets, data.AssetId, asset)
+
+	fmt.Println("RepoTileConvResult update state=>", ret)
+
+	return err
+}

+ 4 - 3
3dshow-supplier/conf/app.go

@@ -43,9 +43,10 @@ type AppConf struct {
 	}
 
 	Nats struct {
-		Url               string
-		MaxReconnect      int
-		ReconnDelaySecond int
+		Url                 string
+		MaxReconnect        int
+		ReconnDelaySecond   int
+		TileConvStreamTopic string
 	}
 
 	Obs struct {

+ 1 - 1
3dshow-supplier/db/db.go

@@ -36,7 +36,7 @@ func (db *MongoDB) GetOrCreateDatabase(name string) *mongo.Database {
 
 func NewMongoDB(bus *comm.NatsBus) *MongoDB {
 	// inst, err := bus.NewMongoDBFromConfig("3dshow-mongo")
-	inst, err := bus.NewMongoDBFromConfigDev("3dshow-mongo")
+	inst, err := bus.NewMongoDBFromConfig("3dshow-mongo")
 	if err != nil {
 		panic(err)
 	}

+ 12 - 0
3dshow-supplier/db/model/asset.go

@@ -6,6 +6,14 @@ import (
 	"go.mongodb.org/mongo-driver/bson/primitive"
 )
 
+const (
+	GROUPSTATE_UNSET   = "unset"
+	GROUPSTATE_ADDED   = "added"
+	GROUPSTATE_CROPING = "croping"
+	GROUPSTATE_SUCC    = "succ"
+	GROUPSTATE_FAIL    = "fail"
+)
+
 // 一套360度图片
 type Asset360Group struct {
 	Id        string `bson:"_id,omitempty" json:"_id"`
@@ -18,6 +26,10 @@ type Asset360Group struct {
 	ImageHeight int    `bson:"imageHeight,omitempty" json:"imageHeight"` //2592,
 
 	Url string `bson:"url,omitempty" json:"url"` //http://192.168.110.115:8082/scene/Id/index.html?assetPath="https:/xxx/xx"
+
+	//已创建 / 后台处理中 / 后台处理失败 / 处理成功
+	//created/croping/fail/succ
+	State string `bson:"state,omitempty" json:"state"`
 }
 
 type Asset360Fake3d struct {

+ 59 - 0
3dshow-supplier/funcgraph/tile360.go

@@ -0,0 +1,59 @@
+package funcgraph
+
+import (
+	"3dshow-supplier/conf"
+	"fmt"
+	"strings"
+
+	"github.com/huaweicloud/huaweicloud-sdk-go-v3/core/auth/basic"
+	functiongraph "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/functiongraph/v2"
+	"github.com/huaweicloud/huaweicloud-sdk-go-v3/services/functiongraph/v2/model"
+	region "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/functiongraph/v2/region"
+)
+
+const (
+	ak = "RA1D7CFVCVKUFX1FHHPB"
+	sk = "cDrR2NgAF2KaA4MRkcK19r93P3P6hLKOPhHvPu9p"
+)
+
+func createFuncGraphClient() *functiongraph.FunctionGraphClient {
+	auth := basic.NewCredentialsBuilder().
+		WithAk(ak).
+		WithSk(sk).
+		Build()
+	return functiongraph.NewFunctionGraphClient(
+		functiongraph.FunctionGraphClientBuilder().
+			WithRegion(region.ValueOf("cn-east-3")).
+			WithCredential(auth).
+			Build())
+
+}
+
+func Tile360onvRequest(assetId string, groupId string, sourcePath string, natsUrl string) error {
+
+	ConvStreamTopic := conf.AppConfig.Nats.TileConvStreamTopic
+	streamTopics := strings.Split(ConvStreamTopic, "#")
+
+	client := createFuncGraphClient()
+
+	request := &model.AsyncInvokeFunctionRequest{Body: map[string]interface{}{
+		"groupId":    groupId,
+		"assetId":    assetId,
+		"sourcePath": sourcePath,
+
+		"notifyNatsUrl": natsUrl,
+		"notifyStream":  streamTopics[0],
+		"notifySubject": streamTopics[1],
+	}}
+
+	request.FunctionUrn = "urn:fss:cn-east-3:0956c65fd600f29f2ff6c00dbb3d1e2e:function:default:osgconv:v1"
+	response, err := client.AsyncInvokeFunction(request)
+
+	if err == nil {
+		fmt.Printf("%+v\n", response)
+		return nil
+	}
+	fmt.Println(err)
+
+	return err
+}

+ 3 - 1
3dshow-supplier/go.mod

@@ -9,6 +9,7 @@ require (
 	github.com/gin-gonic/gin v1.7.4
 	github.com/go-redis/redis/v8 v8.11.5
 	github.com/huaweicloud/huaweicloud-sdk-go-obs v3.22.11+incompatible
+	github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.14
 	github.com/natefinch/lumberjack v2.0.0+incompatible
 	github.com/spf13/viper v1.9.0
 	go.mongodb.org/mongo-driver v1.9.1
@@ -63,7 +64,7 @@ require (
 	github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // indirect
 	go.uber.org/atomic v1.7.0 // indirect
 	go.uber.org/multierr v1.6.0 // indirect
-	golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4 // indirect
+	golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e // indirect
 	golang.org/x/net v0.1.0 // indirect
 	golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 // indirect
 	golang.org/x/sys v0.1.0 // indirect
@@ -74,6 +75,7 @@ require (
 	gopkg.in/ini.v1 v1.66.6 // indirect
 	gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect
 	gopkg.in/yaml.v2 v2.4.0 // indirect
+	gopkg.in/yaml.v3 v3.0.1 // indirect
 )
 
 replace infish.cn/comm => ../comm

+ 9 - 4
3dshow-supplier/go.sum

@@ -230,6 +230,8 @@ github.com/hashicorp/memberlist v0.2.2/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOn
 github.com/hashicorp/serf v0.9.5/go.mod h1:UWDWwZeL5cuWDJdl0C6wrvrUwEqtQ4ZKBKKENpqIUyk=
 github.com/huaweicloud/huaweicloud-sdk-go-obs v3.22.11+incompatible h1:bSww59mgbqFRGCRvlvfQutsptE3lRjNiU5C0YNT/bWw=
 github.com/huaweicloud/huaweicloud-sdk-go-obs v3.22.11+incompatible/go.mod h1:l7VUhRbTKCzdOacdT4oWCwATKyvZqUOlOqr0Ous3k4s=
+github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.14 h1:VpsQBOCedTPmK557Wgx4SENbg3lXgBr7bH3hJ3iSi1A=
+github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.14/go.mod h1:QpZ96CRqyqd5fEODVmnzDNp3IWi5W95BFmWz1nfkq+s=
 github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
 github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
 github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
@@ -338,8 +340,9 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV
 github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
 github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
 github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
-github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
 github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.7.2 h1:4jaiDzPyXQvSd7D0EjG45355tLlV3VOECpq10pLC+8s=
+github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
 github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s=
 github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
 github.com/tidwall/gjson v1.9.4 h1:oNis7dk9Rs3dKJNNigXZT1MTOiJeBtpurn+IpCB75MY=
@@ -397,8 +400,8 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh
 golang.org/x/crypto v0.0.0-20201216223049-8b5274cf687f/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
 golang.org/x/crypto v0.0.0-20210314154223-e6e6c4f2bb5b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
 golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
-golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4 h1:kUhD7nTDoI3fVd9G4ORWrbV5NY0liEs/Jg2pv5f+bBA=
-golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
+golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e h1:T8NU3HyQ8ClP4SEE+KbFlg6n0NhuTsN4MyznaarGsZM=
+golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
 golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@@ -472,6 +475,7 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v
 golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=
 golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
 golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
 golang.org/x/net v0.1.0 h1:hZ/3BUoy5aId7sCpA/Tc5lt8DkFgdVS2onTpJsZ/fl0=
 golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
 golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
@@ -787,8 +791,9 @@ gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
 gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
 gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
-gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
 gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
+gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
 honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
 honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=