From 4756ffad637adedd897ffb17cd4fac84e9571f9e Mon Sep 17 00:00:00 2001 From: Alexander Avery Date: Mon, 19 May 2025 18:27:18 -0400 Subject: [PATCH] first commit for odl --- go.mod | 3 ++ odl.go | 102 ++++++++++++++++++++++++++++++++++++++++++++++ odl_test.go | 62 ++++++++++++++++++++++++++++ testdata/somefile | 1 + 4 files changed, 168 insertions(+) create mode 100644 go.mod create mode 100644 odl.go create mode 100644 odl_test.go create mode 100644 testdata/somefile diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..246bcbe --- /dev/null +++ b/go.mod @@ -0,0 +1,3 @@ +module gitea.beetbox.io/Alex/odl + +go 1.18 diff --git a/odl.go b/odl.go new file mode 100644 index 0000000..9f77d10 --- /dev/null +++ b/odl.go @@ -0,0 +1,102 @@ +package main + +import ( + "bufio" + "flag" + "fmt" + "io" + "log" + "net/http" + "net/url" + "os" + "path/filepath" + "strconv" +) + +func main() { + flag.Parse() + + var err error + f := os.Stdin + filename := flag.Arg(0) + + if filename != "-" && filename != "" { + f, err = os.Open(filename) + if err != nil { + log.Fatalf("failed to open file %s: %v", filename, err) + } + } + + Download(Read(".", f)) +} + +type request struct { + w io.Writer + url string +} + +func Download(c <-chan request) { + dl := func(w io.Writer, url string) error { + response, err := http.Get(url) + if err != nil { + return fmt.Errorf("downloading file %s: %v", url, err) + } + defer response.Body.Close() + + if response.StatusCode != http.StatusOK { + return fmt.Errorf("unexpected status code for %s: %d", url, response.StatusCode) + } + + _, err = io.Copy(w, response.Body) + return err + } + + for r := range c { + if err := dl(r.w, r.url); err != nil { + log.Println(err) + } + } +} + +func Read(root string, r io.Reader) <-chan request { + scanner := bufio.NewScanner(r) + + var n int + var name string + c := make(chan request) + + create := func(name, uri string, n int) (io.Writer, error) { + var f io.Writer + + u, err := url.Parse(uri) + if err != nil { + return f, fmt.Errorf("parsing url %s: %v", uri, err) + } + + filename := filepath.Join(root, name+strconv.Itoa(n)+filepath.Ext(u.Path)) + return os.Create(filename) + } + + go func() { + + for scanner.Scan() { + txt := scanner.Text() + + if name == "" || txt == "" { + name = txt + n = 0 + continue + } + + f, err := create(name, txt, n) + if err != nil { + log.Println(err) + continue + } + c <- request{w: f, url: txt} + n++ + } + close(c) + }() + return c +} diff --git a/odl_test.go b/odl_test.go new file mode 100644 index 0000000..dbe5934 --- /dev/null +++ b/odl_test.go @@ -0,0 +1,62 @@ +package main + +import ( + "bytes" + "net/http" + "net/http/httptest" + "strings" + "testing" + "os" + "testing/fstest" +) + +var fs = http.FileServer(http.Dir("./testdata")) + +var srv = httptest.NewServer(fs) + +func TestDownload(t *testing.T) { + var ( + b bytes.Buffer + c = make(chan request) + ) + + url := srv.URL + "/somefile" + t.Logf("file URL: %s", url) + + go func() { c <- request{&b, url}; close(c) }() + Download(c) + + want := "somefile inner data" + if got := b.String(); got != want { + t.Errorf("file buffer received unexpected value\nGot:\n%s\nWant:\n%s", got, want) + } +} + +func TestRead(t *testing.T) { + input := `boston +http://localhost/someboston +http://localhost/anotherboston.mp4 +http://localhost/finalboston.jpg + +orlando +http://localhost/someorlando.jpg +` + dir := t.TempDir() + t.Logf("root directory: %s", dir) + + c := Read(dir, strings.NewReader(input)) + for range c { + } // drain the channel + + err := fstest.TestFS( + os.DirFS(dir), + "boston0", + "boston1.mp4", + "boston2.jpg", + "orlando0.jpg", + ) + + if err != nil { + t.Fatal(err) + } +} diff --git a/testdata/somefile b/testdata/somefile new file mode 100644 index 0000000..39e5b17 --- /dev/null +++ b/testdata/somefile @@ -0,0 +1 @@ +somefile inner data \ No newline at end of file