From 7c0a0557576271f4a160f5a65902e1289248e656 Mon Sep 17 00:00:00 2001 From: takacb Date: Mon, 26 Nov 2018 02:09:20 +0900 Subject: [PATCH 1/4] first commit. --- kadai3-1/happylifetaka/typing.go | 11 ++ .../happylifetaka/typinggame/typinggame.go | 80 +++++++++ kadai3-2/happylifetaka/downloader.go | 40 +++++ .../happylifetaka/downloader/downloader.go | 159 ++++++++++++++++++ 4 files changed, 290 insertions(+) create mode 100644 kadai3-1/happylifetaka/typing.go create mode 100644 kadai3-1/happylifetaka/typinggame/typinggame.go create mode 100644 kadai3-2/happylifetaka/downloader.go create mode 100644 kadai3-2/happylifetaka/downloader/downloader.go diff --git a/kadai3-1/happylifetaka/typing.go b/kadai3-1/happylifetaka/typing.go new file mode 100644 index 0000000..dd7c84f --- /dev/null +++ b/kadai3-1/happylifetaka/typing.go @@ -0,0 +1,11 @@ +package main + +import ( + "github.com/happylifetaka/dojo4/kadai3-1/happylifetaka/typinggame" + "os" +) + +func main() { + var t typinggame.TypingGame + t.Start(os.Stdin) +} \ No newline at end of file diff --git a/kadai3-1/happylifetaka/typinggame/typinggame.go b/kadai3-1/happylifetaka/typinggame/typinggame.go new file mode 100644 index 0000000..c9707b7 --- /dev/null +++ b/kadai3-1/happylifetaka/typinggame/typinggame.go @@ -0,0 +1,80 @@ +package typinggame + +import ( + "bufio" + "fmt" + "io" + "math/rand" + "time" +) +type TypingGame int +//Start +//description:start 1 minute typing game. +//Param +//r:io.Reader example:os.Stdin +func (t *TypingGame)Start(r io.Reader){ + ch1 := input(r) + ch2 := wait(60) + var words = []string{"apple","banana","cherry","plum","grape","pineapple",} + + shuffle(words) + i:=0 + //success count + s_cnt:=0 + //fail count + f_cnt :=0 + fmt.Println("try typing.1 minute.") + fmt.Println(words[i]) + +TIMEOUT_LABEL: + for { + select { + case msg:=<-ch1: + if(words[i] == msg){ + if len(words) <= (i + 1){ + i = 0 + }else { + i++ + } + s_cnt++ + }else{ + fmt.Println("miss.retyping words.") + f_cnt++ + } + fmt.Println(words[i]) + case <-ch2: + fmt.Println("") + fmt.Println("time up.success count:",s_cnt," fail count:", f_cnt) + + break TIMEOUT_LABEL + } + } +} + +func shuffle(a []string){ + for i:=len(a)-1;i >= 0;i-- { + j:=rand.Intn(i+1) + a[i],a[j] = a[j],a[i] + } +} + +func input(r io.Reader) <-chan string { + ch := make(chan string) + go func() { + s := bufio.NewScanner(r) + defer close(ch) + for s.Scan() { + ch <- s.Text() + } + }() + return ch +} + +func wait(sec int) <-chan bool { + ch := make(chan bool) + go func() { + time.Sleep(time.Duration(sec) * time.Second) + ch <- true + }() + return ch +} diff --git a/kadai3-2/happylifetaka/downloader.go b/kadai3-2/happylifetaka/downloader.go new file mode 100644 index 0000000..4cc5327 --- /dev/null +++ b/kadai3-2/happylifetaka/downloader.go @@ -0,0 +1,40 @@ +package main + +import ( + "flag" + "fmt" + "github.com/happylifetaka/dojo4/kadai3-2/happylifetaka/downloader" + "os" +) + +type downloadByteInfo struct { + start int64 + end int64 +} + +func main(){ + div := flag.Int64("div", 3, "file download division") + usageMsg :="udage:downloader [-div] url saveFilePath" + flag.Usage = func() { + fmt.Println(usageMsg) + flag.PrintDefaults() + os.Exit(0) + } + flag.Parse() + args := flag.Args() + if len(args) != 2 { + fmt.Println("parameter error.") + fmt.Println(usageMsg) + flag.PrintDefaults() + os.Exit(0) + } + url := args[0] + saveFilePath := args[1] + + var d downloader.Downloader + if err:=d.Download(url,saveFilePath,*div);err != nil{ + fmt.Println(err) + os.Exit(1) + } + os.Exit(0) +} \ No newline at end of file diff --git a/kadai3-2/happylifetaka/downloader/downloader.go b/kadai3-2/happylifetaka/downloader/downloader.go new file mode 100644 index 0000000..8b896f3 --- /dev/null +++ b/kadai3-2/happylifetaka/downloader/downloader.go @@ -0,0 +1,159 @@ +package downloader + +import ( + "fmt" + "golang.org/x/sync/errgroup" + "io" + "io/ioutil" + "net/http" + "os" + "strconv" +) + +type Downloader int + +type downloadInfo struct { + startByte int64 + endByte int64 +} + +// Download +// description:Download specified URL. +// parameter +// url :download target url. +// saveFilePath:save file path. +// div:Number of divided downloads. +func (d *Downloader) Download(url string,saveFilePath string,div int64) error{ + res,err := http.Head(url) + if err != nil { + fmt.Println("http Head error") + return err + } + if(res.StatusCode != 200) { + fmt.Println("bad status code") + fmt.Println("status code:", res.StatusCode) + return err + } + + if !canRangeDownload(res.Header) { + fmt.Println("range download not support.") + return err + } + + di := splitDownloadLength(res.ContentLength,div) + filenames := make([]string,div) + + var eg errgroup.Group + + i:=1 + for _,d := range di{ + j:=i + eg.Go (func() error { + err := rangeDownload(j, url, d.startByte, d.endByte) + return err + }) + filenames[i-1] = strconv.Itoa(j)+".temp.download" + i++ + } + if err := eg.Wait();err != nil{ + fmt.Println("download error") + return err + } + + if err:= joinFiles(filenames,saveFilePath);err != nil{ + fmt.Println("join file error") + return err + } + + if err:= deleteFiles(filenames);err != nil{ + fmt.Println("join file error") + return err + } + fmt.Println("download finish.") + return nil +} + +func canRangeDownload(h http.Header) bool{ + f := false + for k, v := range h { + if(k == "Accept-Ranges" && len(v) > 0 && v[0] == "bytes"){ + f=true + break + } + } + return f +} + + +func splitDownloadLength(length int64,div int64)[]downloadInfo { + + divLength := length / div + + a := make([]downloadInfo,div) + + + var i int64 + for i=0;i Date: Wed, 28 Nov 2018 18:09:56 +0900 Subject: [PATCH 2/4] apply code format. typing game change success and fail count variable name. --- kadai3-1/happylifetaka/typing.go | 5 +- .../happylifetaka/typinggame/typinggame.go | 40 ++++++------ kadai3-2/happylifetaka/downloader.go | 13 ++-- .../happylifetaka/downloader/downloader.go | 62 +++++++++---------- 4 files changed, 61 insertions(+), 59 deletions(-) diff --git a/kadai3-1/happylifetaka/typing.go b/kadai3-1/happylifetaka/typing.go index dd7c84f..40516d7 100644 --- a/kadai3-1/happylifetaka/typing.go +++ b/kadai3-1/happylifetaka/typing.go @@ -1,11 +1,12 @@ package main import ( - "github.com/happylifetaka/dojo4/kadai3-1/happylifetaka/typinggame" "os" + + "github.com/happylifetaka/dojo4/kadai3-1/happylifetaka/typinggame" ) func main() { var t typinggame.TypingGame t.Start(os.Stdin) -} \ No newline at end of file +} diff --git a/kadai3-1/happylifetaka/typinggame/typinggame.go b/kadai3-1/happylifetaka/typinggame/typinggame.go index c9707b7..3419ada 100644 --- a/kadai3-1/happylifetaka/typinggame/typinggame.go +++ b/kadai3-1/happylifetaka/typinggame/typinggame.go @@ -7,54 +7,56 @@ import ( "math/rand" "time" ) + +//TypingGame 1 minute typing game. type TypingGame int -//Start -//description:start 1 minute typing game. + +//Start start 1 minute typing game. //Param //r:io.Reader example:os.Stdin -func (t *TypingGame)Start(r io.Reader){ +func (t *TypingGame) Start(r io.Reader) { ch1 := input(r) ch2 := wait(60) - var words = []string{"apple","banana","cherry","plum","grape","pineapple",} + var words = []string{"apple", "banana", "cherry", "plum", "grape", "pineapple"} shuffle(words) - i:=0 + i := 0 //success count - s_cnt:=0 + sucessCnt := 0 //fail count - f_cnt :=0 + failCnt := 0 fmt.Println("try typing.1 minute.") fmt.Println(words[i]) TIMEOUT_LABEL: for { select { - case msg:=<-ch1: - if(words[i] == msg){ - if len(words) <= (i + 1){ + case msg := <-ch1: + if words[i] == msg { + if len(words) <= (i + 1) { i = 0 - }else { + } else { i++ } - s_cnt++ - }else{ + sucessCnt++ + } else { fmt.Println("miss.retyping words.") - f_cnt++ + failCnt++ } fmt.Println(words[i]) case <-ch2: fmt.Println("") - fmt.Println("time up.success count:",s_cnt," fail count:", f_cnt) + fmt.Println("time up.success count:", sucessCnt, " fail count:", failCnt) break TIMEOUT_LABEL } } } -func shuffle(a []string){ - for i:=len(a)-1;i >= 0;i-- { - j:=rand.Intn(i+1) - a[i],a[j] = a[j],a[i] +func shuffle(a []string) { + for i := len(a) - 1; i >= 0; i-- { + j := rand.Intn(i + 1) + a[i], a[j] = a[j], a[i] } } diff --git a/kadai3-2/happylifetaka/downloader.go b/kadai3-2/happylifetaka/downloader.go index 4cc5327..5ca4a7d 100644 --- a/kadai3-2/happylifetaka/downloader.go +++ b/kadai3-2/happylifetaka/downloader.go @@ -3,18 +3,19 @@ package main import ( "flag" "fmt" - "github.com/happylifetaka/dojo4/kadai3-2/happylifetaka/downloader" "os" + + "github.com/happylifetaka/dojo4/kadai3-2/happylifetaka/downloader" ) type downloadByteInfo struct { start int64 - end int64 + end int64 } -func main(){ +func main() { div := flag.Int64("div", 3, "file download division") - usageMsg :="udage:downloader [-div] url saveFilePath" + usageMsg := "udage:downloader [-div] url saveFilePath" flag.Usage = func() { fmt.Println(usageMsg) flag.PrintDefaults() @@ -32,9 +33,9 @@ func main(){ saveFilePath := args[1] var d downloader.Downloader - if err:=d.Download(url,saveFilePath,*div);err != nil{ + if err := d.Download(url, saveFilePath, *div); err != nil { fmt.Println(err) os.Exit(1) } os.Exit(0) -} \ No newline at end of file +} diff --git a/kadai3-2/happylifetaka/downloader/downloader.go b/kadai3-2/happylifetaka/downloader/downloader.go index 8b896f3..ba58030 100644 --- a/kadai3-2/happylifetaka/downloader/downloader.go +++ b/kadai3-2/happylifetaka/downloader/downloader.go @@ -2,19 +2,20 @@ package downloader import ( "fmt" - "golang.org/x/sync/errgroup" "io" "io/ioutil" "net/http" "os" "strconv" + + "golang.org/x/sync/errgroup" ) type Downloader int type downloadInfo struct { startByte int64 - endByte int64 + endByte int64 } // Download @@ -23,13 +24,13 @@ type downloadInfo struct { // url :download target url. // saveFilePath:save file path. // div:Number of divided downloads. -func (d *Downloader) Download(url string,saveFilePath string,div int64) error{ - res,err := http.Head(url) +func (d *Downloader) Download(url string, saveFilePath string, div int64) error { + res, err := http.Head(url) if err != nil { fmt.Println("http Head error") return err } - if(res.StatusCode != 200) { + if res.StatusCode != 200 { fmt.Println("bad status code") fmt.Println("status code:", res.StatusCode) return err @@ -40,32 +41,32 @@ func (d *Downloader) Download(url string,saveFilePath string,div int64) error{ return err } - di := splitDownloadLength(res.ContentLength,div) - filenames := make([]string,div) + di := splitDownloadLength(res.ContentLength, div) + filenames := make([]string, div) var eg errgroup.Group - i:=1 - for _,d := range di{ - j:=i - eg.Go (func() error { + i := 1 + for _, d := range di { + j := i + eg.Go(func() error { err := rangeDownload(j, url, d.startByte, d.endByte) return err }) - filenames[i-1] = strconv.Itoa(j)+".temp.download" + filenames[i-1] = strconv.Itoa(j) + ".temp.download" i++ } - if err := eg.Wait();err != nil{ + if err := eg.Wait(); err != nil { fmt.Println("download error") return err } - if err:= joinFiles(filenames,saveFilePath);err != nil{ + if err := joinFiles(filenames, saveFilePath); err != nil { fmt.Println("join file error") return err } - if err:= deleteFiles(filenames);err != nil{ + if err := deleteFiles(filenames); err != nil { fmt.Println("join file error") return err } @@ -73,36 +74,34 @@ func (d *Downloader) Download(url string,saveFilePath string,div int64) error{ return nil } -func canRangeDownload(h http.Header) bool{ +func canRangeDownload(h http.Header) bool { f := false for k, v := range h { - if(k == "Accept-Ranges" && len(v) > 0 && v[0] == "bytes"){ - f=true + if k == "Accept-Ranges" && len(v) > 0 && v[0] == "bytes" { + f = true break } } return f } - -func splitDownloadLength(length int64,div int64)[]downloadInfo { +func splitDownloadLength(length int64, div int64) []downloadInfo { divLength := length / div - a := make([]downloadInfo,div) - + a := make([]downloadInfo, div) var i int64 - for i=0;i Date: Sun, 9 Dec 2018 10:28:31 +0900 Subject: [PATCH 3/4] fix words variable initialize --- kadai3-1/happylifetaka/typinggame/typinggame.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kadai3-1/happylifetaka/typinggame/typinggame.go b/kadai3-1/happylifetaka/typinggame/typinggame.go index 3419ada..4845157 100644 --- a/kadai3-1/happylifetaka/typinggame/typinggame.go +++ b/kadai3-1/happylifetaka/typinggame/typinggame.go @@ -17,7 +17,7 @@ type TypingGame int func (t *TypingGame) Start(r io.Reader) { ch1 := input(r) ch2 := wait(60) - var words = []string{"apple", "banana", "cherry", "plum", "grape", "pineapple"} + words := []string{"apple", "banana", "cherry", "plum", "grape", "pineapple"} shuffle(words) i := 0 From e9b286fd65d2769fbf7179d7b88edae0bfc6b46b Mon Sep 17 00:00:00 2001 From: takacb Date: Sun, 9 Dec 2018 10:31:22 +0900 Subject: [PATCH 4/4] fix of review content --- .../happylifetaka/downloader/downloader.go | 78 ++++++++++++------- 1 file changed, 48 insertions(+), 30 deletions(-) diff --git a/kadai3-2/happylifetaka/downloader/downloader.go b/kadai3-2/happylifetaka/downloader/downloader.go index ba58030..3b8566d 100644 --- a/kadai3-2/happylifetaka/downloader/downloader.go +++ b/kadai3-2/happylifetaka/downloader/downloader.go @@ -1,9 +1,9 @@ package downloader import ( + "errors" "fmt" "io" - "io/ioutil" "net/http" "os" "strconv" @@ -11,6 +11,7 @@ import ( "golang.org/x/sync/errgroup" ) +// Downloader divide support donwloader type Downloader int type downloadInfo struct { @@ -18,13 +19,18 @@ type downloadInfo struct { endByte int64 } -// Download +type deleteFileError struct { + filename string + err error +} + +// Download download action // description:Download specified URL. // parameter // url :download target url. // saveFilePath:save file path. // div:Number of divided downloads. -func (d *Downloader) Download(url string, saveFilePath string, div int64) error { +func (d *Downloader) Download(url, saveFilePath string, div int64) error { res, err := http.Head(url) if err != nil { fmt.Println("http Head error") @@ -37,8 +43,8 @@ func (d *Downloader) Download(url string, saveFilePath string, div int64) error } if !canRangeDownload(res.Header) { - fmt.Println("range download not support.") - return err + fmt.Println("[warn]range download not support.") + div = 1 } di := splitDownloadLength(res.ContentLength, div) @@ -66,26 +72,30 @@ func (d *Downloader) Download(url string, saveFilePath string, div int64) error return err } - if err := deleteFiles(filenames); err != nil { - fmt.Println("join file error") - return err + deleteFileError := deleteFiles(filenames) + + if len(deleteFileError) != 0 { + for _, e := range deleteFileError { + fmt.Printf("[delete file error.%s %s", e.filename, e.err) + } + return errors.New("download fail") } + fmt.Println("download finish.") return nil } func canRangeDownload(h http.Header) bool { - f := false - for k, v := range h { - if k == "Accept-Ranges" && len(v) > 0 && v[0] == "bytes" { - f = true - break - } + accept := h.Get("Accept-Ranges") + + if accept == "bytes" { + return true + } else { + return false } - return f } -func splitDownloadLength(length int64, div int64) []downloadInfo { +func splitDownloadLength(length, div int64) []downloadInfo { divLength := length / div @@ -101,7 +111,7 @@ func splitDownloadLength(length int64, div int64) []downloadInfo { return a } -func rangeDownload(index int, url string, s int64, e int64) error { +func rangeDownload(index int, url string, s, e int64) error { req, err := http.NewRequest("GET", url, nil) if err != nil { return err @@ -110,19 +120,22 @@ func rangeDownload(index int, url string, s int64, e int64) error { req.Header.Set("Range", fmt.Sprintf("bytes=%d-%d", s, e)) res, err := http.DefaultClient.Do(req) - defer res.Body.Close() if err != nil { return err } + defer res.Body.Close() - out_path := strconv.Itoa(index) + ".temp.download" - out, err := os.Create(out_path) - defer out.Close() + outPath := strconv.Itoa(index) + ".temp.download" + out, err := os.Create(outPath) if err != nil { return err } + defer out.Close() - io.Copy(out, res.Body) + _, copyerr := io.Copy(out, res.Body) + if copyerr != nil { + return err + } return nil } @@ -133,25 +146,30 @@ func joinFiles(filenames []string, saveFilePath string) error { files[i], _ = os.Open(filename) } - reader := io.MultiReader(files...) - b, _ := ioutil.ReadAll(reader) + src := io.MultiReader(files...) - file, err := os.Create(saveFilePath) + dst, err := os.Create(saveFilePath) + if err != nil { + return err + } + defer dst.Close() + + _, err = io.Copy(dst, src) if err != nil { return err } - defer file.Close() - file.Write(([]byte)(b)) return nil } -func deleteFiles(filenames []string) error { +func deleteFiles(filenames []string) []deleteFileError { + result := []deleteFileError{} + for _, f := range filenames { err := os.Remove(f) if err != nil { - return err + result = append(result, deleteFileError{f, err}) } } - return nil + return result }