github.com/vmware/govmomi@v0.51.0/nfc/lease_updater.go (about)

     1  // © Broadcom. All Rights Reserved.
     2  // The term “Broadcom” refers to Broadcom Inc. and/or its subsidiaries.
     3  // SPDX-License-Identifier: Apache-2.0
     4  
     5  package nfc
     6  
     7  import (
     8  	"context"
     9  	"log"
    10  	"net/url"
    11  	"sync"
    12  	"sync/atomic"
    13  	"time"
    14  
    15  	"github.com/vmware/govmomi/vim25/progress"
    16  	"github.com/vmware/govmomi/vim25/types"
    17  )
    18  
    19  type FileItem struct {
    20  	types.OvfFileItem
    21  
    22  	URL        *url.URL
    23  	Thumbprint string
    24  
    25  	ch chan progress.Report
    26  }
    27  
    28  func NewFileItem(u *url.URL, item types.OvfFileItem) FileItem {
    29  	return FileItem{
    30  		OvfFileItem: item,
    31  		URL:         u,
    32  		ch:          make(chan progress.Report),
    33  	}
    34  }
    35  
    36  func (o FileItem) Sink() chan<- progress.Report {
    37  	return o.ch
    38  }
    39  
    40  // File converts the FileItem.OvfFileItem to an OvfFile
    41  func (o FileItem) File() types.OvfFile {
    42  	return types.OvfFile{
    43  		DeviceId: o.DeviceId,
    44  		Path:     o.Path,
    45  		Size:     o.Size,
    46  	}
    47  }
    48  
    49  type LeaseUpdater struct {
    50  	pos   int64 // Number of bytes (keep first to ensure 64 bit alignment)
    51  	total int64 // Total number of bytes (keep first to ensure 64 bit alignment)
    52  
    53  	lease *Lease
    54  
    55  	done chan struct{} // When lease updater should stop
    56  
    57  	wg sync.WaitGroup // Track when update loop is done
    58  }
    59  
    60  func newLeaseUpdater(ctx context.Context, lease *Lease, info *LeaseInfo) *LeaseUpdater {
    61  	l := LeaseUpdater{
    62  		lease: lease,
    63  
    64  		done: make(chan struct{}),
    65  	}
    66  
    67  	for _, item := range info.Items {
    68  		l.total += item.Size
    69  		go l.waitForProgress(item)
    70  	}
    71  
    72  	// Kickstart update loop
    73  	l.wg.Add(1)
    74  	go l.run()
    75  
    76  	return &l
    77  }
    78  
    79  func (l *LeaseUpdater) waitForProgress(item FileItem) {
    80  	var pos, total int64
    81  
    82  	total = item.Size
    83  
    84  	for {
    85  		select {
    86  		case <-l.done:
    87  			return
    88  		case p, ok := <-item.ch:
    89  			// Return in case of error
    90  			if ok && p.Error() != nil {
    91  				return
    92  			}
    93  
    94  			if !ok {
    95  				// Last element on the channel, add to total
    96  				atomic.AddInt64(&l.pos, total-pos)
    97  				return
    98  			}
    99  
   100  			// Approximate progress in number of bytes
   101  			x := int64(float32(total) * (p.Percentage() / 100.0))
   102  			atomic.AddInt64(&l.pos, x-pos)
   103  			pos = x
   104  		}
   105  	}
   106  }
   107  
   108  func (l *LeaseUpdater) run() {
   109  	defer l.wg.Done()
   110  
   111  	tick := time.NewTicker(2 * time.Second)
   112  	defer tick.Stop()
   113  
   114  	for {
   115  		select {
   116  		case <-l.done:
   117  			return
   118  		case <-tick.C:
   119  			// From the vim api HttpNfcLeaseProgress(percent) doc, percent ==
   120  			// "Completion status represented as an integer in the 0-100 range."
   121  			// Always report the current value of percent, as it will renew the
   122  			// lease even if the value hasn't changed or is 0.
   123  			percent := int32(float32(100*atomic.LoadInt64(&l.pos)) / float32(l.total))
   124  			err := l.lease.Progress(context.TODO(), percent)
   125  			if err != nil {
   126  				log.Printf("NFC lease progress: %s", err)
   127  				return
   128  			}
   129  		}
   130  	}
   131  }
   132  
   133  func (l *LeaseUpdater) Done() {
   134  	close(l.done)
   135  	l.wg.Wait()
   136  }