improve repl
add addr & help commands, don't restart if paused
This commit is contained in:
parent
c3ee33f8ce
commit
6f2e2fd666
2
main.go
2
main.go
|
@ -83,7 +83,7 @@ func main() {
|
||||||
|
|
||||||
// local 🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊
|
// local 🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
go pixelflut.Flut(img, offset, *shuffle, false, false, false, *address, *connections, stopChan, &wg)
|
go pixelflut.Flut(img, offset, *shuffle, false, false, *address, *connections, stopChan, &wg)
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if *hevringAddr != "" {
|
} else if *hevringAddr != "" {
|
||||||
|
|
|
@ -16,7 +16,7 @@ import (
|
||||||
// using `conns` connections. Pixels are sent column wise, unless `shuffle`
|
// using `conns` connections. Pixels are sent column wise, unless `shuffle`
|
||||||
// is set. Stops when stop is closed.
|
// is set. Stops when stop is closed.
|
||||||
// @cleanup: use FlutTask{} as arg
|
// @cleanup: use FlutTask{} as arg
|
||||||
func Flut(img *image.NRGBA, position image.Point, shuffle, rgbsplit, randoffset, recreateConns bool, address string, conns int, stop chan bool, wg *sync.WaitGroup) {
|
func Flut(img *image.NRGBA, position image.Point, shuffle, rgbsplit, randoffset bool, address string, conns int, stop chan bool, wg *sync.WaitGroup) {
|
||||||
var cmds commands
|
var cmds commands
|
||||||
if rgbsplit {
|
if rgbsplit {
|
||||||
// do a RGB split of white
|
// do a RGB split of white
|
||||||
|
|
|
@ -34,10 +34,17 @@ type FlutTask struct {
|
||||||
MaxConns int
|
MaxConns int
|
||||||
Img *image.NRGBA
|
Img *image.NRGBA
|
||||||
Offset image.Point
|
Offset image.Point
|
||||||
|
Paused bool
|
||||||
Shuffle bool // TODO: refactor these as RenderOpts bitfield
|
Shuffle bool // TODO: refactor these as RenderOpts bitfield
|
||||||
RGBSplit bool
|
RGBSplit bool
|
||||||
RandOffset bool
|
RandOffset bool
|
||||||
NewConn bool
|
}
|
||||||
|
|
||||||
|
func (t FlutTask) String() string {
|
||||||
|
return fmt.Sprintf(
|
||||||
|
" %d conns @ %s\n img %v offset %v\n shuffle %v rgbsplit %v randoffset %v paused %v",
|
||||||
|
t.MaxConns, t.Address, t.Img.Bounds().Size(), t.Offset, t.Shuffle, t.RGBSplit, t.RandOffset, t.Paused,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
type FlutAck struct{ Ok bool }
|
type FlutAck struct{ Ok bool }
|
||||||
|
@ -54,11 +61,11 @@ func (h *Hevring) Flut(task FlutTask, reply *FlutAck) error {
|
||||||
close(h.taskQuit)
|
close(h.taskQuit)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf("[hevring] Rán gave us /w o r k/! %v\n", task)
|
fmt.Printf("[hevring] Rán gave us /w o r k/!\n%v\n", task)
|
||||||
h.task = task
|
h.task = task
|
||||||
h.taskQuit = make(chan bool)
|
h.taskQuit = make(chan bool)
|
||||||
|
|
||||||
go pixelflut.Flut(task.Img, task.Offset, task.Shuffle, task.RGBSplit, task.RandOffset, task.NewConn, task.Address, task.MaxConns, h.taskQuit, nil)
|
go pixelflut.Flut(task.Img, task.Offset, task.Shuffle, task.RGBSplit, task.RandOffset, task.Address, task.MaxConns, h.taskQuit, nil)
|
||||||
reply.Ok = true
|
reply.Ok = true
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
16
rpc/ran.go
16
rpc/ran.go
|
@ -109,12 +109,14 @@ func (r *Rán) applyTask(t FlutTask) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
r.task = t
|
r.task = t
|
||||||
for _, c := range r.clients {
|
if t.Paused {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for i, c := range r.clients {
|
||||||
ack := FlutAck{}
|
ack := FlutAck{}
|
||||||
// @speed: should send tasks async
|
|
||||||
err := c.Call("Hevring.Flut", r.task, &ack)
|
err := c.Call("Hevring.Flut", r.task, &ack)
|
||||||
if err != nil || !ack.Ok {
|
if err != nil || !ack.Ok {
|
||||||
log.Printf("[rán] client didn't accept task")
|
log.Printf("[rán] client %d didn't accept task", i)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -142,5 +144,11 @@ func (r *Rán) SetTask(img *image.NRGBA, offset image.Point, address string, max
|
||||||
// fetch server state & sample foreign activity in image regions. assign
|
// fetch server state & sample foreign activity in image regions. assign
|
||||||
// subregions to clients (per connection), considering their bandwidth.
|
// subregions to clients (per connection), considering their bandwidth.
|
||||||
|
|
||||||
r.applyTask(FlutTask{address, maxConns, img, offset, true})
|
r.applyTask(FlutTask{
|
||||||
|
Address: address,
|
||||||
|
MaxConns: maxConns,
|
||||||
|
Img: img,
|
||||||
|
Offset: offset,
|
||||||
|
Shuffle: true,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
81
rpc/repl.go
81
rpc/repl.go
|
@ -21,8 +21,8 @@ type Fluter interface {
|
||||||
toggleMetrics()
|
toggleMetrics()
|
||||||
}
|
}
|
||||||
|
|
||||||
const commandMode = "CMD"
|
const commandMode = "cmd"
|
||||||
const textMode = "TXT"
|
const textMode = "txt"
|
||||||
|
|
||||||
// RunREPL starts reading os.Stdin for commands to apply to the given Fluter
|
// RunREPL starts reading os.Stdin for commands to apply to the given Fluter
|
||||||
func RunREPL(f Fluter) {
|
func RunREPL(f Fluter) {
|
||||||
|
@ -31,13 +31,16 @@ func RunREPL(f Fluter) {
|
||||||
var textCol image.Image = image.White
|
var textCol image.Image = image.White
|
||||||
var bgCol image.Image = image.Transparent
|
var bgCol image.Image = image.Transparent
|
||||||
|
|
||||||
|
fmt.Print("[rán] REPL is active. ")
|
||||||
|
printHelp()
|
||||||
|
|
||||||
scanner := bufio.NewScanner(os.Stdin)
|
scanner := bufio.NewScanner(os.Stdin)
|
||||||
for scanner.Scan() {
|
for scanner.Scan() {
|
||||||
inputStr := scanner.Text()
|
inputStr := scanner.Text()
|
||||||
|
|
||||||
switch mode {
|
switch strings.ToLower(mode) {
|
||||||
case textMode:
|
case textMode:
|
||||||
if inputStr == commandMode {
|
if strings.ToLower(inputStr) == commandMode {
|
||||||
fmt.Println("[rán] command mode")
|
fmt.Println("[rán] command mode")
|
||||||
mode = commandMode
|
mode = commandMode
|
||||||
continue
|
continue
|
||||||
|
@ -50,52 +53,48 @@ func RunREPL(f Fluter) {
|
||||||
input := strings.Split(inputStr, " ")
|
input := strings.Split(inputStr, " ")
|
||||||
cmd := strings.ToLower(input[0])
|
cmd := strings.ToLower(input[0])
|
||||||
args := input[1:]
|
args := input[1:]
|
||||||
|
t := f.getTask()
|
||||||
|
printTask := true
|
||||||
|
|
||||||
switch cmd {
|
switch cmd {
|
||||||
case "stop":
|
case "stop":
|
||||||
|
t.Paused = true
|
||||||
f.stopTask()
|
f.stopTask()
|
||||||
|
printTask = false
|
||||||
|
|
||||||
case "start":
|
case "start":
|
||||||
f.applyTask(f.getTask())
|
t.Paused = false
|
||||||
|
|
||||||
case "offset":
|
case "offset":
|
||||||
if len(args) == 2 {
|
if len(args) == 1 && args[0] == "rand" {
|
||||||
|
t.RandOffset = true
|
||||||
|
t.Offset = image.Point{}
|
||||||
|
} else if len(args) == 2 {
|
||||||
|
t.RandOffset = false
|
||||||
x, err := strconv.Atoi(args[0])
|
x, err := strconv.Atoi(args[0])
|
||||||
y, err2 := strconv.Atoi(args[1])
|
y, err2 := strconv.Atoi(args[1])
|
||||||
if err == nil && err2 == nil {
|
if err == nil && err2 == nil {
|
||||||
t := f.getTask()
|
|
||||||
t.Offset = image.Pt(x, y)
|
t.Offset = image.Pt(x, y)
|
||||||
f.applyTask(t)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
case "conns":
|
case "conns":
|
||||||
if len(args) == 1 {
|
if len(args) == 1 {
|
||||||
if conns, err := strconv.Atoi(args[0]); err == nil {
|
if conns, err := strconv.Atoi(args[0]); err == nil {
|
||||||
t := f.getTask()
|
|
||||||
t.MaxConns = conns
|
t.MaxConns = conns
|
||||||
f.applyTask(t)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case "addr":
|
||||||
|
if len(args) == 1 {
|
||||||
|
t.Address = args[0]
|
||||||
|
}
|
||||||
|
|
||||||
case "shuffle":
|
case "shuffle":
|
||||||
t := f.getTask()
|
|
||||||
t.Shuffle = !t.Shuffle
|
t.Shuffle = !t.Shuffle
|
||||||
f.applyTask(t)
|
|
||||||
|
|
||||||
case "rgbsplit":
|
case "rgbsplit":
|
||||||
t := f.getTask()
|
|
||||||
t.RGBSplit = !t.RGBSplit
|
t.RGBSplit = !t.RGBSplit
|
||||||
f.applyTask(t)
|
|
||||||
|
|
||||||
case "randoffset":
|
|
||||||
t := f.getTask()
|
|
||||||
t.RandOffset = !t.RandOffset
|
|
||||||
f.applyTask(t)
|
|
||||||
|
|
||||||
case "newconn":
|
|
||||||
t := f.getTask()
|
|
||||||
t.NewConn = !t.NewConn
|
|
||||||
f.applyTask(t)
|
|
||||||
|
|
||||||
case "txt":
|
case "txt":
|
||||||
if len(args) > 0 {
|
if len(args) > 0 {
|
||||||
|
@ -110,33 +109,57 @@ func RunREPL(f Fluter) {
|
||||||
bgCol = parseColorOrPalette(args[2])
|
bgCol = parseColorOrPalette(args[2])
|
||||||
}
|
}
|
||||||
if len(args) < 4 {
|
if len(args) < 4 {
|
||||||
fmt.Printf("[rán] text mode, return via %v\n", commandMode)
|
fmt.Printf("[rán] text mode, return via '%v'\n", strings.ToUpper(commandMode))
|
||||||
mode = textMode
|
mode = textMode
|
||||||
|
printTask = false
|
||||||
} else {
|
} else {
|
||||||
input := strings.Join(args[3:], " ")
|
input := strings.Join(args[3:], " ")
|
||||||
t := f.getTask()
|
|
||||||
t.Img = render.RenderText(input, textSize, textCol, bgCol)
|
t.Img = render.RenderText(input, textSize, textCol, bgCol)
|
||||||
f.applyTask(t)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case "img":
|
case "img":
|
||||||
if len(args) > 0 {
|
if len(args) > 0 {
|
||||||
path := strings.Join(args, " ")
|
path := strings.Join(args, " ")
|
||||||
t := f.getTask()
|
|
||||||
if img, err := render.ReadImage(path); err != nil {
|
if img, err := render.ReadImage(path); err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
} else {
|
} else {
|
||||||
t.Img = render.ImgToNRGBA(img)
|
t.Img = render.ImgToNRGBA(img)
|
||||||
f.applyTask(t)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
case "metrics":
|
case "metrics":
|
||||||
f.toggleMetrics()
|
f.toggleMetrics()
|
||||||
|
printTask = false
|
||||||
|
|
||||||
|
default:
|
||||||
|
printTask = false
|
||||||
|
fmt.Print("[rán] unknown command. ")
|
||||||
|
printHelp()
|
||||||
|
}
|
||||||
|
|
||||||
|
if printTask {
|
||||||
|
fmt.Println(t)
|
||||||
|
}
|
||||||
|
f.applyTask(t)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func printHelp() {
|
||||||
|
fmt.Println(`available commands:
|
||||||
|
start start fluting
|
||||||
|
stop pause fluting
|
||||||
|
conns <n> set number of connections per client
|
||||||
|
addr <host>:<port> set target server
|
||||||
|
offset <x> <y> set top-left offset
|
||||||
|
offset rand random offset for each draw
|
||||||
|
metrics toggle bandwidth reporting (may cost some performance)
|
||||||
|
|
||||||
|
img <filepath> set image
|
||||||
|
txt <scale> <color <bgcolor> <txt> send text
|
||||||
|
txt [<scale> [<color> [<bgcolor>]] enter interactive text mode
|
||||||
|
rgbsplit toggle RGB split effect
|
||||||
|
shuffle toggle between column-wise & randomized draw order`)
|
||||||
}
|
}
|
||||||
|
|
||||||
// try to parse as hex-encoded RGB color,
|
// try to parse as hex-encoded RGB color,
|
||||||
|
|
Loading…
Reference in New Issue