Fixed a number of compilation bugs.

This commit is contained in:
Nathan Osman 2016-04-25 01:01:01 -07:00
parent b62a889ab5
commit c0f04dc076
4 changed files with 57 additions and 42 deletions

View File

@ -13,16 +13,12 @@ type Entry struct {
}
// LoadEntry loads an entry from disk.
func LoadEntry(filename string) (*Entry, error) {
func (e *Entry) LoadEntry(filename string) error {
f, err := os.Open(filename)
if err != nil {
return nil, err
return err
}
e := &Entry{}
if err = json.NewDecoder(f).Decode(e); err != nil {
return nil, err
}
return e, nil
return json.NewDecoder(f).Decode(e)
}
// Save writes the entry to disk.

View File

@ -28,7 +28,7 @@ func NewReader(writer *Writer, jsonFilename, dataFilename string) *Reader {
status: StatusNone,
statusChanged: make(chan Status),
}
if r.writer {
if r.writer != nil {
r.writer.Subscribe(r.statusChanged)
}
return r
@ -76,7 +76,7 @@ func (r *Reader) Read(p []byte) (n int, err error) {
err = errors.New("writer error")
return
case StatusDone:
err = os.EOF
err = io.EOF
return
default:
for n < len(p) {
@ -84,7 +84,7 @@ func (r *Reader) Read(p []byte) (n int, err error) {
bytesRead, err = r.file.Read(p[n:])
n += bytesRead
if err != nil {
if err == os.EOF && r.writer != nil {
if err == io.EOF && r.writer != nil {
err = nil
var watcher *fsnotify.Watcher
watcher, err = fsnotify.NewWatcher()

View File

@ -3,7 +3,6 @@ package main
import (
"crypto/md5"
"fmt"
"io"
"os"
"path"
"sync"
@ -13,27 +12,46 @@ import (
// avoid race conditions, adding and testing for entries in the cache are
// protected by a mutex.
type Storage struct {
Directory string
mutex sync.Mutex
directory string
writers map[string]*Writer
writerDone chan *Writer
mutex sync.Mutex
}
// GetReader returns an io.Reader for the specified URL. If the file does not
// NewStorage creates a new storage manager.
func NewStorage(directory string) *Storage {
return &Storage{
directory: directory,
writers: make(map[string]*Writer),
writerDone: make(chan *Writer),
}
}
// GetReader returns a *Reader for the specified URL. If the file does not
// exist, both a writer (for downloading the file) and a reader are created.
func (s *Storage) GetReader(url string) (io.Reader, error) {
func (s *Storage) GetReader(url string) (*Reader, error) {
var (
hash = string(md5.Sum([]byte(url)))
jsonFilename = path.Join(s.Directory, fmt.Sprintf("%s.json", hash))
dataFilename = path.Join(s.Directory, fmt.Sprintf("%s.data", hash))
jsonFilename = path.Join(s.directory, fmt.Sprintf("%s.json", hash))
dataFilename = path.Join(s.directory, fmt.Sprintf("%s.data", hash))
)
s.mutex.Lock()
defer s.mutex.Unlock()
i, err := os.Stat(jsonFilename)
if err != nil {
if os.IsNotExist(err) {
NewWriter(url, jsonFilename, dataFilename)
w, ok := s.writers[hash]
if ok {
return NewReader(w, jsonFilename, dataFilename), nil
} else {
_, err := os.Stat(jsonFilename)
if err != nil {
if os.IsNotExist(err) {
w = NewWriter(url, jsonFilename, dataFilename, s.writerDone)
s.writers[hash] = w
return NewReader(w, jsonFilename, dataFilename), nil
} else {
return nil, err
}
} else {
return nil, err
return NewReader(nil, jsonFilename, dataFilename), nil
}
}
return NewReader(url, jsonFilename, dataFilename)
}

View File

@ -3,7 +3,6 @@ package main
import (
"container/list"
"io"
"log"
"net/http"
"os"
"sync"
@ -27,7 +26,7 @@ type Writer struct {
status Status
}
func (w *Writer) sendStatus(statusChan chan Status, status Status) {
func (w *Writer) sendStatus(statusChan chan<- Status, status Status) {
statusChan <- status
}
@ -36,17 +35,16 @@ func (w *Writer) setStatus(status Status) {
defer w.mutex.Unlock()
w.status = status
for e := w.channels.Front(); e != nil; e = e.Next() {
go w.sendStatus(e.Value.(chan Status), status)
go w.sendStatus(e.Value.(chan<- Status), status)
}
}
// Create a new writer for the given URL. Status information is passed along to
// subscribed channels. The done channel is used to notify the storage system
// that the download is complete (either success or an error).
// NewWriter creates a new writer for the given URL. Status information is
// passed along to subscribed channels. The done channel is used to notify the
// storage system that the download is complete (either success or an error).
func NewWriter(url, jsonFilename, dataFilename string, done chan<- *Writer) *Writer {
w := &Writer{
channels: make([]chan Status),
status: StatusNone,
channels: list.New(),
}
go func() {
r, err := http.Get(url)
@ -55,8 +53,9 @@ func NewWriter(url, jsonFilename, dataFilename string, done chan<- *Writer) *Wri
}
defer r.Body.Close()
e := &Entry{
URL: url,
ContentType: r.Header.Get("Content-Type"),
URL: url,
ContentLength: r.ContentLength,
ContentType: r.Header.Get("Content-Type"),
}
if err = e.Save(jsonFilename); err != nil {
goto error
@ -82,21 +81,23 @@ func NewWriter(url, jsonFilename, dataFilename string, done chan<- *Writer) *Wri
// Subscribe adds a channel to the list to be notified when the writer's status
// changes. The channel will also immediately receive the current status.
func (w *Writer) Subscribe(statusChan chan Status) {
func (w *Writer) Subscribe(statusChan chan<- Status) {
w.mutex.Lock()
defer w.mutex.Unlock()
w.channels = append(w.channels, c)
w.sendStatus(c, w.status)
w.channels.PushBack(statusChan)
// TODO: is "go" necessary here?
go w.sendStatus(statusChan, w.status)
}
// Unsubscribe a channel from the list to be notified. This may occur when a
// client cancels a request, for example.
func (w *Writer) Unsubscribe(statusChan chan Status) {
// Unsubscribe removes a channel from the list to be notified. This may occur
// when a client cancels a request, for example.
func (w *Writer) Unsubscribe(statusChan chan<- Status) {
w.mutex.Lock()
defer w.mutex.Unlock()
for i, c := range w.channels {
if c == statusChan {
w.channels = append(w.channels[:i], w.channels[i+1:]...)
for e := w.channels.Front(); e != nil; e = e.Next() {
if e.Value.(chan<- Status) == statusChan {
w.channels.Remove(e)
}
}
}