Skip to content

Commit 96510d8

Browse files
committed
fix(sandbox): resolve image and file browsing issues
1 parent 84146e0 commit 96510d8

File tree

8 files changed

+82
-23
lines changed

8 files changed

+82
-23
lines changed

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
build/bin
22
node_modules
33
frontend/dist
4-
.DS_Store
4+
.DS_Store
5+
sign-and-notarize.sh

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -81,8 +81,8 @@ wails dev
8181

8282
The application will start with:
8383
- Main window with React app
84-
- Development server at http://localhost:34115 (for testing Go methods in browser)
85-
- Local file server at http://localhost:34116 (for generated assets)
84+
- Development server at http://127.0.0.1:34115 (for testing Go methods in browser)
85+
- Local file server at http://127.0.0.1:34116 (for generated assets)
8686

8787
### Build
8888

@@ -176,7 +176,7 @@ visionflow/
176176
- **Service Layer First**: Implement logic in `service/` first, then expose through `binding/`
177177
- **Wails Bindings**: Never manually edit `frontend/wailsjs/go/` - they are auto-generated
178178
- **Node Execution**: Use `useNodeRun` Hook with `runTrigger` UUID to manage state
179-
- **Asset Access**: Frontend accesses generated files via `http://localhost:34116/{filename}`
179+
- **Asset Access**: Frontend accesses generated files via `http://127.0.0.1:34116/{filename}`
180180

181181
## 🤝 Contributing
182182

README.zh-CN.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -81,8 +81,8 @@ wails dev
8181

8282
应用将启动并包含:
8383
- 带有 React 应用的主窗口
84-
- 开发服务器 http://localhost:34115(用于浏览器测试 Go 方法)
85-
- 本地文件服务器 http://localhost:34116(用于生成的资源)
84+
- 开发服务器 http://127.0.0.1:34115(用于浏览器测试 Go 方法)
85+
- 本地文件服务器 http://127.0.0.1:34116(用于生成的资源)
8686

8787
### 构建
8888

@@ -176,7 +176,7 @@ visionflow/
176176
- **服务层优先**:先在 `service/` 中实现逻辑,再通过 `binding/` 暴露
177177
- **Wails 绑定**:永远不要手动编辑 `frontend/wailsjs/go/` - 它们是自动生成的
178178
- **节点执行**:使用 `useNodeRun` Hook,通过 `runTrigger` UUID 管理状态
179-
- **资源访问**:前端使用 `http://localhost:34116/{filename}` 访问生成的文件
179+
- **资源访问**:前端使用 `http://127.0.0.1:34116/{filename}` 访问生成的文件
180180

181181
## 🤝 贡献
182182

binding/ai/service.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -316,5 +316,5 @@ func (s *Service) processContent(projectID int, data []byte, b64 string, url str
316316
}
317317
}
318318

319-
return fmt.Sprintf("http://localhost:34116/%s", filename), nil
319+
return fmt.Sprintf("http://127.0.0.1:34116/%s", filename), nil
320320
}

binding/database/service.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ func (s *Service) ListAssets(projectID int) ([]db.Asset, error) {
5858
return nil, err
5959
}
6060
for i := range assets {
61-
assets[i].URL = fmt.Sprintf("http://localhost:34116/%s", assets[i].Path)
61+
assets[i].URL = fmt.Sprintf("http://127.0.0.1:34116/%s", assets[i].Path)
6262
}
6363
return assets, nil
6464
}

build/darwin/Info.plist

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,13 @@
2121
<string>10.13.0</string>
2222
<key>NSHighResolutionCapable</key>
2323
<string>true</string>
24+
<key>NSAppTransportSecurity</key>
25+
<dict>
26+
<key>NSAllowsLocalNetworking</key>
27+
<true/>
28+
<key>NSAllowsArbitraryLoads</key>
29+
<true/>
30+
</dict>
2431
<key>NSHumanReadableCopyright</key>
2532
<string>{{.Info.Copyright}}</string>
2633
{{if .Info.FileAssociations}}

main.go

