From ffd954fe2fbd0fc926bf5d73629de37a85bb7078 Mon Sep 17 00:00:00 2001 From: "allen.wq" Date: Wed, 1 Apr 2020 10:37:43 +0800 Subject: [PATCH] define some api types. Signed-off-by: allen.wq --- apis/swagger.yml | 149 ++++++++++++++++++++++ apis/types/extra.go | 52 ++++++++ apis/types/heart_beat_request.go | 104 +++++++++++++++ apis/types/network_info_fetch_request.go | 44 +++++++ apis/types/network_info_fetch_response.go | 80 ++++++++++++ apis/types/node.go | 111 ++++++++++++++++ apis/types/task_create_request.go | 11 ++ apis/types/task_fetch_info.go | 105 +++++++++++++++ apis/types/task_info.go | 4 + apis/types/task_register_request.go | 15 +++ dfget/types/fetch_p2p_networkinfo.go | 35 +++++ dfget/types/register_request.go | 3 + dfget/types/report_piece_request.go | 4 + 13 files changed, 717 insertions(+) create mode 100644 apis/types/extra.go create mode 100644 apis/types/heart_beat_request.go create mode 100644 apis/types/network_info_fetch_request.go create mode 100644 apis/types/network_info_fetch_response.go create mode 100644 apis/types/node.go create mode 100644 apis/types/task_fetch_info.go create mode 100644 dfget/types/fetch_p2p_networkinfo.go diff --git a/apis/swagger.yml b/apis/swagger.yml index 193f7f7ff..f20f1295e 100644 --- a/apis/swagger.yml +++ b/apis/swagger.yml @@ -648,6 +648,47 @@ paths: 500: $ref: "#/responses/500ErrorResponse" + /peer/heartbeat: + get: + summary: "report the heart beat to super node." + description: | + This endpoint is mainly for reporting the heart beat to supernode. + And supernode could know if peer is alive in strem mode. + parameters: + - name: "body" + in: "body" + description: "request body which contains peer info." + schema: + $ref: "#/definitions/HeartBeatRequest" + responses: + 200: + description: "no error" + schema: + $ref: "#/definitions/ResultInfo" + 500: + $ref: "#/responses/500ErrorResponse" + + /peer/network: + get: + summary: "peer request the p2p network info from supernode." + description: | + In the new mode which dfdaemon will provide the seed file so that other peers + could download. This endpoint is mainly for fetching the p2p network info. + parameters: + - name: "body" + in: "body" + description: "request body which filter urls." + schema: + $ref: "#/definitions/NetworkInfoFetchRequest" + responses: + 200: + description: "no error" + schema: + $ref: "#/definitions/NetworkInfoFetchResponse" + 500: + $ref: "#/responses/500ErrorResponse" + + definitions: Error: type: "object" @@ -793,6 +834,22 @@ definitions: this field to supernode and supernode can do some checking and filtering via black/white list mechanism to guarantee security, or some other purposes like debugging. minLength: 1 + taskId: + type: "string" + description: | + Dfdaemon or dfget could specific the taskID which will represents the key of this resource + in supernode. + fileLength: + type: "integer" + description: | + This attribute represents the length of resource, dfdaemon or dfget catches and calculates + this parameter from the headers of request URL. If fileLength is vaild, the supernode need + not get the length of resource by accessing the rawURL. + format: "int64" + asSeed: + type: "boolean" + description: | + This attribute represents the node as a seed node for the taskURL. PeerCreateRequest: type: "object" @@ -945,6 +1002,18 @@ definitions: downloads, if there is already a task a.b.com/fileA. items: type: "string" + taskId: + type: "string" + description: | + This attribute represents the digest of resource, dfdaemon or dfget catches this parameter + from the headers of request URL. The digest will be considered as the taskID if not null. + fileLength: + type: "integer" + description: | + This attribute represents the length of resource, dfdaemon or dfget catches and calculates + this parameter from the headers of request URL. If fileLength is vaild, the supernode need + not get the length of resource by accessing the rawURL. + format: "int64" peerID: type: "string" description: | @@ -1055,6 +1124,10 @@ definitions: from source server as user's wish. additionalProperties: type: "string" + asSeed: + type: "boolean" + description: | + This attribute represents the node as a seed node for the taskURL. TaskUpdateRequest: type: "object" @@ -1362,6 +1435,82 @@ definitions: format: "int64" description: "The length of the file dfget requests to download in bytes." + NetworkInfoFetchRequest: + type: "object" + description: "The request is to fetch p2p network info from supernode." + properties: + urls: + type: "array" + description: | + The urls is to filter the peer node, the url should be match with taskURL in TaskInfo. + items: + type: "string" + + TaskFetchInfo: + type: "object" + description: "It shows the task info and pieces info." + properties: + task: + $ref: "#/definitions/TaskInfo" + pieces: + type: "array" + description: "The pieces which should belong to the peer node" + items: + $ref: "#/definitions/PieceInfo" + + Node: + type: "object" + description: "The object shows the basic info of node and the task belongs to the node." + properties: + basic: + $ref: "#/definitions/PeerInfo" + description: "Basic node info" + extra: + type: "object" + additionalProperties: + type: "string" + load: + type: "integer" + description: "The load of node, which as the schedule weight in peer schedule." + tasks: + type: "array" + items: + $ref: "#/definitions/TaskFetchInfo" + + NetworkInfoFetchResponse: + type: "object" + description: "The response is from supernode to peer which is requested to fetch p2p network info." + properties: + nodes: + type: "array" + items: + $ref: "#/definitions/Node" + + HeartBeatRequest: + type: "object" + description: "The request is to report the heart beat to super node." + properties: + IP: + type: "string" + description: "IP address which peer client carries." + format: "ipv4" + port: + type: "integer" + description: | + when registering, dfget will setup one uploader process. + This one acts as a server for peer pulling tasks. + This port is which this server listens on. + format: "int32" + minimum: 15000 + maximum: 65000 + cID: + type: "string" + description: | + CID means the client ID. It maps to the specific dfget process. + When user wishes to download an image/file, user would start a dfget process to do this. + This dfget is treated a client and carries a client ID. + Thus, multiple dfget processes on the same peer have different CIDs. + ErrorResponse: type: "object" description: | diff --git a/apis/types/extra.go b/apis/types/extra.go new file mode 100644 index 000000000..0bcc98bfc --- /dev/null +++ b/apis/types/extra.go @@ -0,0 +1,52 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package types + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + strfmt "github.com/go-openapi/strfmt" + + "github.com/go-openapi/swag" +) + +// Extra extra +// swagger:model Extra +type Extra struct { + + // idc + Idc string `json:"idc,omitempty"` + + // rack + Rack string `json:"rack,omitempty"` + + // room + Room string `json:"room,omitempty"` + + // site + Site string `json:"site,omitempty"` +} + +// Validate validates this extra +func (m *Extra) Validate(formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *Extra) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *Extra) UnmarshalBinary(b []byte) error { + var res Extra + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/apis/types/heart_beat_request.go b/apis/types/heart_beat_request.go new file mode 100644 index 000000000..494dd80b3 --- /dev/null +++ b/apis/types/heart_beat_request.go @@ -0,0 +1,104 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package types + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + strfmt "github.com/go-openapi/strfmt" + + "github.com/go-openapi/errors" + "github.com/go-openapi/swag" + "github.com/go-openapi/validate" +) + +// HeartBeatRequest The request is to report the heart beat to super node. +// swagger:model HeartBeatRequest +type HeartBeatRequest struct { + + // IP address which peer client carries. + // Format: ipv4 + IP strfmt.IPv4 `json:"IP,omitempty"` + + // CID means the client ID. It maps to the specific dfget process. + // When user wishes to download an image/file, user would start a dfget process to do this. + // This dfget is treated a client and carries a client ID. + // Thus, multiple dfget processes on the same peer have different CIDs. + // + CID string `json:"cID,omitempty"` + + // when registering, dfget will setup one uploader process. + // This one acts as a server for peer pulling tasks. + // This port is which this server listens on. + // + // Maximum: 65000 + // Minimum: 15000 + Port int32 `json:"port,omitempty"` +} + +// Validate validates this heart beat request +func (m *HeartBeatRequest) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateIP(formats); err != nil { + res = append(res, err) + } + + if err := m.validatePort(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *HeartBeatRequest) validateIP(formats strfmt.Registry) error { + + if swag.IsZero(m.IP) { // not required + return nil + } + + if err := validate.FormatOf("IP", "body", "ipv4", m.IP.String(), formats); err != nil { + return err + } + + return nil +} + +func (m *HeartBeatRequest) validatePort(formats strfmt.Registry) error { + + if swag.IsZero(m.Port) { // not required + return nil + } + + if err := validate.MinimumInt("port", "body", int64(m.Port), 15000, false); err != nil { + return err + } + + if err := validate.MaximumInt("port", "body", int64(m.Port), 65000, false); err != nil { + return err + } + + return nil +} + +// MarshalBinary interface implementation +func (m *HeartBeatRequest) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *HeartBeatRequest) UnmarshalBinary(b []byte) error { + var res HeartBeatRequest + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/apis/types/network_info_fetch_request.go b/apis/types/network_info_fetch_request.go new file mode 100644 index 000000000..85944d687 --- /dev/null +++ b/apis/types/network_info_fetch_request.go @@ -0,0 +1,44 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package types + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + strfmt "github.com/go-openapi/strfmt" + + "github.com/go-openapi/swag" +) + +// NetworkInfoFetchRequest The request is to fetch p2p network info from supernode. +// swagger:model NetworkInfoFetchRequest +type NetworkInfoFetchRequest struct { + + // The urls is to filter the peer node, the url should be match with taskURL in TaskInfo. + // + Urls []string `json:"urls"` +} + +// Validate validates this network info fetch request +func (m *NetworkInfoFetchRequest) Validate(formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *NetworkInfoFetchRequest) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *NetworkInfoFetchRequest) UnmarshalBinary(b []byte) error { + var res NetworkInfoFetchRequest + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/apis/types/network_info_fetch_response.go b/apis/types/network_info_fetch_response.go new file mode 100644 index 000000000..8195b8e1f --- /dev/null +++ b/apis/types/network_info_fetch_response.go @@ -0,0 +1,80 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package types + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "strconv" + + strfmt "github.com/go-openapi/strfmt" + + "github.com/go-openapi/errors" + "github.com/go-openapi/swag" +) + +// NetworkInfoFetchResponse The response is from supernode to peer which is requested to fetch p2p network info. +// swagger:model NetworkInfoFetchResponse +type NetworkInfoFetchResponse struct { + + // nodes + Nodes []*Node `json:"nodes"` +} + +// Validate validates this network info fetch response +func (m *NetworkInfoFetchResponse) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateNodes(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *NetworkInfoFetchResponse) validateNodes(formats strfmt.Registry) error { + + if swag.IsZero(m.Nodes) { // not required + return nil + } + + for i := 0; i < len(m.Nodes); i++ { + if swag.IsZero(m.Nodes[i]) { // not required + continue + } + + if m.Nodes[i] != nil { + if err := m.Nodes[i].Validate(formats); err != nil { + if ve, ok := err.(*errors.Validation); ok { + return ve.ValidateName("nodes" + "." + strconv.Itoa(i)) + } + return err + } + } + + } + + return nil +} + +// MarshalBinary interface implementation +func (m *NetworkInfoFetchResponse) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *NetworkInfoFetchResponse) UnmarshalBinary(b []byte) error { + var res NetworkInfoFetchResponse + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/apis/types/node.go b/apis/types/node.go new file mode 100644 index 000000000..5d5c51098 --- /dev/null +++ b/apis/types/node.go @@ -0,0 +1,111 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package types + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "strconv" + + strfmt "github.com/go-openapi/strfmt" + + "github.com/go-openapi/errors" + "github.com/go-openapi/swag" +) + +// Node The object shows the basic info of node and the task belongs to the node. +// swagger:model Node +type Node struct { + + // Basic node info + Basic *PeerInfo `json:"basic,omitempty"` + + // extra + Extra map[string]string `json:"extra,omitempty"` + + // The load of node, which as the schedule weight in peer schedule. + Load int64 `json:"load,omitempty"` + + // tasks + Tasks []*TaskFetchInfo `json:"tasks"` +} + +// Validate validates this node +func (m *Node) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateBasic(formats); err != nil { + res = append(res, err) + } + + if err := m.validateTasks(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *Node) validateBasic(formats strfmt.Registry) error { + + if swag.IsZero(m.Basic) { // not required + return nil + } + + if m.Basic != nil { + if err := m.Basic.Validate(formats); err != nil { + if ve, ok := err.(*errors.Validation); ok { + return ve.ValidateName("basic") + } + return err + } + } + + return nil +} + +func (m *Node) validateTasks(formats strfmt.Registry) error { + + if swag.IsZero(m.Tasks) { // not required + return nil + } + + for i := 0; i < len(m.Tasks); i++ { + if swag.IsZero(m.Tasks[i]) { // not required + continue + } + + if m.Tasks[i] != nil { + if err := m.Tasks[i].Validate(formats); err != nil { + if ve, ok := err.(*errors.Validation); ok { + return ve.ValidateName("tasks" + "." + strconv.Itoa(i)) + } + return err + } + } + + } + + return nil +} + +// MarshalBinary interface implementation +func (m *Node) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *Node) UnmarshalBinary(b []byte) error { + var res Node + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/apis/types/task_create_request.go b/apis/types/task_create_request.go index c9eb85f21..30d4bf83c 100644 --- a/apis/types/task_create_request.go +++ b/apis/types/task_create_request.go @@ -37,6 +37,12 @@ type TaskCreateRequest struct { // Dfdaemon bool `json:"dfdaemon,omitempty"` + // This attribute represents the length of resource, dfdaemon or dfget catches and calculates + // this parameter from the headers of request URL. If fileLength is vaild, the supernode need + // not get the length of resource by accessing the rawURL. + // + FileLength int64 `json:"fileLength,omitempty"` + // filter is used to filter request queries in URL. // For example, when a user wants to start to download a task which has a remote URL of // a.b.com/fileA?user=xxx&auth=yyy, user can add a filter parameter ["user", "auth"] @@ -86,6 +92,11 @@ type TaskCreateRequest struct { // IP address of supernode which the peer connects to SupernodeIP string `json:"supernodeIP,omitempty"` + // This attribute represents the digest of resource, dfdaemon or dfget catches this parameter + // from the headers of request URL. The digest will be considered as the taskID if not null. + // + TaskID string `json:"taskId,omitempty"` + // taskURL is generated from rawURL. rawURL may contains some queries or parameter, dfget will filter some queries via // --filter parameter of dfget. The usage of it is that different rawURL may generate the same taskID. // diff --git a/apis/types/task_fetch_info.go b/apis/types/task_fetch_info.go new file mode 100644 index 000000000..ccbdb317e --- /dev/null +++ b/apis/types/task_fetch_info.go @@ -0,0 +1,105 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package types + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "strconv" + + strfmt "github.com/go-openapi/strfmt" + + "github.com/go-openapi/errors" + "github.com/go-openapi/swag" +) + +// TaskFetchInfo It shows the task info and pieces info. +// swagger:model TaskFetchInfo +type TaskFetchInfo struct { + + // The pieces which should belong to the peer node + Pieces []*PieceInfo `json:"pieces"` + + // task + Task *TaskInfo `json:"task,omitempty"` +} + +// Validate validates this task fetch info +func (m *TaskFetchInfo) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validatePieces(formats); err != nil { + res = append(res, err) + } + + if err := m.validateTask(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *TaskFetchInfo) validatePieces(formats strfmt.Registry) error { + + if swag.IsZero(m.Pieces) { // not required + return nil + } + + for i := 0; i < len(m.Pieces); i++ { + if swag.IsZero(m.Pieces[i]) { // not required + continue + } + + if m.Pieces[i] != nil { + if err := m.Pieces[i].Validate(formats); err != nil { + if ve, ok := err.(*errors.Validation); ok { + return ve.ValidateName("pieces" + "." + strconv.Itoa(i)) + } + return err + } + } + + } + + return nil +} + +func (m *TaskFetchInfo) validateTask(formats strfmt.Registry) error { + + if swag.IsZero(m.Task) { // not required + return nil + } + + if m.Task != nil { + if err := m.Task.Validate(formats); err != nil { + if ve, ok := err.(*errors.Validation); ok { + return ve.ValidateName("task") + } + return err + } + } + + return nil +} + +// MarshalBinary interface implementation +func (m *TaskFetchInfo) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *TaskFetchInfo) UnmarshalBinary(b []byte) error { + var res TaskFetchInfo + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/apis/types/task_info.go b/apis/types/task_info.go index f88a43985..f2686d624 100644 --- a/apis/types/task_info.go +++ b/apis/types/task_info.go @@ -22,6 +22,10 @@ type TaskInfo struct { // ID of the task. ID string `json:"ID,omitempty"` + // This attribute represents the node as a seed node for the taskURL. + // + AsSeed bool `json:"asSeed,omitempty"` + // The status of the created task related to CDN functionality. // // Enum: [WAITING RUNNING FAILED SUCCESS SOURCE_ERROR] diff --git a/apis/types/task_register_request.go b/apis/types/task_register_request.go index 85a5def96..f45cd330f 100644 --- a/apis/types/task_register_request.go +++ b/apis/types/task_register_request.go @@ -21,6 +21,10 @@ type TaskRegisterRequest struct { // Format: ipv4 IP strfmt.IPv4 `json:"IP,omitempty"` + // This attribute represents the node as a seed node for the taskURL. + // + AsSeed bool `json:"asSeed,omitempty"` + // CID means the client ID. It maps to the specific dfget process. // When user wishes to download an image/file, user would start a dfget process to do this. // This dfget is treated a client and carries a client ID. @@ -41,6 +45,12 @@ type TaskRegisterRequest struct { // Dfdaemon bool `json:"dfdaemon,omitempty"` + // This attribute represents the length of resource, dfdaemon or dfget catches and calculates + // this parameter from the headers of request URL. If fileLength is vaild, the supernode need + // not get the length of resource by accessing the rawURL. + // + FileLength int64 `json:"fileLength,omitempty"` + // extra HTTP headers sent to the rawURL. // This field is carried with the request to supernode. // Supernode will extract these HTTP headers, and set them in HTTP downloading requests @@ -97,6 +107,11 @@ type TaskRegisterRequest struct { // The address of supernode that the client can connect to SuperNodeIP string `json:"superNodeIp,omitempty"` + // Dfdaemon or dfget could specific the taskID which will represents the key of this resource + // in supernode. + // + TaskID string `json:"taskId,omitempty"` + // taskURL is generated from rawURL. rawURL may contains some queries or parameter, dfget will filter some queries via // --filter parameter of dfget. The usage of it is that different rawURL may generate the same taskID. // diff --git a/dfget/types/fetch_p2p_networkinfo.go b/dfget/types/fetch_p2p_networkinfo.go new file mode 100644 index 000000000..0b89d3b0b --- /dev/null +++ b/dfget/types/fetch_p2p_networkinfo.go @@ -0,0 +1,35 @@ +/* + * Copyright The Dragonfly Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package types + +import "github.com/dragonflyoss/Dragonfly/apis/types" + +// FetchP2PNetworkInfoRequest is send to supernode to fetch p2p network info +type FetchP2PNetworkInfoRequest struct { + // the urls is to filter the peer node, the url should be match with taskURL in TaskInfo + Urls []string `json:"urls"` +} + +// FetchP2PNetworkInfoResponse is send to supernode to fetch p2p network info +type FetchP2PNetworkInfoResponse struct { + *BaseResponse + Data *FetchNetworkInfoDataResponse `json:"data,omitempty"` +} + +type FetchNetworkInfoDataResponse struct { + Nodes []*types.Node `json:"nodes"` +} diff --git a/dfget/types/register_request.go b/dfget/types/register_request.go index 614a472b6..b89691dba 100644 --- a/dfget/types/register_request.go +++ b/dfget/types/register_request.go @@ -39,6 +39,9 @@ type RegisterRequest struct { Dfdaemon bool `json:"dfdaemon,omitempty"` Insecure bool `json:"insecure,omitempty"` RootCAs [][]byte `json:"rootCAs,omitempty"` + TaskID string `json:"taskId,omitempty"` + FileLength int64 `json:"fileLength,omitempty"` + AsSeed bool `json:"asSeed,omitempty"` } func (r *RegisterRequest) String() string { diff --git a/dfget/types/report_piece_request.go b/dfget/types/report_piece_request.go index 8cfbe6501..4698992e3 100644 --- a/dfget/types/report_piece_request.go +++ b/dfget/types/report_piece_request.go @@ -23,4 +23,8 @@ type ReportPieceRequest struct { Cid string `request:"cid"` DstCid string `request:"dstCid"` PieceRange string `request:"pieceRange"` + // seed resp + AsSeed bool `json:"asSeed"` + // if as seed, SeedTaskID is the taskID of seed file. + SeedTaskID string `json:"seedTaskID"` }