Skip to content

Commit dc08c35

Browse files
authored
Merge pull request #217 from tencentyun/feature_jojoliang_a7d2e3b2
add object symlink
2 parents 66ad1e4 + 2a7f5ab commit dc08c35

File tree

4 files changed

+168
-1
lines changed

4 files changed

+168
-1
lines changed

cos.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ import (
2424

2525
const (
2626
// Version current go sdk version
27-
Version = "0.7.45"
27+
Version = "0.7.46"
2828
UserAgent = "cos-go-sdk-v5/" + Version
2929
contentTypeXML = "application/xml"
3030
defaultServiceBaseURL = "http://service.cos.myqcloud.com"

example/object/symlink.go

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
package main
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"io/ioutil"
7+
"net/url"
8+
"os"
9+
"strings"
10+
11+
"net/http"
12+
13+
"github.com/tencentyun/cos-go-sdk-v5"
14+
"github.com/tencentyun/cos-go-sdk-v5/debug"
15+
)
16+
17+
func log_status(err error) {
18+
if err == nil {
19+
return
20+
}
21+
if cos.IsNotFoundError(err) {
22+
// WARN
23+
fmt.Println("WARN: Resource is not existed")
24+
} else if e, ok := cos.IsCOSError(err); ok {
25+
fmt.Printf("ERROR: Code: %v\n", e.Code)
26+
fmt.Printf("ERROR: Message: %v\n", e.Message)
27+
fmt.Printf("ERROR: Resource: %v\n", e.Resource)
28+
fmt.Printf("ERROR: RequestId: %v\n", e.RequestID)
29+
// ERROR
30+
} else {
31+
fmt.Printf("ERROR: %v\n", err)
32+
// ERROR
33+
}
34+
}
35+
36+
func main() {
37+
// 存储桶名称,由bucketname-appid 组成,appid必须填入,可以在COS控制台查看存储桶名称。 https://console.cloud.tencent.com/cos5/bucket
38+
// 替换为用户的 region,存储桶region可以在COS控制台“存储桶概览”查看 https://console.cloud.tencent.com/ ,关于地域的详情见 https://cloud.tencent.com/document/product/436/6224 。
39+
u, _ := url.Parse("https://test-1259654469.cos.ap-guangzhou.myqcloud.com")
40+
b := &cos.BaseURL{BucketURL: u}
41+
c := cos.NewClient(b, &http.Client{
42+
Transport: &cos.AuthorizationTransport{
43+
// 通过环境变量获取密钥
44+
// 环境变量 COS_SECRETID 表示用户的 SecretId,登录访问管理控制台查看密钥,https://console.cloud.tencent.com/cam/capi
45+
SecretID: os.Getenv("COS_SECRETID"),
46+
// 环境变量 COS_SECRETKEY 表示用户的 SecretKey,登录访问管理控制台查看密钥,https://console.cloud.tencent.com/cam/capi
47+
SecretKey: os.Getenv("COS_SECRETKEY"),
48+
// Debug 模式,把对应 请求头部、请求内容、响应头部、响应内容 输出到标准输出
49+
Transport: &debug.DebugRequestTransport{
50+
RequestHeader: true,
51+
// Notice when put a large file and set need the request body, might happend out of memory error.
52+
RequestBody: false,
53+
ResponseHeader: true,
54+
ResponseBody: false,
55+
},
56+
},
57+
})
58+
59+
// Case1 上传对象
60+
target := "example"
61+
_, err := c.Object.Put(context.Background(), target, strings.NewReader("test"), nil)
62+
log_status(err)
63+
64+
key := "sym"
65+
opt := &cos.ObjectPutSymlinkOptions{
66+
SymlinkTarget: target,
67+
}
68+
_, err = c.Object.PutSymlink(context.Background(), key, opt)
69+
log_status(err)
70+
71+
res, _, err := c.Object.GetSymlink(context.Background(), key, nil)
72+
log_status(err)
73+
fmt.Printf("res: %v\n", res)
74+
75+
resp, err := c.Object.Get(context.Background(), key, nil)
76+
log_status(err)
77+
defer resp.Body.Close()
78+
79+
bs, _ := ioutil.ReadAll(resp.Body)
80+
fmt.Printf("body: %v\n", string(bs))
81+
82+
_, err = c.Object.Delete(context.Background(), key, nil)
83+
log_status(err)
84+
}

object.go

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1706,3 +1706,39 @@ func (s *ObjectService) GetFetchTask(ctx context.Context, bucket string, taskid
17061706
}
17071707
return &res, resp, err
17081708
}
1709+
1710+
type ObjectPutSymlinkOptions struct {
1711+
SymlinkTarget string `header:"x-cos-symlink-target" url:"-"`
1712+
XOptionHeader *http.Header `header:"-,omitempty" url:"-" xml:"-"`
1713+
}
1714+
1715+
type ObjectGetSymlinkOptions struct {
1716+
XOptionHeader *http.Header `header:"-,omitempty" url:"-" xml:"-"`
1717+
}
1718+
1719+
func (s *ObjectService) PutSymlink(ctx context.Context, name string, opt *ObjectPutSymlinkOptions) (*Response, error) {
1720+
if opt == nil || opt.SymlinkTarget == "" {
1721+
return nil, errors.New("SymlinkTarget is empty")
1722+
}
1723+
sendOpt := &sendOptions{
1724+
baseURL: s.client.BaseURL.BucketURL,
1725+
uri: "/" + encodeURIComponent(name) + "?symlink",
1726+
method: http.MethodPut,
1727+
optHeader: opt,
1728+
}
1729+
resp, err := s.client.doRetry(ctx, sendOpt)
1730+
return resp, err
1731+
}
1732+
1733+
func (s *ObjectService) GetSymlink(ctx context.Context, name string, opt *ObjectGetSymlinkOptions) (string, *Response, error) {
1734+
sendOpt := &sendOptions{
1735+
baseURL: s.client.BaseURL.BucketURL,
1736+
uri: "/" + encodeURIComponent(name) + "?symlink",
1737+
method: http.MethodGet,
1738+
}
1739+
resp, err := s.client.doRetry(ctx, sendOpt)
1740+
if err != nil || resp == nil {
1741+
return "", resp, err
1742+
}
1743+
return resp.Header.Get("x-cos-symlink-target"), resp, err
1744+
}

