Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Writer struct allowing io.Copy or io.TeeReader from a reader #66

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

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
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.

None yet

1 participant