diff --git a/ipblocklist/files/http.go b/ipblocklist/files/http.go new file mode 100644 index 0000000..c024399 --- /dev/null +++ b/ipblocklist/files/http.go @@ -0,0 +1,51 @@ +package files + +import ( + "context" + "fmt" + "io" + "net/http" + "net/url" +) + +type httpFile struct { + http *http.Client + url string +} + +func (h httpFile) Open(ctx context.Context) (io.ReadCloser, error) { + request, err := http.NewRequestWithContext(ctx, http.MethodGet, h.url, nil) + if err != nil { + panic(err) + } + + response, err := h.http.Do(request) + if err != nil { + if response != nil { + io.Copy(io.Discard, response.Body) + response.Body.Close() + } + + return nil, fmt.Errorf("cannot get url %s: %w", h.url, err) + } + + return response.Body, nil +} + +func NewHTTP(client *http.Client, endpoint string) (File, error) { + parsed, err := url.Parse(endpoint) + if err != nil { + return nil, fmt.Errorf("incorrect url %s: %w", endpoint, err) + } + + switch parsed.Scheme { + case "http", "https": + default: + return nil, fmt.Errorf("unsupported url %s", endpoint) + } + + return httpFile{ + http: client, + url: endpoint, + }, nil +} diff --git a/ipblocklist/files/init.go b/ipblocklist/files/init.go new file mode 100644 index 0000000..922b211 --- /dev/null +++ b/ipblocklist/files/init.go @@ -0,0 +1,10 @@ +package files + +import ( + "context" + "io" +) + +type File interface { + Open(context.Context) (io.ReadCloser, error) +} diff --git a/ipblocklist/files/local.go b/ipblocklist/files/local.go new file mode 100644 index 0000000..8e3fe64 --- /dev/null +++ b/ipblocklist/files/local.go @@ -0,0 +1,30 @@ +package files + +import ( + "context" + "fmt" + "io" + "io/fs" + "os" + "path/filepath" +) + +type localFile struct { + root fs.FS + name string +} + +func (l localFile) Open(ctx context.Context) (io.ReadCloser, error) { + return l.root.Open(l.name) +} + +func NewLocal(path string) (File, error) { + if stat, err := os.Stat(path); os.IsNotExist(err) || stat.IsDir() || stat.Mode().Perm()&0o400 == 0 { + return nil, fmt.Errorf("%s is not a readable file", path) + } + + return localFile{ + root: os.DirFS(filepath.Dir(path)), + name: filepath.Base(path), + }, nil +} diff --git a/ipblocklist/files/local_test.go b/ipblocklist/files/local_test.go new file mode 100644 index 0000000..3108dab --- /dev/null +++ b/ipblocklist/files/local_test.go @@ -0,0 +1,55 @@ +package files_test + +import ( + "context" + "io" + "path/filepath" + "strings" + "testing" + + "github.com/9seconds/mtg/v2/ipblocklist/files" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/suite" +) + +type LocalTestSuite struct { + suite.Suite +} + +func (suite *LocalTestSuite) GetLocalFile(name string) string { + return filepath.Join("testdata", name) +} + +func (suite *LocalTestSuite) TestIncorrect() { + names := []string{ + "absent", + "directory", + } + + for _, v := range names { + value := v + + suite.T().Run(v, func(t *testing.T) { + _, err := files.NewLocal(suite.GetLocalFile(value)) + assert.Error(t, err) + }) + } +} + +func (suite *LocalTestSuite) TestOk() { + file, err := files.NewLocal(suite.GetLocalFile("readable")) + suite.NoError(err) + + reader, err := file.Open(context.Background()) + suite.NoError(err) + + data, err := io.ReadAll(reader) + suite.NoError(err) + + suite.Equal("Hooray!", strings.TrimSpace(string(data))) +} + +func TestLocal(t *testing.T) { + t.Parallel() + suite.Run(t, &LocalTestSuite{}) +} diff --git a/ipblocklist/files/testdata/directory/.gitkeep b/ipblocklist/files/testdata/directory/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/ipblocklist/files/testdata/readable b/ipblocklist/files/testdata/readable new file mode 100644 index 0000000..715fcb7 --- /dev/null +++ b/ipblocklist/files/testdata/readable @@ -0,0 +1 @@ +Hooray!