Add local file abstraction

This commit is contained in:
9seconds
2021-11-29 07:26:27 +03:00
parent 3540408adf
commit c14a2329c5
6 changed files with 147 additions and 0 deletions
+51
View File
@@ -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
}
+10
View File
@@ -0,0 +1,10 @@
package files
import (
"context"
"io"
)
type File interface {
Open(context.Context) (io.ReadCloser, error)
}
+30
View File
@@ -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
}
+55
View File
@@ -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{})
}
View File
+1
View File
@@ -0,0 +1 @@
Hooray!