148 lines
2.2 KiB
Go
148 lines
2.2 KiB
Go
package ipalloc
|
|
|
|
import (
|
|
"bufio"
|
|
"fmt"
|
|
"log"
|
|
"net/netip"
|
|
"os"
|
|
"slices"
|
|
"syscall"
|
|
)
|
|
|
|
type Store interface {
|
|
Append(Operation) error
|
|
Operations() (Scanner, error)
|
|
}
|
|
|
|
type Scanner interface {
|
|
Next() bool
|
|
Operation() Operation
|
|
Err() error
|
|
}
|
|
|
|
type Operation interface {
|
|
Prefix() netip.Prefix
|
|
}
|
|
|
|
type op struct {
|
|
prefix netip.Prefix
|
|
}
|
|
|
|
func (o op) Prefix() netip.Prefix {
|
|
return o.prefix
|
|
}
|
|
|
|
type OpProvision struct{ op }
|
|
|
|
type OpAllocation struct{ op }
|
|
|
|
type OpDeallocation struct{ op }
|
|
|
|
type Memstore struct {
|
|
ops []Operation
|
|
}
|
|
|
|
func (m *Memstore) Append(op Operation) error {
|
|
m.ops = append(m.ops, op)
|
|
return nil
|
|
}
|
|
|
|
func (m *Memstore) Operations() (Scanner, error) {
|
|
return &memscanner{opQueue: slices.Clip(m.ops)}, nil
|
|
}
|
|
|
|
type memscanner struct {
|
|
cur Operation
|
|
opQueue []Operation
|
|
}
|
|
|
|
func (m *memscanner) Next() bool {
|
|
if len(m.opQueue) == 0 {
|
|
return false
|
|
}
|
|
|
|
m.opQueue, m.cur = m.opQueue[1:], m.opQueue[0]
|
|
return true
|
|
}
|
|
|
|
func (m *memscanner) Operation() Operation {
|
|
return m.cur
|
|
}
|
|
|
|
func (m *memscanner) Err() error {
|
|
return nil
|
|
}
|
|
|
|
type Filestore struct {
|
|
filepath string
|
|
}
|
|
|
|
func (fs *Filestore) Append(op Operation) error {
|
|
f, err := os.OpenFile(fs.filepath, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer f.Close()
|
|
|
|
if err = syscall.Flock(int(f.Fd()), syscall.LOCK_EX); err != nil {
|
|
return err
|
|
}
|
|
|
|
_, err = fmt.Fprintln(f, op)
|
|
return err
|
|
}
|
|
|
|
func (fs *Filestore) Operations() (Scanner, error) {
|
|
f, err := os.OpenFile(fs.filepath, os.O_RDONLY, 0)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if err = syscall.Flock(int(f.Fd()), syscall.LOCK_SH); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return newFileScanner(f), nil
|
|
}
|
|
|
|
type fileScanner struct {
|
|
err error
|
|
cur Operation
|
|
f *os.File
|
|
s bufio.Scanner
|
|
}
|
|
|
|
func newFileScanner(f *os.File) *fileScanner {
|
|
return &fileScanner{
|
|
err: nil,
|
|
cur: nil,
|
|
f: f,
|
|
s: *bufio.NewScanner(f),
|
|
}
|
|
}
|
|
|
|
func (f *fileScanner) Next() bool {
|
|
if f.f == nil {
|
|
return false
|
|
}
|
|
if !f.s.Scan() {
|
|
f.err = f.s.Err()
|
|
if err := f.f.Close(); err != nil {
|
|
log.Println(err)
|
|
}
|
|
return false
|
|
}
|
|
log.Println(f.s.Text())
|
|
f.cur = nil // TODO: parse
|
|
return true
|
|
}
|
|
|
|
func (f *fileScanner) Operation() Operation {
|
|
return f.cur
|
|
}
|
|
|
|
func (f *fileScanner) Err() error {
|
|
return f.err
|
|
}
|