Files
zmkgC/api/webodm/service.go
2025-07-07 20:11:59 +08:00

465 lines
12 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package webodm
import (
"bytes"
"context"
"encoding/base64"
"encoding/json"
"errors"
"fmt"
"github.com/go-resty/resty/v2"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gctx"
"github.com/tidwall/gjson"
"github.com/tiger1103/gfast/v3/api/v1/common/coryCommon"
"io"
"io/ioutil"
"mime/multipart"
"net/http"
"net/url"
"os"
fpath "path/filepath"
"strconv"
"strings"
"time"
)
// 获取项目列表及其对应的任务列表
func (w WebOdmApi) ProjectList(ctx context.Context, req *ProjectListReq) (res *ProjectListRes, err error) {
res, err = ProjectListFunc()
return
}
func ProjectListFunc() (res *ProjectListRes, err error) {
res = new(ProjectListRes)
url := fmt.Sprintf("http://%s:%s/api/projects/?ordering=-created_at&page=1", Host, Port)
// 创建基本身份验证信息
auth := Username + ":" + Password
authEncoded := base64.StdEncoding.EncodeToString([]byte(auth))
// 创建请求
request, err := http.NewRequest("GET", url, nil)
if err != nil {
fmt.Println("Error creating request:", err)
return nil, err
}
// 添加基本身份验证信息到请求头
request.Header.Set("Authorization", "Basic "+authEncoded)
// 发送请求
client := &http.Client{}
resp, err := client.Do(request)
if err != nil {
fmt.Println("Error sending request:", err)
return nil, err
}
defer resp.Body.Close()
// 读取响应体
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
fmt.Println("Error reading response body:", err)
return nil, err
}
// 解析 JSON 响应
var projectsResponse ProjectsResponse
err = json.Unmarshal(body, &projectsResponse)
if err != nil {
fmt.Println("Error decoding JSON:", err)
return nil, err
}
// 设置响应结果
res.ProjectsResponse = projectsResponse
return res, nil
}
// 创建任务
func (w WebOdmApi) TaskCreate(ctx context.Context, req *TaskCreateReq) (res *TaskCreateRes, err error) {
res = new(TaskCreateRes)
res, err = TaskCreateFunc(ctx, req)
return
}
func TaskCreateFunc(ctx context.Context, req *TaskCreateReq) (res *TaskCreateRes, err error) {
res = new(TaskCreateRes)
// 准备图片 URL 列表
imageURLs := req.UrlList
// 准备一个 buffer 来保存 multipart form 的内容
body := &bytes.Buffer{}
writer := multipart.NewWriter(body)
// 遍历图片 URL 列表并从 URL 获取图片并添加到 multipart form 中
for i, imageURL := range imageURLs {
// 从 URL 获取图片
resp, err := http.Get(imageURL)
if err != nil {
fmt.Println("Failed to fetch image from URL:", err)
return res, err
}
defer resp.Body.Close()
// 准备一个 multipart form 的 part将图片数据写入
part, err := writer.CreateFormFile("file"+strconv.Itoa(i+1), fpath.Base(imageURL))
if err != nil {
fmt.Println("Failed to create form file:", err)
return res, err
}
_, err = io.Copy(part, resp.Body)
if err != nil {
fmt.Println("Failed to write image data:", err)
return res, err
}
}
// 写入项目ID到 multipart form 中
writer.WriteField("project_id", req.ProjectId)
// 设置任务参数以生成合并后的tif图片
writer.WriteField("merge", "true")
// 关闭 multipart writer
writer.Close()
// 创建包含基本身份验证的请求
url := fmt.Sprintf("http://%s:%s/api/projects/%s/tasks/", Host, Port, req.ProjectId)
request, err := http.NewRequest("POST", url, body)
if err != nil {
fmt.Println("Failed to create request:", err)
return res, err
}
// 添加基本身份验证信息
auth := Username + ":" + Password
authEncoded := base64.StdEncoding.EncodeToString([]byte(auth))
request.Header.Set("Authorization", "Basic "+authEncoded)
// 设置请求头中的 Content-Type 为 multipart/form-data
request.Header.Set("Content-Type", writer.FormDataContentType())
// 发送请求
client := &http.Client{}
resp, err := client.Do(request)
if err != nil {
fmt.Println("Failed to send request:", err)
return res, err
}
defer resp.Body.Close()
// 读取响应体
respBody, err := io.ReadAll(resp.Body)
if err != nil {
fmt.Println("Failed to read response body:", err)
return res, err
}
// 解析 JSON 响应
var jsonResponse map[string]interface{}
err = json.Unmarshal(respBody, &jsonResponse)
if err != nil {
fmt.Println("Failed to parse JSON response:", err)
return res, err
}
// 提取任务ID
taskID, ok := jsonResponse["id"].(string)
if !ok {
fmt.Println("Failed to extract task ID from response")
return res, err
}
// 设置任务ID到响应结构体中
res.TaskId = taskID
return res, nil
}
// 获取任务进度
func (w WebOdmApi) TaskProcess(ctx context.Context, req *TaskProcessReq) (*TaskProcessRes, error) {
ressss, err := TaskProcessFunc(ctx, req)
return ressss, err
}
func TaskProcessFunc(ctx context.Context, req *TaskProcessReq) (res *TaskProcessRes, err error) {
res = new(TaskProcessRes)
// 构建请求 URL
url := fmt.Sprintf("http://%s:%s/api/projects/"+req.ProjectId+"/tasks/%s/", Host, Port, req.TaskId)
// 创建基本身份验证信息
auth := Username + ":" + Password
authEncoded := base64.StdEncoding.EncodeToString([]byte(auth))
// 创建请求
request, err := http.NewRequest("GET", url, nil)
if err != nil {
fmt.Println("Error creating request:", err)
return nil, err
}
// 添加基本身份验证信息到请求头
request.Header.Set("Authorization", "Basic "+authEncoded)
// 发送请求
client := &http.Client{}
resp, err := client.Do(request)
if err != nil {
fmt.Println("Error sending request:", err)
return nil, err
}
defer resp.Body.Close()
// 读取响应体
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
fmt.Println("Error reading response body:", err)
return nil, err
}
// 解析 JSON 响应
err = json.Unmarshal(body, res)
if err != nil {
fmt.Println("Error decoding JSON:", err)
return nil, err
}
return res, nil
}
// 下载任务得到的结果
func (w WebOdmApi) DownloadTask(ctx context.Context, req *TaskDownloadReq) (res *TaskDownloadRes, err error) {
res, err = DownloadTask(ctx, req)
return
}
func DownloadTask(ctx context.Context, req *TaskDownloadReq) (res *TaskDownloadRes, err error) {
res = new(TaskDownloadRes)
// 构建请求 URL
requestURL := fmt.Sprintf("http://%s:%s/api/projects/"+req.ProjectId+"/tasks/%s/orthophoto/export", Host, Port, req.TaskId)
// 创建基本身份验证信息
auth := Username + ":" + Password
authEncoded := base64.StdEncoding.EncodeToString([]byte(auth))
// 获取任务的 epsg
epsg, err := GetEpsgByTaskID(req.ProjectId, req.TaskId)
if err != nil {
return nil, err
}
// 构建请求体
form := url.Values{}
form.Set("format", req.Format)
form.Set("epsg", epsg)
// 创建请求
httpRequest, err := http.NewRequest("POST", requestURL, strings.NewReader(form.Encode()))
if err != nil {
return nil, err
}
// 设置基本身份验证头部
httpRequest.Header.Set("Authorization", "Basic "+authEncoded)
httpRequest.Header.Set("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8")
// 执行请求
client := &http.Client{}
httpResponse, err := client.Do(httpRequest)
if err != nil {
return nil, err
}
defer httpResponse.Body.Close()
// 读取响应体
responseBody, err := ioutil.ReadAll(httpResponse.Body)
if err != nil {
return nil, err
}
var TaskExportRes struct {
CeleryTaskID string `json:"celery_task_id"`
Filename string `json:"filename"`
}
// 解析 JSON 响应
err = json.Unmarshal(responseBody, &TaskExportRes)
if err != nil {
return nil, err
}
celeryTaskID := TaskExportRes.CeleryTaskID
filename := TaskExportRes.Filename
type WorkerCheckRes struct {
Ready bool `json:"ready"`
}
// 定义 worker 检查结果的变量
var workerCheckRes WorkerCheckRes
// 循环检查任务状态,直到 Ready 为 true
for {
// 发起请求到 http://%s:%s/api/workers/check/celeryTaskID
workerCheckURL := fmt.Sprintf("http://%s:%s/api/workers/check/%s", Host, Port, celeryTaskID)
// 创建新的 GET 请求
workerCheckRequest, err := http.NewRequest("GET", workerCheckURL, nil)
if err != nil {
return nil, err
}
// 设置基本身份验证头部
workerCheckRequest.Header.Set("Authorization", "Basic "+authEncoded)
workerCheckRequest.Header.Set("Accept", "application/json")
// 执行 GET 请求
workerCheckResponse, err := client.Do(workerCheckRequest)
if err != nil {
return nil, err
}
defer workerCheckResponse.Body.Close()
// 读取 GET 响应体
workerCheckResponseBody, err := ioutil.ReadAll(workerCheckResponse.Body)
if err != nil {
return nil, err
}
// 解析 GET 响应
err = json.Unmarshal(workerCheckResponseBody, &workerCheckRes)
if err != nil {
return nil, err
}
// 输出 worker 检查结果
fmt.Println("Worker Check Result:", workerCheckRes)
// 如果 Ready 为 true则退出循环
if workerCheckRes.Ready {
break
}
// 如果 Ready 为 false则等待 1 秒后重新检查
time.Sleep(1 * time.Second)
}
// 构建下载 URL
downloadURL := fmt.Sprintf("http://%s:%s/api/workers/get/%s?filename=%s", Host, Port, celeryTaskID, filename)
// 发送 GET 请求并获取响应
resp, err := http.Get(downloadURL)
if err != nil {
return nil, err
}
defer resp.Body.Close()
// 检查响应状态码
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("unexpected status code: %d", resp.StatusCode)
}
// 读取图片数据
imageData, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}
// 创建目标文件夹路径
if err := os.MkdirAll(coryCommon.UavMerge, os.ModePerm); err != nil {
return nil, err
}
// 构建文件名,添加当前时间的年月日时分秒作为前缀
currentTime := time.Now().Format("20060102150405")
fileNameWithTime := fmt.Sprintf("%s%s", currentTime, filename)
// 构建文件路径
filepath := fpath.Join(coryCommon.UavMerge, fileNameWithTime)
// 写入图片数据到文件
err = ioutil.WriteFile(filepath, imageData, 0644)
if err != nil {
return nil, err
}
// 打印下载文件的信息
fmt.Printf("Downloaded image saved as: %s\n", filepath)
// 获取IP和端口
//host := g.RequestFromCtx(ctx).Host
res.FileUrl = fmt.Sprintf("/%s/%s", coryCommon.UavMerge, fileNameWithTime)
return res, nil
}
// GetEpsgByTaskID 根据任务ID 获取 epsg
func GetEpsgByTaskID(projectID, taskID string) (string, error) {
client := &http.Client{}
auth := Username + ":" + Password
authEncoded := base64.StdEncoding.EncodeToString([]byte(auth))
url := fmt.Sprintf("http://%s:%s/api/projects/%s/tasks/?ordering=-created_at", Host, Port, projectID)
request, err := http.NewRequest("GET", url, nil)
if err != nil {
return "", err
}
request.Header.Set("Authorization", "Basic "+authEncoded)
resp, err := client.Do(request)
if err != nil {
return "", err
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
return "", err
}
result := gjson.Parse(string(body))
for _, value := range result.Array() {
if value.Get("id").String() == taskID {
return value.Get("epsg").String(), nil
}
}
return "", nil
}
// @Title DelUuidFunc 2024/8/13 11:40:00
// @Description 根据项目ID及任务ID 找到资源并删除
// @Auth Cory
// @param projectID ---> "webdom项目ID"
// @Return taskID ---> "webdom任务ID"
func DelUuidFunc(projectID, taskID string) (flag bool, err error) {
client := resty.New()
header := client.R().
SetHeader("Content-Type", "application/json").
SetHeader("Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte(Username+":"+Password)))
//1、获取uuid
url := fmt.Sprintf("http://%s:%s/api/projects/%s/tasks/%s", Host, Port, projectID, taskID)
resp, err := header.Get(url)
if err != nil {
g.Log().Error(gctx.New(), err)
return
}
uuid := gjson.Get(string(resp.Body()), "uuid").String()
if uuid == "" {
err = errors.New("删除失败无法获取uuid")
return
}
//2、根据uuid去删除对应的资源
m := make(map[string]string)
m["uuid"] = uuid
url = url + "/remove/"
post, err := header.SetBody(m).Post(url)
if err != nil {
g.Log().Error(gctx.New(), err)
return false, err
}
return gjson.Get(string(post.Body()), "succeed").Bool(), nil
}