11package main
22
33import (
4+ "embed"
45 "fmt"
6+ "html/template"
7+ "io/fs"
58 "log"
69 "net/http"
710 "os"
811 "path/filepath"
912 "strings"
1013)
1114
12- const (
13- archiveDir = "/archives"
14- port = "8080"
15+ //go:embed templates/*.html
16+ var templateFS embed.FS
17+
18+ //go:embed static/*
19+ var staticFS embed.FS
20+
21+ var (
22+ archiveDir = getEnv ("ARCHIVE_DIR" , "/archives" )
23+ port = getEnv ("PORT" , "8080" )
24+ pageTemplate = template .Must (template .ParseFS (templateFS , "templates/index.html" ))
1525)
1626
27+ func getEnv (key , fallback string ) string {
28+ if v := os .Getenv (key ); v != "" {
29+ return v
30+ }
31+ return fallback
32+ }
33+
34+ type archiveFile struct {
35+ Name string
36+ Size float64
37+ OS string
38+ Arch string
39+ Checksum string
40+ }
41+
1742func main () {
18- // Verify archives exist
1943 files , err := filepath .Glob (filepath .Join (archiveDir , "*.tar.gz" ))
2044 if err != nil || len (files ) == 0 {
2145 log .Fatal ("No archives found in " , archiveDir )
2246 }
2347 log .Printf ("Found %d archives" , len (files ))
2448
49+ staticContent , err := fs .Sub (staticFS , "static" )
50+ if err != nil {
51+ log .Fatal ("Failed to load static files: " , err )
52+ }
53+ http .Handle ("/static/" , http .StripPrefix ("/static/" , http .FileServer (http .FS (staticContent ))))
2554 http .HandleFunc ("/" , listBinaries )
2655 http .HandleFunc ("/download/" , downloadBinary )
2756
@@ -40,40 +69,72 @@ func listBinaries(w http.ResponseWriter, r *http.Request) {
4069 return
4170 }
4271
43- w .Header ().Set ("Content-Type" , "text/html" )
44- fmt .Fprintf (w , "<html><head><title>kubectl-oadp Downloads</title></head><body>" )
45- fmt .Fprintf (w , "<h1>kubectl-oadp Binary Downloads</h1>" )
46- fmt .Fprintf (w , "<p>Download pre-built binaries for your platform:</p><ul>" )
47-
72+ var linuxFiles , darwinFiles , windowsFiles []archiveFile
4873 for _ , file := range files {
4974 name := filepath .Base (file )
5075 info , err := os .Stat (file )
5176 if err != nil {
5277 continue
5378 }
54- size := float64 (info .Size ()) / (1024 * 1024 ) // MB
55- fmt .Fprintf (w , `<li><a href="/download/%s">%s</a> (%.2f MB)</li>` , name , name , size )
79+ size := float64 (info .Size ()) / (1024 * 1024 )
80+ osName , arch := parsePlatform (name )
81+ checksum := readChecksum (file + ".sha256" )
82+ af := archiveFile {Name : name , Size : size , OS : osName , Arch : arch , Checksum : checksum }
83+ switch osName {
84+ case "linux" :
85+ linuxFiles = append (linuxFiles , af )
86+ case "darwin" :
87+ darwinFiles = append (darwinFiles , af )
88+ case "windows" :
89+ windowsFiles = append (windowsFiles , af )
90+ default :
91+ linuxFiles = append (linuxFiles , af )
92+ }
5693 }
5794
58- fmt .Fprintf (w , "</ul>" )
59- fmt .Fprintf (w , "<h3>Installation:</h3>" )
60- fmt .Fprintf (w , "<pre>tar -xzf kubectl-oadp_*.tar.gz\n " )
61- fmt .Fprintf (w , "chmod +x kubectl-oadp\n " )
62- fmt .Fprintf (w , "sudo mv kubectl-oadp /usr/local/bin/</pre>" )
95+ data := struct {
96+ LinuxFiles []archiveFile
97+ DarwinFiles []archiveFile
98+ WindowsFiles []archiveFile
99+ }{linuxFiles , darwinFiles , windowsFiles }
100+
101+ w .Header ().Set ("Content-Type" , "text/html" )
102+ if err := pageTemplate .Execute (w , data ); err != nil {
103+ log .Printf ("Template error: %v" , err )
104+ }
105+ }
106+
107+ func readChecksum (path string ) string {
108+ data , err := os .ReadFile (path )
109+ if err != nil {
110+ return ""
111+ }
112+ fields := strings .Fields (string (data ))
113+ if len (fields ) > 0 {
114+ return fields [0 ]
115+ }
116+ return ""
117+ }
118+
119+ func parsePlatform (filename string ) (string , string ) {
120+ name := strings .TrimSuffix (filename , ".tar.gz" )
121+ parts := strings .Split (name , "_" )
122+ if len (parts ) >= 3 {
123+ return parts [len (parts )- 2 ], parts [len (parts )- 1 ]
124+ }
125+ return "unknown" , "unknown"
63126}
64127
65128func downloadBinary (w http.ResponseWriter , r * http.Request ) {
66129 filename := filepath .Base (r .URL .Path [len ("/download/" ):])
67130
68- // Security: ensure filename is just the archive name
69131 if filepath .Dir (filename ) != "." || ! strings .HasSuffix (filename , ".tar.gz" ) {
70132 http .Error (w , "Invalid filename" , http .StatusBadRequest )
71133 return
72134 }
73135
74136 filePath := filepath .Join (archiveDir , filename )
75137
76- // Verify file exists
77138 if _ , err := os .Stat (filePath ); os .IsNotExist (err ) {
78139 http .Error (w , "Archive not found" , http .StatusNotFound )
79140 return
0 commit comments