diff --git a/kadai1/tamura/README.md b/kadai1/tamura/README.md new file mode 100644 index 0000000..0e210a3 --- /dev/null +++ b/kadai1/tamura/README.md @@ -0,0 +1,12 @@ +# 第1回課題 画像変換コマンド + +## 使い方 +### png変換 +``` +$ go rum main.go -f sample.png sample.jpg +``` + +### ディレクトリ配下をpng変換 +``` +$ go rum main.go -f jpg test/ "sample.png" +``` diff --git a/kadai1/tamura/convert/cli.go b/kadai1/tamura/convert/cli.go new file mode 100644 index 0000000..b3291b2 --- /dev/null +++ b/kadai1/tamura/convert/cli.go @@ -0,0 +1,91 @@ +package convert + +import ( + "bytes" + "flag" + "fmt" + "os" + "path/filepath" + "strings" + "text/template" +) + +var ( + format string +) + +func init() { + flag.StringVar(&format, "f", "", "ディレクトリ指定の場合に、変換する画像ファイルのフォーマット(`png|jpeg|jpg`)") + flag.Parse() +} + +type file string + +func (f file) Ext() string { + return filepath.Ext(string(f)) +} + +func (f file) Dir() string { + return filepath.Dir(string(f)) +} + +func (f file) Name() string { + return strings.Replace(filepath.Base(string(f)), f.Ext(), "", -1) +} + +func Run() error { + args := flag.Args() + + if len(args) < 1 { + return fmt.Errorf("画像ファイルを指定してください。") + } + + info, err := os.Stat(args[0]) + if os.IsNotExist(err) { + return fmt.Errorf("画像ファイルが存在しません。%s", args[0]) + } + + if info.IsDir() { + t, err := template.New("dst").Parse(args[1]) + if err != nil { + return err + } + + return filepath.Walk(args[0], func(p string, info os.FileInfo, err error) error { + if err != nil { + return err + } + + if info.IsDir() { + return nil + } + + ext := strings.ToLower(filepath.Ext(p)) + + if format != "" { + if ext != "."+format { + return nil + } + } else if ext != ".png" && ext != ".jpg" && ext != ".jpeg" { + return nil + } + + var buf bytes.Buffer + t.Execute(&buf, file(p)) + + imgConvert := Convert{ + dst: buf.String(), + src: p, + } + + return imgConvert.Convert() + }) + } + + imgConvert := Convert{ + dst: os.Args[2], + src: os.Args[3], + } + + return imgConvert.Convert() +} diff --git a/kadai1/tamura/convert/convert.go b/kadai1/tamura/convert/convert.go new file mode 100644 index 0000000..1551f4d --- /dev/null +++ b/kadai1/tamura/convert/convert.go @@ -0,0 +1,43 @@ +package convert + +import ( + "fmt" + "image" + "image/jpeg" + "image/png" + "os" + "path" + "strings" +) + +type Convert struct { + dst string + src string +} + +func (c *Convert) Convert() error { + sf, err := os.Open(c.src) + if err != nil { + return fmt.Errorf("画像ファイルが開けませんでした。%s", c.src) + } + defer sf.Close() + + df, err := os.Create(c.dst) + if err != nil { + return fmt.Errorf("画像ファイルが書き出せませんでした。%s", c.dst) + } + defer df.Close() + + img, _, err := image.Decode(sf) + if err != nil { + return err + } + + ext := strings.ToLower(path.Ext(c.dst)) + if ext == ".png" { + err = png.Encode(df, img) + } else if ext == ".jpeg" || ext == ".jpg" { + err = jpeg.Encode(df, img, &jpeg.Options{jpeg.DefaultQuality}) + } + return nil +} diff --git a/kadai1/tamura/main.go b/kadai1/tamura/main.go new file mode 100644 index 0000000..59c751c --- /dev/null +++ b/kadai1/tamura/main.go @@ -0,0 +1,15 @@ +package main + +import ( + "fmt" + "os" + + "./convert" +) + +func main() { + if err := convert.Run(); err != nil { + fmt.Fprintf(os.Stderr, "%s\n", err.Error()) + os.Exit(1) + } +} diff --git a/kadai2/tamura/README.md b/kadai2/tamura/README.md new file mode 100644 index 0000000..abad490 --- /dev/null +++ b/kadai2/tamura/README.md @@ -0,0 +1,20 @@ +# 第2回課題 + +# io.Readerとio.Writerについて調べてみよう +## どのように使用されているのか。 + +* 読み込みでio.Reader、書き込みでio.Writerが利用していた。 +→ os.Stdin、os.File、net.Conn、bytes.Buffer + +## io.Readerとio.Writerがあることで、どういう利点があるのか。 + +* 拡張性の実装 +様々な出力先を抽象化出来る。少ない改修の規模で拡張可能。 +* テストで出力先変更 +io.Writerの引数抽象化で、標準出力に書き込み、テストはメモリのバッファに書き込むの切り替えができる +* コードを提供可能 +io.Writer,io.Readerが使われているので、活用の幅が広い。 + +# テスト + +作成中 diff --git a/kadai2/tamura/convert/cli.go b/kadai2/tamura/convert/cli.go new file mode 100644 index 0000000..b3291b2 --- /dev/null +++ b/kadai2/tamura/convert/cli.go @@ -0,0 +1,91 @@ +package convert + +import ( + "bytes" + "flag" + "fmt" + "os" + "path/filepath" + "strings" + "text/template" +) + +var ( + format string +) + +func init() { + flag.StringVar(&format, "f", "", "ディレクトリ指定の場合に、変換する画像ファイルのフォーマット(`png|jpeg|jpg`)") + flag.Parse() +} + +type file string + +func (f file) Ext() string { + return filepath.Ext(string(f)) +} + +func (f file) Dir() string { + return filepath.Dir(string(f)) +} + +func (f file) Name() string { + return strings.Replace(filepath.Base(string(f)), f.Ext(), "", -1) +} + +func Run() error { + args := flag.Args() + + if len(args) < 1 { + return fmt.Errorf("画像ファイルを指定してください。") + } + + info, err := os.Stat(args[0]) + if os.IsNotExist(err) { + return fmt.Errorf("画像ファイルが存在しません。%s", args[0]) + } + + if info.IsDir() { + t, err := template.New("dst").Parse(args[1]) + if err != nil { + return err + } + + return filepath.Walk(args[0], func(p string, info os.FileInfo, err error) error { + if err != nil { + return err + } + + if info.IsDir() { + return nil + } + + ext := strings.ToLower(filepath.Ext(p)) + + if format != "" { + if ext != "."+format { + return nil + } + } else if ext != ".png" && ext != ".jpg" && ext != ".jpeg" { + return nil + } + + var buf bytes.Buffer + t.Execute(&buf, file(p)) + + imgConvert := Convert{ + dst: buf.String(), + src: p, + } + + return imgConvert.Convert() + }) + } + + imgConvert := Convert{ + dst: os.Args[2], + src: os.Args[3], + } + + return imgConvert.Convert() +} diff --git a/kadai2/tamura/convert/cli_test.go b/kadai2/tamura/convert/cli_test.go new file mode 100644 index 0000000..233bcde --- /dev/null +++ b/kadai2/tamura/convert/cli_test.go @@ -0,0 +1 @@ +package convert diff --git a/kadai2/tamura/convert/convert.go b/kadai2/tamura/convert/convert.go new file mode 100644 index 0000000..1551f4d --- /dev/null +++ b/kadai2/tamura/convert/convert.go @@ -0,0 +1,43 @@ +package convert + +import ( + "fmt" + "image" + "image/jpeg" + "image/png" + "os" + "path" + "strings" +) + +type Convert struct { + dst string + src string +} + +func (c *Convert) Convert() error { + sf, err := os.Open(c.src) + if err != nil { + return fmt.Errorf("画像ファイルが開けませんでした。%s", c.src) + } + defer sf.Close() + + df, err := os.Create(c.dst) + if err != nil { + return fmt.Errorf("画像ファイルが書き出せませんでした。%s", c.dst) + } + defer df.Close() + + img, _, err := image.Decode(sf) + if err != nil { + return err + } + + ext := strings.ToLower(path.Ext(c.dst)) + if ext == ".png" { + err = png.Encode(df, img) + } else if ext == ".jpeg" || ext == ".jpg" { + err = jpeg.Encode(df, img, &jpeg.Options{jpeg.DefaultQuality}) + } + return nil +} diff --git a/kadai2/tamura/convert/convert_test.go b/kadai2/tamura/convert/convert_test.go new file mode 100644 index 0000000..3c03b5e --- /dev/null +++ b/kadai2/tamura/convert/convert_test.go @@ -0,0 +1 @@ +package convert_test diff --git a/kadai2/tamura/main.go b/kadai2/tamura/main.go new file mode 100644 index 0000000..59c751c --- /dev/null +++ b/kadai2/tamura/main.go @@ -0,0 +1,15 @@ +package main + +import ( + "fmt" + "os" + + "./convert" +) + +func main() { + if err := convert.Run(); err != nil { + fmt.Fprintf(os.Stderr, "%s\n", err.Error()) + os.Exit(1) + } +} diff --git a/kadai3-2/tamura/README.md b/kadai3-2/tamura/README.md new file mode 100644 index 0000000..56f96e9 --- /dev/null +++ b/kadai3-2/tamura/README.md @@ -0,0 +1,3 @@ +# Kadai3-2 + +## 分割ダウンロードを行う diff --git a/kadai3-2/tamura/main.go b/kadai3-2/tamura/main.go new file mode 100644 index 0000000..e9ebc24 --- /dev/null +++ b/kadai3-2/tamura/main.go @@ -0,0 +1,22 @@ +package main + +import ( + "context" + "fmt" + "time" +) + +func main() { + ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) + defer cancel() + + errCh := make(chan error, 1) + errCh <- Run(ctx) + + select { + case err := <-errCh: + if err != nil { + fmt.Printf("%v\n", err) + } + } +} diff --git a/kadai3-2/tamura/req.go b/kadai3-2/tamura/req.go new file mode 100644 index 0000000..5274913 --- /dev/null +++ b/kadai3-2/tamura/req.go @@ -0,0 +1,128 @@ +package main + +import ( + "bytes" + "context" + "fmt" + "io" + "io/ioutil" + "net/http" + "strconv" + "sync" +) + +const sample = "http://i.imgur.com/z4d4kWk.jpg" +const splitNum = 4 + +func request(r *http.Request, client *http.Client, errCh chan<- error) (*http.Response, []byte) { + res, err := client.Do(r) + if err != nil { + errCh <- err + } + + buf := new(bytes.Buffer) + _, err = io.Copy(buf, res.Body) + if err != nil { + errCh <- err + } + + // debug + header := res.Header + // for h := range header { + fmt.Printf("Content-Range: %v\n", header["Content-Range"]) + // } + + /* + err = ioutil.WriteFile("test.jpg", buf.Bytes(), 0777) + if err != nil { + errCh <- err + }*/ + + return res, buf.Bytes() +} + +func requestWithRange(r *http.Request, client *http.Client, errCh chan<- error, start, end int) (*http.Response, []byte) { + r.Header.Add("Range", fmt.Sprintf("bytes=%v-%v", start, end)) + + return request(r, client, errCh) +} + +func fetchRange(r *http.Request, client *http.Client, errCh chan<- error) (int, error) { + res, _ := request(r, client, errCh) + cl := res.Header.Get("Content-Length") + l, err := strconv.Atoi(cl) + return l, err +} + +func makeRequest(method, url string, ctx context.Context) (*http.Request, error) { + req, err := http.NewRequest(method, url, nil) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + return req, nil +} + +func Run(ctx context.Context) error { + tr := &http.Transport{} + client := &http.Client{Transport: tr} + errCh := make(chan error, 1) + done := make(chan struct{}, 1) + + req, err := makeRequest("HEAD", sample, ctx) + if err != nil { + return err + } + l, err := fetchRange(req, client, errCh) + if err != nil { + return err + } + chunk := l / splitNum + result := make([]byte, l, l) + + var wg sync.WaitGroup + + for i := 0; i < splitNum; i++ { + i := i + wg.Add(1) + go func() { + start := chunk * i + end := chunk * (i + 1) + if i == splitNum-1 { + end = l + } + req, err := makeRequest("GET", sample, ctx) + if err != nil { + errCh <- err + } + _, body := requestWithRange(req, client, errCh, start, end) + copy(result[start:end], body) + wg.Done() + }() + } + + go func() { + wg.Wait() + close(done) + }() + + select { + case err := <-errCh: + if err != nil { + println("errCh") + return err + } + case <-ctx.Done(): + println("done") + <-errCh + return ctx.Err() + case <-done: + return writeFile(result) + } + + return err +} + +func writeFile(result []byte) error { + return ioutil.WriteFile("test.jpg", result, 0777) +}