Skip to content

Commit

Permalink
Merge pull request #1 from Khalid-Nowaf/refactor-desgin
Browse files Browse the repository at this point in the history
Refactor design
  • Loading branch information
Khalid-Nowaf authored Jun 30, 2024
2 parents b4b094f + 6745e81 commit 2eff7ab
Show file tree
Hide file tree
Showing 17 changed files with 1,173 additions and 1,047 deletions.
11 changes: 11 additions & 0 deletions backlog.todo
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,19 @@
☐ @Feat(Trie): Optimize feature to convert Trie to LCTrie @idea
☐ @Refactor(Supernet): extract binary operations to separate package @low
☐ @Refactor(Supernet): extract IPNet wrapping logic to file or a package @low
☐ @Docs(Supernet): rewrite the comments
☐ @Feat(CLI): detect file type from extension
☐ @Feat(CLI): configurable output format
✔ @Feat(CLI): logs flag @done(24-06-30 23:55)
✔ @Feat(Supernet): Build cmd `supernet` that take a file and resolve the conflict @high @done(24-06-25 20:32)
✔ @Feat(Supernet): add a report function to report what is conflicted and how it was resolved @high @done(24-06-25 20:32)
✔ @Feat(Supernet): add recursive conflict resolution during splitting @high @high @done(24-06-25 20:32)
✔ replace AddChildIfNotExist with super.Insert and refactor the code if needed @done(24-06-25 20:32)
✔ find a way if to detect if the conflicted was created during the insertion, to avoid conflict resolution @done(24-06-25 20:32)
✔ @Refactor(Supernet): clean the code @done(24-06-30 23:32)
✔ @Refactor(Supernet): make the resolvers and actions easy to track @done(24-06-30 23:32)
✔ @feat(Supernet): make the supernet configurable @done(24-06-30 23:32)
✔ @feat(Supernet): add custom comparator @done(24-06-30 23:32)
✔ feat(Supernet): add custom logger @done(24-06-30 23:32)


136 changes: 3 additions & 133 deletions cmd/supernet/main.go
Original file line number Diff line number Diff line change
@@ -1,140 +1,10 @@
// supernet resolve file.[csv,json] resolved.csv --cidrCol cidr --priorityCol priority --priorityDel "|"
package main

import (
"encoding/csv"
"encoding/json"
"fmt"
"os"

"github.com/alecthomas/kong"
"github.com/khalid_nowaf/supernet"
"github.com/khalid_nowaf/supernet/pkg/cli"
"github.com/khalid_nowaf/supernet/pkg/supernet"
)

// ResolveCmd represents the command to resolve CIDR conflicts.
type ResolveCmd struct {
Files []string `arg:"" type:"existingfile" help:"Input file containing CIDRs in CSV or JSON format"`
CidrKey string `help:"Index of the CIDRs in the file" default:"cidr"`
PriorityKey string `help:"Index of the CIDRs priorities" default:"priority"`
PriorityDel string `help:"Delimiter for priorities in the field" default:" "`
Report bool `help:"Report only conflicted CIDRs"`
}

// Run executes the resolve command.
func (cmd *ResolveCmd) Run(ctx *kong.Context) error {
fmt.Printf("%v \n", *cmd)
supernet := supernet.NewSupernet()

for _, file := range cmd.Files {
if err := parseAndInsertCidrs(supernet, cmd, file); err != nil {
return err
}
if err := writeCsvResults(supernet, ".", cmd.CidrKey); err != nil {

}
}

return nil
}

// parseAndInsertCidrs parses a file and inserts CIDRs into the supernet.
func parseAndInsertCidrs(super *supernet.Supernet, cmd *ResolveCmd, file string) error {
return parseCsv(cmd, file, func(cidr *CIDR) error {
fmt.Printf("\nInserting CIDR: %s with P %v ...\n", cidr.cidr.String(), cidr.Priority)
results := super.InsertCidr(cidr.cidr, cidr.Metadata)
for _, r := range results {
fmt.Printf(r.String())
}
return nil
})
}

