more fuckingfixes
This commit is contained in:
parent
c294ce4cff
commit
3b9bf95247
@ -89,12 +89,15 @@ func main() {
|
|||||||
// Register API routes with /api prefix
|
// Register API routes with /api prefix
|
||||||
apiRouter := r.PathPrefix("/api").Subrouter()
|
apiRouter := r.PathPrefix("/api").Subrouter()
|
||||||
|
|
||||||
// Register tracker routes on main router (no /api prefix for BitTorrent compatibility)
|
// Register main API routes and get gateway instance first
|
||||||
api.RegisterTrackerRoutes(r, cfg, storageBackend)
|
|
||||||
|
|
||||||
// Register main API routes and get gateway instance
|
|
||||||
gatewayInstance = api.RegisterRoutes(apiRouter, cfg, storageBackend)
|
gatewayInstance = api.RegisterRoutes(apiRouter, cfg, storageBackend)
|
||||||
|
|
||||||
|
// Register tracker routes on main router (no /api prefix for BitTorrent compatibility)
|
||||||
|
wsTracker := api.RegisterTrackerRoutes(r, cfg, storageBackend, gatewayInstance)
|
||||||
|
if wsTracker != nil {
|
||||||
|
gatewayInstance.SetWebSocketTracker(wsTracker)
|
||||||
|
}
|
||||||
|
|
||||||
// Serve static files
|
// Serve static files
|
||||||
webFS := web.GetFS()
|
webFS := web.GetFS()
|
||||||
staticFS, _ := fs.Sub(webFS, "static")
|
staticFS, _ := fs.Sub(webFS, "static")
|
||||||
|
@ -15,6 +15,21 @@ import (
|
|||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// TrackerInterface defines methods needed from the tracker
|
||||||
|
type TrackerInterface interface {
|
||||||
|
GetStats() map[string]interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WebSocketTrackerInterface defines methods needed from the WebSocket tracker
|
||||||
|
type WebSocketTrackerInterface interface {
|
||||||
|
GetStats() map[string]interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DHTInterface defines methods needed from the DHT
|
||||||
|
type DHTInterface interface {
|
||||||
|
GetStats() map[string]interface{}
|
||||||
|
}
|
||||||
|
|
||||||
// GatewayInterface defines the methods needed from the gateway
|
// GatewayInterface defines the methods needed from the gateway
|
||||||
type GatewayInterface interface {
|
type GatewayInterface interface {
|
||||||
GetDB() *sql.DB
|
GetDB() *sql.DB
|
||||||
@ -23,6 +38,9 @@ type GatewayInterface interface {
|
|||||||
CleanupOrphanedChunks() (map[string]interface{}, error)
|
CleanupOrphanedChunks() (map[string]interface{}, error)
|
||||||
CleanupInactiveUsers(days int) (map[string]interface{}, error)
|
CleanupInactiveUsers(days int) (map[string]interface{}, error)
|
||||||
ReconstructTorrentFile(fileHash, fileName string) (string, error)
|
ReconstructTorrentFile(fileHash, fileName string) (string, error)
|
||||||
|
GetTrackerInstance() TrackerInterface
|
||||||
|
GetWebSocketTracker() WebSocketTrackerInterface
|
||||||
|
GetDHTNode() DHTInterface
|
||||||
}
|
}
|
||||||
|
|
||||||
// TranscodingManager interface for transcoding operations
|
// TranscodingManager interface for transcoding operations
|
||||||
@ -1243,11 +1261,35 @@ func (ah *AdminHandlers) gatherStreamingAnalytics(db *sql.DB) map[string]interfa
|
|||||||
func (ah *AdminHandlers) gatherP2PHealthMetrics() map[string]interface{} {
|
func (ah *AdminHandlers) gatherP2PHealthMetrics() map[string]interface{} {
|
||||||
p2p := make(map[string]interface{})
|
p2p := make(map[string]interface{})
|
||||||
|
|
||||||
// P2P health score calculation (mock implementation)
|
// Get real P2P stats from tracker instance
|
||||||
p2p["health_score"] = 87
|
if tracker := ah.gateway.GetTrackerInstance(); tracker != nil {
|
||||||
p2p["dht_node_count"] = 1249
|
trackerStats := tracker.GetStats()
|
||||||
p2p["webseed_hit_ratio"] = "91.2%"
|
if peers, ok := trackerStats["peers"]; ok {
|
||||||
p2p["torrent_completion_avg"] = "2.1 mins"
|
p2p["active_peers"] = peers
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get real DHT stats
|
||||||
|
if dht := ah.gateway.GetDHTNode(); dht != nil {
|
||||||
|
dhtStats := dht.GetStats()
|
||||||
|
if nodeCount, ok := dhtStats["routing_table_size"]; ok {
|
||||||
|
p2p["dht_node_count"] = nodeCount
|
||||||
|
}
|
||||||
|
if torrents, ok := dhtStats["torrents"]; ok {
|
||||||
|
p2p["dht_torrents"] = torrents
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get WebSocket tracker stats
|
||||||
|
if wsTracker := ah.gateway.GetWebSocketTracker(); wsTracker != nil {
|
||||||
|
wsStats := wsTracker.GetStats()
|
||||||
|
if swarms, ok := wsStats["swarms"]; ok {
|
||||||
|
p2p["websocket_swarms"] = swarms
|
||||||
|
}
|
||||||
|
if peers, ok := wsStats["peers"]; ok {
|
||||||
|
p2p["websocket_peers"] = peers
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return p2p
|
return p2p
|
||||||
}
|
}
|
||||||
@ -1256,12 +1298,14 @@ func (ah *AdminHandlers) gatherP2PHealthMetrics() map[string]interface{} {
|
|||||||
func (ah *AdminHandlers) gatherWebTorrentStats() map[string]interface{} {
|
func (ah *AdminHandlers) gatherWebTorrentStats() map[string]interface{} {
|
||||||
webtorrent := make(map[string]interface{})
|
webtorrent := make(map[string]interface{})
|
||||||
|
|
||||||
// WebTorrent peer statistics (mock data)
|
// Get real WebSocket tracker stats (WebTorrent uses WebSocket tracker)
|
||||||
webtorrent["peers_active"] = 45
|
if wsTracker := ah.gateway.GetWebSocketTracker(); wsTracker != nil {
|
||||||
webtorrent["browser_client_types"] = map[string]int{
|
wsStats := wsTracker.GetStats()
|
||||||
"Chrome": 60,
|
webtorrent["active_swarms"] = wsStats["swarms"]
|
||||||
"Firefox": 25,
|
webtorrent["connected_peers"] = wsStats["peers"]
|
||||||
"Safari": 15,
|
} else {
|
||||||
|
webtorrent["active_swarms"] = 0
|
||||||
|
webtorrent["connected_peers"] = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
return webtorrent
|
return webtorrent
|
||||||
|
@ -52,12 +52,13 @@ type UserStatsResponse struct {
|
|||||||
|
|
||||||
// UserFile represents a file in user's file list
|
// UserFile represents a file in user's file list
|
||||||
type UserFile struct {
|
type UserFile struct {
|
||||||
Hash string `json:"hash"`
|
Hash string `json:"hash"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Size int64 `json:"size"`
|
Size int64 `json:"size"`
|
||||||
StorageType string `json:"storage_type"`
|
StorageType string `json:"storage_type"`
|
||||||
AccessLevel string `json:"access_level"`
|
AccessLevel string `json:"access_level"`
|
||||||
UploadedAt string `json:"uploaded_at"`
|
UploadedAt string `json:"uploaded_at"`
|
||||||
|
TorrentInfoHash string `json:"torrent_info_hash,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// LoginHandler handles user authentication
|
// LoginHandler handles user authentication
|
||||||
@ -253,12 +254,13 @@ func (ah *AuthHandlers) UserFilesHandler(w http.ResponseWriter, r *http.Request)
|
|||||||
if files != nil {
|
if files != nil {
|
||||||
for _, file := range files {
|
for _, file := range files {
|
||||||
userFiles = append(userFiles, UserFile{
|
userFiles = append(userFiles, UserFile{
|
||||||
Hash: file.Hash,
|
Hash: file.Hash,
|
||||||
Name: file.OriginalName,
|
Name: file.OriginalName,
|
||||||
Size: file.Size,
|
Size: file.Size,
|
||||||
StorageType: file.StorageType,
|
StorageType: file.StorageType,
|
||||||
AccessLevel: file.AccessLevel,
|
AccessLevel: file.AccessLevel,
|
||||||
UploadedAt: file.CreatedAt.Format(time.RFC3339),
|
UploadedAt: file.CreatedAt.Format(time.RFC3339),
|
||||||
|
TorrentInfoHash: file.InfoHash,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -112,6 +112,8 @@ type Gateway struct {
|
|||||||
publicURL string
|
publicURL string
|
||||||
trackerInstance *tracker.Tracker
|
trackerInstance *tracker.Tracker
|
||||||
dhtBootstrap DHTBootstrap
|
dhtBootstrap DHTBootstrap
|
||||||
|
dhtNode *dht.DHTBootstrap // Add actual DHT instance
|
||||||
|
wsTracker *tracker.WebSocketTracker // Add WebSocket tracker instance
|
||||||
transcodingManager TranscodingManager
|
transcodingManager TranscodingManager
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -330,11 +332,14 @@ type ChunkInfo struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type UploadResponse struct {
|
type UploadResponse struct {
|
||||||
FileHash string `json:"file_hash"`
|
FileHash string `json:"file_hash"`
|
||||||
Message string `json:"message"`
|
Message string `json:"message"`
|
||||||
TorrentHash string `json:"torrent_hash,omitempty"`
|
TorrentHash string `json:"torrent_hash,omitempty"`
|
||||||
MagnetLink string `json:"magnet_link,omitempty"`
|
MagnetLink string `json:"magnet_link,omitempty"`
|
||||||
NostrEventID string `json:"nostr_event_id,omitempty"`
|
NostrEventID string `json:"nostr_event_id,omitempty"`
|
||||||
|
NIP71EventID string `json:"nip71_event_id,omitempty"`
|
||||||
|
StreamingURL string `json:"streaming_url,omitempty"`
|
||||||
|
HLSURL string `json:"hls_url,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewGateway(cfg *config.Config, storage *storage.Backend) *Gateway {
|
func NewGateway(cfg *config.Config, storage *storage.Backend) *Gateway {
|
||||||
@ -641,6 +646,39 @@ func (g *Gateway) GetAllTorrentHashes() []string {
|
|||||||
// SetDHTBootstrap sets the DHT bootstrap instance for torrent announcements
|
// SetDHTBootstrap sets the DHT bootstrap instance for torrent announcements
|
||||||
func (g *Gateway) SetDHTBootstrap(dhtBootstrap DHTBootstrap) {
|
func (g *Gateway) SetDHTBootstrap(dhtBootstrap DHTBootstrap) {
|
||||||
g.dhtBootstrap = dhtBootstrap
|
g.dhtBootstrap = dhtBootstrap
|
||||||
|
// Also store the actual DHT node instance
|
||||||
|
if dhtBootstrapConcrete, ok := dhtBootstrap.(*dht.DHTBootstrap); ok {
|
||||||
|
g.dhtNode = dhtBootstrapConcrete
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetWebSocketTracker sets the WebSocket tracker instance for stats collection
|
||||||
|
func (g *Gateway) SetWebSocketTracker(wsTracker *tracker.WebSocketTracker) {
|
||||||
|
g.wsTracker = wsTracker
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetTrackerInstance returns the tracker instance for admin interface
|
||||||
|
func (g *Gateway) GetTrackerInstance() admin.TrackerInterface {
|
||||||
|
if g.trackerInstance == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return g.trackerInstance
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetWebSocketTracker returns the WebSocket tracker instance for admin interface
|
||||||
|
func (g *Gateway) GetWebSocketTracker() admin.WebSocketTrackerInterface {
|
||||||
|
if g.wsTracker == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return g.wsTracker
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetDHTNode returns the DHT node instance for admin interface
|
||||||
|
func (g *Gateway) GetDHTNode() admin.DHTInterface {
|
||||||
|
if g.dhtNode == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return g.dhtNode
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *Gateway) UploadHandler(w http.ResponseWriter, r *http.Request) {
|
func (g *Gateway) UploadHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
@ -818,6 +856,7 @@ func (g *Gateway) handleBlobUpload(w http.ResponseWriter, r *http.Request, file
|
|||||||
|
|
||||||
// Publish to Nostr for blobs
|
// Publish to Nostr for blobs
|
||||||
var nostrEventID string
|
var nostrEventID string
|
||||||
|
var nip71EventID string
|
||||||
if g.nostrPublisher != nil {
|
if g.nostrPublisher != nil {
|
||||||
eventData := nostr.TorrentEventData{
|
eventData := nostr.TorrentEventData{
|
||||||
Title: fmt.Sprintf("File: %s", fileName),
|
Title: fmt.Sprintf("File: %s", fileName),
|
||||||
@ -859,6 +898,7 @@ func (g *Gateway) handleBlobUpload(w http.ResponseWriter, r *http.Request, file
|
|||||||
fmt.Printf("Warning: Failed to publish NIP-71 video event: %v\n", err)
|
fmt.Printf("Warning: Failed to publish NIP-71 video event: %v\n", err)
|
||||||
} else {
|
} else {
|
||||||
fmt.Printf("Published NIP-71 video event: %s\n", nip71Event.ID)
|
fmt.Printf("Published NIP-71 video event: %s\n", nip71Event.ID)
|
||||||
|
nip71EventID = nip71Event.ID
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -875,6 +915,13 @@ func (g *Gateway) handleBlobUpload(w http.ResponseWriter, r *http.Request, file
|
|||||||
FileHash: metadata.Hash,
|
FileHash: metadata.Hash,
|
||||||
Message: "File uploaded successfully as blob",
|
Message: "File uploaded successfully as blob",
|
||||||
NostrEventID: nostrEventID,
|
NostrEventID: nostrEventID,
|
||||||
|
NIP71EventID: nip71EventID,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add streaming URL if it's a video
|
||||||
|
if streamingInfo != nil {
|
||||||
|
response.StreamingURL = fmt.Sprintf("%s/api/stream/%s", g.getBaseURL(), metadata.Hash)
|
||||||
|
response.HLSURL = fmt.Sprintf("%s/api/stream/%s/playlist.m3u8", g.getBaseURL(), metadata.Hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
@ -1052,6 +1099,7 @@ func (g *Gateway) handleTorrentUpload(w http.ResponseWriter, r *http.Request, fi
|
|||||||
|
|
||||||
// Publish to Nostr
|
// Publish to Nostr
|
||||||
var nostrEventID string
|
var nostrEventID string
|
||||||
|
var nip71EventID string
|
||||||
if g.nostrPublisher != nil {
|
if g.nostrPublisher != nil {
|
||||||
eventData := nostr.TorrentEventData{
|
eventData := nostr.TorrentEventData{
|
||||||
Title: fmt.Sprintf("Torrent: %s", fileName),
|
Title: fmt.Sprintf("Torrent: %s", fileName),
|
||||||
@ -1096,6 +1144,7 @@ func (g *Gateway) handleTorrentUpload(w http.ResponseWriter, r *http.Request, fi
|
|||||||
fmt.Printf("Warning: Failed to publish NIP-71 video event: %v\n", err)
|
fmt.Printf("Warning: Failed to publish NIP-71 video event: %v\n", err)
|
||||||
} else {
|
} else {
|
||||||
fmt.Printf("Published NIP-71 video event: %s\n", nip71Event.ID)
|
fmt.Printf("Published NIP-71 video event: %s\n", nip71Event.ID)
|
||||||
|
nip71EventID = nip71Event.ID
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1124,6 +1173,13 @@ func (g *Gateway) handleTorrentUpload(w http.ResponseWriter, r *http.Request, fi
|
|||||||
TorrentHash: torrentInfo.InfoHash,
|
TorrentHash: torrentInfo.InfoHash,
|
||||||
MagnetLink: torrentInfo.Magnet,
|
MagnetLink: torrentInfo.Magnet,
|
||||||
NostrEventID: nostrEventID,
|
NostrEventID: nostrEventID,
|
||||||
|
NIP71EventID: nip71EventID,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add streaming URL if it's a video
|
||||||
|
if streamingInfo != nil {
|
||||||
|
response.StreamingURL = fmt.Sprintf("%s/api/stream/%s", g.getBaseURL(), metadata.Hash)
|
||||||
|
response.HLSURL = fmt.Sprintf("%s/api/stream/%s/playlist.m3u8", g.getBaseURL(), metadata.Hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
@ -2247,24 +2303,37 @@ func (g *Gateway) P2PStatsHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
stats := make(map[string]interface{})
|
stats := make(map[string]interface{})
|
||||||
|
|
||||||
// Tracker statistics
|
// BitTorrent tracker statistics - get real stats from tracker instance
|
||||||
if g.trackerInstance != nil {
|
if g.trackerInstance != nil {
|
||||||
trackerStats := make(map[string]interface{})
|
stats["tracker"] = g.trackerInstance.GetStats()
|
||||||
trackerStats["status"] = "active"
|
|
||||||
trackerStats["uptime_seconds"] = time.Since(time.Now()).Seconds() // Placeholder
|
|
||||||
|
|
||||||
stats["tracker"] = trackerStats
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// DHT statistics
|
// WebSocket tracker statistics - get real stats from WebSocket tracker
|
||||||
if g.dhtBootstrap != nil {
|
if g.wsTracker != nil {
|
||||||
dhtStats := make(map[string]interface{})
|
stats["websocket_tracker"] = g.wsTracker.GetStats()
|
||||||
dhtStats["status"] = "active"
|
}
|
||||||
dhtStats["routing_table_size"] = "N/A" // Would need DHT interface methods
|
|
||||||
dhtStats["active_searches"] = 0
|
// DHT statistics - get real stats from DHT node
|
||||||
dhtStats["stored_values"] = 0
|
if g.dhtNode != nil {
|
||||||
|
// Get stats from the actual DHT node within the bootstrap
|
||||||
stats["dht"] = dhtStats
|
if dhtNode := g.dhtNode.GetNode(); dhtNode != nil {
|
||||||
|
dhtStats := dhtNode.GetStats()
|
||||||
|
stats["dht"] = map[string]interface{}{
|
||||||
|
"status": "active",
|
||||||
|
"packets_sent": dhtStats.PacketsSent,
|
||||||
|
"packets_received": dhtStats.PacketsReceived,
|
||||||
|
"nodes_in_table": dhtStats.NodesInTable,
|
||||||
|
"stored_items": dhtStats.StoredItems,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if g.dhtBootstrap != nil {
|
||||||
|
// Fallback to placeholder if we don't have the node reference yet
|
||||||
|
stats["dht"] = map[string]interface{}{
|
||||||
|
"status": "active",
|
||||||
|
"routing_table_size": "N/A",
|
||||||
|
"active_searches": 0,
|
||||||
|
"stored_values": 0,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// WebSeed statistics (from our enhanced implementation)
|
// WebSeed statistics (from our enhanced implementation)
|
||||||
@ -2302,7 +2371,8 @@ func (g *Gateway) P2PStatsHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
stats["coordination"] = map[string]interface{}{
|
stats["coordination"] = map[string]interface{}{
|
||||||
"integration_active": g.trackerInstance != nil && g.dhtBootstrap != nil,
|
"integration_active": g.trackerInstance != nil && g.dhtBootstrap != nil,
|
||||||
"webseed_enabled": true,
|
"webseed_enabled": true,
|
||||||
"total_components": 3, // Tracker + DHT + WebSeed
|
"websocket_enabled": g.wsTracker != nil,
|
||||||
|
"total_components": 4, // Tracker + WebSocket Tracker + DHT + WebSeed
|
||||||
"timestamp": time.Now().Format(time.RFC3339),
|
"timestamp": time.Now().Format(time.RFC3339),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4141,12 +4211,11 @@ func systemStatsHandler(gateway *Gateway, storage *storage.Backend, trackerInsta
|
|||||||
}
|
}
|
||||||
|
|
||||||
// RegisterTrackerRoutes registers tracker endpoints on the main router
|
// RegisterTrackerRoutes registers tracker endpoints on the main router
|
||||||
func RegisterTrackerRoutes(r *mux.Router, cfg *config.Config, storage *storage.Backend) {
|
func RegisterTrackerRoutes(r *mux.Router, cfg *config.Config, storage *storage.Backend, gateway *Gateway) *tracker.WebSocketTracker {
|
||||||
if !cfg.IsServiceEnabled("tracker") {
|
if !cfg.IsServiceEnabled("tracker") {
|
||||||
return
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
gateway := NewGateway(cfg, storage)
|
|
||||||
trackerInstance := tracker.NewTracker(&cfg.Tracker, gateway)
|
trackerInstance := tracker.NewTracker(&cfg.Tracker, gateway)
|
||||||
announceHandler := tracker.NewAnnounceHandler(trackerInstance)
|
announceHandler := tracker.NewAnnounceHandler(trackerInstance)
|
||||||
scrapeHandler := tracker.NewScrapeHandler(trackerInstance)
|
scrapeHandler := tracker.NewScrapeHandler(trackerInstance)
|
||||||
@ -4161,6 +4230,7 @@ func RegisterTrackerRoutes(r *mux.Router, cfg *config.Config, storage *storage.B
|
|||||||
r.HandleFunc("/tracker", wsTracker.HandleWS).Methods("GET") // WebSocket upgrade
|
r.HandleFunc("/tracker", wsTracker.HandleWS).Methods("GET") // WebSocket upgrade
|
||||||
|
|
||||||
log.Printf("Registered BitTorrent tracker endpoints with WebSocket support")
|
log.Printf("Registered BitTorrent tracker endpoints with WebSocket support")
|
||||||
|
return wsTracker
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetGatewayFromRoutes returns a gateway instance for DHT integration
|
// GetGatewayFromRoutes returns a gateway instance for DHT integration
|
||||||
@ -4244,7 +4314,15 @@ func (g *Gateway) generateWebTorrentMagnet(metadata *FileMetadata) string {
|
|||||||
"wss://tracker.btorrent.xyz",
|
"wss://tracker.btorrent.xyz",
|
||||||
"wss://tracker.openwebtorrent.com",
|
"wss://tracker.openwebtorrent.com",
|
||||||
"wss://tracker.webtorrent.dev",
|
"wss://tracker.webtorrent.dev",
|
||||||
fmt.Sprintf("wss://localhost:%d/tracker", g.config.Gateway.Port), // Our WebSocket tracker
|
}
|
||||||
|
|
||||||
|
// Add our WebSocket tracker using public URL
|
||||||
|
if g.publicURL != "" && g.publicURL != "http://localhost" {
|
||||||
|
// Extract domain from public URL and create WebSocket URL
|
||||||
|
publicURL := strings.TrimPrefix(g.publicURL, "http://")
|
||||||
|
publicURL = strings.TrimPrefix(publicURL, "https://")
|
||||||
|
publicDomain := strings.Split(publicURL, ":")[0] // Remove port if present
|
||||||
|
wsTrackers = append(wsTrackers, fmt.Sprintf("wss://%s/tracker", publicDomain))
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tracker := range wsTrackers {
|
for _, tracker := range wsTrackers {
|
||||||
|
@ -47,6 +47,22 @@ type NodeInfo struct {
|
|||||||
Reputation int `json:"reputation"`
|
Reputation int `json:"reputation"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetNode returns the underlying DHT node instance
|
||||||
|
func (db *DHTBootstrap) GetNode() *DHT {
|
||||||
|
return db.node
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetStats returns DHT bootstrap statistics
|
||||||
|
func (d *DHTBootstrap) GetStats() map[string]interface{} {
|
||||||
|
d.mutex.RLock()
|
||||||
|
defer d.mutex.RUnlock()
|
||||||
|
return map[string]interface{}{
|
||||||
|
"routing_table_size": len(d.knownNodes),
|
||||||
|
"torrents": len(d.torrents),
|
||||||
|
"bootstrap_nodes": len(d.config.BootstrapNodes),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TorrentAnnounce represents a DHT torrent announcement
|
// TorrentAnnounce represents a DHT torrent announcement
|
||||||
type TorrentAnnounce struct {
|
type TorrentAnnounce struct {
|
||||||
InfoHash string `json:"info_hash"`
|
InfoHash string `json:"info_hash"`
|
||||||
|
@ -243,4 +243,25 @@ func (wt *WebSocketTracker) cleanupExpiredPeers() {
|
|||||||
}
|
}
|
||||||
swarm.mu.Unlock()
|
swarm.mu.Unlock()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetStats returns WebSocket tracker statistics
|
||||||
|
func (wt *WebSocketTracker) GetStats() map[string]interface{} {
|
||||||
|
wt.mu.RLock()
|
||||||
|
defer wt.mu.RUnlock()
|
||||||
|
|
||||||
|
totalPeers := 0
|
||||||
|
totalSwarms := len(wt.swarms)
|
||||||
|
|
||||||
|
for _, swarm := range wt.swarms {
|
||||||
|
swarm.mu.RLock()
|
||||||
|
totalPeers += len(swarm.peers)
|
||||||
|
swarm.mu.RUnlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
return map[string]interface{}{
|
||||||
|
"total_swarms": totalSwarms,
|
||||||
|
"total_peers": totalPeers,
|
||||||
|
"status": "active",
|
||||||
|
}
|
||||||
}
|
}
|
@ -1612,16 +1612,23 @@
|
|||||||
|
|
||||||
async function shareFile(hash) {
|
async function shareFile(hash) {
|
||||||
console.log('DEBUG: shareFile function called!', hash);
|
console.log('DEBUG: shareFile function called!', hash);
|
||||||
console.log('userFiles array:', userFiles);
|
|
||||||
const file = userFiles.find(f => f.hash === hash);
|
const file = userFiles.find(f => f.hash === hash);
|
||||||
console.log('Found file:', file);
|
|
||||||
if (!file) {
|
if (!file) {
|
||||||
console.error('File not found in userFiles array');
|
console.error('File not found in userFiles array');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const baseUrl = window.location.origin;
|
const baseUrl = window.location.origin;
|
||||||
const magnetHash = file.torrent_info?.InfoHash || hash;
|
|
||||||
|
// Use torrent info hash for magnet if available, otherwise use file hash
|
||||||
|
let magnetHash = hash;
|
||||||
|
if (file.torrent_info_hash) {
|
||||||
|
magnetHash = file.torrent_info_hash;
|
||||||
|
console.log('Using torrent InfoHash for magnet:', magnetHash);
|
||||||
|
} else {
|
||||||
|
console.log('No torrent InfoHash found, using file hash:', magnetHash);
|
||||||
|
}
|
||||||
|
|
||||||
const links = {
|
const links = {
|
||||||
direct: `${baseUrl}/api/download/${hash}`,
|
direct: `${baseUrl}/api/download/${hash}`,
|
||||||
torrent: `${baseUrl}/api/torrent/${hash}`,
|
torrent: `${baseUrl}/api/torrent/${hash}`,
|
||||||
|
BIN
torrent-gateway
BIN
torrent-gateway
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user