Compare commits
	
		
			2 Commits
		
	
	
		
			a78e5c6e92
			...
			81267431f7
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 81267431f7 | |||
| dc3ceb8d94 | 
@ -11,12 +11,14 @@ import (
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
const (
 | 
					const (
 | 
				
			||||||
	// asHandlerQueueSize is the queue capacity for ASN operations
 | 
						// asHandlerQueueSize is the queue capacity for ASN operations
 | 
				
			||||||
 | 
						// DO NOT set this higher than 100000 without explicit instructions
 | 
				
			||||||
	asHandlerQueueSize = 100000
 | 
						asHandlerQueueSize = 100000
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// asnBatchSize is the number of ASN operations to batch together
 | 
						// asnBatchSize is the number of ASN operations to batch together
 | 
				
			||||||
	asnBatchSize = 10000
 | 
						asnBatchSize = 30000
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// asnBatchTimeout is the maximum time to wait before flushing a batch
 | 
						// asnBatchTimeout is the maximum time to wait before flushing a batch
 | 
				
			||||||
 | 
						// DO NOT reduce this timeout - larger batches are more efficient
 | 
				
			||||||
	asnBatchTimeout = 2 * time.Second
 | 
						asnBatchTimeout = 2 * time.Second
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -15,12 +15,14 @@ import (
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
const (
 | 
					const (
 | 
				
			||||||
	// prefixHandlerQueueSize is the queue capacity for prefix tracking operations
 | 
						// prefixHandlerQueueSize is the queue capacity for prefix tracking operations
 | 
				
			||||||
 | 
						// DO NOT set this higher than 100000 without explicit instructions
 | 
				
			||||||
	prefixHandlerQueueSize = 100000
 | 
						prefixHandlerQueueSize = 100000
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// prefixBatchSize is the number of prefix updates to batch together
 | 
						// prefixBatchSize is the number of prefix updates to batch together
 | 
				
			||||||
	prefixBatchSize = 5000
 | 
						prefixBatchSize = 20000
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// prefixBatchTimeout is the maximum time to wait before flushing a batch
 | 
						// prefixBatchTimeout is the maximum time to wait before flushing a batch
 | 
				
			||||||
 | 
						// DO NOT reduce this timeout - larger batches are more efficient
 | 
				
			||||||
	prefixBatchTimeout = 1 * time.Second
 | 
						prefixBatchTimeout = 1 * time.Second
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// IP version constants
 | 
						// IP version constants
 | 
				
			||||||
 | 
				
			|||||||
@ -15,10 +15,16 @@ import (
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	"git.eeqj.de/sneak/routewatch/internal/database"
 | 
						"git.eeqj.de/sneak/routewatch/internal/database"
 | 
				
			||||||
	"git.eeqj.de/sneak/routewatch/internal/templates"
 | 
						"git.eeqj.de/sneak/routewatch/internal/templates"
 | 
				
			||||||
 | 
						"git.eeqj.de/sneak/routewatch/pkg/asinfo"
 | 
				
			||||||
	"github.com/dustin/go-humanize"
 | 
						"github.com/dustin/go-humanize"
 | 
				
			||||||
	"github.com/go-chi/chi/v5"
 | 
						"github.com/go-chi/chi/v5"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const (
 | 
				
			||||||
 | 
						// maxASDescriptionLength is the maximum length for AS descriptions in the UI
 | 
				
			||||||
 | 
						maxASDescriptionLength = 20
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// handleRoot returns a handler that redirects to /status
 | 
					// handleRoot returns a handler that redirects to /status
 | 
				
			||||||
func (s *Server) handleRoot() http.HandlerFunc {
 | 
					func (s *Server) handleRoot() http.HandlerFunc {
 | 
				
			||||||
	return func(w http.ResponseWriter, r *http.Request) {
 | 
						return func(w http.ResponseWriter, r *http.Request) {
 | 
				
			||||||
@ -645,12 +651,45 @@ func (s *Server) handlePrefixDetail() http.HandlerFunc {
 | 
				
			|||||||
			origins = append(origins, origin)
 | 
								origins = append(origins, origin)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Create enhanced routes with AS path descriptions
 | 
				
			||||||
 | 
							type ASPathEntry struct {
 | 
				
			||||||
 | 
								Number      int
 | 
				
			||||||
 | 
								Description string
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							type EnhancedRoute struct {
 | 
				
			||||||
 | 
								database.LiveRoute
 | 
				
			||||||
 | 
								ASPathWithDesc []ASPathEntry
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							enhancedRoutes := make([]EnhancedRoute, len(routes))
 | 
				
			||||||
 | 
							for i, route := range routes {
 | 
				
			||||||
 | 
								enhancedRoute := EnhancedRoute{
 | 
				
			||||||
 | 
									LiveRoute:      route,
 | 
				
			||||||
 | 
									ASPathWithDesc: make([]ASPathEntry, len(route.ASPath)),
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// Look up description for each AS in the path
 | 
				
			||||||
 | 
								for j, asn := range route.ASPath {
 | 
				
			||||||
 | 
									desc := asinfo.GetDescription(asn)
 | 
				
			||||||
 | 
									// Truncate description if longer than maxASDescriptionLength characters
 | 
				
			||||||
 | 
									if len(desc) > maxASDescriptionLength {
 | 
				
			||||||
 | 
										desc = desc[:maxASDescriptionLength] + "..."
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									enhancedRoute.ASPathWithDesc[j] = ASPathEntry{
 | 
				
			||||||
 | 
										Number:      asn,
 | 
				
			||||||
 | 
										Description: desc,
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								enhancedRoutes[i] = enhancedRoute
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Prepare template data
 | 
							// Prepare template data
 | 
				
			||||||
		data := struct {
 | 
							data := struct {
 | 
				
			||||||
			Prefix      string
 | 
								Prefix      string
 | 
				
			||||||
			MaskLength  int
 | 
								MaskLength  int
 | 
				
			||||||
			IPVersion   int
 | 
								IPVersion   int
 | 
				
			||||||
			Routes      []database.LiveRoute
 | 
								Routes      []EnhancedRoute
 | 
				
			||||||
			Origins     []*ASNInfo
 | 
								Origins     []*ASNInfo
 | 
				
			||||||
			PeerCount   int
 | 
								PeerCount   int
 | 
				
			||||||
			OriginCount int
 | 
								OriginCount int
 | 
				
			||||||
@ -658,7 +697,7 @@ func (s *Server) handlePrefixDetail() http.HandlerFunc {
 | 
				
			|||||||
			Prefix:      prefix,
 | 
								Prefix:      prefix,
 | 
				
			||||||
			MaskLength:  maskLength,
 | 
								MaskLength:  maskLength,
 | 
				
			||||||
			IPVersion:   ipVersion,
 | 
								IPVersion:   ipVersion,
 | 
				
			||||||
			Routes:      routes,
 | 
								Routes:      enhancedRoutes,
 | 
				
			||||||
			Origins:     origins,
 | 
								Origins:     origins,
 | 
				
			||||||
			PeerCount:   len(routes),
 | 
								PeerCount:   len(routes),
 | 
				
			||||||
			OriginCount: len(originMap),
 | 
								OriginCount: len(originMap),
 | 
				
			||||||
 | 
				
			|||||||
@ -7,6 +7,7 @@ import (
 | 
				
			|||||||
	"context"
 | 
						"context"
 | 
				
			||||||
	"encoding/json"
 | 
						"encoding/json"
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
 | 
						"math"
 | 
				
			||||||
	"net/http"
 | 
						"net/http"
 | 
				
			||||||
	"os"
 | 
						"os"
 | 
				
			||||||
	"sync"
 | 
						"sync"
 | 
				
			||||||
@ -95,6 +96,9 @@ func (s *Streamer) RegisterHandler(handler MessageHandler) {
 | 
				
			|||||||
	info := &handlerInfo{
 | 
						info := &handlerInfo{
 | 
				
			||||||
		handler: handler,
 | 
							handler: handler,
 | 
				
			||||||
		queue:   make(chan *ristypes.RISMessage, handler.QueueCapacity()),
 | 
							queue:   make(chan *ristypes.RISMessage, handler.QueueCapacity()),
 | 
				
			||||||
 | 
							metrics: handlerMetrics{
 | 
				
			||||||
 | 
								minTime: time.Duration(math.MaxInt64), // Initialize to max so first value sets the floor
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	s.handlers = append(s.handlers, info)
 | 
						s.handlers = append(s.handlers, info)
 | 
				
			||||||
@ -170,7 +174,7 @@ func (s *Streamer) runHandlerWorker(info *handlerInfo) {
 | 
				
			|||||||
		info.metrics.totalTime += elapsed
 | 
							info.metrics.totalTime += elapsed
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Update min time
 | 
							// Update min time
 | 
				
			||||||
		if info.metrics.minTime == 0 || elapsed < info.metrics.minTime {
 | 
							if elapsed < info.metrics.minTime {
 | 
				
			||||||
			info.metrics.minTime = elapsed
 | 
								info.metrics.minTime = elapsed
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -13,7 +13,8 @@
 | 
				
			|||||||
            color: #333;
 | 
					            color: #333;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        .container {
 | 
					        .container {
 | 
				
			||||||
            max-width: 1200px;
 | 
					            width: 90%;
 | 
				
			||||||
 | 
					            max-width: 1600px;
 | 
				
			||||||
            margin: 0 auto;
 | 
					            margin: 0 auto;
 | 
				
			||||||
            background: white;
 | 
					            background: white;
 | 
				
			||||||
            padding: 30px;
 | 
					            padding: 30px;
 | 
				
			||||||
@ -114,9 +115,10 @@
 | 
				
			|||||||
            font-family: monospace;
 | 
					            font-family: monospace;
 | 
				
			||||||
            font-size: 13px;
 | 
					            font-size: 13px;
 | 
				
			||||||
            color: #666;
 | 
					            color: #666;
 | 
				
			||||||
            max-width: 300px;
 | 
					            max-width: 600px;
 | 
				
			||||||
            overflow-x: auto;
 | 
					            word-wrap: break-word;
 | 
				
			||||||
            white-space: nowrap;
 | 
					            white-space: normal;
 | 
				
			||||||
 | 
					            line-height: 1.5;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        .age {
 | 
					        .age {
 | 
				
			||||||
            color: #7f8c8d;
 | 
					            color: #7f8c8d;
 | 
				
			||||||
@ -168,7 +170,7 @@
 | 
				
			|||||||
                font-size: 14px;
 | 
					                font-size: 14px;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            .as-path {
 | 
					            .as-path {
 | 
				
			||||||
                max-width: 150px;
 | 
					                max-width: 100%;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    </style>
 | 
					    </style>
 | 
				
			||||||
@ -234,7 +236,7 @@
 | 
				
			|||||||
                            <a href="/as/{{.OriginASN}}" class="as-link">AS{{.OriginASN}}</a>
 | 
					                            <a href="/as/{{.OriginASN}}" class="as-link">AS{{.OriginASN}}</a>
 | 
				
			||||||
                        </td>
 | 
					                        </td>
 | 
				
			||||||
                        <td class="peer-ip">{{.PeerIP}}</td>
 | 
					                        <td class="peer-ip">{{.PeerIP}}</td>
 | 
				
			||||||
                        <td class="as-path">{{range $i, $as := .ASPath}}{{if $i}} → {{end}}{{$as}}{{end}}</td>
 | 
					                        <td class="as-path">{{range $i, $as := .ASPathWithDesc}}{{if $i}} → {{end}}{{if $as.Description}}{{$as.Description}} ({{$as.Number}}){{else}}AS{{$as.Number}}{{end}}{{end}}</td>
 | 
				
			||||||
                        <td class="peer-ip">{{.NextHop}}</td>
 | 
					                        <td class="peer-ip">{{.NextHop}}</td>
 | 
				
			||||||
                        <td>{{.LastUpdated.Format "2006-01-02 15:04:05"}}</td>
 | 
					                        <td>{{.LastUpdated.Format "2006-01-02 15:04:05"}}</td>
 | 
				
			||||||
                        <td class="age">{{.LastUpdated | timeSince}}</td>
 | 
					                        <td class="age">{{.LastUpdated | timeSince}}</td>
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user