
# 自定义函数开发规范
![](https://support.huaweicloud.com/usermanual-obs/public_sys-resources/note_3.0-zh-cn.png)
文档已迁移至[数据工坊 DWR](https://support.huaweicloud.com/dwr/index.html)，请前往查看。
用户在自行开发自定义函数时，函数的输入参数和输出参数需要遵守本节的开发规范。
自定义函数的编译方式请参考FunctionGraph的[《开发指南》](https://support.huaweicloud.com/devg-functiongraph/functiongraph_02_0101.html)。
#### 函数输入参数
Data+工作流执行自定义函数时，函数输入参数的JSON格式的结构体和环境变量的定义如下：
表1函数输入的JSON格式体 
| **名称**         | **是否必选** | **参数类型**            | **说明**                |
|:---|:---|:---|:---|
| execution_name | 是        | String              | 工作流实例名称。              |
| graph_name     | 是        | String              | 工作流名称。                |
| Records        | 是        | Array               | 工作流触发的事件源事件消息。        |
| inputs         | 否        | Map\[String\]String | 用户可修改参数列表，可以为空。       |
| dynamic_source | 否        | Map                 | 函数执行必须的参数，可用于传入调用的服务。 |
   
表2函数的环境变量 
| **名称** | **是否必选** | **参数类型** | **说明**  |
|:---|:---|:---|:---|
| region | 否        | String   | 当前区域名称。 |
   
函数输入的JSON示例
```
{
  "execution_name": "84a3dd2bd67f43aa9b98cdd74604ca68",//工作流实例名称
  "graph_name": "test_workflow",//工作流名称
  "Records": [
    {
      "eventName": "ObjectCreated:Put",//触发事件通知的事件名
      "eventRegion": "cn-north-4",//事件所在的region
      "eventSource": "OBS",//消息源，固定为"OBS"
      "eventTime": "2021-12-23T14:50:22.957Z",//事件时间，格式为ISO-8601，示例：2020-07-10T09:24:11.418Z
      "eventVersion": "3.0",//版本号，目前为"3.0"
      "obs": {
        "Version": "1.0",
        "bucket": {
          "bucket": "examplebucket",//桶名
          "name": "examplebucket",//桶名
          "ownerIdentity": {
            "ID": "08b4efe0fc00d3ce0f17c01b948f6e80"//桶拥有者的账号ID
          }
        },
        "configurationId":"test-trigger",//此事件匹配的OBS中事件触发器的名称
        "object": {
          "eTag": "fc85a07cff68977bf5b2108e7436ca2d",//对象的etag
          "key": "exampleobject.docx",//对象名
          "oldpsxpth": "",//文件在并行文件系统中rename前的路径
          "sequencer": "1",//确定某个特定对象事件顺序的标识
          "size": "524298",//对象的大小
          "versionId": "G001017DE60E176D0000401106696610null"//对象的版本ID
        }
      },
      "requestParameters": {
        "sourceIPAddress": "x.x.x.x"//请求的源IP
      },
      "responseElements": {
        "x-obs-id-2": "",//帮助定位问题的特殊符号
        "x-obs-request-id": "84a3dd2bd67f43aa9b98cdd74604ca68"//请求对应的requestid
      },
      "userIdentity": {
        "ID": "08b4efe0fc00d3ce0f17c01b948f6e80"//触发事件的用户对应的计费ID
      }
    }
  ],
  "inputs": {  //执行工作流的输入参数
    "parametername": "parametervalue",
    "parametername": "parametervalue" 
},
  "dynamic_source": { //执行自定义函数的输入参数
    "parametername": "parametervalue",
    "parametername": "parametervalue"
  }
}
```
#### 函数输出参数
函数输出参数的JSON格式的结构体定义如下:
表3函数输出的JSON格式体 
| **名称**         | **是否必选** | **参数类型**            | **说明**                  | **约束**                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |
|:---|:---|:---|:---|:---|
| execution_name | 是        | String              | 工作流实例名称。                | 继承函数输入参数的execution_name。                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       |
| graph_name     | 是        | String              | 工作流名称。                  | 继承函数输入参数的graph_name。                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           |
| Records        | 是        | Array               | 工作流触发的事件源事件消息。          | 如果没有变化，则继承函数输入参数的records。                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      |
| inputs         | 否        | Map\[String\]String | 用户可修改参数列表。              | 如果没有新增，则继承函数输入参数的inputs。                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       |
| dynamic_source | 否        | Map                 | 函数的输出参数，可用于传递给下一个执行的函数。 | -                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              |
| operation_name | 否        | String              | 函数操作名。                  | 系统内置的工作流函数操作名有： - 视频解析：MPC.Metadata  - 视频截图：MPC.Thumbnail  - 视频转码：MPC.Transcode   |
   
#### 对接截图函数示例（GO语言）
```
package main
import (
"encoding/json"
"errors"
"go-runtime/go-api/context"
)
func DemoHandler(jsonData []byte, ctx context.RuntimeContext) (interface{}, error) {
var eventMsg Payload
err := json.Unmarshal(jsonData, &eventMsg)
if err != nil {
return nil, errors.New("not correct format")
}
// 存储输入桶和对象值
record := eventMsg.Records[0]
// 定义输出
resp := struct {
OBSMessages
Inputs        map[string]interface{} `json:"inputs"`
ExecutionName string                 `json:"execution_name"`
GraphName     string                 `json:"graph_name"`
DynamicSource struct {
*CreateThumbnailDynamicSourceBody
} `json:"dynamic_source"`
}{}
// 配置截图参数，为下游截图任务提供参数配置
resp.DynamicSource.CreateThumbnailDynamicSourceBody = &CreateThumbnailDynamicSourceBody{
Thumbnails: []*ThumbnailCreateTaskBody{
&ThumbnailCreateTaskBody{
//源文件地址。
Input: &FileAddr{
Location:   "cn-north-1",
BucketName: record.Obs.Bucket.Name,
Object:     record.Obs.Object.Key,
},
//输出地址。
Output: &FileAddr{
Location:   "cn-north-1",
BucketName: record.Obs.Bucket.Name,
Object:     "thumb_out",
},
//是否压缩抽帧图片生成tar包。
Tar: 0,
//是否同步处理，同步处理是指不下载全部文件，快速定位到截图位置进行截图。
Mode: 0,
//截图参数
ThumbnailParam: &ThumbnailParam{
Type:           "DOTS",
MaxLength:      0,
Dots:           []int64{2, 10, 14}, // 截图的位置(s)
OutputFileName: "default_cover.jpg",
},
},
},
}
// 以下参数需要继承传递，方便工作流下游函数获取对应参数值
resp.Inputs = eventMsg.Inputs
resp.Records = eventMsg.Records
resp.GraphName = eventMsg.GraphName
resp.ExecutionName = eventMsg.ExecutionName
return resp, nil
}
```
#### 对接转码函数示例（GO语言）
```
package main
import (
"encoding/json"
"errors"
"go-runtime/go-api/context"
)
func DemoTranscodeHandler(jsonData []byte, ctx context.RuntimeContext) (interface{}, error) {
var eventMsg Payload
err := json.Unmarshal(jsonData, &eventMsg)
if err != nil {
return nil, errors.New("not correct format")
}
// 存储输入桶和对象值
record := eventMsg.Records[0]
// 定义输出
resp := struct {
OBSMessages
Inputs        map[string]interface{} `json:"inputs"`
ExecutionName string                 `json:"execution_name"`
GraphName     string                 `json:"graph_name"`
DynamicSource struct {
*CreateTranscodeDynamicSourceBody
} `json:"dynamic_source"`
}{}
// 配置截图参数，为下游截图任务提供参数配置
resp.DynamicSource.CreateTranscodeDynamicSourceBody = &CreateTranscodeDynamicSourceBody{
Transcodes: []*CreateTranscodeTaskBody{
&CreateTranscodeTaskBody{
//源文件地址。
Input: &FileAddr{
Location:   "cn-north-4",
BucketName: record.Obs.Bucket.Name,
Object:     record.Obs.Object.Key,
},
//输出地址。
Output: &FileAddr{
Location:   "cn-north-4",
BucketName: record.Obs.Bucket.Name,
Object:     "transcode_out",
},
TransTemplateID: []int{7000523, 7000524, 7000526, 7000528, 7000530, 7000538},
OutputFilenames: []string{"out_file1", "out_file2", "out_file3", "out_file4", "out_file5", "out_file6"},
},
},
}
// 以下参数需要继承传递，方便工作流下游函数获取对应参数值
resp.Inputs = eventMsg.Inputs
resp.Records = eventMsg.Records
resp.GraphName = eventMsg.GraphName
resp.ExecutionName = eventMsg.ExecutionName
return resp, nil
}
```
#### 结构体示例（GO语言）
```
package main
type CreateTranscodeDynamicSourceBody struct {
Transcodes []*CreateTranscodeTaskBody `json:"transcodes"`
}
type CreateTranscodeTaskBody struct {
//源文件存储地址。
Input *FileAddr `json:"input,omitempty"`
//转码后的视频文件存储地址。
Output *FileAddr `json:"output"`
//转码模板ID，数组
TransTemplateID []int `json:"trans_template_id,omitempty"`
//支持图片水印和文字水印，最多支持20个。
Watermarks []*Watermark `json:"watermarks,omitempty"`
//任务优先级。
Priority string `json:"priority,omitempty"`
//输出文件名称，每一路转码输出对应一个名称，需要与转码模板ID数组的顺序对应。
OutputFilenames []string `json:"output_filenames,omitempty"`
}
type Watermark struct {
Input          *FileAddr       `json:"input,omitempty"`
TemplateID     int             `json:"template_id,omitempty"`
TextContext    string          `json:"text_context,omitempty"`
ImageWatermark *ImageWatermark `json:"image_watermark,omitempty"`
TextWatermark  *TextWatermark  `json:"text_watermark,omitempty"`
}
type TextWatermark struct {
Dx               string `json:"dx,omitempty"`
Dy               string `json:"dy,omitempty"`
ReferPos         string `json:"referpos,omitempty"`
TimelineStart    string `json:"timeline_start,omitempty"`
TimelineDuration string `json:"timeline_duration,omitempty"`
FontName         string `json:"font_name,omitempty"`
FontSize         string `json:"font_size,omitempty"`
FontColor        string `json:"font_color,omitempty"`
Base             string `json:"base,omitempty"`
}
type ImageWatermark struct {
Dx               string `json:"dx,omitempty"`
Dy               string `json:"dy,omitempty"`
ReferPos         string `json:"referpos,omitempty"`
TimelineStart    string `json:"timeline_start,omitempty"`
TimelineDuration string `json:"timeline_duration,omitempty"`
ImageProcess     string `json:"image_process,omitempty"`
Width            string `json:"width,omitempty"`
Height           string `json:"height,omitempty"`
Base             string `json:"base,omitempty"`
}
type CreateThumbnailDynamicSourceBody struct {
Thumbnails []*ThumbnailCreateTaskBody `json:"thumbnails"`
}
//FileAddr 文件路径结构定义
type FileAddr struct {
Location   string `json:"location"`
BucketName string `json:"bucket"`
Object     string `json:"object"`
}
type ThumbnailCreateTaskBody struct {
//源文件地址。
Input *FileAddr `json:"input"`
//输出地址。
Output *FileAddr `json:"output"`
//是否压缩抽帧图片生成tar包。
Tar int `json:"tar,omitempty"`
//是否同步处理，同步处理是指不下载全部文件，快速定位到截图位置进行截图。
Mode int `json:"sync,omitempty"`
//截图参数
ThumbnailParam *ThumbnailParam `json:"thumbnail_para"`
}
type ThumbnailParam struct {
Type           string  `json:"type"`
Time           int64   `json:"time,omitempty"`
StartTime      int64   `json:"start_time,omitempty"`
Duration       int64   `json:"duration,omitempty"`
Dots           []int64 `json:"dots,omitempty"`
Format         int64   `json:"format,omitempty"`
AspectRatio    int64   `json:"aspect_ratio,omitempty"`
Width          int64   `json:"width,omitempty"`
Height         int64   `json:"height,omitempty"`
MaxLength      int64   `json:"max_length,omitempty"`
OutputFileName string  `json:"output_filename,omitempty"`
}
type OBSMessages struct {
Records []OBSRecord `json:"Records"`
}
// OBSRecord OBS消息格式
type OBSRecord struct {
EventVersion      string            `json:"eventVersion"`
EventSource       string            `json:"eventSource"`
EventRegion       string            `json:"eventRegion"`
EventTime         string            `json:"eventTime"`
EventName         string            `json:"eventName"`
UserIdentity      UserIdentity      `json:"userIdentity"`
RequestParameters RequestParameters `json:"requestParameters"`
ResponseElements  ResponseElements  `json:"responseElements"`
Obs               *OBSInfo          `json:"obs"`
}
// UserIdentity 用户id
type UserIdentity struct {
ID string `json:"ID,omitempty"`
}
//RequestParameters 原始请求参数
type RequestParameters struct {
SourceIPAddress string `json:"sourceIPAddress,omitempty"`
}
//ResponseElements 响应参数
type ResponseElements struct {
OBSRequestID string `json:"x-obs-request-id"`
OBSID2       string `json:"x-obs-id-2"`
}
//OBSInfo OBS信息
type OBSInfo struct {
Version         string     `json:"Version"`
ConfigurationID string     `json:"configurationId"`
Bucket          BucketInfo `json:"bucket"`
Object          ObjectInfo `json:"object"`
}
//BucketInfo 桶信息
type BucketInfo struct {
Name          string       `json:"name"`
OwnerIdentity UserIdentity `json:"ownerIdentity"`
Bucket        string       `json:"bucket"`
}
//ObjectInfo 对象信息
type ObjectInfo struct {
Key       string `json:"key"`
Tag       string `json:"eTag"`
Size      uint64 `json:"size"`
VersionID string `json:"versionId"`
Sequencer string `json:"sequencer"`
}
type Payload struct {
ExecutionName string `json:"execution_name"`
GraphName     string `json:"graph_name"`
OBSMessages
DynamicSource interface{}            `json:"dynamic_source"`
Inputs        map[string]interface{} `json:"inputs"`
}
```
