@@ -6,14 +6,19 @@ import (
66 "io/ioutil"
77 "log"
88 httpLocal "main/graph/net/http"
9+ "math"
910 "net/http"
1011 "os"
1112 "path"
1213 "path/filepath"
14+ "strconv"
1315 "strings"
16+ "sync"
1417 "time"
1518 "unsafe"
1619
20+ "google.golang.org/api/googleapi"
21+
1722 "golang.org/x/net/context"
1823 "golang.org/x/oauth2"
1924 "golang.org/x/oauth2/google"
@@ -22,6 +27,21 @@ import (
2227
2328// refs https://developers.google.com/drive/v3/web/quickstart/go
2429
30+ var chunkSize = 10 * 1024 * 1024
31+
32+ func changeChunkSize (block int ) {
33+ chunkSize = block * 1024 * 1024
34+ }
35+
36+ var wg sync.WaitGroup
37+ var threads = 3
38+ var pool = make (chan struct {}, threads )
39+
40+ func changeThread (thread int ) {
41+ threads = thread
42+ pool = make (chan struct {}, threads )
43+ }
44+
2545// getClient uses a Context and Config to retrieve a Token
2646// then generate a Client. It returns the generated Client.
2747func getClient (file string , ctx context.Context , config * oauth2.Config ) * http.Client {
@@ -82,7 +102,7 @@ func tokenCacheFile() string {
82102
83103// tokenFromFile retrieves a Token from a given file path.
84104// It returns the retrieved Token and any read error encountered.
85- func tokenFromFile (file string , Thread int , BlockSize int , Language string , TimeOut int , BotKey string , UserID string ) (* oauth2.Token , error ) {
105+ func tokenFromFile (c * oauth2. Config , file string , Thread int , BlockSize int , Language string , TimeOut int , BotKey string , UserID string ) (* oauth2.Token , error ) {
86106 //搜尋路徑,有token檔就開啟並Decode,沒有就回傳nil
87107 f , err := os .Open (file )
88108 if err != nil {
@@ -92,14 +112,19 @@ func tokenFromFile(file string, Thread int, BlockSize int, Language string, Time
92112 ts := & httpLocal.Certificate {}
93113 err = json .NewDecoder (f ).Decode (ts ) //Decode錯誤也會回傳err
94114 oauth2Token := ts .Other .(map [string ]interface {})
95- expiry , _ := time .ParseInLocation ( "2021-04-29T16:27:54.2042271+08:00" , oauth2Token ["expiry" ].(string ), time . Local )
115+ expiry , _ := time .Parse ( time . RFC3339 , oauth2Token ["expiry" ].(string ))
96116 t := & oauth2.Token {
97117 AccessToken : oauth2Token ["access_token" ].(string ),
98118 TokenType : oauth2Token ["token_type" ].(string ),
99119 RefreshToken : oauth2Token ["refresh_token" ].(string ),
100120 Expiry : expiry ,
101121 }
102122 defer f .Close ()
123+ f , err = os .OpenFile (file , os .O_WRONLY | os .O_TRUNC , 0666 )
124+ defer f .Close ()
125+ // log.Printf("%+v\n", t)
126+ updatedToken , err := c .TokenSource (context .TODO (), t ).Token ()
127+ // log.Printf("%+v\n", updatedToken)
103128 data := httpLocal.Certificate {
104129 Drive : "GoogleDrive" ,
105130 RefreshToken : ts .RefreshToken ,
@@ -110,17 +135,23 @@ func tokenFromFile(file string, Thread int, BlockSize int, Language string, Time
110135 TimeOut : TimeOut ,
111136 BotKey : BotKey ,
112137 UserID : UserID ,
113- Other : ts . Other ,
138+ Other : updatedToken ,
114139 }
115- json .NewEncoder (f ).Encode (data )
116- return t , err
140+ err = json .NewEncoder (f ).Encode (data )
141+ if err != nil {
142+ log .Fatalf ("Unable to cache oauth token: %v" , err )
143+ }
144+ changeThread (Thread )
145+ changeChunkSize (BlockSize )
146+ return updatedToken , err
117147}
118148
119149// saveToken uses a file path to create a file and store the
120150// token in it.
151+
121152func saveToken (file string , token * oauth2.Token , lang string ) {
122153 //fmt.Printf("Saving credential file to: %s\n", file)
123- f , err := os .Create (file )
154+ f , err := os .OpenFile (file , os . O_APPEND | os . O_WRONLY | os . O_CREATE , 0666 )
124155 if err != nil {
125156 log .Fatalf ("Unable to cache oauth token: %v" , err )
126157 }
@@ -140,7 +171,46 @@ func saveToken(file string, token *oauth2.Token, lang string) {
140171 json .NewEncoder (f ).Encode (data )
141172}
142173
143- func UploadAllFile (pathname string , folderIDList []string , srv * drive.Service , startTime int64 , username string , sendMsg func (text string ), locText func (text string ) string ) error {
174+ func byte2Readable (bytes float64 ) string {
175+ const kb float64 = 1024
176+ const mb float64 = kb * 1024
177+ const gb float64 = mb * 1024
178+ var readable float64
179+ var unit string
180+ _bytes := bytes
181+
182+ if _bytes >= gb {
183+ // xx GB
184+ readable = _bytes / gb
185+ unit = "GB"
186+ } else if _bytes < gb && _bytes >= mb {
187+ // xx MB
188+ readable = _bytes / mb
189+ unit = "MB"
190+ } else {
191+ // xx KB
192+ readable = _bytes / kb
193+ unit = "KB"
194+ }
195+ return strconv .FormatFloat (readable , 'f' , 2 , 64 ) + " " + unit
196+ }
197+
198+ func UploadAllFile (pathname string , folderIDList []string , srv * drive.Service , startTime int64 , username string , sendMsg func () (func (text string ), string , string , func (string , string , string ) func (string )), locText func (text string ) string ) (func (string ), error ) {
199+
200+ filePath := path .Base (pathname )
201+ temps , _botKey , iUserID , BotSend := sendMsg ()
202+ var iSendMsg func (string )
203+ tip := "`" + filePath + "`" + locText ("startUploadGoogleDrive" )
204+ if _botKey != "" && iUserID != "" {
205+ iSendMsg = BotSend (_botKey , iUserID , tip )
206+ }
207+ temp := func (text string ) {
208+ temps (text )
209+ if _botKey != "" && iUserID != "" {
210+ iSendMsg (text )
211+ }
212+ }
213+ temp (tip )
144214
145215 rd , err := ioutil .ReadDir (pathname )
146216 if err != nil {
@@ -156,11 +226,9 @@ func UploadAllFile(pathname string, folderIDList []string, srv *drive.Service, s
156226 defer f .Close ()
157227 //log.Println("file", fi.Name(), fullName)
158228 //上傳檔案,create要給定檔案名稱,要傳進資料夾就加上Parents參數給定folderID的array,media傳入我們要上傳的檔案,最後Do
159- _ , err = srv .Files .Create (& drive.File {Name : fullName , Parents : tempFolderIDList }).Media (f ).Do ()
160- if err != nil {
161- log .Panicf ("Unable to create file: %v" , err )
162- }
163- sendMsg (fmt .Sprintf (locText ("googleDriveUploadTip" ), username , fullName , time .Now ().Unix ()- startTime ))
229+
230+ uploadFile (srv , pathname , fullName , tempFolderIDList , f , sendMsg , locText , username )
231+ // sendMsg(fmt.Sprintf(locText("googleDriveUploadTip"), username, fullName, time.Now().Unix()-startTime))
164232 }
165233 _ , foldName := filepath .Split (pathname )
166234 //log.Println(foldName)
@@ -182,13 +250,13 @@ func UploadAllFile(pathname string, folderIDList []string, srv *drive.Service, s
182250 tempFolderIDList = folderIDList
183251 }
184252 tempFolderIDList = append (tempFolderIDList , createFolder .Id )
185- err := UploadAllFile (fullDir , tempFolderIDList , srv , startTime , username , sendMsg , locText )
253+ _ , err := UploadAllFile (fullDir , tempFolderIDList , srv , startTime , username , sendMsg , locText )
186254 if err != nil {
187255 log .Panic ("read dir fail:" , err )
188- return err
256+ return nil , err
189257 }
190258 //log.Println("folder", fi.Name(), fullDir)
191- sendMsg (fmt .Sprintf (locText ("googleDriveUploadTip" ), username , fullDir , time .Now ().Unix ()- startTime ))
259+ // sendMsg(fmt.Sprintf(locText("googleDriveUploadTip"), username, fullDir, time.Now().Unix()-startTime))
192260 } else {
193261 fullName := pathname + "/" + fi .Name ()
194262 var tempFolderIDList []string
@@ -203,15 +271,93 @@ func UploadAllFile(pathname string, folderIDList []string, srv *drive.Service, s
203271 defer f .Close ()
204272 //log.Println("file", fi.Name(), fullName)
205273 //上傳檔案,create要給定檔案名稱,要傳進資料夾就加上Parents參數給定folderID的array,media傳入我們要上傳的檔案,最後Do
206- _ , err = srv .Files .Create (& drive.File {Name : fi .Name (), Parents : tempFolderIDList }).Media (f ).Do ()
274+ // _, err = srv.Files.Create(&drive.File{Name: fi.Name(), Parents: tempFolderIDList}).Media(f, googleapi.ChunkSize(chunkSize)).Do()
275+ uploadFile (srv , fullName , fi .Name (), tempFolderIDList , f , sendMsg , locText , username )
207276 if err != nil {
208277 log .Panicf ("Unable to create file: %v" , err )
209278 }
210- sendMsg (fmt .Sprintf (locText ("googleDriveUploadTip" ), username , fullName , time .Now ().Unix ()- startTime ))
279+ // sendMsg(fmt.Sprintf(locText("googleDriveUploadTip"), username, fullName, time.Now().Unix()-startTime))
211280 //log.Printf("file: %+v", driveFile)
212281 }
213282 }
214- return nil
283+ wg .Wait ()
284+ return temp , nil
285+ }
286+
287+ func FileSizeFormat (bytes int64 , forceBytes bool ) string {
288+ if forceBytes {
289+ return fmt .Sprintf ("%v B" , bytes )
290+ }
291+
292+ units := []string {"B" , "KB" , "MB" , "GB" , "TB" , "PB" }
293+
294+ var i int
295+ value := float64 (bytes )
296+
297+ for value > 1000 {
298+ value /= 1000
299+ i ++
300+ }
301+ return fmt .Sprintf ("%.1f %s" , value , units [i ])
302+ }
303+
304+ func MeasureTransferRate () func (int64 ) string {
305+ start := time .Now ()
306+
307+ return func (bytes int64 ) string {
308+ seconds := int64 (time .Now ().Sub (start ).Seconds ())
309+ if seconds < 1 {
310+ return fmt .Sprintf ("%s/s" , FileSizeFormat (bytes , false ))
311+ }
312+ bps := bytes / seconds
313+ return fmt .Sprintf ("%s/s" , FileSizeFormat (bps , false ))
314+ }
315+ }
316+
317+ func uploadFile (srv * drive.Service , filePath string , filename string , tempFolderIDList []string , f * os.File , sendMsg func () (func (text string ), string , string , func (string , string , string ) func (string )), locText func (text string ) string , username string ) {
318+ wg .Add (1 )
319+ pool <- struct {}{}
320+ startTime := time .Now ().Unix ()
321+ go func () {
322+ defer wg .Done ()
323+ defer func () {
324+ <- pool
325+ }()
326+ temps , _botKey , iUserID , botSend := sendMsg ()
327+ var iSendMsg func (string )
328+ tip := "`" + filePath + "`" + locText ("startToUpload1" )
329+ if _botKey != "" && iUserID != "" {
330+ iSendMsg = botSend (_botKey , iUserID , tip )
331+ }
332+ temp := func (text string ) {
333+ temps (text )
334+ if _botKey != "" && iUserID != "" {
335+ iSendMsg (text )
336+ }
337+ }
338+ fi , err := os .Stat (filePath )
339+ if err != nil {
340+ fi , err = os .Stat (filename )
341+ if err != nil {
342+ log .Panicln (err )
343+ }
344+ }
345+ getRate := MeasureTransferRate ()
346+ size := fi .Size ()
347+ // log.Println(byte2Readable(float64(size)))
348+
349+ showProgress := func (current , total int64 ) {
350+ temp (fmt .Sprintf (locText ("googleDriveUploadTip1" ), username , filePath , byte2Readable (float64 (size )), byte2Readable (float64 (current )), int (math .Ceil (float64 (current )/ float64 (chunkSize ))), int (math .Ceil (float64 (size )/ float64 (chunkSize ))), getRate (current ), time .Now ().Unix ()- startTime ))
351+ }
352+
353+ _ , err = srv .Files .Create (& drive.File {Name : filename , Parents : tempFolderIDList }).Media (f , googleapi .ChunkSize (chunkSize )).ProgressUpdater (showProgress ).Do ()
354+ if err != nil {
355+ log .Panicln (err )
356+ }
357+
358+ defer temp ("close" )
359+ }()
360+
215361}
216362
217363/*func main() {
@@ -266,7 +412,8 @@ func CreateNewInfo(code string, lang string) string {
266412
267413func Upload (infoPath string , filePath string , sendMsg func () (func (text string ), string , string , func (string , string , string ) func (string )), locText func (text string ) string , Thread int , BlockSize int , Language string , TimeOut int , BotKey string , UserID string ) {
268414 ctx , config := gdInit ()
269- tok , _ := tokenFromFile (infoPath , Thread , BlockSize , Language , TimeOut , BotKey , UserID )
415+ infoPath , _ = filepath .Abs (infoPath )
416+ tok , _ := tokenFromFile (config , infoPath , Thread , BlockSize , Language , TimeOut , BotKey , UserID )
270417 client := config .Client (ctx , tok )
271418 srv , err := drive .New (client )
272419 username := strings .ReplaceAll (filepath .Base (infoPath ), ".json" , "" )
@@ -280,26 +427,12 @@ func Upload(infoPath string, filePath string, sendMsg func() (func(text string),
280427 if err != nil {
281428 log .Panic (err )
282429 }
283- filePath = path .Base (filePath )
284- temps , _botKey , iUserID , BotSend := sendMsg ()
285- var iSendMsg func (string )
286- tip := "`" + filePath + "`" + locText ("startUploadGoogleDrive" )
287- if _botKey != "" && iUserID != "" {
288- iSendMsg = BotSend (_botKey , iUserID , tip )
289- }
290- temp := func (text string ) {
291- temps (text )
292- if _botKey != "" && iUserID != "" {
293- iSendMsg (text )
294- }
295- }
296- temp (tip )
297430
298431 if err != nil {
299432 log .Fatalf ("Unable to retrieve drive Client %v" , err )
300433
301434 }
302- _ = UploadAllFile (filePath , nil , srv , time .Now ().Unix (), username , temp , locText )
435+ temp , _ : = UploadAllFile (filePath , nil , srv , time .Now ().Unix (), username , sendMsg , locText )
303436 temp (locText ("uploadGoogleDriveComplete" ))
304437 err = os .Chdir (oldDir )
305438 if err != nil {
0 commit comments