예제 #1
0
파일: diff.go 프로젝트: itchio/wharf
func makeSigWriter(wc *wire.WriteContext) wsync.SignatureWriter {
	return func(bl wsync.BlockHash) error {
		return wc.WriteMessage(&BlockHash{
			WeakHash:   bl.WeakHash,
			StrongHash: bl.StrongHash,
		})
	}
}
예제 #2
0
파일: compression.go 프로젝트: itchio/wharf
// CompressWire wraps a wire.WriteContext into a compressor, according to given settings,
// so that any messages written through the returned WriteContext will first be compressed.
func CompressWire(ctx *wire.WriteContext, compression *CompressionSettings) (*wire.WriteContext, error) {
	if compression == nil {
		return nil, errors.Wrap(fmt.Errorf("no compression specified"), 1)
	}

	if compression.Algorithm == CompressionAlgorithm_NONE {
		return ctx, nil
	}

	compressor := compressors[compression.Algorithm]
	if compressor == nil {
		return nil, errors.Wrap(fmt.Errorf("no compressor registered for %s", compression.Algorithm.String()), 1)
	}

	compressedWriter, err := compressor.Apply(ctx.Writer(), compression.Quality)
	if err != nil {
		return nil, errors.Wrap(err, 1)
	}

	return wire.NewWriteContext(compressedWriter), nil
}
예제 #3
0
파일: diff.go 프로젝트: itchio/wharf
func makeOpsWriter(wc *wire.WriteContext, dctx *DiffContext) wsync.OperationWriter {
	numOps := 0
	wop := &SyncOp{}

	files := dctx.TargetContainer.Files

	return func(op wsync.Operation) error {
		numOps++
		wop.Reset()

		switch op.Type {
		case wsync.OpBlockRange:
			wop.Type = SyncOp_BLOCK_RANGE
			wop.FileIndex = op.FileIndex
			wop.BlockIndex = op.BlockIndex
			wop.BlockSpan = op.BlockSpan

			fileSize := files[op.FileIndex].Size
			lastBlockIndex := op.BlockIndex + op.BlockSpan - 1
			tailSize := ComputeBlockSize(fileSize, lastBlockIndex)
			dctx.ReusedBytes += BlockSize*(op.BlockSpan-1) + tailSize

		case wsync.OpData:
			wop.Type = SyncOp_DATA
			wop.Data = op.Data

			dctx.FreshBytes += int64(len(op.Data))

		default:
			return errors.Wrap(fmt.Errorf("unknown rsync op type: %d", op.Type), 1)
		}

		err := wc.WriteMessage(wop)
		if err != nil {
			return errors.Wrap(err, 1)
		}

		return nil
	}
}
예제 #4
0
파일: wounds.go 프로젝트: itchio/wharf
// Do only create a file at WoundsPath when it receives the first wound.
// If no wounds are ever received, Do will effectively be a no-op.
func (ww *WoundsWriter) Do(container *tlc.Container, wounds chan *Wound) error {
	var fw *os.File
	var wc *wire.WriteContext

	defer func() {
		if wc != nil {
			wc.Close()
		}

		if fw != nil {
			fw.Close()
		}
	}()

	writeWound := func(wound *Wound) error {
		ww.totalCorrupted += wound.Size()

		if wc == nil {
			var err error
			fw, err = os.Create(ww.WoundsPath)
			if err != nil {
				return errors.Wrap(err, 1)
			}

			wc = wire.NewWriteContext(fw)
			if err != nil {
				return errors.Wrap(err, 1)
			}

			err = wc.WriteMagic(WoundsMagic)
			if err != nil {
				return errors.Wrap(err, 1)
			}

			err = wc.WriteMessage(&WoundsHeader{})
			if err != nil {
				return errors.Wrap(err, 1)
			}

			err = wc.WriteMessage(container)
			if err != nil {
				return errors.Wrap(err, 1)
			}
		}

		err := wc.WriteMessage(wound)
		if err != nil {
			return errors.Wrap(err, 1)
		}

		return nil
	}

	for wound := range wounds {
		if wound.Healthy() {
			continue
		}

		ww.hasWounds = true
		err := writeWound(wound)
		if err != nil {
			return err
		}
	}

	return nil
}