// writeResults writes the results of CIDR resolution to a JSON file.
func writeJsonResults(super *supernet.Supernet, directory string, cidrCol string) error {
filePath := directory + "/resolved.json"
file, err := os.Create(filePath)
if err != nil {
return err
}
defer file.Close()

encoder := json.NewEncoder(file)
cidrs := super.GetAllV4Cidrs(false)

fmt.Println("Starting to write resolved CIDRs...")
if _, err = file.Write([]byte("[")); err != nil {
return err
}

for i, cidr := range cidrs {
cidr.Metadata.Attributes[cidrCol] = supernet.NodeToCidr(cidr)
if i > 0 {
if _, err = file.Write([]byte(",")); err != nil {
return err
}
}
if err = encoder.Encode(cidr.Metadata.Attributes); err != nil {
return err
}
}

if _, err = file.Write([]byte("]")); err != nil {
return err
}
fmt.Println("Writing complete.")
return nil
}

// writeResults writes the results of CIDR resolution to a CSV file.
func writeCsvResults(super *supernet.Supernet, directory string, cidrCol string) error {
filePath := directory + "/resolved.csv"
file, err := os.Create(filePath)
if err != nil {
return err
}
defer file.Close()

// Create a CSV writer
writer := csv.NewWriter(file)
defer writer.Flush()

cidrs := super.GetAllV4Cidrs(false)

fmt.Println("Starting to write resolved CIDRs...")

// Optional: Write headers to the CSV file
headers := []string{}
for key := range cidrs[0].Metadata.Attributes {
headers = append(headers, key)
}
if err := writer.Write(headers); err != nil {
return err
}

// Write data to the CSV file
for _, cidr := range cidrs {
cidr.Metadata.Attributes[cidrCol] = supernet.NodeToCidr(cidr)
record := make([]string, 0, len(cidr.Metadata.Attributes))
// Ensure the fields are written in the same order as headers
for _, header := range headers {
record = append(record, cidr.Metadata.Attributes[header])
}
if err := writer.Write(record); err != nil {
return err
}
}

fmt.Println("Writing complete.")
return nil
}

var CLI struct {
Resolve ResolveCmd `cmd:"" help:"Resolve CIDR conflicts"`
}

func main() {
ctx := kong.Parse(&CLI, kong.UsageOnError())
if err := ctx.Run(); err != nil {
fmt.Printf("Error: %v\n", err)
}
cli.NewCLI(supernet.NewSupernet())
}
28 changes: 28 additions & 0 deletions pkg/cli/cli.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package cli

import (
"fmt"

"github.com/alecthomas/kong"
"github.com/khalid_nowaf/supernet/pkg/supernet"
)

// ResolveCmd represents the command to resolve CIDR conflicts.
type Context struct {
super *supernet.Supernet
}

var cli struct {
Log bool `help:"Print the details about the inserted CIDR and the conflicts if any"`
Resolve ResolveCmd `cmd:"" help:"Resolve CIDR conflicts"`
}

func NewCLI(super *supernet.Supernet) {
ctx := kong.Parse(&cli, kong.UsageOnError())
if cli.Log {
super = supernet.WithSimpleLogger()(super)
}
if err := ctx.Run(&Context{super: super}); err != nil {
fmt.Printf("Error: %v\n", err)
}
}
5 changes: 3 additions & 2 deletions cmd/supernet/parser.go → pkg/cli/parser.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package main
package cli

