Blame vendor/github.com/vmware/govmomi/nfc/lease_updater.go

Packit Service 4d2de5
/*
Packit Service 4d2de5
Copyright (c) 2014-2015 VMware, Inc. All Rights Reserved.
Packit Service 4d2de5
Packit Service 4d2de5
Licensed under the Apache License, Version 2.0 (the "License");
Packit Service 4d2de5
you may not use this file except in compliance with the License.
Packit Service 4d2de5
You may obtain a copy of the License at
Packit Service 4d2de5
Packit Service 4d2de5
    http://www.apache.org/licenses/LICENSE-2.0
Packit Service 4d2de5
Packit Service 4d2de5
Unless required by applicable law or agreed to in writing, software
Packit Service 4d2de5
distributed under the License is distributed on an "AS IS" BASIS,
Packit Service 4d2de5
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Packit Service 4d2de5
See the License for the specific language governing permissions and
Packit Service 4d2de5
limitations under the License.
Packit Service 4d2de5
*/
Packit Service 4d2de5
Packit Service 4d2de5
package nfc
Packit Service 4d2de5
Packit Service 4d2de5
import (
Packit Service 4d2de5
	"context"
Packit Service 4d2de5
	"log"
Packit Service 4d2de5
	"net/url"
Packit Service 4d2de5
	"sync"
Packit Service 4d2de5
	"sync/atomic"
Packit Service 4d2de5
	"time"
Packit Service 4d2de5
Packit Service 4d2de5
	"github.com/vmware/govmomi/vim25/progress"
Packit Service 4d2de5
	"github.com/vmware/govmomi/vim25/types"
Packit Service 4d2de5
)
Packit Service 4d2de5
Packit Service 4d2de5
type FileItem struct {
Packit Service 4d2de5
	types.OvfFileItem
Packit Service 4d2de5
	URL *url.URL
Packit Service 4d2de5
Packit Service 4d2de5
	ch chan progress.Report
Packit Service 4d2de5
}
Packit Service 4d2de5
Packit Service 4d2de5
func NewFileItem(u *url.URL, item types.OvfFileItem) FileItem {
Packit Service 4d2de5
	return FileItem{
Packit Service 4d2de5
		OvfFileItem: item,
Packit Service 4d2de5
		URL:         u,
Packit Service 4d2de5
		ch:          make(chan progress.Report),
Packit Service 4d2de5
	}
Packit Service 4d2de5
}
Packit Service 4d2de5
Packit Service 4d2de5
func (o FileItem) Sink() chan<- progress.Report {
Packit Service 4d2de5
	return o.ch
Packit Service 4d2de5
}
Packit Service 4d2de5
Packit Service 4d2de5
// File converts the FileItem.OvfFileItem to an OvfFile
Packit Service 4d2de5
func (o FileItem) File() types.OvfFile {
Packit Service 4d2de5
	return types.OvfFile{
Packit Service 4d2de5
		DeviceId: o.DeviceId,
Packit Service 4d2de5
		Path:     o.Path,
Packit Service 4d2de5
		Size:     o.Size,
Packit Service 4d2de5
	}
Packit Service 4d2de5
}
Packit Service 4d2de5
Packit Service 4d2de5
type LeaseUpdater struct {
Packit Service 4d2de5
	pos   int64 // Number of bytes (keep first to ensure 64 bit alignment)
Packit Service 4d2de5
	total int64 // Total number of bytes (keep first to ensure 64 bit alignment)
Packit Service 4d2de5
Packit Service 4d2de5
	lease *Lease
Packit Service 4d2de5
Packit Service 4d2de5
	done chan struct{} // When lease updater should stop
Packit Service 4d2de5
Packit Service 4d2de5
	wg sync.WaitGroup // Track when update loop is done
Packit Service 4d2de5
}
Packit Service 4d2de5
Packit Service 4d2de5
func newLeaseUpdater(ctx context.Context, lease *Lease, info *LeaseInfo) *LeaseUpdater {
Packit Service 4d2de5
	l := LeaseUpdater{
Packit Service 4d2de5
		lease: lease,
Packit Service 4d2de5
Packit Service 4d2de5
		done: make(chan struct{}),
Packit Service 4d2de5
	}
Packit Service 4d2de5
Packit Service 4d2de5
	for _, item := range info.Items {
Packit Service 4d2de5
		l.total += item.Size
Packit Service 4d2de5
		go l.waitForProgress(item)
Packit Service 4d2de5
	}
Packit Service 4d2de5
Packit Service 4d2de5
	// Kickstart update loop
Packit Service 4d2de5
	l.wg.Add(1)
Packit Service 4d2de5
	go l.run()
Packit Service 4d2de5
Packit Service 4d2de5
	return &l
Packit Service 4d2de5
}
Packit Service 4d2de5
Packit Service 4d2de5
func (l *LeaseUpdater) waitForProgress(item FileItem) {
Packit Service 4d2de5
	var pos, total int64
Packit Service 4d2de5
Packit Service 4d2de5
	total = item.Size
Packit Service 4d2de5
Packit Service 4d2de5
	for {
Packit Service 4d2de5
		select {
Packit Service 4d2de5
		case <-l.done:
Packit Service 4d2de5
			return
Packit Service 4d2de5
		case p, ok := <-item.ch:
Packit Service 4d2de5
			// Return in case of error
Packit Service 4d2de5
			if ok && p.Error() != nil {
Packit Service 4d2de5
				return
Packit Service 4d2de5
			}
Packit Service 4d2de5
Packit Service 4d2de5
			if !ok {
Packit Service 4d2de5
				// Last element on the channel, add to total
Packit Service 4d2de5
				atomic.AddInt64(&l.pos, total-pos)
Packit Service 4d2de5
				return
Packit Service 4d2de5
			}
Packit Service 4d2de5
Packit Service 4d2de5
			// Approximate progress in number of bytes
Packit Service 4d2de5
			x := int64(float32(total) * (p.Percentage() / 100.0))
Packit Service 4d2de5
			atomic.AddInt64(&l.pos, x-pos)
Packit Service 4d2de5
			pos = x
Packit Service 4d2de5
		}
Packit Service 4d2de5
	}
Packit Service 4d2de5
}
Packit Service 4d2de5
Packit Service 4d2de5
func (l *LeaseUpdater) run() {
Packit Service 4d2de5
	defer l.wg.Done()
Packit Service 4d2de5
Packit Service 4d2de5
	tick := time.NewTicker(2 * time.Second)
Packit Service 4d2de5
	defer tick.Stop()
Packit Service 4d2de5
Packit Service 4d2de5
	for {
Packit Service 4d2de5
		select {
Packit Service 4d2de5
		case <-l.done:
Packit Service 4d2de5
			return
Packit Service 4d2de5
		case <-tick.C:
Packit Service 4d2de5
			// From the vim api HttpNfcLeaseProgress(percent) doc, percent ==
Packit Service 4d2de5
			// "Completion status represented as an integer in the 0-100 range."
Packit Service 4d2de5
			// Always report the current value of percent, as it will renew the
Packit Service 4d2de5
			// lease even if the value hasn't changed or is 0.
Packit Service 4d2de5
			percent := int32(float32(100*atomic.LoadInt64(&l.pos)) / float32(l.total))
Packit Service 4d2de5
			err := l.lease.Progress(context.TODO(), percent)
Packit Service 4d2de5
			if err != nil {
Packit Service 4d2de5
				log.Printf("NFC lease progress: %s", err)
Packit Service 4d2de5
				return
Packit Service 4d2de5
			}
Packit Service 4d2de5
		}
Packit Service 4d2de5
	}
Packit Service 4d2de5
}
Packit Service 4d2de5
Packit Service 4d2de5
func (l *LeaseUpdater) Done() {
Packit Service 4d2de5
	close(l.done)
Packit Service 4d2de5
	l.wg.Wait()
Packit Service 4d2de5
}