You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

339 lines
7.0 KiB

4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
  1. package main
  2. import (
  3. "bytes"
  4. "context"
  5. "encoding/base64"
  6. "encoding/json"
  7. "errors"
  8. "flag"
  9. "fmt"
  10. "github.com/AlecAivazis/survey"
  11. "github.com/tencentyun/cos-go-sdk-v5"
  12. "github.com/wailovet/osmanthuswine/src/helper"
  13. "io/ioutil"
  14. "net/http"
  15. "net/url"
  16. "os"
  17. "os/exec"
  18. "os/user"
  19. "path/filepath"
  20. "runtime"
  21. "strings"
  22. )
  23. var config TencentYunConfig
  24. var op string
  25. var path string
  26. var qpath string
  27. var key string
  28. func loadKey() {
  29. homePath, err := home()
  30. if err != nil {
  31. fmt.Println("错误 102: ", err)
  32. return
  33. }
  34. keyFile := filepath.Join(homePath, ".qcloud-key")
  35. data, _ := ioutil.ReadFile(keyFile)
  36. if string(data) == "" {
  37. fmt.Println("错误 204 找不到key,请使用使用set-key进行初始化.")
  38. return
  39. }
  40. key = string(data)
  41. }
  42. func initKey() {
  43. if key == "" {
  44. fmt.Println("key is empty!")
  45. os.Exit(1)
  46. }
  47. var err error
  48. var dekey []byte
  49. dekey, err = base64.StdEncoding.DecodeString(key)
  50. if err != nil {
  51. fmt.Println("错误 201:", err)
  52. os.Exit(1)
  53. }
  54. dekey, err = helper.DefaultAesDecrypt(dekey)
  55. if err != nil {
  56. fmt.Println("错误 202:", err)
  57. os.Exit(1)
  58. }
  59. err = json.Unmarshal(dekey, &config)
  60. if err != nil {
  61. fmt.Println("错误 203:", err)
  62. os.Exit(1)
  63. }
  64. }
  65. func main() {
  66. helper.AesKey = []byte("3136352472abcdef")
  67. flag.StringVar(&op, "op", "", "操作:make-key[生成密钥] | set-key[设置密钥] | upload [上传文件] | list [获取文件]")
  68. flag.StringVar(&path, "path", "", "上传目录")
  69. flag.StringVar(&qpath, "qpath", "", "云上传目的目录")
  70. flag.StringVar(&key, "key", "", "key")
  71. flag.Parse()
  72. switch op {
  73. case "set-key":
  74. key = askText("输入key")
  75. initKey()
  76. _, err := getTencentYunCosFiles("")
  77. if err != nil {
  78. fmt.Println("key error 101:", err)
  79. return
  80. }
  81. homePath, err := home()
  82. if err != nil {
  83. fmt.Println("错误 102:", err)
  84. return
  85. }
  86. keyFile := filepath.Join(homePath, ".qcloud-key")
  87. err = ioutil.WriteFile(keyFile, []byte(key), 0644)
  88. if err != nil {
  89. fmt.Println("错误 103:", err)
  90. return
  91. }
  92. fmt.Println("完成!")
  93. case "make-key":
  94. config.SecretID = askText("输入SecretID")
  95. config.SecretKey = askText("输入SecretKey")
  96. config.BucketURL = askText("输入BucketURL")
  97. config.Root = askText("输入Root")
  98. mkey, err := helper.DefaultAesEncrypt([]byte(helper.JsonEncode(config)))
  99. if err != nil {
  100. fmt.Println("错误 104:", err)
  101. return
  102. }
  103. mkey = []byte(base64.StdEncoding.EncodeToString(mkey))
  104. fmt.Println("key:", string(mkey), " ==> ", "key.txt")
  105. _ = ioutil.WriteFile("key.txt", mkey, 0644)
  106. os.Exit(0)
  107. case "upload":
  108. loadKey()
  109. initKey()
  110. if path != "" {
  111. url := ""
  112. if qpath == "" {
  113. url = UploadDir(path)
  114. } else {
  115. url = UploadDir(path, qpath)
  116. }
  117. fmt.Println("url:", url)
  118. } else {
  119. flag.Usage()
  120. }
  121. case "list":
  122. loadKey()
  123. initKey()
  124. for {
  125. data, err := getTencentYunCosFiles(path)
  126. if err != nil {
  127. fmt.Println("错误 106:", err)
  128. return
  129. }
  130. //for e := range data.CommonPrefixes {
  131. // fmt.Println(data.CommonPrefixes[e])
  132. //}
  133. var files []string
  134. for e := range data.Contents {
  135. files = append(files, data.Contents[e].Key)
  136. }
  137. _, menu := askSelect("Path:"+path, append([]string{".."}, append(data.CommonPrefixes, files...)...)...)
  138. if menu == ".." {
  139. pathSplit := strings.Split(path, "/")
  140. if len(pathSplit) > 1 {
  141. path = strings.Join(pathSplit[0:len(pathSplit)-1], "/")
  142. } else {
  143. path = ""
  144. }
  145. } else {
  146. path = menu
  147. }
  148. }
  149. default:
  150. flag.Usage()
  151. }
  152. }
  153. type TencentYunConfig struct {
  154. SecretID string
  155. SecretKey string
  156. SessionToken string
  157. BucketURL string
  158. Root string
  159. }
  160. var client *cos.Client
  161. func getTencentYunConf(c *TencentYunConfig) *cos.Client {
  162. if client == nil {
  163. BucketURL, _ := url.Parse(c.BucketURL)
  164. b := &cos.BaseURL{
  165. BucketURL: BucketURL,
  166. }
  167. // 1.永久密钥
  168. client = cos.NewClient(b, &http.Client{
  169. Transport: &cos.AuthorizationTransport{
  170. SecretID: c.SecretID,
  171. SecretKey: c.SecretKey,
  172. },
  173. })
  174. }
  175. return client
  176. }
  177. func getTencentYunCosFiles(prefix string) (*cos.BucketGetResult, error) {
  178. // 1.永久密钥
  179. client := getTencentYunConf(&config)
  180. if prefix == "" {
  181. prefix = strings.Replace(config.Root+"/", `//`, `/`, -1)
  182. }
  183. res, _, err := client.Bucket.Get(context.Background(), &cos.BucketGetOptions{
  184. Prefix: prefix,
  185. Delimiter: "/",
  186. })
  187. if err != nil {
  188. return nil, err
  189. }
  190. return res, nil
  191. }
  192. func UploadDir(fpath string, qpaths ...string) string {
  193. qpath := ""
  194. if len(qpaths) > 0 {
  195. qpath = qpaths[0]
  196. } else {
  197. separator := "/"
  198. if runtime.GOOS == "windows" {
  199. separator = `\`
  200. }
  201. separatordir := strings.Split(fpath, separator)
  202. if len(separatordir) > 0 {
  203. qpath = separatordir[len(separatordir)-1]
  204. }
  205. }
  206. client := getTencentYunConf(&config)
  207. files, _ := ioutil.ReadDir(fpath)
  208. for _, f := range files {
  209. if f.Name()[0] == '.' {
  210. continue
  211. }
  212. if f.IsDir() {
  213. UploadDir(filepath.Join(fpath, f.Name()), filepath.Join(qpath, f.Name()))
  214. } else {
  215. filename := filepath.Join(fpath, f.Name())
  216. fmt.Print("上传:", filename, " ==> ", filepath.Join(config.Root, filename), " ")
  217. _, err := client.Object.PutFromFile(context.Background(), strings.Replace(filepath.Join(config.Root, qpath, f.Name()), `\`, `/`, -1), filename, nil)
  218. if err != nil {
  219. fmt.Println("错误 105:", err)
  220. } else {
  221. fmt.Println("完成")
  222. }
  223. }
  224. }
  225. urlPath := "/" + strings.Replace(filepath.Join(config.Root, qpath), `\`, `/`, -1)
  226. for strings.Index(urlPath, "//") > -1 {
  227. urlPath = strings.Replace(urlPath, "//", "/", -1)
  228. }
  229. return config.BucketURL + urlPath
  230. }
  231. func askSelect(title string, v ...string) (int, string) {
  232. result := -1
  233. prompt := &survey.Select{
  234. Message: title,
  235. Options: v,
  236. }
  237. err := survey.AskOne(prompt, &result)
  238. if err != nil {
  239. return 0, ""
  240. }
  241. if result == -1 {
  242. return askSelect(title, v...)
  243. }
  244. return result, v[result]
  245. }
  246. func askText(title string) string {
  247. result := ""
  248. prompt := &survey.Input{
  249. Message: title,
  250. }
  251. survey.AskOne(prompt, &result)
  252. if result == "" {
  253. fmt.Println("不允许为空")
  254. return askText(title)
  255. }
  256. return result
  257. }
  258. func home() (string, error) {
  259. user, err := user.Current()
  260. if nil == err {
  261. return user.HomeDir, nil
  262. }
  263. // cross compile support
  264. if "windows" == runtime.GOOS {
  265. return homeWindows()
  266. }
  267. // Unix-like system, so just assume Unix
  268. return homeUnix()
  269. }
  270. func homeUnix() (string, error) {
  271. // First prefer the HOME environmental variable
  272. if home := os.Getenv("HOME"); home != "" {
  273. return home, nil
  274. }
  275. // If that fails, try the shell
  276. var stdout bytes.Buffer
  277. cmd := exec.Command("sh", "-c", "eval echo ~$USER")
  278. cmd.Stdout = &stdout
  279. if err := cmd.Run(); err != nil {
  280. return "", err
  281. }
  282. result := strings.TrimSpace(stdout.String())
  283. if result == "" {
  284. return "", errors.New("blank output when reading home directory")
  285. }
  286. return result, nil
  287. }
  288. func homeWindows() (string, error) {
  289. drive := os.Getenv("HOMEDRIVE")
  290. path := os.Getenv("HOMEPATH")
  291. home := drive + path
  292. if drive == "" || path == "" {
  293. home = os.Getenv("USERPROFILE")
  294. }
  295. if home == "" {
  296. return "", errors.New("HOMEDRIVE, HOMEPATH, and USERPROFILE are blank")
  297. }
  298. return home, nil
  299. }