main.go 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339
  1. package main
  2. import (
  3. "errors"
  4. "io/ioutil"
  5. "net"
  6. "net/http"
  7. _ "net/http/pprof"
  8. "os"
  9. "path/filepath"
  10. "sort"
  11. "strconv"
  12. "strings"
  13. "webuploader/static"
  14. "github.com/gin-gonic/gin"
  15. "github.com/quillaja/logrus-systemd-formatter/systemdfmt"
  16. log "github.com/sirupsen/logrus"
  17. "github.com/urfave/cli/v2"
  18. )
  19. var (
  20. dir string = getCurrentAbPathByExecutable() + string(filepath.Separator)
  21. port string
  22. group1 *gin.RouterGroup
  23. )
  24. func init() {
  25. gin.SetMode(gin.ReleaseMode)
  26. log.SetFormatter(&systemdfmt.Formatter{})
  27. log.SetOutput(os.Stdout)
  28. //log.SetLevel(log.WarnLevel)
  29. //pprof
  30. go func() {
  31. _ = http.ListenAndServe(":6066", nil)
  32. }()
  33. }
  34. // 获取当前执行文件绝对路径
  35. func getCurrentAbPathByExecutable() string {
  36. exePath, err := os.Executable()
  37. if err != nil {
  38. log.Fatal(err)
  39. }
  40. res, _ := filepath.EvalSymlinks(filepath.Dir(exePath))
  41. return res
  42. }
  43. func getClientIp() (string, error) {
  44. addrs, err := net.InterfaceAddrs()
  45. if err != nil {
  46. return "", err
  47. }
  48. for _, address := range addrs {
  49. if ipnet, ok := address.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
  50. if ipnet.IP.To4() != nil {
  51. return ipnet.IP.String(), nil
  52. }
  53. }
  54. }
  55. return "", errors.New("Can not find the client ip address!")
  56. }
  57. func walkDir(filestr string) ([]string, error) {
  58. files, err := ioutil.ReadDir(filestr) // files为当前目录下的所有文件名称【包括文件夹】
  59. if err != nil {
  60. return nil, err
  61. }
  62. var allfile []string
  63. for _, v := range files {
  64. if v.Name() == ".DS_Store" {
  65. continue
  66. }
  67. fullPath := filestr + string(filepath.Separator) + v.Name() // 全路径 + 文件名称
  68. if v.IsDir() { // 如果是目录
  69. a, _ := walkDir(fullPath) // 遍历改路径下的所有文件
  70. allfile = append(allfile, a...)
  71. } else {
  72. allfile = append(allfile, fullPath) // 如果不是文件夹,就直接追加到路径下
  73. }
  74. }
  75. return allfile, nil
  76. }
  77. // 验证是否上传过该文件
  78. func check(c *gin.Context) {
  79. fileMd5 := c.PostForm("md5File")
  80. path := dir + "wisemodel" + string(filepath.Separator) + "merge" + string(filepath.Separator) + fileMd5
  81. if _, err := os.Stat(path); os.IsNotExist(err) { //判断是否已经上传过该文件,设置返回code 为 -1 :秒传
  82. log.Println("mkDir " + path)
  83. _ = os.MkdirAll(path, os.ModePerm)
  84. c.JSON(http.StatusOK, gin.H{
  85. "resultCode": 0, //
  86. })
  87. return
  88. }
  89. result := 0
  90. // 获取目录里上传文件数量
  91. files, err := ioutil.ReadDir(path)
  92. if err != nil {
  93. log.Infof("Error ioutil.ReadDir %v", err)
  94. } else if len(files) == 0 { //文件没有上传过,下标为零
  95. result = 0
  96. } else {
  97. result = 1
  98. }
  99. c.JSON(http.StatusOK, gin.H{
  100. "resultCode": result,
  101. })
  102. }
  103. // 验证是否上传过该文件
  104. func checkChunk(c *gin.Context) {
  105. fileMd5 := c.PostForm("md5File")
  106. chunk := c.PostForm("chunk")
  107. log.Println(fileMd5)
  108. path := dir + "wisemodel" + string(filepath.Separator) + fileMd5 + string(filepath.Separator) + strings.Trim(chunk, "")
  109. log.Println(path)
  110. if _, err := os.Stat(path); err == nil { //判断是否已经上传过该文件,设置返回code 为 -1 :秒传
  111. c.JSON(http.StatusOK, gin.H{
  112. "resultCode": 1, //
  113. })
  114. return
  115. } else {
  116. c.JSON(http.StatusOK, gin.H{
  117. "resultCode": 0,
  118. })
  119. }
  120. }
  121. // 上传文件分片
  122. func upload(c *gin.Context) {
  123. fileName := c.PostForm("name") // 获取文件名
  124. chunkIndex := strings.Trim(c.PostForm("chunk"), "") // 获取分片下标
  125. fileMd5 := c.PostForm("md5File") //获取文件md5
  126. dst := dir + "wisemodel" + string(filepath.Separator) + fileMd5
  127. if chunkIndex == "" {
  128. chunkIndex = "0"
  129. }
  130. result := 0
  131. defer func(subResult *int) {
  132. c.JSON(http.StatusOK, gin.H{
  133. "resultCode": *subResult, //
  134. })
  135. }(&result)
  136. if _, err := os.Stat(dst); os.IsNotExist(err) { //判断是否存在
  137. _ = os.MkdirAll(dst, os.ModePerm)
  138. }
  139. if file, err := c.FormFile("file"); err == nil { //获取分片文件
  140. if chunkIndex == "" {
  141. err = c.SaveUploadedFile(file, dst+string(filepath.Separator)+fileName)
  142. } else {
  143. err = c.SaveUploadedFile(file, dst+string(filepath.Separator)+chunkIndex)
  144. }
  145. if err != nil {
  146. result = 0
  147. log.Errorf("Error c.SaveUploadedFile %v", err)
  148. } else {
  149. result = 1
  150. }
  151. } else {
  152. result = 0
  153. log.Errorf("Error c.FormFile %v", err)
  154. }
  155. }
  156. // 合并分片
  157. func merge(c *gin.Context) {
  158. fileName := c.PostForm("name")
  159. fileMd5 := c.PostForm("md5File")
  160. chunks := c.PostForm("chunks")
  161. path := dir + "wisemodel" + string(filepath.Separator) + fileMd5 //分片存储位置
  162. result := 0
  163. defer func(subResult *int) {
  164. c.JSON(http.StatusOK, gin.H{
  165. "resultCode": *subResult, //
  166. })
  167. }(&result)
  168. // 获取目录里上传文件分片数量
  169. files, err := ioutil.ReadDir(path)
  170. if err != nil || len(files) == 0 || chunks != strconv.Itoa(len(files)) {
  171. log.Errorf("Error merge ioutil.ReadDir %v", err)
  172. result = 0
  173. return
  174. }
  175. //按名字排序
  176. sort.SliceStable(files, func(i, j int) bool {
  177. numA, _ := strconv.Atoi(files[i].Name())
  178. numB, _ := strconv.Atoi(files[j].Name())
  179. return numA < numB
  180. //return files[i].Name() < files[j].Name()
  181. })
  182. realFilePath := dir + "wisemodel" + string(filepath.Separator) + "merge" + string(filepath.Separator) + fileMd5
  183. _ = os.MkdirAll(realFilePath, os.ModePerm) //创建目录
  184. // 创建一个需要合并的文件
  185. realFile, err := os.OpenFile(realFilePath+string(filepath.Separator)+fileName, os.O_CREATE|os.O_TRUNC|os.O_RDWR, os.ModePerm)
  186. defer realFile.Close()
  187. if err != nil {
  188. result = 0
  189. log.Errorf("Error merge os.OpenFile %v", err)
  190. return
  191. }
  192. for _, v := range files { //
  193. f, err := os.OpenFile(path+string(filepath.Separator)+v.Name(), os.O_RDONLY, os.ModePerm)
  194. if err != nil {
  195. result = 0
  196. log.Errorf("Error for os.OpenFile %v", err)
  197. break
  198. }
  199. b, err := ioutil.ReadAll(f)
  200. if err != nil {
  201. result = 0
  202. log.Errorf("Error for ioutil.ReadAll %v", err)
  203. break
  204. }
  205. realFile.Write(b)
  206. // 关闭分片
  207. f.Close()
  208. os.Remove(f.Name()) //合并后,删除分片
  209. result = 1
  210. }
  211. }
  212. // 文件list
  213. func getFiles(c *gin.Context) {
  214. pathMerge := dir + "wisemodel" + string(filepath.Separator) + "merge" //上传文件存储位置
  215. pathLocal := dir + "wisemodel" + string(filepath.Separator) + "local" //本地文件存储位置
  216. if _, err := os.Stat(pathLocal); os.IsNotExist(err) {
  217. _ = os.MkdirAll(pathLocal, os.ModePerm)
  218. }
  219. mergeFiles, err := walkDir(pathMerge)
  220. if err != nil {
  221. log.Errorf("Error walkDir(pathMerge) %v", err)
  222. }
  223. localFiles, err := walkDir(pathLocal)
  224. if err != nil {
  225. log.Errorf("Error walkDir(pathMerge) %v", err)
  226. }
  227. c.JSON(http.StatusOK, gin.H{
  228. "mergeFiles": mergeFiles,
  229. "localFiles": localFiles,
  230. })
  231. }
  232. func doWork() {
  233. ip, err := getClientIp()
  234. if err != nil {
  235. log.Errorf("Error getClientIp %v", err)
  236. return
  237. }
  238. log.Infof("HTTP://" + ip + ":" + port)
  239. r := gin.Default()
  240. //加载静态文件
  241. r.StaticFS("/static", http.FS(static.FS))
  242. // 最大文件大小M
  243. r.MaxMultipartMemory = 8 << 20
  244. // 跳转上传页面
  245. r.GET("/", func(c *gin.Context) {
  246. c.Redirect(http.StatusMovedPermanently, "/static/upload.html")
  247. })
  248. //路由分组
  249. group1 = r.Group("/bigfile")
  250. group1.POST("/check", check)
  251. group1.POST("/checkChunk", checkChunk)
  252. group1.POST("/upload", upload)
  253. group1.POST("/merge", merge)
  254. group1.GET("/getFiles", getFiles)
  255. group1.GET("/down", func(c *gin.Context) {
  256. pathName := c.DefaultQuery("path", "")
  257. fileName := filepath.Base(pathName)
  258. if pathName != "" {
  259. c.Header("Content-Type", "application/octet-stream")
  260. c.Header("Content-Disposition", "attachment; filename="+fileName)
  261. c.Header("Content-Disposition", "inline;filename="+fileName)
  262. c.Header("Content-Transfer-Encoding", "binary")
  263. c.Header("Cache-Control", "no-cache")
  264. c.File(pathName)
  265. }
  266. })
  267. _ = r.Run(":" + port)
  268. }
  269. func main() {
  270. app := &cli.App{
  271. Name: "webuploader", //app名字
  272. Usage: "文件服务", //详细描述该app的用途
  273. // 设置参数列表
  274. Flags: []cli.Flag{
  275. &cli.StringFlag{
  276. Name: "port",
  277. Value: "8888",
  278. Aliases: []string{"p"},
  279. Usage: "port",
  280. Destination: &port,
  281. },
  282. },
  283. Action: func(context *cli.Context) error {
  284. doWork()
  285. return nil
  286. },
  287. }
  288. if err := app.Run(os.Args); err != nil {
  289. log.Errorln("app run error: ", err.Error())
  290. os.Exit(1)
  291. }
  292. }