初始
This commit is contained in:
8
api/webodm/constant.go
Normal file
8
api/webodm/constant.go
Normal file
@ -0,0 +1,8 @@
|
||||
package webodm
|
||||
|
||||
const (
|
||||
Username = "yjdsj"
|
||||
Password = "CQyj20200808!"
|
||||
Host = "58.17.134.85"
|
||||
Port = "8000"
|
||||
)
|
30
api/webodm/req.go
Normal file
30
api/webodm/req.go
Normal file
@ -0,0 +1,30 @@
|
||||
package webodm
|
||||
|
||||
import "github.com/gogf/gf/v2/frame/g"
|
||||
|
||||
// 项目及其任务列表请求
|
||||
type ProjectListReq struct {
|
||||
g.Meta `path:"projectList" method:"get" tags:"图片合成相关" summary:"获取图片合成项目及其任务列表"`
|
||||
}
|
||||
|
||||
// 发起任务请求【只有手动测试一下这个接口】
|
||||
type TaskCreateReq struct {
|
||||
g.Meta `path:"taskCreate" method:"post" tags:"图片合成相关" summary:"针对某个项目发起图片合成任务"`
|
||||
ProjectId string `json:"projectId"`
|
||||
UrlList []string `json:"urlList"`
|
||||
}
|
||||
|
||||
// 获取某个任务的进度
|
||||
type TaskProcessReq struct {
|
||||
g.Meta `path:"taskProcess" method:"get" tags:"图片合成相关" summary:"查看某个任务的进度"`
|
||||
TaskId string `json:"taskId" `
|
||||
ProjectId string `json:"projectId" `
|
||||
}
|
||||
|
||||
// 下载某个任务的结果
|
||||
type TaskDownloadReq struct {
|
||||
g.Meta `path:"download" method:"post" tags:"图片合成相关" summary:"下载某个任务的结果"`
|
||||
TaskId string `json:"taskId"`
|
||||
Format string `json:"format"`
|
||||
ProjectId string `json:"projectId" `
|
||||
}
|
64
api/webodm/res.go
Normal file
64
api/webodm/res.go
Normal file
@ -0,0 +1,64 @@
|
||||
package webodm
|
||||
|
||||
// 项目列表响应
|
||||
type ProjectListRes struct {
|
||||
ProjectsResponse
|
||||
}
|
||||
type ProjectsResponse struct {
|
||||
Count int `json:"count"`
|
||||
Next *string `json:"next"`
|
||||
Previous *string `json:"previous"`
|
||||
Results []Project `json:"results"`
|
||||
}
|
||||
type Project struct {
|
||||
ID int `json:"id"`
|
||||
Tasks []string `json:"tasks"`
|
||||
CreatedAt string `json:"created_at"`
|
||||
Permissions []string `json:"permissions"`
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
}
|
||||
|
||||
// 发起任务响应
|
||||
type TaskCreateRes struct {
|
||||
TaskId string `json:"taskId" dc:"任务ID"`
|
||||
}
|
||||
|
||||
// 获取某个任务的进度
|
||||
type TaskProcessRes struct {
|
||||
TaskProcessResponse
|
||||
}
|
||||
|
||||
type TaskProcessResponse struct {
|
||||
ID string `json:"id"`
|
||||
Project int `json:"project"`
|
||||
ProcessingNode int `json:"processing_node"`
|
||||
ProcessingNodeName string `json:"processing_node_name"`
|
||||
CanRerunFrom []string `json:"can_rerun_from"`
|
||||
Statistics map[string]interface{} `json:"statistics"`
|
||||
UUID string `json:"uuid"`
|
||||
Name interface{} `json:"name"`
|
||||
ProcessingTime int `json:"processing_time"`
|
||||
AutoProcessingNode bool `json:"auto_processing_node"`
|
||||
Status int `json:"status"`
|
||||
LastError interface{} `json:"last_error"`
|
||||
Options map[string]interface{} `json:"options"`
|
||||
AvailableAssets []string `json:"available_assets"`
|
||||
CreatedAt string `json:"created_at"`
|
||||
PendingAction interface{} `json:"pending_action"`
|
||||
Public bool `json:"public"`
|
||||
ResizeTo int `json:"resize_to"`
|
||||
UploadProgress float64 `json:"upload_progress"`
|
||||
ResizeProgress float64 `json:"resize_progress"`
|
||||
RunningProgress float64 `json:"running_progress"`
|
||||
ImportURL string `json:"import_url"`
|
||||
ImagesCount int `json:"images_count"`
|
||||
Partial bool `json:"partial"`
|
||||
PotreeScene map[string]interface{} `json:"potree_scene"`
|
||||
EPSG interface{} `json:"epsg"`
|
||||
}
|
||||
|
||||
// 下载任务
|
||||
type TaskDownloadRes struct {
|
||||
FileUrl string `json:"fileUrl"`
|
||||
}
|
15
api/webodm/router.go
Normal file
15
api/webodm/router.go
Normal file
@ -0,0 +1,15 @@
|
||||
package webodm
|
||||
|
||||
import "github.com/gogf/gf/v2/net/ghttp"
|
||||
|
||||
type WebOdmApi struct {
|
||||
}
|
||||
|
||||
func InitWebOdmAPI(group *ghttp.RouterGroup) {
|
||||
group.Middleware(ghttp.MiddlewareCORS)
|
||||
group.Group("/", func(group *ghttp.RouterGroup) {
|
||||
group.Group("/api/v1", func(group *ghttp.RouterGroup) {
|
||||
group.Bind(new(WebOdmApi))
|
||||
})
|
||||
})
|
||||
}
|
464
api/webodm/service.go
Normal file
464
api/webodm/service.go
Normal file
@ -0,0 +1,464 @@
|
||||
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
|
||||
}
|
Reference in New Issue
Block a user