文件同步
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.

handle.go 14 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
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
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
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
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
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
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
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
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
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
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
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
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
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633
  1. package handle
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "fts/config"
  6. "github.com/gorilla/websocket"
  7. _ "github.com/ipfs/go-ipfs-api"
  8. shell "github.com/ipfs/go-ipfs-api"
  9. "io"
  10. "log"
  11. "os"
  12. "os/exec"
  13. "path"
  14. "path/filepath"
  15. "strconv"
  16. "strings"
  17. "time"
  18. )
  19. var gobalLoginUserId string
  20. //key:filepath,value:hash
  21. var gobalFileMap = make(map[string] string)
  22. var gobalFileUpdateTimeMap = make(map[string] string)
  23. //var gobalFileChangeMap = make(map[string] string)
  24. var getLocalFileListDir string
  25. var gobalSubscriptionFileChangeSwitch int =0 //订阅文件变更开关
  26. var ipfsPath=os.Getenv("IPFS-PATH")
  27. /**
  28. 文件上传下载进度
  29. */
  30. type processStruct struct {
  31. Size string `json:"size"`
  32. CurrentSize string `json:"currentSize"`
  33. Unit string `json:"unit"`
  34. CurrentUnit string `json:"currentUnit"`
  35. Process float64 `json:"process"`
  36. Hash string `json:"hash"`
  37. }
  38. func main() {
  39. //config.InitConfig()
  40. //InitLocalWorkSpace("320872793405132801","test1")
  41. //
  42. //DownCommand("QmTp2hEo8eXRp6wg7jXv1BLCMh5a4F3B7buAUZNZUu772j","testOne","hello.txt","a/b/")
  43. //
  44. //UploadCommand("C:\\Users\\yuan_rh\\Downloads\\QmRzN7uW6HCVAkGMXNWv3rC9dqPJijvEgvtW6DKsQQE8Js","QmRzN7uW6HCVAkGMXNWv3rC9dqPJijvEgvtW6DKsQQE8Js","testOne","a/b/")
  45. //
  46. //GetLocalFileList("testOne")
  47. }
  48. /**
  49. 初始化本地工作目录
  50. @param userId 用户ID
  51. @param projectName 项目名称
  52. */
  53. func InitLocalWorkSpace(conn *websocket.Conn,userId,projectName string) (error){
  54. //空格路径处理
  55. ipfsPath=strings.Replace(os.Getenv("IPFS-PATH"),"\"","",1)+"\\ipfs.exe"
  56. //初始化当前登陆用户
  57. gobalLoginUserId = userId
  58. // 检查本地目录是否存在
  59. var projectPath = config.LocalWorkSpaceDir +"\\"+userId+"\\"+projectName
  60. _,err := os.Stat(projectPath)
  61. if err != nil {
  62. //创建文件目录
  63. os.MkdirAll(projectPath, os.ModePerm)
  64. /*os.MkdirAll(projectPath+"\\我的文件", os.ModePerm)
  65. os.MkdirAll(projectPath+"\\工作文件", os.ModePerm)
  66. os.MkdirAll(projectPath+"\\协作文件", os.ModePerm)
  67. os.MkdirAll(projectPath+"\\公共文件", os.ModePerm)*/
  68. }
  69. log.Println("切换本地工作目录至 "+projectPath)
  70. if err := conn.WriteMessage(websocket.TextMessage, []byte(fmt.Sprint(projectPath))); err != nil {
  71. log.Println(err)
  72. return err
  73. }
  74. return nil
  75. }
  76. /**
  77. 下载指令
  78. @param hash ipfs哈希值
  79. @param projectName 项目名称
  80. @para fileName 文件名称
  81. @param dir 云文件目录
  82. */
  83. func DownCommand(conn *websocket.Conn, hash, projectName, fileName, dir string) error{
  84. absoluteDir := config.LocalWorkSpaceDir+"\\"+gobalLoginUserId+"\\"+projectName+"\\"+dir
  85. //检查目录
  86. _,err := os.Stat(absoluteDir)
  87. if err != nil {
  88. //创建文件目录
  89. err = os.MkdirAll(absoluteDir, os.ModePerm)
  90. if err!=nil{
  91. log.Println(err)
  92. return err
  93. }
  94. }
  95. var downloading bool = false
  96. //检测文件打开状态
  97. tfile,err := os.OpenFile(fmt.Sprint(absoluteDir+"\\"+fileName),os.O_RDWR,1)
  98. if err != nil && (!os.IsNotExist(err)) {
  99. log.Println("文件被占用,请关闭打开的软件")
  100. if err := conn.WriteMessage(websocket.TextMessage, []byte("-2")); err != nil {
  101. return err
  102. }
  103. return err
  104. }
  105. defer tfile.Close()
  106. //serverSh := shell.NewShell(config.ServerIpfsUrl)
  107. ////检测引导节点是否连接成功
  108. //isUp := serverSh.IsUp()
  109. //if !isUp {
  110. // if err := conn.WriteMessage(websocket.TextMessage, []byte("-1")); err != nil {
  111. // return err
  112. // }
  113. // return nil
  114. //}
  115. cmd := exec.Command(ipfsPath,"get", hash,"-o",fmt.Sprint(absoluteDir+"\\"+fileName))
  116. progress := make(chan string,10000)
  117. var stdout, stderr []byte
  118. var errStdout, errStderr error
  119. stdoutIn, _ := cmd.StdoutPipe()
  120. stderrIn, _ := cmd.StderrPipe()
  121. cmd.Start()
  122. go func() {
  123. stdout, errStdout = copyAndCapture(os.Stdout, stdoutIn, progress)
  124. }()
  125. go func() {
  126. stderr, errStderr = copyAndCapture(os.Stderr, stderrIn, progress)
  127. }()
  128. go func(){
  129. millSeconds := time.Now().UnixNano() / 1e6
  130. for content := range progress { // 通道关闭后会退出for range循环
  131. current :=time.Now().UnixNano() / 1e6
  132. if current-millSeconds>500{
  133. projson,err := contentToJSONByte(content)
  134. if projson==nil && err==nil{
  135. continue
  136. }
  137. if err != nil {
  138. log.Printf("json.Marshal error %s\n", err)
  139. }
  140. millSeconds = current
  141. downloading = true
  142. if err := conn.WriteMessage(websocket.TextMessage, projson); err != nil {
  143. log.Println(err)
  144. break
  145. }
  146. }
  147. if strings.Index(content,"100.00%")!=-1{
  148. projson,err := contentToJSONByte(content)
  149. if projson==nil && err==nil{
  150. continue
  151. }
  152. if err != nil {
  153. log.Printf("json.Marshal error %s\n", err)
  154. }
  155. downloading = true
  156. if err := conn.WriteMessage(websocket.TextMessage, projson); err != nil {
  157. panic(err)
  158. }
  159. break
  160. }
  161. }
  162. }()
  163. log.Println("下载资源连接中...")
  164. //设置30秒连接超时
  165. go func() {
  166. index :=0
  167. for true{
  168. index++
  169. if downloading==true{
  170. return
  171. }
  172. time.Sleep(time.Duration(1)*time.Second)
  173. if downloading==false && index==30{
  174. err = cmd.Process.Kill()
  175. log.Println("进程连接超时30s已被Kill")
  176. if err := conn.WriteMessage(websocket.TextMessage, []byte("-1")); err != nil {
  177. return
  178. }
  179. return
  180. }
  181. }
  182. }()
  183. err = cmd.Wait()
  184. if err != nil {
  185. log.Printf("cmd.Run() failed with %s\n", err)
  186. }
  187. if errStdout != nil || errStderr != nil {
  188. log.Printf("failed to capture stdout or stderr\n")
  189. }
  190. outStr, errStr := string(stdout), string(stderr)
  191. log.Printf("out:%s ,err:%s", outStr, errStr)
  192. if err==nil{
  193. log.Println("下载成功")
  194. }
  195. //time.Sleep(time.Duration(6)*time.Second)
  196. defer close(progress)
  197. return nil
  198. }
  199. func contentToJSONByte(content string) ([]byte,error){
  200. sts :=strings.Split(content," ")
  201. if len(sts)<8{
  202. log.Println("字符长度小于8")
  203. return nil,nil
  204. }
  205. var processFloat float64
  206. if (len(sts)==9 || len(sts)==8){
  207. processFloat,_ =strconv.ParseFloat(strings.Replace(sts[7],"%","",1), 64)
  208. }else{
  209. processFloat,_ =strconv.ParseFloat(strings.Replace(sts[8],"%","",1), 64)
  210. }
  211. if processFloat==0{
  212. //log.Println("当前进度0")
  213. return nil,nil
  214. }
  215. pro :=&processStruct{
  216. Size:sts[4],
  217. CurrentSize: sts[1],
  218. Unit: sts[2],
  219. CurrentUnit: sts[5],
  220. Process: processFloat,
  221. Hash: "",
  222. }
  223. projson,err :=json.Marshal(pro)
  224. return projson,err
  225. }
  226. /**
  227. 上传本地文件
  228. @param absolutePath 文件本地绝对路径
  229. @param fileName 文件名称
  230. @param projectName 项目名称
  231. @param dir 云文件目录
  232. */
  233. func UploadCommand(conn *websocket.Conn,absolutePath,fileName,projectName,dir string) error{
  234. //本地拷贝文件
  235. absoluteDir := config.LocalWorkSpaceDir+"\\"+gobalLoginUserId+"\\"+projectName+"\\"+dir
  236. //检查目录
  237. _,err := os.Stat(absoluteDir)
  238. if err != nil {
  239. //创建文件目录
  240. err = os.MkdirAll(absoluteDir, os.ModePerm)
  241. if err!=nil{
  242. return err
  243. }
  244. }
  245. //检测文件打开状态
  246. tfile,err := os.OpenFile(absolutePath,os.O_RDWR,1)
  247. if err != nil {
  248. log.Println("文件被占用,请关闭打开的软件")
  249. if err := conn.WriteMessage(websocket.TextMessage, []byte("-2")); err != nil {
  250. return err
  251. }
  252. return err
  253. }
  254. defer tfile.Close()
  255. serverSh := shell.NewShell(config.ServerIpfsUrl)
  256. //检测引导节点是否连接成功
  257. isUp := serverSh.IsUp()
  258. if !isUp {
  259. if err := conn.WriteMessage(websocket.TextMessage, []byte("-1")); err != nil {
  260. return err
  261. }
  262. return nil
  263. }
  264. var uploading bool=false
  265. cmd := exec.Command(ipfsPath, "add",absolutePath)
  266. uploadProgress := make(chan string,10000)
  267. var stdout, stderr []byte
  268. var errStdout, errStderr error
  269. stdoutIn, _ := cmd.StdoutPipe()
  270. stderrIn, _ := cmd.StderrPipe()
  271. cmd.Start()
  272. go func() {
  273. stdout, errStdout = copyAndCapture(os.Stdout, stdoutIn, uploadProgress)
  274. }()
  275. go func() {
  276. stderr, errStderr = copyAndCapture(os.Stderr, stderrIn, uploadProgress)
  277. }()
  278. go func(){
  279. millSeconds := time.Now().UnixNano() / 1e6
  280. for content := range uploadProgress { // 通道关闭后会退出for range循环
  281. current :=time.Now().UnixNano() / 1e6
  282. if current-millSeconds>500{
  283. projson,err := contentToJSONByte(content)
  284. if projson==nil && err==nil{
  285. continue
  286. }
  287. if err != nil {
  288. log.Println("json.Marshal error %s\n", err)
  289. }
  290. uploading=true
  291. if err := conn.WriteMessage(websocket.TextMessage, projson); err != nil {
  292. break
  293. }
  294. millSeconds = current
  295. }
  296. if strings.Index(content,"100.00%")!=-1{
  297. projson,err := contentToJSONByte(content)
  298. if projson==nil && err==nil{
  299. continue
  300. }
  301. if err != nil {
  302. log.Println("json.Marshal error %s\n", err)
  303. }
  304. uploading=true
  305. if err := conn.WriteMessage(websocket.TextMessage, projson); err != nil {
  306. panic(err)
  307. }
  308. break
  309. }
  310. }
  311. }()
  312. log.Println("文件上传中...")
  313. //设置30秒连接超时
  314. go func() {
  315. index :=0
  316. for true{
  317. index++
  318. if uploading==true{
  319. return
  320. }
  321. time.Sleep(time.Duration(1)*time.Second)
  322. if uploading==false && index==30{
  323. err = cmd.Process.Kill()
  324. log.Println("进程连接超时30s已被Kill")
  325. if err := conn.WriteMessage(websocket.TextMessage, []byte("-1")); err != nil {
  326. return
  327. }
  328. return
  329. }
  330. }
  331. }()
  332. err = cmd.Wait()
  333. if err != nil {
  334. log.Println("cmd.Run() failed with %s\n", err)
  335. }
  336. if errStdout != nil || errStderr != nil {
  337. log.Println("failed to capture stdout or stderr\n")
  338. }
  339. outStr, errStr := string(stdout), string(stderr)
  340. log.Printf("out:%s,err:%s", outStr, errStr)
  341. /*sh.Get(hash,absoluteDir+fileName)
  342. if err != nil {
  343. return "",err
  344. }*/
  345. defer close(uploadProgress)
  346. prog := new(processStruct)
  347. prog.Hash=strings.Split(outStr," ")[1]
  348. prog.Process=100.00
  349. sh := shell.NewShell(config.GobalIpfsUrl)
  350. objectStat,err :=sh.ObjectStat(prog.Hash)
  351. if err != nil {
  352. log.Println(err)
  353. return err
  354. }
  355. prog.Size=strconv.Itoa(objectStat.CumulativeSize)
  356. projson,err :=json.Marshal(prog)
  357. err = serverSh.Pin(prog.Hash)
  358. if err != nil {
  359. log.Println("引导节点备份失败")
  360. log.Println(err)
  361. if err := conn.WriteMessage(websocket.TextMessage, []byte("-1")); err != nil {
  362. return err
  363. }
  364. return err
  365. }
  366. if err := conn.WriteMessage(websocket.TextMessage, projson); err != nil {
  367. log.Println(err)
  368. }
  369. log.Println("引导节点文件备份成功")
  370. //本地文件夹拷贝
  371. err = sh.Get(prog.Hash,fmt.Sprint((absoluteDir+"\\"+fileName)))
  372. if err != nil {
  373. log.Println(err)
  374. return err
  375. }
  376. log.Println("上传成功")
  377. return nil
  378. }
  379. func copyAndCapture(w io.Writer, r io.Reader, progress chan string) ([]byte, error) {
  380. var out []byte
  381. buf := make([]byte, 1024, 1024)
  382. for {
  383. n, err := r.Read(buf[:])
  384. if n > 0 {
  385. d := buf[:n]
  386. out = append(out, d...)
  387. progress <- string(d)
  388. }
  389. if err != nil {
  390. // Read returns io.EOF at the end of file, which is not an error for us
  391. if err == io.EOF {
  392. err = nil
  393. }
  394. return out, err
  395. }
  396. }
  397. // never reached
  398. panic(true)
  399. return nil, nil
  400. }
  401. /**
  402. 单个文件信息
  403. */
  404. type simpleFileInfo struct {
  405. Name string `json:"name" `
  406. Extension string `json:"extension"`
  407. RelativePath string `json:"relativePath"`
  408. AbsolutePath string `json:"absolutePath"`
  409. }
  410. var gobalFolderFileMap = make(map[string] *simpleFileInfo)
  411. var gobalRelativePath string
  412. /**
  413. 获取指定目录或文件的文件信息,如果是目录递归获取文件信息
  414. @param id 文件id
  415. */
  416. func GetFolderFileInfo(conn *websocket.Conn,absolutePath string) error{
  417. fileInfo,err :=os.Stat(absolutePath)
  418. if err!=nil{
  419. log.Println(err)
  420. return err
  421. }
  422. log.Println(filepath.Dir(absolutePath))
  423. //单个文件处理
  424. if !fileInfo.IsDir() {
  425. simpleFileInfo := new(simpleFileInfo)
  426. simpleFileInfo.Name=fileInfo.Name()
  427. simpleFileInfo.Extension=path.Ext(absolutePath)
  428. simpleFileInfo.RelativePath=""
  429. simpleFileInfo.AbsolutePath=absolutePath
  430. gobalFolderFileMap[absolutePath]=simpleFileInfo
  431. bytes,err :=json.Marshal(gobalFolderFileMap)
  432. if err != nil {
  433. log.Println(err)
  434. return err
  435. }
  436. if err := conn.WriteMessage(websocket.TextMessage, bytes); err != nil {
  437. log.Println(err)
  438. return err
  439. }
  440. return nil
  441. }
  442. //文件目录处理
  443. gobalRelativePath = filepath.Dir(absolutePath)+"\\"
  444. err =filepath.Walk(absolutePath, myWalkfunc)
  445. if err != nil {
  446. log.Println(err)
  447. return err
  448. }
  449. bytes,err :=json.Marshal(gobalFolderFileMap)
  450. if err != nil {
  451. log.Println(err)
  452. return err
  453. }
  454. if err := conn.WriteMessage(websocket.TextMessage, bytes); err != nil {
  455. log.Println(err)
  456. return err
  457. }
  458. return nil
  459. }
  460. func myWalkfunc(path string, info os.FileInfo, err error) error {
  461. if info.IsDir()==false{
  462. simpleFileInfo := new(simpleFileInfo)
  463. simpleFileInfo.Name=info.Name()
  464. simpleFileInfo.Extension=filepath.Ext(path)
  465. simpleFileInfo.RelativePath=strings.Replace(path,gobalRelativePath,"",1)
  466. simpleFileInfo.AbsolutePath=path
  467. gobalFolderFileMap[path]=simpleFileInfo
  468. return nil
  469. }
  470. return nil
  471. }
  472. /**
  473. 获取本地文件列表
  474. */
  475. func SubscriptionFileChange(conn *websocket.Conn, projectName string) error{
  476. getLocalFileListDir = fmt.Sprint(config.LocalWorkSpaceDir+"\\"+gobalLoginUserId+"\\"+projectName+"\\")
  477. for {
  478. err :=filepath.Walk(getLocalFileListDir,walkfunc)
  479. if err != nil {
  480. log.Println(err)
  481. time.Sleep(time.Duration(1)*time.Minute)
  482. continue
  483. }
  484. mapByte,err:=json.Marshal(gobalFileMap)
  485. if err != nil {
  486. log.Println(err)
  487. return err
  488. }
  489. if err := conn.WriteMessage(websocket.TextMessage, mapByte); err != nil {
  490. log.Println(err)
  491. return err
  492. }
  493. log.Println("检查本地目录文件变更状态,执行睡眠时间1分钟")
  494. //清空gobalFileMap
  495. gobalFileMap = make(map[string] string)
  496. time.Sleep(time.Duration(1)*time.Minute)
  497. }
  498. return nil
  499. }
  500. func walkfunc(path string, info os.FileInfo, err error) error {
  501. if info.IsDir()==false{
  502. sh := shell.NewShell(config.GobalIpfsUrl)
  503. file,err :=os.Open(path)
  504. if err != nil{
  505. log.Println(err)
  506. return err
  507. }
  508. defer file.Close()
  509. hash,err :=sh.Add(file)
  510. if err != nil {
  511. log.Println(err)
  512. return err
  513. }
  514. dir :=strings.Replace(fmt.Sprint(path),fmt.Sprint(getLocalFileListDir),"",1)
  515. gobalFileMap[dir]=hash
  516. }
  517. return nil
  518. }