Lines changed: 64 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,13 @@ package main
33
import (
44
"embed"
55
"fmt"
6+
"io"
7+
"mime"
68
"net/http"
9+
"os"
10+
"path/filepath"
11+
"strconv"
12+
"strings"
713

814
bindingAI "visionflow/binding/ai"
915
bindingApp "visionflow/binding/app"
@@ -32,27 +38,72 @@ func startFileServer() {
3238
return
3339
}
3440

35-
fs := http.FileServer(http.Dir(genDir))
36-
37-
// CORS wrapper
3841
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
39-
w.Header().Set("Access-Control-Allow-Origin", "*")
40-
w.Header().Set("Access-Control-Allow-Methods", "GET, OPTIONS")
41-
w.Header().Set("Access-Control-Allow-Headers", "*")
42-
4342
if r.Method == "OPTIONS" {
43+
w.Header().Set("Access-Control-Allow-Origin", "*")
44+
w.Header().Set("Access-Control-Allow-Methods", "GET, OPTIONS")
45+
w.Header().Set("Access-Control-Allow-Headers", "*")
4446
w.WriteHeader(http.StatusOK)
4547
return
4648
}
4749

48-
fmt.Printf("[FileServer] Request: %s\n", r.URL.Path)
49-
fs.ServeHTTP(w, r)
50+
filePath := filepath.Join(genDir, r.URL.Path)
51+
file, err := os.Open(filePath)
52+
if err != nil {
53+
http.NotFound(w, r)
54+
return
55+
}
56+
defer file.Close()
57+
58+
fileInfo, err := file.Stat()
59+
if err != nil {
60+
http.Error(w, "Error getting file info", http.StatusInternalServerError)
61+
return
62+
}
63+
64+
fileSize := fileInfo.Size()
65+
contentType := mime.TypeByExtension(filepath.Ext(filePath))
66+
if contentType == "" {
67+
contentType = "application/octet-stream"
68+
}
69+
70+
w.Header().Set("Access-Control-Allow-Origin", "*")
71+
w.Header().Set("Content-Type", contentType)
72+
w.Header().Set("Accept-Ranges", "bytes")
73+
74+
// Handle Range request
75+
rangeHeader := r.Header.Get("Range")
76+
if rangeHeader != "" {
77+
ranges := strings.TrimPrefix(rangeHeader, "bytes=")
78+
parts := strings.Split(ranges, "-")
79+
80+
start, _ := strconv.ParseInt(parts[0], 10, 64)
81+
end := fileSize - 1
82+
if len(parts) > 1 && parts[1] != "" {
83+
end, _ = strconv.ParseInt(parts[1], 10, 64)
84+
}
85+
86+
if start > end || start < 0 || end >= fileSize {
87+
w.WriteHeader(http.StatusRequestedRangeNotSatisfiable)
88+
return
89+
}
90+
91+
contentLength := end - start + 1
92+
w.Header().Set("Content-Range", fmt.Sprintf("bytes %d-%d/%d", start, end, fileSize))
93+
w.Header().Set("Content-Length", strconv.FormatInt(contentLength, 10))
94+
w.WriteHeader(http.StatusPartialContent)
95+
96+
file.Seek(start, 0)
97+
io.CopyN(w, file, contentLength)
98+
} else {
99+
w.Header().Set("Content-Length", strconv.FormatInt(fileSize, 10))
100+
buffer := make([]byte, 32*1024)
101+
io.CopyBuffer(w, file, buffer)
102+
}
50103
})
51104

52-
fmt.Println("Starting local file server on :34116 serving", genDir)
53-
if err := http.ListenAndServe(":34116", handler); err != nil {
54-
fmt.Println("Error starting file server:", err)
55-
}
105+
fmt.Println("Starting local file server on 127.0.0.1:34116 serving", genDir)
106+
http.ListenAndServe("127.0.0.1:34116", handler)
56107
}
57108

58109
func main() {

wails.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
"info": {
1414
"companyName": "MiaoMint",
1515
"productName": "VisionFlow",
16-
"productVersion": "0.0.2",
16+
"productVersion": "0.0.3",
1717
"copyright": "Copyright © 2026 MiaoMint. All rights reserved.",
1818
"comments": "VisionFlow - Visual AI Workflow Builder"
1919
}

0 commit comments

Comments
 (0)