Browse Source

Ruspa worker and methods.

Blallo 5 years ago
parent
commit
1e7fa8a26e
1 changed files with 121 additions and 0 deletions
  1. 121 0
      sizer/worker.go

+ 121 - 0
sizer/worker.go

@@ -0,0 +1,121 @@
+package sizer
+
+import (
+	"fmt"
+
+	"github.com/gosuri/uilive"
+)
+
+// Ruspa is the asynchronous worker that is in charge of collecting
+// the underlying sizes and relay the total to the eventual parent.
+type Ruspa struct {
+	INode  *INode
+	Send   chan StatusReport
+	Recv   chan StatusReport
+	Done   chan StatusReport
+	Opened map[string]*Ruspa
+}
+
+// NewRuspa inits a new Ruspa
+func NewRuspa(inode *INode, collect chan StatusReport) *Ruspa {
+	var r Ruspa
+	r.INode = inode
+	r.Recv = make(chan StatusReport)
+	if collect == nil {
+		r.Send = make(chan StatusReport)
+	} else {
+		r.Send = collect
+	}
+	r.Done = make(chan StatusReport)
+	r.Opened = make(map[string]*Ruspa)
+	return &r
+}
+
+// Scava starts a worker on the given INode.
+func (w *Ruspa) Scava(done chan StatusReport) {
+	Console.Debugln("Scava: ", w.INode.Path)
+	children, err := ls(w.INode.Path)
+	if err != nil {
+		w.Send <- StatusReport{path: w.INode.Path, err: err}
+	}
+	for _, childPath := range children {
+		kind, size, err := IdentifyType(childPath)
+		if err != nil {
+			w.Send <- StatusReport{path: childPath, err: err}
+		}
+		childINode := NewINode(kind, size, childPath)
+		w.INode.Children.Append(childINode)
+		switch {
+		case kind == FileType:
+			Console.Debugln("[file]", w.INode.Path, " ~> ", childINode.Path)
+			w.Send <- StatusReport{path: childPath, size: size}
+		case kind == DirType:
+			Console.Debugln("[dir]", w.INode.Path, " ~> ", childINode.Path)
+			cw := NewRuspa(childINode, w.Recv)
+			w.Opened[childPath] = cw
+			go cw.Scava(w.Done)
+			// go cw.Ammucchia(w.Done)
+		}
+	}
+	if len(w.Opened) == 0 {
+		done <- StatusReport{path: w.INode.Path}
+	} else {
+		go w.Ammucchia(done)
+	}
+}
+
+// Ammucchia gathers the size of the underlying Ruspa workers
+// and adds to the INode size.
+func (w *Ruspa) Ammucchia(done chan StatusReport) {
+	for len(w.Opened) > 0 {
+		select {
+		case report := <-w.Recv:
+			if report.err != nil {
+				Console.Debugln(Red(report.err))
+			}
+			if report.err == nil {
+				w.INode.Size += report.size
+			}
+		case leaf := <-w.Done:
+			Console.Debugln("Done:", leaf.path)
+			delete(w.Opened, leaf.path)
+		}
+	}
+	Console.Debugln(w.INode.Path, ": Completed. Exiting...")
+	done <- StatusReport{path: w.INode.Path, size: w.INode.Size}
+}
+
+// Pesa starts the worker for current inode and returns the channel
+// to listen to get the size.
+func (i *INode) Pesa(done chan StatusReport) chan StatusReport {
+	result := make(chan StatusReport)
+	w := NewRuspa(i, result)
+	go w.Scava(done)
+	// go w.Ammucchia(done)
+	return result
+}
+
+// NastroConvogliatore starts a Pesa on a given path and displays
+// the current value of the size.
+func NastroConvogliatore(path string) {
+	pathINode, err := INodeFromPath(path)
+	if err != nil {
+		Console.Fatalln("Failed creating inode:", err)
+	}
+	Console.Debugln("Starting Pesa on path:", path)
+	done := make(chan StatusReport)
+	result := pathINode.Pesa(done)
+	writer := uilive.New()
+	writer.Start()
+	fmt.Fprintf(writer, "%s\n", Green("Starting..."))
+	for {
+		select {
+		case res := <-result:
+			fmt.Fprintf(writer, "%s: %d\n", res.path, res.size)
+		case res := <-done:
+			fmt.Fprintf(writer, "%s: %d\n", res.path, res.size)
+			writer.Stop()
+			return
+		}
+	}
+}