Skip to content

Commit 8957650

Browse files
authored
Merge pull request #187 from moov-io/download-fixes
fix: download fed files in-memory instead of flat files
2 parents 0463ff6 + 8ce8506 commit 8957650

File tree

7 files changed

+61
-55
lines changed

7 files changed

+61
-55
lines changed

CHANGELOG.md

+6
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
## v0.9.0 (Released 2022-08-03)
2+
3+
IMPROVEMENTS
4+
5+
- Remove `DOWNLOAD_DIRECTORY` and store downloaded files in memory.
6+
17
## v0.8.1 (Released 2022-08-02)
28

39
IMPROVEMENTS

README.md

-1
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,6 @@ PONG
187187
| `FEDWIRE_DATA_PATH` | Filepath to Fedwire data file | `./data/fpddir.txt` |
188188
| `FRB_ROUTING_NUMBER` | Federal Reserve Board eServices (ABA) routing number used to download FedACH and FedWire files | Empty |
189189
| `FRB_DOWNLOAD_CODE` | Federal Reserve Board eServices (ABA) download code used to download FedACH and FedWire files | Empty |
190-
| `DOWNLOAD_DIRECTORY` | Directory for saving downloaded eServices files into | OS Temp Dir |
191190
| `LOG_FORMAT` | Format for logging lines to be written as. | Options: `json`, `plain` - Default: `plain` |
192191
| `HTTP_BIND_ADDRESS` | Address for Fed to bind its HTTP server on. This overrides the command-line flag `-http.addr`. | Default: `:8086` |
193192
| `HTTP_ADMIN_BIND_ADDRESS` | Address for Fed to bind its admin HTTP server on. This overrides the command-line flag `-admin.addr`. | Default: `:9096` |

cmd/server/main.go

+9-7
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"errors"
1111
"flag"
1212
"fmt"
13+
"io"
1314
"net/http"
1415
"os"
1516
"os/signal"
@@ -111,7 +112,11 @@ func main() {
111112

112113
// Start our searcher
113114
searcher := &searcher{logger: logger}
114-
if err := setupSearcher(logger, searcher, fedACHDataFile(logger), fedWireDataFile(logger)); err != nil {
115+
116+
fedACHData := fedACHDataFile(logger)
117+
fedWireData := fedWireDataFile(logger)
118+
119+
if err := setupSearcher(logger, searcher, fedACHData, fedWireData); err != nil {
115120
logger.Logf("read: %v", err)
116121
os.Exit(1)
117122
}
@@ -154,23 +159,20 @@ func addPingRoute(r *mux.Router) {
154159
})
155160
}
156161

