Skip to content

Commit 0eaabfa

Browse files
committed
init:build success
0 parents  commit 0eaabfa

25 files changed

+1093
-0
lines changed

.gitignore

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
.now
2+
.idea
3+
config.yaml
4+
go.sum

.nowignore

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
.now
2+
.idea
3+
api/config.yaml
4+
go.sum

README.md

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
## Pines
2+
3+
[Pines](https://github.com/xuthus5/pines)是一个基于 Go+Vue 构建的对象存储服务管理应用,目前集成了阿里云OSS,腾讯云COS,又拍云云存储。
4+
5+
### ZEIT.CO无服务函数版本
6+
7+
演示地址(请勿恶意上传):[https://pines.xuthus.cc/](https://pines.xuthus.cc/)
8+
9+
token:AKIDa3M4qZAKPOD6sSyVDwVOEyYlvwwrONxR
10+
11+
[![Deploy to now](https://deploy.now.sh/static/button.svg)](https://zeit.co/new/project?template=togo-soft/zeit-pines)
12+
13+
### 构建与运行
14+
15+
1. 重命名 config.yaml.example 为 config.yaml
16+
17+
2. 修改 config.yaml 内容
18+
19+
3. 从源代码运行或下载release版本直接运行
20+
21+
```bash
22+
# 从源代码运行
23+
git clone https://github.com/xuthus5/pines
24+
cd pines
25+
go run .
26+
```

api/config.yaml.example

+49
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
# 注意: Domain 域名选项均以 / 结尾 如 Ups.Domain: https://test.cc/
2+
3+
# 服务端口 (默认 :7125)
4+
Port: :7125
5+
# 默认上传接口 Ups 参数: [Ups/Cos/Oss]
6+
# 用于外部上传指定接口
7+
Default: Ups
8+
# 上传Token 供外部上传的接口需要Token验证
9+
UToken: LTAIeNu9L0MzBtJH
10+
# 身份认证Token 通过该Token进行服务管理
11+
Token: AKIDa3M4qZAKPOD6sSyVDwVOEyYlvwwrONxR
12+
# 腾讯云Cos服务
13+
Cos:
14+
# API密钥ID
15+
SecretID:
16+
# API密钥私钥
17+
SecretKey:
18+
# 存储桶名称 规则 bucketname-appid => test-1234567889
19+
Bucket:
20+
# 存储桶所属地域 规则 ap-nanjing
21+
Region:
22+
# API地址(访问域名) 在存储桶列表->配置管理->基础配置中可见
23+
# 规则 https://<bucket>.cos.<region>.myqcloud.com
24+
# 默认为空 自动生成
25+
APIAddress:
26+
# 自定义域名
27+
Domain:
28+
# 阿里云OSS服务
29+
Oss:
30+
# AccessKey ID
31+
Ak:
32+
# Access Key Secret
33+
Sk:
34+
# 存储桶名称
35+
Bucket:
36+
# 外网访问地域节点(非Bucket域名) 规则 oss-cn-shanghai.aliyuncs.com
37+
Endpoint:
38+
# 自定义域名(Bucket域名或自定义) 规则 https://test-cn-shanghai.aliyuncs.com/
39+
Domain:
40+
# 又拍云云存储服务
41+
Ups:
42+
# 存储桶名称
43+
Bucket:
44+
# 被授权的操作员名称
45+
Operator:
46+
# 被授权的操作员密码
47+
Password:
48+
# 加速域名
49+
Domain:

api/cos.go

+260
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,260 @@
1+
package handler
2+
3+
import (
4+
"context"
5+
"encoding/json"
6+
"fmt"
7+
"net/http"
8+
"net/url"
9+
"strings"
10+
"time"
11+
12+
"io/ioutil"
13+
"strconv"
14+
15+
"github.com/tencentyun/cos-go-sdk-v5"
16+
"gopkg.in/yaml.v2"
17+
)
18+
19+
// Cos 腾讯云Cos服务
20+
type Cos struct {
21+
SecretID string `yaml:"SecretID"` //API密钥ID
22+
SecretKey string `yaml:"SecretKey"` //API密钥私钥
23+
Bucket string `yaml:"Bucket"` //存储桶名称 规则 test-1234567889
24+
Region string `yaml:"Region"` //存储桶所属地域 规则 ap-nanjing
25+
Domain string `yaml:"Domain"` //自定义域名
26+
APIAddress string `yaml:"APIAddress"` //API地址(访问域名) 在存储桶列表->配置管理->基础配置中可见 规则 https://<bucket>.cos.<region>.myqcloud.com
27+
}
28+
29+
// Response 是交付层的基本回应
30+
type Response struct {
31+
Code int `json:"code"` //请求状态代码
32+
Message interface{} `json:"message"` //请求结果提示
33+
Data interface{} `json:"data"` //请求结果与错误原因
34+
}
35+
36+
// List 会返回给交付层一个列表回应
37+
type List struct {
38+
Code int `json:"code"` //请求状态代码
39+
Count int `json:"count"` //数据量
40+
Message interface{} `json:"message"` //请求结果提示
41+
Data interface{} `json:"data"` //请求结果
42+
}
43+
44+
// ListObject 对象列表
45+
type ListObject struct {
46+
Filename string `json:"filename"`
47+
Prefix string `json:"prefix"`
48+
IsDir bool `json:"is_dir"`
49+
Size interface{} `json:"size"`
50+
CreateTime interface{} `json:"create_time"`
51+
}
52+
53+
// Config 配置文件解析
54+
type Config struct {
55+
Port string `yaml:"Port"`
56+
Default string `yaml:"Default"`
57+
Token string `yaml:"Token"`
58+
UToken string `yaml:"UToken"`
59+
Cos `yaml:"Cos"`
60+
}
61+
62+
var (
63+
// CosConfig 配置项
64+
CosConfig *Config
65+
// CosClient 客户端
66+
CosClient *cos.Client
67+
//response 返回值
68+
response []byte
69+
)
70+
71+
// GetConfig 调用该方法会实例化conf 项目运行会读取一次配置文件 确保不会有多余的读取损耗
72+
func GetConfig() *Config {
73+
var config = new(Config)
74+
yamlFile, err := ioutil.ReadFile("config.yaml")
75+
if err != nil {
76+
panic(err)
77+
}
78+
err = yaml.Unmarshal(yamlFile, config)
79+
if err != nil {
80+
//读取配置文件失败,停止执行
81+
panic("read config file error:" + err.Error())
82+
}
83+
return config
84+
}
85+
86+
// Write 输出返回结果
87+
func Write(w http.ResponseWriter, response []byte) {
88+
//公共的响应头设置
89+
w.Header().Set("Access-Control-Allow-Origin", "*")
90+
w.Header().Set("Access-Control-Allow-Headers", "*")
91+
w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PATCH, PUT, OPTIONS")
92+
w.Header().Set("Content-Type", "application/json;charset=utf-8")
93+
w.Header().Set("Content-Length", strconv.Itoa(len(string(response))))
94+
_, _ = w.Write(response)
95+
return
96+
}
97+
98+
// InitCosClient 初始化操作
99+
func InitCosClient() {
100+
CosConfig = GetConfig()
101+
CosConfig.APIAddress = fmt.Sprintf("https://%s.cos.%s.myqcloud.com", CosConfig.Bucket, CosConfig.Region)
102+
u, _ := url.Parse(CosConfig.APIAddress)
103+
b := &cos.BaseURL{BucketURL: u}
104+
CosClient = cos.NewClient(b, &http.Client{
105+
//设置超时时间
106+
Timeout: 100 * time.Second,
107+
Transport: &cos.AuthorizationTransport{
108+
//如实填写账号和密钥,也可以设置为环境变量
109+
SecretID: CosConfig.SecretID,
110+
SecretKey: CosConfig.SecretKey,
111+
},
112+
})
113+
}
114+
115+
// Handler 请求参数信息
116+
// Operate: 操作类型 [list,delete,upload,domain,mkdir]
117+
// Prefix: 操作的前缀(前缀意为操作所在的目录)
118+
// Path: 操作的绝对地址
119+
120+
// CosHandler 句柄
121+
func CosHandler(w http.ResponseWriter, r *http.Request) {
122+
//初始化
123+
InitCosClient()
124+
var operate = r.URL.Query().Get("operate")
125+
if operate == "list" {
126+
// 列举当前目录下的所有文件
127+
var result []ListObject //结果集
128+
//设置筛选器
129+
var prefix = r.URL.Query().Get("prefix")
130+
opt := &cos.BucketGetOptions{
131+
Prefix: prefix,
132+
Delimiter: "/",
133+
Marker: prefix,
134+
}
135+
//结果入 result
136+
v, _, err := CosClient.Bucket.Get(context.Background(), opt)
137+
if err != nil {
138+
response, _ = json.Marshal(&Response{
139+
Code: 500,
140+
Message: "ErrorListObject:" + err.Error(),
141+
})
142+
Write(w, response)
143+
return
144+
}
145+
for _, dirname := range v.CommonPrefixes {
146+
result = append(result, ListObject{
147+
Filename: strings.Replace(dirname, prefix, "", 1),
148+
CreateTime: "",
149+
IsDir: true,
150+
Prefix: prefix,
151+
})
152+
}
153+
for _, obj := range v.Contents {
154+
result = append(result, ListObject{
155+
Filename: strings.Replace(obj.Key, prefix, "", 1),
156+
CreateTime: obj.LastModified,
157+
IsDir: false,
158+
Prefix: prefix,
159+
Size: obj.Size,
160+
})
161+
}
162+
163+
var domain string
164+
if CosConfig.Domain == "" {
165+
domain = CosConfig.APIAddress + "/"
166+
} else {
167+
domain = CosConfig.Domain
168+
}
169+
response, _ = json.Marshal(&List{
170+
Code: 200,
171+
Message: domain,
172+
Data: result,
173+
Count: len(result),
174+
})
175+
} else if operate == "delete" {
176+
//需要删除的文件绝对路径
177+
var path = r.URL.Query().Get("path")
178+
_, err := CosClient.Object.Delete(context.Background(), path)
179+
if err != nil {
180+
response, _ = json.Marshal(&Response{
181+
Code: 500,
182+
Message: "ErrorObjectDelete:" + err.Error(),
183+
})
184+
Write(w, response)
185+
return
186+
}
187+
response, _ = json.Marshal(&Response{
188+
Code: 200,
189+
Message: "ok",
190+
})
191+
} else if operate == "upload" {
192+
var _, header, err = r.FormFile("file")
193+
var prefix string
194+
_ = r.ParseMultipartForm(32 << 20)
195+
if r.MultipartForm != nil {
196+
values := r.MultipartForm.Value["prefix"]
197+
if len(values) > 0 {
198+
prefix = values[0]
199+
}
200+
}
201+
if err != nil {
202+
response, _ = json.Marshal(&Response{
203+
Code: 500,
204+
Message: "ErrorUpload:" + err.Error(),
205+
})
206+
Write(w, response)
207+
return
208+
}
209+
dst := header.Filename
210+
source, _ := header.Open()
211+
_, err = CosClient.Object.Put(context.Background(), prefix+dst, source, nil)
212+
if err != nil {
213+
response, _ = json.Marshal(&Response{
214+
Code: 500,
215+
Message: "ErrorObjectUpload:" + err.Error(),
216+
})
217+
Write(w, response)
218+
return
219+
}
220+
var domain string
221+
if CosConfig.Domain == "" {
222+
domain = CosConfig.APIAddress + "/"
223+
} else {
224+
domain = CosConfig.Domain
225+
}
226+
response, _ = json.Marshal(&Response{
227+
Code: 200,
228+
Message: "ok",
229+
Data: domain + prefix + dst,
230+
})
231+
} else if operate == "domain" {
232+
var domain string
233+
if CosConfig.Domain == "" {
234+
domain = CosConfig.APIAddress + "/"
235+
} else {
236+
domain = CosConfig.Domain
237+
}
238+
response, _ = json.Marshal(&Response{
239+
Code: 200,
240+
Message: domain,
241+
})
242+
} else if operate == "mkdir" {
243+
var prefix = r.URL.Query().Get("prefix")
244+
var dirname = r.URL.Query().Get("dirname")
245+
_, err := CosClient.Object.Put(context.Background(), prefix+dirname, nil, nil)
246+
if err != nil {
247+
response, _ = json.Marshal(&Response{
248+
Code: 500,
249+
Message: "ErrorMkdir:" + err.Error(),
250+
})
251+
Write(w, response)
252+
return
253+
}
254+
response, _ = json.Marshal(&Response{
255+
Code: 200,
256+
Message: "ok",
257+
})
258+
}
259+
Write(w, response)
260+
}

api/go.mod

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
module Pines
2+
3+
go 1.13
4+
5+
require (
6+
github.com/aliyun/aliyun-oss-go-sdk v2.0.8+incompatible
7+
github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f // indirect
8+
github.com/julienschmidt/httprouter v1.3.0
9+
github.com/satori/go.uuid v1.2.0 // indirect
10+
github.com/tencentyun/cos-go-sdk-v5 v0.7.4
11+
github.com/upyun/go-sdk v2.1.0+incompatible
12+
golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1 // indirect
13+
gopkg.in/yaml.v2 v2.2.8
14+
)

0 commit comments

Comments
 (0)