从存储桶将多个文件传递给exec.Command调用

时间:2019-07-17 13:29:48

标签: go google-cloud-platform google-cloud-functions

我正在尝试构建一个用Go编写的云函数,该函数将使用Google的Cloud Functions基础结构中可用的ImageMagick库来合成和处理多个图像,以生成最终的输出图像。

问题的根源是我要使用的ImageMagick函数可用,但是它需要多个不同的输入才能起作用。我的输入是存储桶中的对象。

os / exec Cmd结构允许您通过使用“ ExtraFiles”数组来执行此操作,并且我知道如何将这些额外的文件提供给ImageMagick命令。

但是,“ ExtraFiles”数组只想存储os.File实例,而GCP Storage Client在打开文件时为您提供“ Reader”实例。

lastModifiedFileName

1 个答案:

答案 0 :(得分:1)

对于以后遇到这个问题的任何人-我找到了一种解决方法。我不为它感到兴奋,但是它是实用的。

从本质上讲,我能够读取存储Readers的内容,然后在Cloud Functions上下文中创建自己的os.File对象。然后,将该os.File传递给exec.Cmd调用。绝对不理想,但是下面是代码:

func Overlay(ctx context.Context, inputBucket, outputBucket, background string, foreground string, output string) (string, error) {
        // Retrieve the Background Image from the storage API
        backgroundBlob := storageClient.Bucket(inputBucket).Object(background)
        backgroundImg, err := backgroundBlob.NewReader(ctx)
        if err != nil {
                return "", fmt.Errorf("backgroundImg: %v", err)
        }        
        // Read the contents of the file into a variable
        backgroundSlurp, err := ioutil.ReadAll(backgroundImg)
        if err != nil {
                return "", fmt.Errorf("readFile: unable to read data from bucket %q, file %q: %v", inputBucket, background, err)
        }
        // Write the contents of Background Image to an os.File instance
        err = ioutil.WriteFile(fmt.Sprintf("/tmp/%s",background), backgroundSlurp, 0644)
        if err != nil {
                return "", fmt.Errorf("backgroundImg: %v", err)
        }
        // Open the os.File instance to pass it on to os.exec later
        backgroundFile, err := os.Open(fmt.Sprintf("/tmp/%s",background))
        if err != nil {
                return "", fmt.Errorf("backgroundFile: %v", err)
        }

        foregroundBlob := storageClient.Bucket(inputBucket).Object(foreground)
        foregroundImg, err := foregroundBlob.NewReader(ctx)
        if err != nil {
                return "", fmt.Errorf("foregroundImg: %v", err)
        }
        // Read the contents of the file into a variable
        foreroundSlurp, err := ioutil.ReadAll(foregroundImg)
        if err != nil {
                return "", fmt.Errorf("readFile: unable to read data from bucket %q, file %q: %v", inputBucket, foreground, err)
        }
        // Write the contents of Foreground Image to an os.File instance
        err = ioutil.WriteFile(fmt.Sprintf("/tmp/%s",foreground), foreroundSlurp, 0644)
        if err != nil {
                return "", fmt.Errorf("foregroundImg: %v", err)
        }
        // Open the os.File instance to pass it on to os.exec later
        foregroundFile, err := os.Open(fmt.Sprintf("/tmp/%s",foreground))
        if err != nil {
                return "", fmt.Errorf("foregroundFile: %v", err)
        }

        outputBlob := storageClient.Bucket(outputBucket).Object(output)
        outputImg := outputBlob.NewWriter(ctx)
        defer outputImg.Close()

        // Set up some additional file handles since we're delaqing with more inputs than STDIN Can cope with
        cmd := exec.Command("convert", "fd:3", "fd:4", "-composite", "-")
        cmd.Stdout = outputImg
        cmd.ExtraFiles = append(cmd.ExtraFiles,backgroundFile)
        cmd.ExtraFiles = append(cmd.ExtraFiles,foregroundFile)

        if err := cmd.Run(); err != nil {
                return "", fmt.Errorf("cmd.Run: %v", err)
        }

        log.Printf("Blurred image has been uploaded to %s", outputBlob.ObjectName())

        return outputBlob.ObjectName(), nil
}