Skip to content

Conversation

@javiercbk
Copy link

@javiercbk javiercbk commented Apr 6, 2019

History of this PR:

I was looking to write an io.Reader (a file incoming through http multipart) into a file while extracting the MD5 checksum (using crypto/md5)and detect the MIME type. I came across with this library but I realized I needed to create an io.Writer struct to wrap this library in order to use it along with io.TeeReader to perform the three actions in one step.

Work done:

I basically created a struct that wraps a buffer which reads the first 8192 bytes and discards the rest by implemented the io.Writer. I also added a method that passes the internal buffer into the Match function.

Also I added a simple test which could be improved.

Things I don't like:

  • It seems that the Write method (which makes the struct coply with io.Writer interface) could be improved, at least it seems a bit complicated.
  • The name of the struct could be better

Anyway, I wanted to know what do you think of this patch. Maybe it is not necessary, maybe is not even a good patch. Here is how I ended up using it.

// FileMetadata is a bit masking value to enumerate options to extract metadata from writers
type FileMetadata uint32

const (
	// Checksum extracts the file checksum from the reader
	Checksum FileMetadata = 1 << iota
	// MIME extracts the file MIME from the reader
	MIME
)

// WriteInfo modes all the information that can be extracted when writing a Writer
type WriteInfo struct {
	Written  int64
	Checksum []byte
	MimeType string
}

// WriteWithMetadata writes a reader to a writer and extract the required metadata
func WriteWithMetadata(writer io.Writer, reader io.Reader, meta FileMetadata) (WriteInfo, error) {
	var h hash.Hash
	var t types.Type
	var mw *filetype.MatcherWriter
	wi := WriteInfo{}
	currentReader := reader
	if meta&Checksum != 0 {
		h = md5.New()
		teeReader := io.TeeReader(currentReader, h)
		currentReader = teeReader
	}
	if meta&MIME != 0 {
		mw = filetype.NewMatcherWriter()
		teeReader := io.TeeReader(currentReader, mw)
		currentReader = teeReader
	}
	written, err := io.Copy(writer, currentReader)
	wi.Written = written
	if err != nil {
		return wi, err
	}
	if meta&Checksum != 0 {
		wi.Checksum = h.Sum(nil)
	}
	if meta&MIME != 0 {
		// if error it will be returned on the last return
		t, err = mw.Match()
		wi.MimeType = t.MIME.Value
	}
	return wi, err
}

Hey, thanks for this library. It's really good.

@javiercbk javiercbk changed the title Writer struct allowing io.Copy or Tee from a reader Writer struct allowing io.Copy or io.TeeReader from a reader Apr 6, 2019
@javiercbk javiercbk force-pushed the jl/matcher-writer branch from f5b6ce9 to f041400 Compare April 7, 2019 01:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant