2024-01-04 19:36:26 +00:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
2024-01-06 12:51:26 +00:00
|
|
|
"encoding/json"
|
|
|
|
"fmt"
|
|
|
|
"io"
|
|
|
|
"io/fs"
|
|
|
|
"mime/multipart"
|
|
|
|
"net/http"
|
2024-01-07 12:20:52 +00:00
|
|
|
"net/textproto"
|
2024-01-06 12:51:26 +00:00
|
|
|
"os"
|
|
|
|
"path/filepath"
|
2024-01-07 12:54:14 +00:00
|
|
|
"strings"
|
2024-01-06 12:51:26 +00:00
|
|
|
|
|
|
|
"github.com/sethvargo/go-githubactions"
|
2024-01-04 19:36:26 +00:00
|
|
|
)
|
|
|
|
|
2024-01-06 12:51:26 +00:00
|
|
|
type AddResponse struct {
|
|
|
|
Bytes int64
|
|
|
|
Hash string
|
|
|
|
Name string
|
|
|
|
Size string
|
|
|
|
}
|
|
|
|
|
2024-01-07 12:54:14 +00:00
|
|
|
type IpfsMultipartWriter struct {
|
|
|
|
multipart.Writer
|
|
|
|
}
|
|
|
|
|
|
|
|
var quoteEscaper = strings.NewReplacer("\\", "\\\\", `"`, "\\\"")
|
|
|
|
|
|
|
|
func escapeQuotes(s string) string {
|
|
|
|
return quoteEscaper.Replace(s)
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewIpfsMultipartWriter(w io.Writer) *IpfsMultipartWriter {
|
|
|
|
return &IpfsMultipartWriter{
|
|
|
|
Writer: *multipart.NewWriter(w),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (w *IpfsMultipartWriter) CreateIpfsDirectoryPart(name string) (io.Writer, error) {
|
|
|
|
h := make(textproto.MIMEHeader)
|
|
|
|
h.Set("Content-Disposition", fmt.Sprintf(`form-data; name="file"; filename="%s"`, name))
|
|
|
|
h.Set("Content-Type", "application/x-directory")
|
|
|
|
return w.CreatePart(h)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (w *IpfsMultipartWriter) CreateIpfsFilePart(absPath, name string) (io.Writer, error) {
|
|
|
|
h := make(textproto.MIMEHeader)
|
|
|
|
h.Set("AbsPath", absPath)
|
|
|
|
h.Set("Content-Disposition", fmt.Sprintf(`form-data; name="file"; filename="%s"`, escapeQuotes(name)))
|
|
|
|
h.Set("Content-Type", "application/octet-stream")
|
|
|
|
return w.CreatePart(h)
|
|
|
|
}
|
|
|
|
|
2024-01-04 19:36:26 +00:00
|
|
|
func main() {
|
2024-01-06 18:54:00 +00:00
|
|
|
githubactions.Infof("Checking inputs...")
|
|
|
|
|
2024-01-06 12:51:26 +00:00
|
|
|
// Check inputs
|
|
|
|
path := githubactions.GetInput("path_to_add")
|
|
|
|
if path == "" {
|
|
|
|
githubactions.Fatalf("Missing: path_to_add")
|
|
|
|
}
|
|
|
|
|
|
|
|
ipfsHost := githubactions.GetInput("ipfs_host")
|
|
|
|
if ipfsHost == "" {
|
|
|
|
githubactions.Fatalf("Missing: ipfs_host")
|
|
|
|
}
|
|
|
|
|
|
|
|
ipfsPort := githubactions.GetInput("ipfs_port")
|
|
|
|
if ipfsPort == "" {
|
|
|
|
githubactions.Fatalf("Missing: ipfs_port")
|
|
|
|
}
|
|
|
|
|
|
|
|
targetPath, err := os.Open(path)
|
|
|
|
if err != nil {
|
|
|
|
githubactions.Fatalf("Unable to access path_to_add: %v", err.Error())
|
|
|
|
}
|
|
|
|
defer targetPath.Close()
|
|
|
|
|
|
|
|
targetPathInfo, err := targetPath.Stat()
|
|
|
|
if err != nil {
|
|
|
|
githubactions.Fatalf("Unable to access to access path_to_add info: %v", fmt.Errorf("%w", err))
|
|
|
|
}
|
|
|
|
|
|
|
|
if !targetPathInfo.IsDir() {
|
|
|
|
githubactions.Fatalf("%v is not a directory", path)
|
|
|
|
}
|
|
|
|
|
2024-01-06 18:54:00 +00:00
|
|
|
githubactions.Infof("Inputs OK")
|
|
|
|
|
2024-01-06 12:51:26 +00:00
|
|
|
body, writer := io.Pipe()
|
|
|
|
|
2024-01-06 18:58:18 +00:00
|
|
|
url := fmt.Sprintf("http://%v:%v/api/v0/add", ipfsHost, ipfsPort)
|
|
|
|
req, err := http.NewRequest(http.MethodPost, url, body)
|
2024-01-06 12:51:26 +00:00
|
|
|
if err != nil {
|
|
|
|
githubactions.Fatalf("Unable to create request: %v", err.Error())
|
|
|
|
}
|
|
|
|
|
2024-01-07 12:54:14 +00:00
|
|
|
mwriter := NewIpfsMultipartWriter(writer)
|
2024-01-06 20:36:09 +00:00
|
|
|
req.Header.Add("Content-Type", mwriter.FormDataContentType())
|
2024-01-06 12:51:26 +00:00
|
|
|
|
2024-01-06 20:49:47 +00:00
|
|
|
go func() {
|
2024-01-06 21:17:31 +00:00
|
|
|
defer mwriter.Close()
|
|
|
|
defer writer.Close()
|
|
|
|
|
2024-01-07 12:54:14 +00:00
|
|
|
w, err := mwriter.CreateIpfsDirectoryPart(path)
|
|
|
|
if err != nil {
|
|
|
|
githubactions.Fatalf("Unable to create root dir path: %v", fmt.Errorf("%w", err))
|
|
|
|
}
|
2024-01-07 12:20:52 +00:00
|
|
|
|
2024-01-06 20:49:47 +00:00
|
|
|
err = filepath.Walk(path, func(innerPath string, info fs.FileInfo, err error) error {
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if info.IsDir() {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2024-01-07 12:13:11 +00:00
|
|
|
githubactions.Infof("Reading %v", innerPath)
|
2024-01-07 14:46:07 +00:00
|
|
|
w, err = mwriter.CreateIpfsFilePart(innerPath, innerPath)
|
2024-01-06 20:49:47 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2024-01-07 11:58:46 +00:00
|
|
|
fileReader, err := os.Open(innerPath)
|
2024-01-06 20:49:47 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2024-01-07 11:58:46 +00:00
|
|
|
defer fileReader.Close()
|
2024-01-06 20:49:47 +00:00
|
|
|
|
2024-01-07 11:58:46 +00:00
|
|
|
written, err := io.Copy(w, fileReader)
|
|
|
|
if err != nil {
|
2024-01-07 12:13:11 +00:00
|
|
|
return fmt.Errorf("error copying %s (%d bytes written): %v", innerPath, written, err)
|
2024-01-07 11:58:46 +00:00
|
|
|
} else {
|
2024-01-07 12:13:11 +00:00
|
|
|
githubactions.Infof("Read %v bytes from %s", written, innerPath)
|
2024-01-06 20:49:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
})
|
2024-01-06 20:05:26 +00:00
|
|
|
|
2024-01-06 20:36:09 +00:00
|
|
|
if err != nil {
|
2024-01-06 20:57:37 +00:00
|
|
|
githubactions.Fatalf("Unable to create request body: %v", fmt.Errorf("%w", err))
|
|
|
|
}
|
2024-01-06 20:49:47 +00:00
|
|
|
}()
|
2024-01-06 12:51:26 +00:00
|
|
|
|
2024-01-06 18:54:00 +00:00
|
|
|
githubactions.Infof("Calling node API")
|
2024-01-06 12:51:26 +00:00
|
|
|
client := &http.Client{}
|
|
|
|
res, err := client.Do(req)
|
2024-01-06 18:46:27 +00:00
|
|
|
if err != nil {
|
|
|
|
githubactions.Fatalf(err.Error())
|
|
|
|
}
|
2024-01-06 12:51:26 +00:00
|
|
|
|
2024-01-06 18:54:00 +00:00
|
|
|
githubactions.Infof("Reading response")
|
2024-01-06 12:51:26 +00:00
|
|
|
resBody, err := io.ReadAll(res.Body)
|
|
|
|
if err != nil {
|
2024-01-06 18:46:27 +00:00
|
|
|
githubactions.Fatalf(err.Error())
|
2024-01-06 12:51:26 +00:00
|
|
|
}
|
|
|
|
|
2024-01-07 12:06:21 +00:00
|
|
|
githubactions.Infof("Response: %v", string(resBody))
|
2024-01-07 11:58:46 +00:00
|
|
|
|
2024-01-06 12:51:26 +00:00
|
|
|
var ipfsAddResponse AddResponse
|
|
|
|
json.Unmarshal(resBody, &ipfsAddResponse)
|
|
|
|
|
2024-01-06 18:54:00 +00:00
|
|
|
githubactions.Infof("Upload size is %v", ipfsAddResponse.Bytes)
|
|
|
|
githubactions.Infof("CID is %v", ipfsAddResponse.Hash)
|
2024-01-06 12:54:39 +00:00
|
|
|
githubactions.SetOutput("cid", ipfsAddResponse.Hash)
|
2024-01-04 19:36:26 +00:00
|
|
|
}
|