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 }