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 }