package bldr_plugin import ( "context" "github.com/aperturerobotics/controllerbus/directive" "github.com/aperturerobotics/starpc/rpcstream" "github.com/aperturerobotics/starpc/srpc" "github.com/pkg/errors" "github.com/s4wave/spacewave/db/unixfs" unixfs_access "github.com/s4wave/spacewave/db/unixfs/access" unixfs_rpc "github.com/s4wave/spacewave/db/unixfs/rpc" unixfs_rpc_client "github.com/s4wave/spacewave/db/unixfs/rpc/client" ) // ParsePluginUnixfsID parses a unixfs ID and returns the plugin ID and matched prefix. // Returns the plugin ID (which may be empty for current plugin) and the prefix. // Returns empty matchedPrefix if no valid prefix is found. // // Matches UnixFS IDs like: // - plugin-dist: matches the current plugin dist fs // - plugin-assets: matches the current plugin assets fs // - plugin-dist/{plugin-id}: matches the plugin dist fs for plugin-id // - plugin-assets/{plugin-id}: matches the plugin assets fs for plugin-id func ParsePluginUnixfsID(unixfsID string) (pluginID string, matchedPrefix string) { pluginID, matchedPrefix = srpc.CheckStripPrefix(unixfsID, []string{PluginDistFsIdPrefix, PluginAssetsFsIdPrefix}) if matchedPrefix == "" { pluginID = "" if unixfsID == PluginDistFsId("") { matchedPrefix = PluginDistFsIdPrefix } else if unixfsID == PluginAssetsFsId("") { matchedPrefix = PluginAssetsFsIdPrefix } } return pluginID, matchedPrefix } // ValidatePluginUnixfsID validates a plugin unixfs ID and returns the plugin ID and matched prefix. // If allowEmpty is true, allows empty plugin ID which refers to current plugin. // Returns an error if the unixfsID is invalid. func ValidatePluginUnixfsID(unixfsID string, allowEmpty bool) (pluginID string, matchedPrefix string, err error) { // An empty unixfs id is invalid. if unixfsID == "" { return "", "", errors.New("unixfs id must be set") } // The id must match a known prefix. pluginID, matchedPrefix = ParsePluginUnixfsID(unixfsID) if matchedPrefix == "" { return "", "", errors.New("unixfs id prefix must be plugin-dist or plugin-assets") } // A filesystem may select an immutable manifest instead of the current plugin. if _, _, err := ParsePluginArtifactID(pluginID, allowEmpty); err != nil { return "", "", err } return pluginID, matchedPrefix, nil } // ResolveAccessUnixfs resolves a AccessUnixfs directive with another plugin. // // Resolves unixfs IDs like: // - plugin-dist/{plugin-id} // - plugin-assets/{plugin-id} // // Returns nil, nil if the service ID does not match any of the known prefixes. // Returns an error if the plugin id is invalid. func ResolveAccessUnixfs(ctx context.Context, dir unixfs_access.AccessUnixFS, h LookupRpcClientHandler) (directive.Resolver, error) { // An empty unixfs id resolves nothing. unixfsID := dir.AccessUnixFSID() if unixfsID == "" { return nil, nil } // check if the unixfs ID matches one of the known prefixes. _, matchedPrefix := ParsePluginUnixfsID(unixfsID) if matchedPrefix == "" { // ignore return nil, nil } // AccessUnixFSFunc is a function to access a UnixFS. // Optionally pass a released function that may be called when the handle was released. // Returns a release function. // TODO: move this to a common place in unixfs_access or unixfs_rpc_client accessFunc := func(ctx context.Context, released func()) (*unixfs.FSHandle, func(), error) { // Wait for the plugin host client for this resolution. pluginHostClient, relFunc, err := h.WaitPluginHostClient(ctx, released) if err != nil { return nil, nil, err } // Open the filesystem handle through the plugin host RPC. pluginHostSvcClient := NewSRPCPluginHostClient(pluginHostClient) fsClient := rpcstream.NewRpcStreamClient(pluginHostSvcClient.PluginFsRpc, unixfsID, true) fsCursorSvcClient := unixfs_rpc.NewSRPCFSCursorServiceClient(fsClient) fsHandle, err := unixfs_rpc_client.BuildFSHandle(ctx, fsCursorSvcClient) if err != nil { if relFunc != nil { relFunc() } return nil, nil, err } // Release the handle and the host client together. return fsHandle, func() { fsHandle.Release() if relFunc != nil { relFunc() } }, nil } // Resolve the directive with the access function value. return directive.NewValueResolver([]unixfs_access.AccessUnixFSValue{accessFunc}), nil }