github.com/MetalBlockchain/metalgo@v1.11.9/vms/registry/vm_getter.go (about)

     1  // Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved.
     2  // See the file LICENSE for licensing terms.
     3  
     4  package registry
     5  
     6  import (
     7  	"errors"
     8  	"fmt"
     9  	"path/filepath"
    10  
    11  	"github.com/MetalBlockchain/metalgo/ids"
    12  	"github.com/MetalBlockchain/metalgo/utils/filesystem"
    13  	"github.com/MetalBlockchain/metalgo/utils/resource"
    14  	"github.com/MetalBlockchain/metalgo/vms"
    15  	"github.com/MetalBlockchain/metalgo/vms/rpcchainvm"
    16  	"github.com/MetalBlockchain/metalgo/vms/rpcchainvm/runtime"
    17  )
    18  
    19  var (
    20  	_ VMGetter = (*vmGetter)(nil)
    21  
    22  	errInvalidVMID = errors.New("invalid vmID")
    23  )
    24  
    25  // VMGetter defines functionality to get the plugins on the node.
    26  type VMGetter interface {
    27  	// Get fetches the VMs that are registered and the VMs that are not
    28  	// registered but available to be installed on the node.
    29  	Get() (
    30  		registeredVMs map[ids.ID]vms.Factory,
    31  		unregisteredVMs map[ids.ID]vms.Factory,
    32  		err error,
    33  	)
    34  }
    35  
    36  // VMGetterConfig defines settings for VMGetter
    37  type VMGetterConfig struct {
    38  	FileReader      filesystem.Reader
    39  	Manager         vms.Manager
    40  	PluginDirectory string
    41  	CPUTracker      resource.ProcessTracker
    42  	RuntimeTracker  runtime.Tracker
    43  }
    44  
    45  type vmGetter struct {
    46  	config VMGetterConfig
    47  }
    48  
    49  // NewVMGetter returns a new instance of a VMGetter
    50  func NewVMGetter(config VMGetterConfig) VMGetter {
    51  	return &vmGetter{
    52  		config: config,
    53  	}
    54  }
    55  
    56  func (getter *vmGetter) Get() (map[ids.ID]vms.Factory, map[ids.ID]vms.Factory, error) {
    57  	files, err := getter.config.FileReader.ReadDir(getter.config.PluginDirectory)
    58  	if err != nil {
    59  		return nil, nil, err
    60  	}
    61  
    62  	registeredVMs := make(map[ids.ID]vms.Factory)
    63  	unregisteredVMs := make(map[ids.ID]vms.Factory)
    64  	for _, file := range files {
    65  		if file.IsDir() {
    66  			continue
    67  		}
    68  
    69  		nameWithExtension := file.Name()
    70  		// Strip any extension from the file. This is to support windows .exe
    71  		// files.
    72  		name := nameWithExtension[:len(nameWithExtension)-len(filepath.Ext(nameWithExtension))]
    73  
    74  		// Skip hidden files.
    75  		if len(name) == 0 {
    76  			continue
    77  		}
    78  
    79  		vmID, err := getter.config.Manager.Lookup(name)
    80  		if err != nil {
    81  			// there is no alias with plugin name, try to use full vmID.
    82  			vmID, err = ids.FromString(name)
    83  			if err != nil {
    84  				return nil, nil, fmt.Errorf("%w: %q", errInvalidVMID, name)
    85  			}
    86  		}
    87  
    88  		registeredFactory, err := getter.config.Manager.GetFactory(vmID)
    89  
    90  		if err == nil {
    91  			// If we already have the VM registered, we shouldn't attempt to
    92  			// register it again.
    93  			registeredVMs[vmID] = registeredFactory
    94  			continue
    95  		}
    96  
    97  		// If the error isn't "not found", then we should report the error.
    98  		if !errors.Is(err, vms.ErrNotFound) {
    99  			return nil, nil, err
   100  		}
   101  
   102  		unregisteredVMs[vmID] = rpcchainvm.NewFactory(
   103  			filepath.Join(getter.config.PluginDirectory, file.Name()),
   104  			getter.config.CPUTracker,
   105  			getter.config.RuntimeTracker,
   106  		)
   107  	}
   108  	return registeredVMs, unregisteredVMs, nil
   109  }