157-
func setupSearcher(logger log.Logger, s *searcher, achFile, wireFile *os.File) error {
162+
func setupSearcher(logger log.Logger, s *searcher, achFile, wireFile io.Reader) error {
158163
if achFile == nil {
159164
return errors.New("missing fedach data file")
160165
}
161166
if wireFile == nil {
162167
return errors.New("missing fedwire data file")
163168
}
164169

165-
logger.Logf("search: loading %s for ACH data", achFile.Name())
166170
if err := s.readFEDACHData(achFile); err != nil {
167-
return fmt.Errorf("error reading ACH file at %s: %v", achFile.Name(), err)
171+
return fmt.Errorf("error reading ACH data: %v", err)
168172
}
169173

170-
logger.Logf("search: loading %s for Wire data", wireFile.Name())
171174
if err := s.readFEDWIREData(wireFile); err != nil {
172-
return fmt.Errorf("error reading wire file at %s: %v", wireFile.Name(), err)
173-
175+
return fmt.Errorf("error reading wire data: %v", err)
174176
}
175177
return nil
176178
}

cmd/server/reader.go

+20-9
Original file line numberDiff line numberDiff line change
@@ -6,44 +6,49 @@ package main
66

77
import (
88
"fmt"
9+
"io"
910
"os"
1011

1112
"github.com/moov-io/base/log"
1213
"github.com/moov-io/fed"
1314
"github.com/moov-io/fed/pkg/download"
1415
)
1516

16-
func fedACHDataFile(logger log.Logger) *os.File {
17+
func fedACHDataFile(logger log.Logger) io.Reader {
1718
if file, err := attemptFileDownload(logger, "fedach"); file != nil {
1819
return file
1920
} else if err != nil {
2021
panic(fmt.Sprintf("problem downloading fedach: %v", err))
2122
}
2223

2324
path := readDataFilepath("FEDACH_DATA_PATH", "./data/FedACHdir.txt")
25+
logger.Logf("search: loading %s for ACH data", path)
26+
2427
file, err := os.Open(path)
2528
if err != nil {
2629
panic(fmt.Sprintf("problem opening %s: %v", path, err))
2730
}
2831
return file
2932
}
3033

31-
func fedWireDataFile(logger log.Logger) *os.File {
34+
func fedWireDataFile(logger log.Logger) io.Reader {
3235
if file, err := attemptFileDownload(logger, "fedwire"); file != nil {
3336
return file
3437
} else if err != nil {
3538
panic(fmt.Sprintf("problem downloading fedwire: %v", err))
3639
}
3740

3841
path := readDataFilepath("FEDWIRE_DATA_PATH", "./data/fpddir.txt")
42+
logger.Logf("search: loading %s for Wire data", path)
43+
3944
file, err := os.Open(path)
4045
if err != nil {
4146
panic(fmt.Sprintf("problem opening %s: %v", path, err))
4247
}
4348
return file
4449
}
4550

46-
func attemptFileDownload(logger log.Logger, listName string) (*os.File, error) {
51+
func attemptFileDownload(logger log.Logger, listName string) (io.Reader, error) {
4752
routingNumber := os.Getenv("FRB_ROUTING_NUMBER")
4853
downloadCode := os.Getenv("FRB_DOWNLOAD_CODE")
4954

@@ -71,14 +76,17 @@ func readDataFilepath(env, fallback string) string {
7176

7277
// readFEDACHData opens and reads FedACHdir.txt then runs ACHDictionary.Read() to
7378
// parse and define ACHDictionary properties
74-
func (s *searcher) readFEDACHData(file *os.File) error {
79+
func (s *searcher) readFEDACHData(reader io.Reader) error {
7580
if s.logger != nil {
7681
s.logger.Logf("Read of FED data")
7782
}
78-
defer file.Close()
83+
84+
if closer, ok := reader.(io.Closer); ok {
85+
defer closer.Close()
86+
}
7987

8088
s.ACHDictionary = fed.NewACHDictionary()
81-
if err := s.ACHDictionary.Read(file); err != nil {
89+
if err := s.ACHDictionary.Read(reader); err != nil {
8290
return fmt.Errorf("ERROR: reading FedACHdir.txt %v", err)
8391
}
8492

@@ -91,14 +99,17 @@ func (s *searcher) readFEDACHData(file *os.File) error {
9199

92100
// readFEDWIREData opens and reads fpddir.txt then runs WIREDictionary.Read() to
93101
// parse and define WIREDictionary properties
94-
func (s *searcher) readFEDWIREData(file *os.File) error {
102+
func (s *searcher) readFEDWIREData(reader io.Reader) error {
95103
if s.logger != nil {
96104
s.logger.Logf("Read of FED data")
97105
}
98-
defer file.Close()
106+
107+
if closer, ok := reader.(io.Closer); ok {
108+
defer closer.Close()
109+
}
99110

100111
s.WIREDictionary = fed.NewWIREDictionary()
101-
if err := s.WIREDictionary.Read(file); err != nil {
112+
if err := s.WIREDictionary.Read(reader); err != nil {
102113
return fmt.Errorf("ERROR: reading fpddir.txt %v", err)
103114
}
104115

pkg/download/download.go

+15-27
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,13 @@
55
package download
66

77
import (
8+
"bytes"
89
"errors"
910
"fmt"
1011
"io"
11-
"io/ioutil"
1212
"net/http"
1313
"net/url"
14-
"os"
1514
"time"
16-
17-
"github.com/moov-io/base/strx"
1815
)
1916

2017
type Client struct {
@@ -55,19 +52,9 @@ func NewClient(opts *ClientOpts) (*Client, error) {
5552
}, nil
5653
}
5754

58-
var (
59-
downloadDirectory = strx.Or(os.Getenv("DOWNLOAD_DIRECTORY"), os.TempDir())
60-
)
61-
62-
func init() {
63-
if _, err := os.Stat(downloadDirectory); os.IsNotExist(err) {
64-
os.MkdirAll(downloadDirectory, 0777)
65-
}
66-
}
67-
68-
// GetList downloads an FRB list and saves it into a temporary file.
55+
// GetList downloads an FRB list and saves it into an io.Reader.
6956
// Example listName values: fedach, fedwire
70-
func (c *Client) GetList(listName string) (*os.File, error) {
57+
func (c *Client) GetList(listName string) (io.Reader, error) {
7158
where, err := url.Parse(fmt.Sprintf("https://frbservices.org/EPaymentsDirectory/directories/%s?format=json", listName))
7259
if err != nil {
7360
return nil, fmt.Errorf("url: %v", err)
@@ -85,20 +72,21 @@ func (c *Client) GetList(listName string) (*os.File, error) {
8572
if err != nil {
8673
return nil, fmt.Errorf("http get: %v", err)
8774
}
88-
defer resp.Body.Close()
75+
if resp != nil && resp.Body != nil {
76+
defer resp.Body.Close()
77+
}
8978

90-
out, err := ioutil.TempFile(downloadDirectory, fmt.Sprintf("%s-*", listName))
91-
if err != nil {
92-
return nil, fmt.Errorf("temp file: %v", err)
79+
// Quit if we fail to download
80+
if resp.StatusCode >= 299 {
81+
return nil, fmt.Errorf("unexpected http status: %d", resp.StatusCode)
9382
}
94-
if n, err := io.Copy(out, resp.Body); n == 0 || err != nil {
83+
84+
var out bytes.Buffer
85+
if n, err := io.Copy(&out, resp.Body); n == 0 || err != nil {
9586
return nil, fmt.Errorf("copying n=%d: %v", n, err)
9687
}
97-
if err := out.Sync(); err != nil {
98-
return nil, fmt.Errorf("sync: %v", err)
99-
}
100-
if _, err := out.Seek(0, io.SeekStart); err != nil {
101-
return nil, fmt.Errorf("seek: %v", err)
88+
if out.Len() > 0 {
89+
return &out, nil
10290
}
103-
return out, nil
91+
return nil, nil
10492
}

pkg/download/download_test.go

+10-10
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ import (
1010
"io/ioutil"
1111
"os"
1212
"testing"
13+
14+
"github.com/stretchr/testify/require"
1315
)
1416

1517
func TestClient__fedach(t *testing.T) {
@@ -20,11 +22,10 @@ func TestClient__fedach(t *testing.T) {
2022
t.Fatal(err)
2123
}
2224

23-
st, err := fedach.Stat()
24-
if err != nil {
25-
t.Fatal(err)
26-
}
27-
if n := st.Size(); n < 1024 {
25+
buf, ok := fedach.(*bytes.Buffer)
26+
require.True(t, ok)
27+
28+
if n := buf.Len(); n < 1024 {
2829
t.Errorf("unexpected size of %d bytes", n)
2930
}
3031

@@ -42,11 +43,10 @@ func TestClient__fedwire(t *testing.T) {
4243
t.Fatal(err)
4344
}
4445

45-
st, err := fedwire.Stat()
46-
if err != nil {
47-
t.Fatal(err)
48-
}
49-
if n := st.Size(); n < 1024 {
46+
buf, ok := fedwire.(*bytes.Buffer)
47+
require.True(t, ok)
48+
49+
if n := buf.Len(); n < 1024 {
5050
t.Errorf("unexpected size of %d bytes", n)
5151
}
5252

version.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,4 @@
55
package fed
66

77
// Version is the current version
8-
const Version = "v0.8.1"
8+
const Version = "v0.9.0"

0 commit comments

Comments
 (0)