package zoopb // this is becoming a standard format // todo: autogenerate this from the .proto file? import ( "fmt" "os" "sort" sync "sync" "time" ) // bad global lock until I figure out some other plan var machinesLock sync.RWMutex type MachineIterator struct { sync.RWMutex packs []*Machine index int } // NewMachineIterator initializes a new iterator. func NewMachineIterator(packs []*Machine) *MachineIterator { return &MachineIterator{packs: packs} } // Scan moves to the next element and returns false if there are no more packs. func (it *MachineIterator) Scan() bool { if it.index >= len(it.packs) { return false } it.index++ return true } // Machine returns the current repo. func (it *MachineIterator) Machine() *Machine { if it.packs[it.index-1] == nil { for i, d := range it.packs { fmt.Println("i =", i, d) } fmt.Println("len =", len(it.packs)) fmt.Println("repo == nil", it.index, it.index-1) os.Exit(-1) } return it.packs[it.index-1] } // Use Scan() in a loop, similar to a while loop // // for iterator.Scan() { // d := iterator.Machine() // fmt.Println("Machine UUID:", d.Uuid) // } func (r *Machines) All() *MachineIterator { repoPointers := r.selectAllMachines() iterator := NewMachineIterator(repoPointers) return iterator } func (r *Machines) SortByName() *MachineIterator { packs := r.selectAllMachines() sort.Sort(ByMachineName(packs)) iterator := NewMachineIterator(packs) return iterator } // enforces no duplicate package names func (r *Machines) Append(newP *Machine) bool { machinesLock.Lock() defer machinesLock.Unlock() for _, p := range r.Machines { if p.Hostname == newP.Hostname { return false } } r.Machines = append(r.Machines, newP) return true } // returns time.Duration since last Update() func (r *Machine) Age(newP *Machine) time.Duration { t := time.Since(r.Laststamp.AsTime()) return t } // find a machine by name func (r *Machines) FindByName(name string) *Machine { machinesLock.RLock() defer machinesLock.RUnlock() for _, p := range r.Machines { if p.Hostname == name { return p } } return nil } // find a package by name func (m *Machine) FindPackageByName(name string) *Package { if m == nil { return nil } if m.Packages == nil { return nil } return m.Packages.FindByName(name) } func (r *Machines) Len() int { machinesLock.RLock() defer machinesLock.RUnlock() return len(r.Machines) } type ByMachineName []*Machine func (a ByMachineName) Len() int { return len(a) } func (a ByMachineName) Less(i, j int) bool { return a[i].Hostname < a[j].Hostname } func (a ByMachineName) Swap(i, j int) { a[i], a[j] = a[j], a[i] } // safely returns a slice of pointers to the Machine protobufs func (r *Machines) selectAllMachines() []*Machine { machinesLock.RLock() defer machinesLock.RUnlock() // Create a new slice to hold pointers to each Machine var allPacks []*Machine allPacks = make([]*Machine, len(r.Machines)) for i, p := range r.Machines { allPacks[i] = p // Copy pointers for safe iteration } return allPacks }