object_test.go

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1646,3 +1646,50 @@ func TestObjectService_checkUploadedParts(t *testing.T) {
16461646
t.Fatalf("Object.checkUploadedParts should return err: %v", err)
16471647
}
16481648
}
1649+
1650+
func TestObjectService_PutSymlink(t *testing.T) {
1651+
setup()
1652+
defer teardown()
1653+
1654+
name := "symlink"
1655+
mux.HandleFunc("/"+name, func(w http.ResponseWriter, r *http.Request) {
1656+
testMethod(t, r, "PUT")
1657+
vs := values{
1658+
"symlink": "",
1659+
}
1660+
testFormValues(t, r, vs)
1661+
testHeader(t, r, "x-cos-symlink-target", "target")
1662+
})
1663+
1664+
opt := &ObjectPutSymlinkOptions{
1665+
SymlinkTarget: "target",
1666+
}
1667+
_, err := client.Object.PutSymlink(context.Background(), name, opt)
1668+
if err != nil {
1669+
t.Fatalf("Object.PutSymlink returned error %v", err)
1670+
}
1671+
}
1672+
1673+
func TestObjectService_GetSymlink(t *testing.T) {
1674+
setup()
1675+
defer teardown()
1676+
1677+
name := "symlink"
1678+
want := "target"
1679+
mux.HandleFunc("/"+name, func(w http.ResponseWriter, r *http.Request) {
1680+
testMethod(t, r, "GET")
1681+
vs := values{
1682+
"symlink": "",
1683+
}
1684+
testFormValues(t, r, vs)
1685+
w.Header().Set("x-cos-symlink-target", want)
1686+
})
1687+
1688+
res, _, err := client.Object.GetSymlink(context.Background(), name, nil)
1689+
if err != nil {
1690+
t.Fatalf("Object.GetSymlink returned error %v", err)
1691+
}
1692+
if res != want {
1693+
t.Fatalf("Object.GetSymlink, target is invalid, return: %v, want: %v", res, want)
1694+
}
1695+
}

0 commit comments

Comments
 (0)