github.com/vmware/govmomi@v0.43.0/simulator/http_nfc_lease.go (about)

     1  /*
     2  Copyright (c) 2019-2023 VMware, Inc. All Rights Reserved.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8  http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package simulator
    18  
    19  import (
    20  	"crypto/sha1"
    21  	"encoding/hex"
    22  	"fmt"
    23  	"hash"
    24  	"io"
    25  	"log"
    26  	"net/http"
    27  	"os"
    28  	"strings"
    29  	"sync"
    30  
    31  	"github.com/vmware/govmomi/vim25/methods"
    32  	"github.com/vmware/govmomi/vim25/mo"
    33  	"github.com/vmware/govmomi/vim25/soap"
    34  	"github.com/vmware/govmomi/vim25/types"
    35  )
    36  
    37  type metadata struct {
    38  	sha1 []byte
    39  	size int64
    40  }
    41  
    42  type HttpNfcLease struct {
    43  	mo.HttpNfcLease
    44  	files    map[string]string
    45  	metadata map[string]metadata
    46  }
    47  
    48  var (
    49  	nfcLease  sync.Map // HTTP access to NFC leases are token based and do not require Session auth
    50  	nfcPrefix = "/nfc/"
    51  )
    52  
    53  // ServeNFC handles NFC file upload/download
    54  func ServeNFC(w http.ResponseWriter, r *http.Request) {
    55  	p := strings.Split(r.URL.Path, "/")
    56  	id, name := p[len(p)-2], p[len(p)-1]
    57  	ref := types.ManagedObjectReference{Type: "HttpNfcLease", Value: id}
    58  	l, ok := nfcLease.Load(ref)
    59  	if !ok {
    60  		log.Printf("invalid NFC lease: %s", id)
    61  		http.NotFound(w, r)
    62  		return
    63  	}
    64  	lease := l.(*HttpNfcLease)
    65  	file, ok := lease.files[name]
    66  	if !ok {
    67  		log.Printf("invalid NFC device id: %s", name)
    68  		http.NotFound(w, r)
    69  		return
    70  	}
    71  
    72  	status := http.StatusOK
    73  	var dst hash.Hash
    74  	var src io.ReadCloser
    75  
    76  	switch r.Method {
    77  	case http.MethodPut, http.MethodPost:
    78  		dst = sha1.New()
    79  		src = r.Body
    80  	case http.MethodGet:
    81  		f, err := os.Open(file)
    82  		if err != nil {
    83  			http.NotFound(w, r)
    84  			return
    85  		}
    86  		src = f
    87  	default:
    88  		status = http.StatusMethodNotAllowed
    89  	}
    90  
    91  	n, err := io.Copy(dst, src)
    92  	_ = src.Close()
    93  	if dst != nil {
    94  		lease.metadata[name] = metadata{
    95  			sha1: dst.Sum(nil),
    96  			size: n,
    97  		}
    98  	}
    99  
   100  	msg := fmt.Sprintf("transferred %d bytes", n)
   101  	if err != nil {
   102  		status = http.StatusInternalServerError
   103  		msg = err.Error()
   104  	}
   105  	tracef("nfc %s %s: %s", r.Method, file, msg)
   106  	w.WriteHeader(status)
   107  }
   108  
   109  func (l *HttpNfcLease) error(ctx *Context, err *types.LocalizedMethodFault) {
   110  	ctx.WithLock(l, func() {
   111  		ctx.Map.Update(l, []types.PropertyChange{
   112  			{Name: "state", Val: types.HttpNfcLeaseStateError},
   113  			{Name: "error", Val: err},
   114  		})
   115  	})
   116  }
   117  
   118  func (l *HttpNfcLease) ready(ctx *Context, entity types.ManagedObjectReference, urls []types.HttpNfcLeaseDeviceUrl) {
   119  	info := &types.HttpNfcLeaseInfo{
   120  		Lease:        l.Self,
   121  		Entity:       entity,
   122  		DeviceUrl:    urls,
   123  		LeaseTimeout: 300,
   124  	}
   125  
   126  	ctx.WithLock(l, func() {
   127  		ctx.Map.Update(l, []types.PropertyChange{
   128  			{Name: "state", Val: types.HttpNfcLeaseStateReady},
   129  			{Name: "info", Val: info},
   130  		})
   131  	})
   132  }
   133  
   134  func newHttpNfcLease(ctx *Context) *HttpNfcLease {
   135  	lease := &HttpNfcLease{
   136  		HttpNfcLease: mo.HttpNfcLease{
   137  			State: types.HttpNfcLeaseStateInitializing,
   138  		},
   139  		files:    make(map[string]string),
   140  		metadata: make(map[string]metadata),
   141  	}
   142  
   143  	ctx.Session.Put(lease)
   144  	nfcLease.Store(lease.Reference(), lease)
   145  
   146  	return lease
   147  }
   148  
   149  func (l *HttpNfcLease) HttpNfcLeaseComplete(ctx *Context, req *types.HttpNfcLeaseComplete) soap.HasFault {
   150  	ctx.Session.Remove(ctx, req.This)
   151  	nfcLease.Delete(req.This)
   152  
   153  	return &methods.HttpNfcLeaseCompleteBody{
   154  		Res: new(types.HttpNfcLeaseCompleteResponse),
   155  	}
   156  }
   157  
   158  func (l *HttpNfcLease) HttpNfcLeaseAbort(ctx *Context, req *types.HttpNfcLeaseAbort) soap.HasFault {
   159  	ctx.Session.Remove(ctx, req.This)
   160  	nfcLease.Delete(req.This)
   161  
   162  	return &methods.HttpNfcLeaseAbortBody{
   163  		Res: new(types.HttpNfcLeaseAbortResponse),
   164  	}
   165  }
   166  
   167  func (l *HttpNfcLease) HttpNfcLeaseProgress(ctx *Context, req *types.HttpNfcLeaseProgress) soap.HasFault {
   168  	l.TransferProgress = req.Percent
   169  
   170  	return &methods.HttpNfcLeaseProgressBody{
   171  		Res: new(types.HttpNfcLeaseProgressResponse),
   172  	}
   173  }
   174  
   175  func (l *HttpNfcLease) getDeviceKey(name string) string {
   176  	for _, devUrl := range l.Info.DeviceUrl {
   177  		if name == devUrl.TargetId {
   178  			return devUrl.Key
   179  		}
   180  	}
   181  	return "unknown"
   182  }
   183  
   184  func (l *HttpNfcLease) HttpNfcLeaseGetManifest(ctx *Context, req *types.HttpNfcLeaseGetManifest) soap.HasFault {
   185  	entries := []types.HttpNfcLeaseManifestEntry{}
   186  	for name, md := range l.metadata {
   187  		entries = append(entries, types.HttpNfcLeaseManifestEntry{
   188  			Key:  l.getDeviceKey(name),
   189  			Sha1: hex.EncodeToString(md.sha1),
   190  			Size: md.size,
   191  		})
   192  	}
   193  	return &methods.HttpNfcLeaseGetManifestBody{
   194  		Res: &types.HttpNfcLeaseGetManifestResponse{
   195  			Returnval: entries,
   196  		},
   197  	}
   198  }