import (
"encoding/csv"
Expand All @@ -9,7 +9,7 @@ import (
"strconv"
"strings"

"github.com/khalid_nowaf/supernet"
"github.com/khalid_nowaf/supernet/pkg/supernet"
)

type CIDR struct {
Expand Down Expand Up @@ -125,6 +125,7 @@ func parseCIDR(record Record, cmd *ResolveCmd) (*CIDR, error) {
priorities = append(priorities, uint8(i))
}
} else {
// TODO: check if the priority at same length, if not (mm maybe we fill the result with Zeros)
panic("No priorities values founded, use 0 as default " + cmd.PriorityKey)
priorities = []uint8{0}
}
Expand Down
119 changes: 119 additions & 0 deletions pkg/cli/reslove.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
package cli

import (
"encoding/csv"
"encoding/json"
"fmt"
"os"

"github.com/khalid_nowaf/supernet/pkg/supernet"
)

type ResolveCmd struct {
Files []string `arg:"" type:"existingfile" help:"Input file containing CIDRs in CSV or JSON format"`
CidrKey string `help:"Index of the CIDRs in the file" default:"cidr"`
PriorityKey string `help:"Index of the CIDRs priorities" default:"priority"`
PriorityDel string `help:"Delimiter for priorities in the field" default:" "`
Report bool `help:"Report only conflicted CIDRs"`
}

// Run executes the resolve command.
func (cmd *ResolveCmd) Run(ctx *Context) error {
for _, file := range cmd.Files {
if err := parseAndInsertCidrs(ctx.super, cmd, file); err != nil {
return err
}
if err := writeCsvResults(ctx.super, ".", cmd.CidrKey); err != nil {

}
}

return nil
}

// parseAndInsertCidrs parses a file and inserts CIDRs into the supernet.
func parseAndInsertCidrs(super *supernet.Supernet, cmd *ResolveCmd, file string) error {
return parseCsv(cmd, file, func(cidr *CIDR) error {
super.InsertCidr(cidr.cidr, cidr.Metadata)
return nil
})
}

// writeResults writes the results of CIDR resolution to a JSON file.
func writeJsonResults(super *supernet.Supernet, directory string, cidrCol string) error {
filePath := directory + "/resolved.json"
file, err := os.Create(filePath)
if err != nil {
return err
}
defer file.Close()

encoder := json.NewEncoder(file)
cidrs := super.AllCIDRS(false)

fmt.Println("Starting to write resolved CIDRs...")
if _, err = file.Write([]byte("[")); err != nil {
return err
}

for i, cidr := range cidrs {
cidr.Metadata().Attributes[cidrCol] = supernet.NodeToCidr(cidr)
if i > 0 {
if _, err = file.Write([]byte(",")); err != nil {
return err
}
}
if err = encoder.Encode(cidr.Metadata().Attributes); err != nil {
return err
}
}

if _, err = file.Write([]byte("]")); err != nil {
return err
}
fmt.Println("Writing complete.")
return nil
}

// writeResults writes the results of CIDR resolution to a CSV file.
func writeCsvResults(super *supernet.Supernet, directory string, cidrCol string) error {
filePath := directory + "/resolved.csv"
file, err := os.Create(filePath)
if err != nil {
return err
}
defer file.Close()

// Create a CSV writer
writer := csv.NewWriter(file)
defer writer.Flush()

cidrs := super.AllCIDRS(false)

fmt.Println("Starting to write resolved CIDRs...")

// Optional: Write headers to the CSV file
headers := []string{}
for key := range cidrs[0].Metadata().Attributes {
headers = append(headers, key)
}
if err := writer.Write(headers); err != nil {
return err
}

// Write data to the CSV file
for _, cidr := range cidrs {
cidr.Metadata().Attributes[cidrCol] = supernet.NodeToCidr(cidr)
record := make([]string, 0, len(cidr.Metadata().Attributes))
// Ensure the fields are written in the same order as headers
for _, header := range headers {
record = append(record, cidr.Metadata().Attributes[header])
}
if err := writer.Write(record); err != nil {
return err
}
}

fmt.Println("Writing complete.")
return nil
}
Loading

0 comments on commit 2eff7ab

Please sign in to comment.