180 lines
4.3 KiB
Go
180 lines
4.3 KiB
Go
package main
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"io/fs"
|
|
"mime/multipart"
|
|
"net/http"
|
|
"net/textproto"
|
|
"net/url"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"github.com/sethvargo/go-githubactions"
|
|
)
|
|
|
|
type AddResponse struct {
|
|
Bytes int64
|
|
Hash string
|
|
Name string
|
|
Size string
|
|
}
|
|
|
|
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)
|
|
encodedName := url.QueryEscape(name)
|
|
h.Set("Content-Disposition", fmt.Sprintf(`form-data; name="file"; filename="%s"`, encodedName))
|
|
h.Set("Content-Type", "application/x-directory")
|
|
return w.CreatePart(h)
|
|
}
|
|
|
|
func (w *IpfsMultipartWriter) CreateIpfsFilePart(name string) (io.Writer, error) {
|
|
h := make(textproto.MIMEHeader)
|
|
encodedName := url.QueryEscape(name)
|
|
h.Set("Content-Disposition", fmt.Sprintf(`form-data; name="file"; filename="%s"`, escapeQuotes(encodedName)))
|
|
h.Set("Content-Type", "application/octet-stream")
|
|
return w.CreatePart(h)
|
|
}
|
|
|
|
func (w *IpfsMultipartWriter) CreateIpfsAbsFilePart(name, absPath string) (io.Writer, error) {
|
|
h := make(textproto.MIMEHeader)
|
|
encodedName := url.QueryEscape(name)
|
|
h.Set("AbsPath", absPath)
|
|
h.Set("Content-Disposition", fmt.Sprintf(`form-data; name="file"; filename="%s"`, escapeQuotes(encodedName)))
|
|
h.Set("Content-Type", "application/octet-stream")
|
|
return w.CreatePart(h)
|
|
}
|
|
|
|
func main() {
|
|
githubactions.Debugf("Checking 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)
|
|
}
|
|
|
|
githubactions.Debugf("Inputs OK")
|
|
|
|
body, writer := io.Pipe()
|
|
|
|
targetUrl := fmt.Sprintf("http://%v:%v/api/v0/add", ipfsHost, ipfsPort)
|
|
req, err := http.NewRequest(http.MethodPost, targetUrl, body)
|
|
if err != nil {
|
|
githubactions.Fatalf("Unable to create request: %v", err.Error())
|
|
}
|
|
|
|
q := req.URL.Query()
|
|
q.Add("progress", "false")
|
|
q.Add("stream-true", "false")
|
|
req.URL.RawQuery = q.Encode()
|
|
|
|
mwriter := NewIpfsMultipartWriter(writer)
|
|
req.Header.Add("Content-Type", mwriter.FormDataContentType())
|
|
|
|
go func() {
|
|
defer writer.Close()
|
|
defer mwriter.Close()
|
|
|
|
err = filepath.Walk(path, func(innerPath string, info fs.FileInfo, err error) error {
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if info.IsDir() {
|
|
return nil
|
|
}
|
|
|
|
w, err := mwriter.CreateIpfsFilePart(innerPath)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
fileReader, err := os.Open(innerPath)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer fileReader.Close()
|
|
|
|
written, err := io.Copy(w, fileReader)
|
|
if err != nil {
|
|
return fmt.Errorf("error copying %s (%d bytes written): %v", innerPath, written, err)
|
|
}
|
|
|
|
return nil
|
|
})
|
|
|
|
if err != nil {
|
|
githubactions.Fatalf("Unable to create request body: %v", fmt.Errorf("%w", err))
|
|
}
|
|
}()
|
|
|
|
githubactions.Debugf("Calling node API...")
|
|
client := &http.Client{}
|
|
res, err := client.Do(req)
|
|
if err != nil {
|
|
githubactions.Fatalf(err.Error())
|
|
}
|
|
|
|
githubactions.Debugf("Reading response...")
|
|
resBody, err := io.ReadAll(res.Body)
|
|
if err != nil {
|
|
githubactions.Fatalf(err.Error())
|
|
}
|
|
|
|
githubactions.Debugf("Response: %v", string(resBody))
|
|
d := json.NewDecoder(res.Body)
|
|
for {
|
|
var ipfsAddResponse []AddResponse
|
|
if err := d.Decode(&ipfsAddResponse); err == io.EOF {
|
|
break
|
|
} else if err != nil {
|
|
githubactions.Warningf("Failed to unmarshal response: %v", fmt.Errorf("%w", err))
|
|
}
|
|
githubactions.Debugf("Unmarshaled response: %v", ipfsAddResponse)
|
|
}
|
|
}
|