github.com/streamingfast/substreams@v1.6.2/info/info.go (about)

     1  package info
     2  
     3  import (
     4  	"fmt"
     5  	"strings"
     6  
     7  	"github.com/streamingfast/substreams/manifest"
     8  	pbsubstreams "github.com/streamingfast/substreams/pb/sf/substreams/v1"
     9  	"github.com/streamingfast/substreams/pipeline/exec"
    10  	"google.golang.org/protobuf/types/descriptorpb"
    11  )
    12  
    13  type BasicInfo struct {
    14  	Name                   string                             `json:"name"`
    15  	Version                string                             `json:"version"`
    16  	Documentation          *string                            `json:"documentation,omitempty"`
    17  	Network                string                             `json:"network,omitempty"`
    18  	Image                  []byte                             `json:"-"`
    19  	Modules                []ModulesInfo                      `json:"modules"`
    20  	SinkInfo               *SinkInfo                          `json:"sink_info,omitempty"`
    21  	ProtoPackages          []string                           `json:"proto_packages"` // list of proto packages
    22  	Networks               map[string]*manifest.NetworkParams `json:"networks,omitempty"`
    23  	ProtoSourceCode        map[string][]*SourceCodeInfo       `json:"proto_source_code"`         // map of proto file name to .proto file contents
    24  	ProtoMessagesByPackage map[string][]*ProtoMessageInfo     `json:"proto_messages_by_package"` // map of package name to a list of messages info in that package
    25  }
    26  
    27  type SourceCodeInfo struct {
    28  	Filename string `json:"filename"`
    29  	Source   string `json:"source"`
    30  }
    31  
    32  type ProtoMessageInfo struct {
    33  	Name           string              `json:"name"`
    34  	Package        string              `json:"package"`
    35  	Type           string              `json:"type"`
    36  	File           string              `json:"file"`
    37  	Proto          string              `json:"proto"`
    38  	Documentation  string              `json:"documentation"`
    39  	NestedMessages []*ProtoMessageInfo `json:"nested_messages"`
    40  }
    41  
    42  type SinkInfo struct {
    43  	Configs string            `json:"desc"`
    44  	TypeUrl string            `json:"type_url"`
    45  	Files   map[string][]byte `json:"files"`
    46  }
    47  
    48  type ExtendedInfo struct {
    49  	*BasicInfo
    50  
    51  	ExecutionStages [][][]string `json:"execution_stages,omitempty"`
    52  }
    53  
    54  type ProtoFileInfo struct {
    55  	Name               *string                                `json:"name,omitempty"`
    56  	Package            *string                                `json:"package,omitempty"`
    57  	Dependencies       []string                               `json:"dependencies,omitempty"`
    58  	PublicDependencies []int32                                `json:"public_dependencies,omitempty"`
    59  	MessageType        []*descriptorpb.DescriptorProto        `json:"message_type,omitempty"`
    60  	Services           []*descriptorpb.ServiceDescriptorProto `json:"services,omitempty"`
    61  }
    62  
    63  type ModulesInfo struct {
    64  	Name          string                           `json:"name"`
    65  	Kind          string                           `json:"kind"`
    66  	Inputs        []ModuleInput                    `json:"inputs"`
    67  	OutputType    *string                          `json:"output_type,omitempty"`   //for map inputs
    68  	ValueType     *string                          `json:"value_type,omitempty"`    //for store inputs
    69  	UpdatePolicy  *string                          `json:"update_policy,omitempty"` //for store inputs
    70  	BlockFilter   *pbsubstreams.Module_BlockFilter `json:"block_filter,omitempty"`
    71  	InitialBlock  uint64                           `json:"initial_block"`
    72  	Documentation *string                          `json:"documentation,omitempty"`
    73  	Hash          string                           `json:"hash"`
    74  }
    75  
    76  type ModuleInput struct {
    77  	Type string  `json:"type"`
    78  	Name string  `json:"name"`
    79  	Mode *string `json:"mode,omitempty"` //for store inputs
    80  }
    81  
    82  func Basic(pkg *pbsubstreams.Package, graph *manifest.ModuleGraph) (*BasicInfo, error) {
    83  	name := "Unnamed"
    84  	var doc, version string
    85  	if len(pkg.PackageMeta) != 0 {
    86  		name = pkg.PackageMeta[0].Name
    87  		version = pkg.PackageMeta[0].Version
    88  		doc = pkg.PackageMeta[0].Doc
    89  	}
    90  
    91  	manifestInfo := &BasicInfo{
    92  		Name:    name,
    93  		Network: pkg.Network,
    94  		Version: version,
    95  		Image:   pkg.Image,
    96  	}
    97  
    98  	if pkg.Networks != nil {
    99  		manifestInfo.Networks = make(map[string]*manifest.NetworkParams)
   100  	}
   101  	for k, v := range pkg.Networks {
   102  		params := &manifest.NetworkParams{}
   103  
   104  		if v.InitialBlocks != nil {
   105  			params.InitialBlocks = make(map[string]uint64)
   106  		}
   107  		for kk, vv := range v.InitialBlocks {
   108  			params.InitialBlocks[kk] = vv
   109  		}
   110  
   111  		if v.Params != nil {
   112  			params.Params = make(map[string]string)
   113  		}
   114  		for kk, vv := range v.Params {
   115  			params.Params[kk] = vv
   116  		}
   117  		manifestInfo.Networks[k] = params
   118  	}
   119  
   120  	if doc != "" {
   121  		manifestInfo.Documentation = strPtr(strings.Replace(doc, "\n", "\n  ", -1))
   122  	}
   123  
   124  	modules := make([]ModulesInfo, 0, len(pkg.Modules.Modules))
   125  
   126  	hashes := manifest.NewModuleHashes()
   127  	for ix, mod := range pkg.Modules.Modules {
   128  		modInfo := ModulesInfo{}
   129  
   130  		_, _ = hashes.HashModule(pkg.Modules, mod, graph)
   131  		modInfo.Hash = hashes.Get(mod.Name)
   132  
   133  		modInfo.Name = mod.Name
   134  		modInfo.InitialBlock = mod.InitialBlock
   135  
   136  		kind := mod.GetKind()
   137  		switch v := kind.(type) {
   138  
   139  		case *pbsubstreams.Module_KindBlockIndex_:
   140  			modInfo.Kind = "index"
   141  			modInfo.OutputType = strPtr(v.KindBlockIndex.OutputType)
   142  		case *pbsubstreams.Module_KindMap_:
   143  			modInfo.Kind = "map"
   144  			modInfo.OutputType = strPtr(v.KindMap.OutputType)
   145  		case *pbsubstreams.Module_KindStore_:
   146  			modInfo.Kind = "store"
   147  			modInfo.ValueType = strPtr(v.KindStore.ValueType)
   148  			modInfo.UpdatePolicy = strPtr(v.KindStore.UpdatePolicy.Pretty())
   149  		default:
   150  			modInfo.Kind = "unknown"
   151  		}
   152  
   153  		if pkg.ModuleMeta != nil {
   154  			modMeta := pkg.ModuleMeta[ix]
   155  			if modMeta != nil && modMeta.Doc != "" {
   156  				modInfo.Documentation = strPtr(strings.Replace(modMeta.Doc, "\n", "\n  ", -1))
   157  			}
   158  		}
   159  
   160  		inputs := make([]ModuleInput, 0, len(mod.Inputs))
   161  		for _, input := range mod.Inputs {
   162  			inputInfo := ModuleInput{}
   163  
   164  			switch v := input.Input.(type) {
   165  			case *pbsubstreams.Module_Input_Source_:
   166  				inputInfo.Type = "source"
   167  				inputInfo.Name = v.Source.Type
   168  			case *pbsubstreams.Module_Input_Map_:
   169  				inputInfo.Type = "map"
   170  				inputInfo.Name = v.Map.ModuleName
   171  			case *pbsubstreams.Module_Input_Store_:
   172  				inputInfo.Type = "store"
   173  				inputInfo.Name = v.Store.ModuleName
   174  				if v.Store.Mode > 0 {
   175  					inputInfo.Mode = strPtr(v.Store.Mode.Pretty())
   176  				}
   177  			case *pbsubstreams.Module_Input_Params_:
   178  				inputInfo.Type = "params"
   179  				inputInfo.Name = input.GetParams().Value
   180  			default:
   181  				inputInfo.Type = "unknown"
   182  				inputInfo.Name = "unknown"
   183  			}
   184  
   185  			inputs = append(inputs, inputInfo)
   186  		}
   187  		modInfo.Inputs = inputs
   188  		modInfo.BlockFilter = mod.BlockFilter
   189  
   190  		modules = append(modules, modInfo)
   191  	}
   192  	manifestInfo.Modules = modules
   193  
   194  	protoPackageParser, err := NewProtoPackageParser(pkg.ProtoFiles)
   195  	if err != nil {
   196  		return nil, fmt.Errorf("proto package parser: %w", err)
   197  	}
   198  	packageMessageMap, err := protoPackageParser.Parse()
   199  	if err != nil {
   200  		return nil, fmt.Errorf("parse proto files: %w", err)
   201  	}
   202  	manifestInfo.ProtoMessagesByPackage = packageMessageMap
   203  
   204  	manifestInfo.ProtoPackages = protoPackageParser.GetPackagesList()
   205  	manifestInfo.ProtoSourceCode = protoPackageParser.GetFilesSourceCode()
   206  
   207  	if pkg.SinkConfig != nil {
   208  		desc, files, err := manifest.DescribeSinkConfigs(pkg)
   209  		if err != nil {
   210  			return nil, fmt.Errorf("describe sink configs: %w", err)
   211  		}
   212  		manifestInfo.SinkInfo = &SinkInfo{
   213  			Configs: desc,
   214  			TypeUrl: pkg.SinkConfig.TypeUrl,
   215  			Files:   files,
   216  		}
   217  	}
   218  
   219  	return manifestInfo, nil
   220  }
   221  
   222  func Extended(manifestPath string, outputModule string, skipValidation bool) (*ExtendedInfo, error) {
   223  	var opts []manifest.Option
   224  	if skipValidation {
   225  		opts = append(opts, manifest.SkipPackageValidationReader())
   226  	}
   227  	reader, err := manifest.NewReader(manifestPath, opts...)
   228  	if err != nil {
   229  		return nil, fmt.Errorf("manifest reader: %w", err)
   230  	}
   231  
   232  	pkg, graph, err := reader.Read()
   233  	if err != nil {
   234  		return nil, fmt.Errorf("read manifest %q: %w", manifestPath, err)
   235  	}
   236  
   237  	return ExtendedWithPackage(pkg, graph, outputModule)
   238  }
   239  
   240  func ExtendedWithPackage(pkg *pbsubstreams.Package, graph *manifest.ModuleGraph, outputModule string) (*ExtendedInfo, error) {
   241  	basicInfo, err := Basic(pkg, graph)
   242  	if err != nil {
   243  		return nil, err
   244  	}
   245  
   246  	var stages [][][]string
   247  	if outputModule != "" {
   248  		execGraph, err := exec.NewOutputModuleGraph(outputModule, true, pkg.Modules)
   249  		if err != nil {
   250  			return nil, fmt.Errorf("creating output module graph: %w", err)
   251  		}
   252  		stages = make([][][]string, 0, len(execGraph.StagedUsedModules()))
   253  		for _, layers := range execGraph.StagedUsedModules() {
   254  			var layerDefs [][]string
   255  			for _, l := range layers {
   256  				var mods []string
   257  				for _, m := range l {
   258  					mods = append(mods, m.Name)
   259  				}
   260  				layerDefs = append(layerDefs, mods)
   261  			}
   262  			stages = append(stages, layerDefs)
   263  		}
   264  	}
   265  
   266  	return &ExtendedInfo{
   267  		BasicInfo:       basicInfo,
   268  		ExecutionStages: stages,
   269  	}, nil
   270  }
   271  
   272  func strPtr(s string) *string {
   273  	return &s
   274  }