From 3c770c469d9cd16e14321f943ddbfce729654c7b Mon Sep 17 00:00:00 2001 From: roboogg133 Date: Thu, 18 Sep 2025 20:12:07 -0300 Subject: [PATCH] better file organization --- cmd/packets/main.go | 190 ++------------------------------ configs/main.go | 58 ++++++++++ configs/structs.go | 26 +++++ internal/consts/consts.go | 11 ++ internal/errors/errors.go | 8 ++ internal/internal.go | 161 --------------------------- internal/utils/lan.go | 80 ++++++++++++++ internal/{ => utils/lua}/lua.go | 8 +- internal/utils/utils.go | 68 ++++++++++++ pkg/packagefiles.go | 95 ++++++++++++++++ 10 files changed, 361 insertions(+), 344 deletions(-) create mode 100644 configs/main.go create mode 100644 configs/structs.go create mode 100644 internal/consts/consts.go create mode 100644 internal/errors/errors.go delete mode 100644 internal/internal.go create mode 100644 internal/utils/lan.go rename internal/{ => utils/lua}/lua.go (98%) create mode 100644 internal/utils/utils.go create mode 100644 pkg/packagefiles.go diff --git a/cmd/packets/main.go b/cmd/packets/main.go index 651c0f3..d057b5d 100644 --- a/cmd/packets/main.go +++ b/cmd/packets/main.go @@ -1,58 +1,25 @@ package main import ( - "archive/tar" "database/sql" - "errors" "fmt" - "io" "log" - "net" "os" - "packets/internal" + "packets/configs" + "packets/internal/consts" "path/filepath" - "strconv" - "strings" - "time" - "github.com/klauspost/compress/zstd" "github.com/pelletier/go-toml/v2" "github.com/spf13/cobra" - "golang.org/x/net/ipv4" _ "modernc.org/sqlite" ) -// Consts - -const DefaultLinux_d = "/etc/packets" -const LANDeadline = 2 * time.Second - -// Errors - -var ErrResponseNot200OK = errors.New("the request is not 200, download failed") - -// Types - -type ConfigTOML struct { - Config struct { - HttpPort int `toml:"httpPort"` - Cache_d string `toml:"cache_d"` - Data_d string `toml:"data_d"` - Bin_d string `toml:"bin_d"` - } `toml:"Config"` -} - -type Peer struct { - IP net.IP - Port int -} - // init is doing some verifications func init() { - _, err := os.Stat(DefaultLinux_d) + _, err := os.Stat(consts.DefaultLinux_d) if os.IsNotExist(err) { - err := os.Mkdir(DefaultLinux_d, 0644) + err := os.Mkdir(consts.DefaultLinux_d, 0644) if err != nil { if os.IsPermission(err) { fmt.Println("can't create packets root directory, please run as root") @@ -63,7 +30,7 @@ func init() { } } - _, err = os.Stat(filepath.Join(DefaultLinux_d, "index.db")) + _, err = os.Stat(filepath.Join(consts.DefaultLinux_d, "index.db")) if err != nil { if os.IsNotExist(err) { @@ -73,10 +40,10 @@ func init() { } } - _, err = os.Stat(filepath.Join(DefaultLinux_d, "installed.db")) + _, err = os.Stat(filepath.Join(consts.DefaultLinux_d, "installed.db")) if err != nil { if os.IsNotExist(err) { - db, err := sql.Open("sqlite", filepath.Join(DefaultLinux_d, "installed.db")) + db, err := sql.Open("sqlite", filepath.Join(consts.DefaultLinux_d, "installed.db")) if err != nil { log.Fatal(db) } @@ -87,9 +54,9 @@ func init() { } } - _, err = os.Stat(filepath.Join(DefaultLinux_d, "config.toml")) + _, err = os.Stat(filepath.Join(consts.DefaultLinux_d, "config.toml")) if os.IsNotExist(err) { - f, err := os.Create(filepath.Join(DefaultLinux_d, "config.toml")) + f, err := os.Create(filepath.Join(consts.DefaultLinux_d, "config.toml")) if err != nil { log.Fatal(err) } @@ -98,7 +65,7 @@ func init() { encoder := toml.NewEncoder(f) - cfg, err := internal.DefaultConfigTOML() + cfg, err := configs.DefaultConfigTOML() if err != nil { log.Fatal(err) } @@ -109,143 +76,6 @@ func init() { } } -// Install exctract and install from a package file -func Install(file *os.File) error { - - manifest, err := internal.ReadManifest(file) - if err != nil { - return err - } - - name := &manifest.Info.Name - - configuration, err := internal.GetConfigTOML() - if err != nil { - return err - } - - destDir := filepath.Join(configuration.Config.Data_d, *name) - - zstdReader, err := zstd.NewReader(file) - if err != nil { - return err - } - defer zstdReader.Close() - - tarReader := tar.NewReader(zstdReader) - - for { - hdr, err := tarReader.Next() - if err == io.EOF { - break - } - if err != nil { - return err - } - - rel := filepath.Clean(hdr.Name) - - if rel == ".." || strings.HasPrefix(rel, ".."+string(os.PathSeparator)) { - continue - } - - if err := os.MkdirAll(destDir, 0755); err != nil { - return err - } - - absPath := filepath.Join(destDir, rel) - - switch hdr.Typeflag { - - case tar.TypeDir: - err = os.MkdirAll(absPath, os.FileMode(hdr.Mode)) - - if err != nil { - return err - } - - case tar.TypeReg: - err = os.MkdirAll(filepath.Dir(absPath), 0755) - if err != nil { - return err - } - - out, err := os.Create(absPath) - if err != nil { - return err - } - - _, err = io.Copy(out, tarReader) - out.Close() - if err != nil { - return err - } - - err = os.Chmod(absPath, os.FileMode(hdr.Mode)) - if err != nil { - return err - } - } - } - - return nil -} - -func AskLAN(filename string) ([]Peer, error) { - var peers []Peer - query := []byte("Q:" + filename) - - pc, err := net.ListenPacket("udp", ":0") - if err != nil { - return []Peer{}, err - } - defer pc.Close() - - if pconn := ipv4.NewPacketConn(pc); pconn != nil { - _ = pconn.SetTTL(1) - } - - ifaces, _ := net.Interfaces() - for _, ifc := range ifaces { - if ifc.Flags&net.FlagUp == 0 || ifc.Flags&net.FlagLoopback != 0 { - continue - } - - addrs, _ := ifc.Addrs() - for _, a := range addrs { - ipnet, ok := a.(*net.IPNet) - if !ok || ipnet.IP.To4() == nil { - continue - } - - bcast := internal.BroadcastAddr(ipnet.IP.To4(), ipnet.Mask) - dst := &net.UDPAddr{IP: bcast, Port: 1333} - - _, err = pc.WriteTo(query, dst) - if err != nil { - fmt.Printf(":: (%s) can't send to %s: %s\n", ifc.Name, bcast, err.Error()) - } - } - } - _ = pc.SetDeadline(time.Now().Add(LANDeadline)) - buf := make([]byte, 1500) - - for { - n, addr, err := pc.ReadFrom(buf) - if err != nil { - break - } - msg := string(buf[:n]) - - if strings.HasPrefix(msg, "H:"+filename) { - parts := strings.Split(msg, ":") - port, _ := strconv.Atoi(parts[2]) - peers = append(peers, Peer{IP: addr.(*net.UDPAddr).IP, Port: port}) - } - } - return peers, nil -} - // COBRA CMDS var rootCmd = &cobra.Command{Use: "packets"} var installCmd = &cobra.Command{ diff --git a/configs/main.go b/configs/main.go new file mode 100644 index 0000000..8a6d4c9 --- /dev/null +++ b/configs/main.go @@ -0,0 +1,58 @@ +package configs + +import ( + "os" + "packets/internal/consts" + "path/filepath" + + "github.com/pelletier/go-toml/v2" +) + +// DefaultConfigTOML returns configTOML struct with all default values and create all directorys +func DefaultConfigTOML() (*ConfigTOML, error) { + + var config ConfigTOML + + _, err := os.Stat(consts.DefaultCache_d) + if err != nil { + if os.IsNotExist(err) { + err := os.MkdirAll(consts.DefaultCache_d, 0666) + if err != nil { + return nil, err + } + } + } + + _, err = os.Stat(consts.DefaultCache_d) + if err != nil { + if os.IsNotExist(err) { + err := os.MkdirAll(consts.DefaultData_d, 0644) + if err != nil { + return nil, err + } + } + } + + config.Config.Cache_d = consts.DefaultCache_d + config.Config.Data_d = consts.DefaultData_d + config.Config.HttpPort = consts.DefaultHttpPort + + return &config, nil +} + +// GetConfigTOML return settings values +func GetConfigTOML() (*ConfigTOML, error) { + f, err := os.Open(filepath.Join(consts.DefaultLinux_d, "config.toml")) + if err != nil { + return nil, err + } + + decoder := toml.NewDecoder(f) + + var config ConfigTOML + if err := decoder.Decode(&config); err != nil { + return nil, err + } + + return &config, nil +} diff --git a/configs/structs.go b/configs/structs.go new file mode 100644 index 0000000..d7d2948 --- /dev/null +++ b/configs/structs.go @@ -0,0 +1,26 @@ +package configs + +type Manifest struct { + Info struct { + Name string `toml:"name"` + Version string `toml:"version"` + Description string `toml:"description"` + Dependencies []string `toml:"dependencies"` + Author string `toml:"author"` + Family string `toml:"family"` + Serial uint `toml:"serial"` + } `toml:"Info"` + Hooks struct { + Install string `toml:"install"` + Remove string `toml:"remove"` + } `toml:"Hooks"` +} + +type ConfigTOML struct { + Config struct { + HttpPort int `toml:"httpPort"` + Cache_d string `toml:"cache_d"` + Data_d string `toml:"data_d"` + Bin_d string `toml:"bin_d"` + } `toml:"Config"` +} diff --git a/internal/consts/consts.go b/internal/consts/consts.go new file mode 100644 index 0000000..7977018 --- /dev/null +++ b/internal/consts/consts.go @@ -0,0 +1,11 @@ +package consts + +import "time" + +const ( + DefaultLinux_d = "/etc/packets" + DefaultCache_d = "/var/cache/packets" + DefaultHttpPort = 9123 + DefaultData_d = "/opt/packets" + LANDeadline = 2 * time.Second +) diff --git a/internal/errors/errors.go b/internal/errors/errors.go new file mode 100644 index 0000000..b5ddfdb --- /dev/null +++ b/internal/errors/errors.go @@ -0,0 +1,8 @@ +package errors_packets + +import "errors" + +var ( + ErrResponseNot200OK = errors.New("the request is not 200, download failed") + ErrCantFindManifestTOML = errors.New("can't find manifest.toml when trying to read the packagefile") +) diff --git a/internal/internal.go b/internal/internal.go deleted file mode 100644 index 8651ef4..0000000 --- a/internal/internal.go +++ /dev/null @@ -1,161 +0,0 @@ -package internal - -import ( - "archive/tar" - "errors" - "io" - "log" - "net" - "net/http" - "os" - "path/filepath" - - "github.com/klauspost/compress/zstd" - "github.com/pelletier/go-toml/v2" -) - -// const - -const DefaultLinux_d = "/etc/packets" -const DefaultCache_d = "/var/cache/packets" -const DefaultHttpPort = 9123 -const DefaultData_d = "/opt/packets" - -// errors -var ErrResponseNot200OK = errors.New("the request is not 200, download failed") -var ErrCantFindManifestTOML = errors.New("can't find manifest.toml when trying to read the packagefile") - -// toml files - -type Manifest struct { - Info struct { - Name string `toml:"name"` - Version string `toml:"version"` - Description string `toml:"description"` - Dependencies []string `toml:"dependencies"` - Author string `toml:"author"` - Family string `toml:"family"` - Serial uint `toml:"serial"` - } `toml:"Info"` - Hooks struct { - Install string `toml:"install"` - Remove string `toml:"remove"` - } `toml:"Hooks"` -} - -type ConfigTOML struct { - Config struct { - HttpPort int `toml:"httpPort"` - Cache_d string `toml:"cache_d"` - Data_d string `toml:"data_d"` - Bin_d string `toml:"bin_d"` - } `toml:"Config"` -} - -func DownloadPackageHTTP(url string) (*[]byte, error) { - - resp, err := http.Get(url) - if err != nil { - log.Fatal(err) - } - - if resp.StatusCode != http.StatusOK { - return nil, ErrResponseNot200OK - } - - fileBytes, err := io.ReadAll(resp.Body) - if err != nil { - return nil, err - } - - return &fileBytes, nil -} - -// DefaultConfigTOML generate a default toml and create the directorys -func DefaultConfigTOML() (*ConfigTOML, error) { - - var config ConfigTOML - - _, err := os.Stat(DefaultCache_d) - if err != nil { - if os.IsNotExist(err) { - err := os.MkdirAll(DefaultCache_d, 0666) - if err != nil { - return nil, err - } - } - } - - _, err = os.Stat(DefaultCache_d) - if err != nil { - if os.IsNotExist(err) { - err := os.MkdirAll(DefaultData_d, 0644) - if err != nil { - return nil, err - } - } - } - - config.Config.Cache_d = DefaultCache_d - config.Config.Data_d = DefaultData_d - config.Config.HttpPort = DefaultHttpPort - - return &config, nil -} - -func ReadManifest(file *os.File) (*Manifest, error) { - zstdReader, err := zstd.NewReader(file) - if err != nil { - return nil, err - } - defer zstdReader.Close() - - tarReader := tar.NewReader(zstdReader) - for { - header, err := tarReader.Next() - if err == io.EOF { - break - } - if err != nil { - return nil, err - } - - if filepath.Base(header.Name) == "manifest.toml" { - decoder := toml.NewDecoder(tarReader) - - var manifest Manifest - - if err := decoder.Decode(&manifest); err != nil { - log.Fatal(err) - } - - return &manifest, nil - } - - } - return nil, ErrCantFindManifestTOML -} - -func GetConfigTOML() (*ConfigTOML, error) { - f, err := os.Open(filepath.Join(DefaultLinux_d, "config.toml")) - if err != nil { - return nil, err - } - - decoder := toml.NewDecoder(f) - - var config ConfigTOML - if err := decoder.Decode(&config); err != nil { - return nil, err - } - - return &config, nil -} - -func BroadcastAddr(ip net.IP, mask net.IPMask) net.IP { - b := make(net.IP, len(ip)) - for i := range ip { - b[i] = ip[i] | ^mask[i] - } - return b -} diff --git a/internal/utils/lan.go b/internal/utils/lan.go new file mode 100644 index 0000000..a07f732 --- /dev/null +++ b/internal/utils/lan.go @@ -0,0 +1,80 @@ +package utils + +import ( + "fmt" + "net" + "packets/internal/consts" + "strconv" + "strings" + "time" + + "golang.org/x/net/ipv4" +) + +type Peer struct { + IP net.IP + Port int +} + +func BroadcastAddr(ip net.IP, mask net.IPMask) net.IP { + b := make(net.IP, len(ip)) + for i := range ip { + b[i] = ip[i] | ^mask[i] + } + return b +} + +func AskLAN(filename string) ([]Peer, error) { + var peers []Peer + query := []byte("Q:" + filename) + + pc, err := net.ListenPacket("udp", ":0") + if err != nil { + return []Peer{}, err + } + defer pc.Close() + + if pconn := ipv4.NewPacketConn(pc); pconn != nil { + _ = pconn.SetTTL(1) + } + + ifaces, _ := net.Interfaces() + for _, ifc := range ifaces { + if ifc.Flags&net.FlagUp == 0 || ifc.Flags&net.FlagLoopback != 0 { + continue + } + + addrs, _ := ifc.Addrs() + for _, a := range addrs { + ipnet, ok := a.(*net.IPNet) + if !ok || ipnet.IP.To4() == nil { + continue + } + + bcast := BroadcastAddr(ipnet.IP.To4(), ipnet.Mask) + dst := &net.UDPAddr{IP: bcast, Port: 1333} + + _, err = pc.WriteTo(query, dst) + if err != nil { + fmt.Printf(":: (%s) can't send to %s: %s\n", ifc.Name, bcast, err.Error()) + } + } + } + _ = pc.SetDeadline(time.Now().Add(consts.LANDeadline)) + buf := make([]byte, 1500) + + for { + n, addr, err := pc.ReadFrom(buf) + if err != nil { + break + } + msg := string(buf[:n]) + + if strings.HasPrefix(msg, "H:"+filename) { + parts := strings.Split(msg, ":") + port, _ := strconv.Atoi(parts[2]) + peers = append(peers, Peer{IP: addr.(*net.UDPAddr).IP, Port: port}) + } + } + return peers, nil +} diff --git a/internal/lua.go b/internal/utils/lua/lua.go similarity index 98% rename from internal/lua.go rename to internal/utils/lua/lua.go index 803c010..5e1f48c 100644 --- a/internal/lua.go +++ b/internal/utils/lua/lua.go @@ -1,4 +1,4 @@ -package internal +package utils import ( "fmt" @@ -6,6 +6,8 @@ import ( "log" "os" "os/exec" + "packets/configs" + "packets/internal/consts" "path/filepath" "strings" @@ -36,9 +38,9 @@ func IsSafe(str string) bool { s = filepath.Clean(str) } - var cfg ConfigTOML + var cfg configs.ConfigTOML - f, err := os.Open(filepath.Join(DefaultLinux_d, "config.toml")) + f, err := os.Open(filepath.Join(consts.DefaultLinux_d, "config.toml")) if err != nil { log.Println("error here opening config.toml") return false diff --git a/internal/utils/utils.go b/internal/utils/utils.go new file mode 100644 index 0000000..7b5425c --- /dev/null +++ b/internal/utils/utils.go @@ -0,0 +1,68 @@ +package utils + +import ( + "archive/tar" + "io" + "log" + "net/http" + "os" + "packets/configs" + errors_packets "packets/internal/errors" + "path/filepath" + + "github.com/klauspost/compress/zstd" + "github.com/pelletier/go-toml/v2" +) + +func DownloadPackageHTTP(url string) (*[]byte, error) { + + resp, err := http.Get(url) + if err != nil { + log.Fatal(err) + } + + if resp.StatusCode != http.StatusOK { + return nil, errors_packets.ErrResponseNot200OK + } + + fileBytes, err := io.ReadAll(resp.Body) + if err != nil { + return nil, err + } + + return &fileBytes, nil +} + +// ReadManifest is crucial to get package metadata it reads manifest.toml from a package file (tar.zst) +func ReadManifest(file *os.File) (*configs.Manifest, error) { + zstdReader, err := zstd.NewReader(file) + if err != nil { + return nil, err + } + defer zstdReader.Close() + + tarReader := tar.NewReader(zstdReader) + for { + header, err := tarReader.Next() + if err == io.EOF { + break + } + if err != nil { + return nil, err + } + + if filepath.Base(header.Name) == "manifest.toml" { + decoder := toml.NewDecoder(tarReader) + + var manifest configs.Manifest + + if err := decoder.Decode(&manifest); err != nil { + log.Fatal(err) + } + + return &manifest, nil + } + + } + return nil, errors_packets.ErrCantFindManifestTOML +} diff --git a/pkg/packagefiles.go b/pkg/packagefiles.go new file mode 100644 index 0000000..afa108a --- /dev/null +++ b/pkg/packagefiles.go @@ -0,0 +1,95 @@ +package pkg + +import ( + "archive/tar" + "io" + "os" + "packets/configs" + "packets/internal/utils" + "path/filepath" + "strings" + + "github.com/klauspost/compress/zstd" +) + +// Install exctract and install from a package file ( tar.zst ) +func InstallPackage(file *os.File) error { + + manifest, err := utils.ReadManifest(file) + if err != nil { + return err + } + + name := &manifest.Info.Name + + configuration, err := configs.GetConfigTOML() + if err != nil { + return err + } + + destDir := filepath.Join(configuration.Config.Data_d, *name) + + zstdReader, err := zstd.NewReader(file) + if err != nil { + return err + } + defer zstdReader.Close() + + tarReader := tar.NewReader(zstdReader) + + for { + hdr, err := tarReader.Next() + if err == io.EOF { + break + } + if err != nil { + return err + } + + rel := filepath.Clean(hdr.Name) + + if rel == ".." || strings.HasPrefix(rel, ".."+string(os.PathSeparator)) { + continue + } + + if err := os.MkdirAll(destDir, 0755); err != nil { + return err + } + + absPath := filepath.Join(destDir, rel) + + switch hdr.Typeflag { + + case tar.TypeDir: + err = os.MkdirAll(absPath, os.FileMode(hdr.Mode)) + + if err != nil { + return err + } + + case tar.TypeReg: + err = os.MkdirAll(filepath.Dir(absPath), 0755) + if err != nil { + return err + } + + out, err := os.Create(absPath) + if err != nil { + return err + } + + _, err = io.Copy(out, tarReader) + out.Close() + if err != nil { + return err + } + + err = os.Chmod(absPath, os.FileMode(hdr.Mode)) + if err != nil { + return err + } + } + } + + return nil +}