mirror of
https://github.com/DeBrosOfficial/network.git
synced 2026-01-30 05:23:03 +00:00
did some fixes
This commit is contained in:
parent
c2071586f8
commit
0a7e3ba3c7
@ -32,6 +32,11 @@ func TestDomainRouting_BasicRouting(t *testing.T) {
|
|||||||
// Wait for deployment to be active
|
// Wait for deployment to be active
|
||||||
time.Sleep(2 * time.Second)
|
time.Sleep(2 * time.Second)
|
||||||
|
|
||||||
|
// Get deployment details for debugging
|
||||||
|
deployment := GetDeployment(t, env, deploymentID)
|
||||||
|
t.Logf("Deployment created: ID=%s, CID=%s, Name=%s, Status=%s",
|
||||||
|
deploymentID, deployment["content_cid"], deployment["name"], deployment["status"])
|
||||||
|
|
||||||
t.Run("Standard domain resolves", func(t *testing.T) {
|
t.Run("Standard domain resolves", func(t *testing.T) {
|
||||||
// Domain format: {deploymentName}.orama.network
|
// Domain format: {deploymentName}.orama.network
|
||||||
domain := fmt.Sprintf("%s.orama.network", deploymentName)
|
domain := fmt.Sprintf("%s.orama.network", deploymentName)
|
||||||
|
|||||||
@ -1,11 +1,14 @@
|
|||||||
package deployments
|
package deployments
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"archive/tar"
|
||||||
|
"compress/gzip"
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
@ -88,8 +91,23 @@ func (h *StaticDeploymentHandler) HandleUpload(w http.ResponseWriter, r *http.Re
|
|||||||
zap.Int64("size", header.Size),
|
zap.Int64("size", header.Size),
|
||||||
)
|
)
|
||||||
|
|
||||||
// Upload to IPFS
|
// Extract tarball to temporary directory
|
||||||
addResp, err := h.ipfsClient.Add(ctx, file, header.Filename)
|
tmpDir, err := os.MkdirTemp("", "static-deploy-*")
|
||||||
|
if err != nil {
|
||||||
|
h.logger.Error("Failed to create temp directory", zap.Error(err))
|
||||||
|
http.Error(w, "Failed to process tarball", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer os.RemoveAll(tmpDir)
|
||||||
|
|
||||||
|
if err := extractTarball(file, tmpDir); err != nil {
|
||||||
|
h.logger.Error("Failed to extract tarball", zap.Error(err))
|
||||||
|
http.Error(w, "Failed to extract tarball", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Upload extracted directory to IPFS
|
||||||
|
addResp, err := h.ipfsClient.AddDirectory(ctx, tmpDir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
h.logger.Error("Failed to upload to IPFS", zap.Error(err))
|
h.logger.Error("Failed to upload to IPFS", zap.Error(err))
|
||||||
http.Error(w, "Failed to upload content", http.StatusInternalServerError)
|
http.Error(w, "Failed to upload content", http.StatusInternalServerError)
|
||||||
@ -232,3 +250,61 @@ func detectContentType(filename string) string {
|
|||||||
|
|
||||||
return "application/octet-stream"
|
return "application/octet-stream"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// extractTarball extracts a .tar.gz file to the specified directory
|
||||||
|
func extractTarball(reader io.Reader, destDir string) error {
|
||||||
|
gzr, err := gzip.NewReader(reader)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to create gzip reader: %w", err)
|
||||||
|
}
|
||||||
|
defer gzr.Close()
|
||||||
|
|
||||||
|
tr := tar.NewReader(gzr)
|
||||||
|
|
||||||
|
for {
|
||||||
|
header, err := tr.Next()
|
||||||
|
if err == io.EOF {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to read tar header: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build target path
|
||||||
|
target := filepath.Join(destDir, header.Name)
|
||||||
|
|
||||||
|
// Prevent path traversal - clean both paths before comparing
|
||||||
|
cleanDest := filepath.Clean(destDir) + string(os.PathSeparator)
|
||||||
|
cleanTarget := filepath.Clean(target)
|
||||||
|
if !strings.HasPrefix(cleanTarget, cleanDest) && cleanTarget != filepath.Clean(destDir) {
|
||||||
|
return fmt.Errorf("invalid file path in tarball: %s", header.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
switch header.Typeflag {
|
||||||
|
case tar.TypeDir:
|
||||||
|
if err := os.MkdirAll(target, 0755); err != nil {
|
||||||
|
return fmt.Errorf("failed to create directory: %w", err)
|
||||||
|
}
|
||||||
|
case tar.TypeReg:
|
||||||
|
// Create parent directory if needed
|
||||||
|
if err := os.MkdirAll(filepath.Dir(target), 0755); err != nil {
|
||||||
|
return fmt.Errorf("failed to create parent directory: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create file
|
||||||
|
f, err := os.OpenFile(target, os.O_CREATE|os.O_RDWR, os.FileMode(header.Mode))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to create file: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := io.Copy(f, tr); err != nil {
|
||||||
|
f.Close()
|
||||||
|
return fmt.Errorf("failed to write file: %w", err)
|
||||||
|
}
|
||||||
|
f.Close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@ -10,6 +10,8 @@ import (
|
|||||||
"mime/multipart"
|
"mime/multipart"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -19,6 +21,7 @@ import (
|
|||||||
// IPFSClient defines the interface for IPFS operations
|
// IPFSClient defines the interface for IPFS operations
|
||||||
type IPFSClient interface {
|
type IPFSClient interface {
|
||||||
Add(ctx context.Context, reader io.Reader, name string) (*AddResponse, error)
|
Add(ctx context.Context, reader io.Reader, name string) (*AddResponse, error)
|
||||||
|
AddDirectory(ctx context.Context, dirPath string) (*AddResponse, error)
|
||||||
Pin(ctx context.Context, cid string, name string, replicationFactor int) (*PinResponse, error)
|
Pin(ctx context.Context, cid string, name string, replicationFactor int) (*PinResponse, error)
|
||||||
PinStatus(ctx context.Context, cid string) (*PinStatus, error)
|
PinStatus(ctx context.Context, cid string) (*PinStatus, error)
|
||||||
Get(ctx context.Context, cid string, ipfsAPIURL string) (io.ReadCloser, error)
|
Get(ctx context.Context, cid string, ipfsAPIURL string) (io.ReadCloser, error)
|
||||||
@ -236,6 +239,104 @@ func (c *Client) Add(ctx context.Context, reader io.Reader, name string) (*AddRe
|
|||||||
return &last, nil
|
return &last, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AddDirectory adds all files in a directory to IPFS and returns the root directory CID
|
||||||
|
func (c *Client) AddDirectory(ctx context.Context, dirPath string) (*AddResponse, error) {
|
||||||
|
var buf bytes.Buffer
|
||||||
|
writer := multipart.NewWriter(&buf)
|
||||||
|
|
||||||
|
// Walk directory and add all files to multipart request
|
||||||
|
var totalSize int64
|
||||||
|
err := filepath.Walk(dirPath, func(path string, info os.FileInfo, err error) error {
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip directories
|
||||||
|
if info.IsDir() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get relative path
|
||||||
|
relPath, err := filepath.Rel(dirPath, path)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to get relative path: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read file
|
||||||
|
data, err := os.ReadFile(path)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to read file %s: %w", path, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
totalSize += int64(len(data))
|
||||||
|
|
||||||
|
// Add file to multipart
|
||||||
|
part, err := writer.CreateFormFile("file", relPath)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to create form file: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := part.Write(data); err != nil {
|
||||||
|
return fmt.Errorf("failed to write file data: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := writer.Close(); err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to close writer: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add with wrap-in-directory to create a root directory node
|
||||||
|
apiURL := c.apiURL + "/add?wrap-in-directory=true"
|
||||||
|
|
||||||
|
req, err := http.NewRequestWithContext(ctx, "POST", apiURL, &buf)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to create add request: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
req.Header.Set("Content-Type", writer.FormDataContentType())
|
||||||
|
|
||||||
|
resp, err := c.httpClient.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("add request failed: %w", err)
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
if resp.StatusCode != http.StatusOK {
|
||||||
|
body, _ := io.ReadAll(resp.Body)
|
||||||
|
return nil, fmt.Errorf("add failed with status %d: %s", resp.StatusCode, string(body))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read NDJSON responses - the last one will be the root directory
|
||||||
|
dec := json.NewDecoder(resp.Body)
|
||||||
|
var last AddResponse
|
||||||
|
|
||||||
|
for {
|
||||||
|
var chunk AddResponse
|
||||||
|
if err := dec.Decode(&chunk); err != nil {
|
||||||
|
if errors.Is(err, io.EOF) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("failed to decode add response: %w", err)
|
||||||
|
}
|
||||||
|
last = chunk
|
||||||
|
}
|
||||||
|
|
||||||
|
if last.Cid == "" {
|
||||||
|
return nil, fmt.Errorf("no CID returned from IPFS")
|
||||||
|
}
|
||||||
|
|
||||||
|
return &AddResponse{
|
||||||
|
Cid: last.Cid,
|
||||||
|
Size: totalSize,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
// Pin pins a CID with specified replication factor
|
// Pin pins a CID with specified replication factor
|
||||||
// IPFS Cluster expects pin options (including name) as query parameters, not in JSON body
|
// IPFS Cluster expects pin options (including name) as query parameters, not in JSON body
|
||||||
func (c *Client) Pin(ctx context.Context, cid string, name string, replicationFactor int) (*PinResponse, error) {
|
func (c *Client) Pin(ctx context.Context, cid string, name string, replicationFactor int) (*PinResponse, error) {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user