Skip to content

Kadai3-2 hioki-daichi #50

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 12 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions kadai3-2/hioki-daichi/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
/parallel-download
/coverage/
/vendor/
25 changes: 25 additions & 0 deletions kadai3-2/hioki-daichi/Gopkg.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

30 changes: 30 additions & 0 deletions kadai3-2/hioki-daichi/Gopkg.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Gopkg.toml example
#
# Refer to https://golang.github.io/dep/docs/Gopkg.toml.html
# for detailed Gopkg.toml documentation.
#
# required = ["github.com/user/thing/cmd/thing"]
# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
#
# [[constraint]]
# name = "github.com/user/project"
# version = "1.0.0"
#
# [[constraint]]
# name = "github.com/user/project2"
# branch = "dev"
# source = "github.com/myfork/project2"
#
# [[override]]
# name = "github.com/x/y"
# version = "2.4.0"
#
# [prune]
# non-go = false
# go-tests = true
# unused-packages = true


[prune]
go-tests = true
unused-packages = true
2 changes: 2 additions & 0 deletions kadai3-2/hioki-daichi/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
Version 2, December 2004
25 changes: 25 additions & 0 deletions kadai3-2/hioki-daichi/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
GOCMD=go
GOBUILD=$(GOCMD) build
GOCLEAN=$(GOCMD) clean
GOTEST=$(GOCMD) test
GOTOOL=$(GOCMD) tool
GODOCCMD=godoc
GODOCPORT=6060
BINARY_NAME=parallel-download

all: test build
build:
dep ensure
$(GOBUILD) -o $(BINARY_NAME) -v
test:
$(GOTEST) ./...
cov:
$(GOTEST) ./... -race -coverprofile=coverage/c.out -covermode=atomic
$(GOTOOL) cover -html=coverage/c.out -o coverage/index.html
open coverage/index.html
clean:
$(GOCLEAN)
rm -f $(BINARY_NAME)
doc:
(sleep 1; open http://localhost:$(GODOCPORT)/pkg/github.com/gopherdojo/dojo3) &
$(GODOCCMD) -http ":$(GODOCPORT)"
80 changes: 80 additions & 0 deletions kadai3-2/hioki-daichi/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
# parallel-download

## Overview

`parallel-download` is a command that can download the resources on the web in parallel.

Available options are below.

| Option | Description |
| --- | --- |
| `-p` | Download files in parallel according to the specified number. (default 8) |
| `-o` | Save the downloaded file in the specified path. (Overwrite if duplicates.) |
| `-t` | Terminate when the specified value has elapsed since download started. (default 30s) |

## How to develop

### 1. Install packages

Execute `$ dep ensure` to install dependent packages.

### 2. Start a dummy server

Execute `$ ./bin/dummy_server.go` to start a dummy server that returns a Gopher image.

```
$ ./bin/dummy_server.go
--------------------------------------------------------------------------------
# Endpoint

GET /foo.png // Get a gopher image

# Command-line options**

-failure-rate int
Probability to return InternalServerError.
-max-delay duration
Maximum time delay randomly applied from receiving a request until returning a response. (default 1s)
-port int
Port on which the dummy server listens. (default 8080)
--------------------------------------------------------------------------------
2018/09/30 00:25:05 Server starting on http://localhost:8080
```

### 3. Execute

Execute the command with specifying the Gopher image endpoint of the dummy server (and some options).

```
$ go run main.go -p=3 -t=3s -o=bar.png http://localhost:8080/foo.png
start HEAD request to get Content-Length
got: Accept-Ranges: bytes
got: Content-Length: 169406
start GET request with header: "Range: bytes=112936-169405"
start GET request with header: "Range: bytes=56468-112935"
start GET request with header: "Range: bytes=0-56467"
downloaded: "/var/folders/f8/1n0bk4tj4ll6clyj868k_nqh0000gn/T/parallel-download301219462/f4ec179a35"
downloaded: "/var/folders/f8/1n0bk4tj4ll6clyj868k_nqh0000gn/T/parallel-download301219462/f8d59617fb"
downloaded: "/var/folders/f8/1n0bk4tj4ll6clyj868k_nqh0000gn/T/parallel-download301219462/9e9b203414"
concatenate downloaded files to tempfile: "/var/folders/f8/1n0bk4tj4ll6clyj868k_nqh0000gn/T/parallel-download301219462/814ff17dbf"
rename "/var/folders/f8/1n0bk4tj4ll6clyj868k_nqh0000gn/T/parallel-download301219462/814ff17dbf" to "bar.png"
completed: "bar.png"
```

## How to run the test

```shell
$ make test
```

## How to read GoDoc

```shell
$ make doc
```

## How to see code coverage

```shell
$ make cov
```
93 changes: 93 additions & 0 deletions kadai3-2/hioki-daichi/bin/dummy_server.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
//usr/bin/env go run $0 $@ ; exit

package main

import (
"flag"
"fmt"
"io/ioutil"
"log"
"math/rand"
"net/http"
"os"
"strconv"
"strings"
"time"
)

func main() {
rand.Seed(time.Now().UnixNano())

flg := flag.NewFlagSet("test", flag.ExitOnError)

port := flg.Int("port", 8080, "Port on which the dummy server listens.")
failureRate := flg.Int("failure-rate", 0, "Probability to return InternalServerError.")
maxDelay := flg.Duration("max-delay", time.Second, "Maximum time delay randomly applied from receiving a request until returning a response.")

flg.Parse(os.Args[1:])

fmt.Print(`--------------------------------------------------------------------------------
# Endpoint

GET /foo.png // Get a gopher image

# Command-line options**

`)
flg.PrintDefaults()
fmt.Println("--------------------------------------------------------------------------------")

contents := func() string {
b, err := ioutil.ReadFile("./downloading/testdata/foo.png")
if err != nil {
panic(err)
}
return string(b)
}()

handler := func(w http.ResponseWriter, req *http.Request) {
if req.Method != "HEAD" {
time.Sleep(time.Duration(rand.Intn(int(*maxDelay))))
}

w.Header().Set("Accept-Ranges", "bytes")

var body string
var statusCode int
if req.Method == "GET" && rand.Intn(100) < *failureRate {
body = "Internal Server Error"
statusCode = http.StatusInternalServerError
} else {
body = func(req *http.Request) string {
rangeHeader := req.Header.Get("Range") // e.g. "bytes=0-99"
if rangeHeader == "" {
return contents
}
c := strings.Split(strings.Split(rangeHeader, "=")[1], "-")
min, _ := strconv.Atoi(c[0])
max, _ := strconv.Atoi(c[1])
return contents[min : max+1]
}(req)
statusCode = http.StatusPartialContent
}

w.Header().Set("Content-Length", fmt.Sprintf("%d", len(body)))
w.WriteHeader(statusCode)
fmt.Fprint(w, body)

log.Printf("%s %s %d %s\n", req.Method, req.RequestURI, statusCode, req.Header.Get("Range"))
}

http.HandleFunc("/foo.png", handler)

if *failureRate > 0 {
log.Printf("Server starting with a failure rate of %d%% on http://localhost:%d\n", *failureRate, *port)
} else {
log.Printf("Server starting on http://localhost:%d\n", *port)
}

err := http.ListenAndServe(fmt.Sprintf(":%d", *port), nil)
if err != nil {
log.Fatal(err)
}
}
Loading