refactor code into separate files
preparation for more refactoring
This commit is contained in:
		
							parent
							
								
									49cda88dd5
								
							
						
					
					
						commit
						2a10ebd77d
					
				|  | @ -0,0 +1,33 @@ | ||||||
|  | package main | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"image" | ||||||
|  | 	_ "image/gif" | ||||||
|  | 	_ "image/jpeg" | ||||||
|  | 	"image/png" | ||||||
|  | 	"log" | ||||||
|  | 	"os" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | func readImage(path string) (img image.Image) { | ||||||
|  | 	reader, err := os.Open(path) | ||||||
|  | 	if err != nil { | ||||||
|  | 		log.Fatal(err) | ||||||
|  | 	} | ||||||
|  | 	img, _, err2 := image.Decode(reader) | ||||||
|  | 	if err2 != nil { | ||||||
|  | 		log.Fatal(err2) | ||||||
|  | 	} | ||||||
|  | 	return img | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func writeImage(path string, img image.Image) { | ||||||
|  | 	f, err := os.Create(path) | ||||||
|  | 	if err != nil { | ||||||
|  | 		log.Fatal(err) | ||||||
|  | 	} | ||||||
|  | 	if err := png.Encode(f, img); err != nil { | ||||||
|  | 		f.Close() | ||||||
|  | 		log.Fatal(err) | ||||||
|  | 	} | ||||||
|  | } | ||||||
							
								
								
									
										162
									
								
								main.go
								
								
								
								
							
							
						
						
									
										162
									
								
								main.go
								
								
								
								
							|  | @ -1,23 +1,15 @@ | ||||||
| package main | package main | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
| 	"bufio" |  | ||||||
| 	"encoding/hex" |  | ||||||
| 	"flag" | 	"flag" | ||||||
| 	"fmt" |  | ||||||
| 	"image" | 	"image" | ||||||
| 	"image/color" |  | ||||||
| 	_ "image/gif" |  | ||||||
| 	_ "image/jpeg" |  | ||||||
| 	"image/png" |  | ||||||
| 	"log" | 	"log" | ||||||
| 	"math/rand" |  | ||||||
| 	"net" | 	"net" | ||||||
| 	"net/textproto" |  | ||||||
| 	"os" | 	"os" | ||||||
| 	"runtime/pprof" | 	"runtime/pprof" | ||||||
| 	"strings" |  | ||||||
| 	"time" | 	"time" | ||||||
|  | 
 | ||||||
|  | 	"github.com/SpeckiJ/Hochwasser/pixelflut" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| var err error | var err error | ||||||
|  | @ -67,23 +59,23 @@ func main() { | ||||||
| 		b2 := b1.Add(image.Pt(b1.Dx(), 0)) | 		b2 := b1.Add(image.Pt(b1.Dx(), 0)) | ||||||
| 		b3 := b1.Add(image.Pt(0, b1.Dy())) | 		b3 := b1.Add(image.Pt(0, b1.Dy())) | ||||||
| 		b4 := b1.Add(b1.Size()) | 		b4 := b1.Add(b1.Size()) | ||||||
| 		go fetchImage(fetchedImg.SubImage(b1).(*image.NRGBA)) | 		go pixelflut.FetchImage(fetchedImg.SubImage(b1).(*image.NRGBA), *address) | ||||||
| 		go fetchImage(fetchedImg.SubImage(b2).(*image.NRGBA)) | 		go pixelflut.FetchImage(fetchedImg.SubImage(b2).(*image.NRGBA), *address) | ||||||
| 		go fetchImage(fetchedImg.SubImage(b3).(*image.NRGBA)) | 		go pixelflut.FetchImage(fetchedImg.SubImage(b3).(*image.NRGBA), *address) | ||||||
| 		go fetchImage(fetchedImg.SubImage(b4).(*image.NRGBA)) | 		go pixelflut.FetchImage(fetchedImg.SubImage(b4).(*image.NRGBA), *address) | ||||||
| 		*connections -= 4 | 		*connections -= 4 | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// Generate and split messages into equal chunks
 | 	// Generate and split messages into equal chunks
 | ||||||
| 	commands := genCommands(img, offset) | 	commands := pixelflut.CommandsFromImage(img, offset) | ||||||
| 	if *shuffle { | 	if *shuffle { | ||||||
| 		shuffleCommands(commands) | 		commands.Shuffle() | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if *connections > 0 { | 	if *connections > 0 { | ||||||
| 		commandGroups := chunkCommands(commands, *connections) | 		commandGroups := commands.Chunk(*connections) | ||||||
| 		for _, messages := range commandGroups { | 		for _, messages := range commandGroups { | ||||||
| 			go bomb(messages) | 			go pixelflut.Bomb(messages, *address) | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -98,137 +90,3 @@ func main() { | ||||||
| 		writeImage(*fetchImgPath, fetchedImg) | 		writeImage(*fetchImgPath, fetchedImg) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 |  | ||||||
| func bomb(messages []byte) { |  | ||||||
| 	conn, err := net.Dial("tcp", *address) |  | ||||||
| 	if err != nil { |  | ||||||
| 		log.Fatal(err) |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	defer conn.Close() |  | ||||||
| 
 |  | ||||||
| 	// Start bombardement
 |  | ||||||
| 	for { |  | ||||||
| 		_, err := conn.Write(messages) |  | ||||||
| 		if err != nil { |  | ||||||
| 			log.Fatal(err) |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func readImage(path string) (img image.Image) { |  | ||||||
| 	reader, err := os.Open(path) |  | ||||||
| 	if err != nil { |  | ||||||
| 		log.Fatal(err) |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	img, _, err2 := image.Decode(reader) |  | ||||||
| 	if err2 != nil { |  | ||||||
| 		log.Fatal(err2) |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	return img |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func writeImage(path string, img image.Image) { |  | ||||||
| 	f, err := os.Create(path) |  | ||||||
| 	if err != nil { |  | ||||||
| 		log.Fatal(err) |  | ||||||
| 	} |  | ||||||
| 	if err := png.Encode(f, img); err != nil { |  | ||||||
| 		f.Close() |  | ||||||
| 		log.Fatal(err) |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // Creates message based on given image
 |  | ||||||
| func genCommands(img image.Image, offset image.Point) (commands [][]byte) { |  | ||||||
| 	b := img.Bounds() |  | ||||||
| 	commands = make([][]byte, b.Size().X*b.Size().Y) |  | ||||||
| 	numCmds := 0 |  | ||||||
| 
 |  | ||||||
| 	for x := b.Min.X; x < b.Max.X; x++ { |  | ||||||
| 		for y := b.Min.Y; y < b.Max.Y; y++ { |  | ||||||
| 			// ensure we're working with RGBA colors (non-alpha-pre-multiplied)
 |  | ||||||
| 			c := color.NRGBAModel.Convert(img.At(x, y)).(color.NRGBA) |  | ||||||
| 
 |  | ||||||
| 			// ignore transparent pixels
 |  | ||||||
| 			if c.A == 0 { |  | ||||||
| 				continue |  | ||||||
| 			} |  | ||||||
| 			// @incomplete: also send alpha? -> bandwidth tradeoff
 |  | ||||||
| 			// @speed: this sprintf call is quite slow..
 |  | ||||||
| 			cmd := fmt.Sprintf("PX %d %d %.2x%.2x%.2x\n", |  | ||||||
| 				x + offset.X, y + offset.Y, c.R, c.G, c.B) |  | ||||||
| 			commands[numCmds] = []byte(cmd) |  | ||||||
| 			numCmds++ |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	return commands[:numCmds] |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // Splits messages into equally sized chunks
 |  | ||||||
| func chunkCommands(commands [][]byte, numChunks int) [][]byte { |  | ||||||
| 	chunks := make([][]byte, numChunks) |  | ||||||
| 
 |  | ||||||
| 	chunkLength := len(commands) / numChunks |  | ||||||
| 	for i := 0; i < numChunks; i++ { |  | ||||||
| 		cmdOffset := i * chunkLength |  | ||||||
| 		for j := 0; j < chunkLength; j++ { |  | ||||||
| 			chunks[i] = append(chunks[i], commands[cmdOffset+j]...) |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	return chunks |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func shuffleCommands(slice [][]byte) { |  | ||||||
| 	for i := range slice { |  | ||||||
| 		j := rand.Intn(i + 1) |  | ||||||
| 		slice[i], slice[j] = slice[j], slice[i] |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func fetchImage(img *image.NRGBA) { |  | ||||||
| 	// FIXME @speed: this is unusably s l o w w w
 |  | ||||||
| 	// bottleneck seems to be our pixel reading/parsing code. cpuprofile!
 |  | ||||||
| 	// -> should buffer it just as in bomb()
 |  | ||||||
| 
 |  | ||||||
| 	conn, err := net.Dial("tcp", *address) |  | ||||||
| 	if err != nil { |  | ||||||
| 		log.Fatal(err) |  | ||||||
| 	} |  | ||||||
| 	defer conn.Close() |  | ||||||
| 
 |  | ||||||
| 	reader := bufio.NewReader(conn) |  | ||||||
| 	tp := textproto.NewReader(reader) |  | ||||||
| 
 |  | ||||||
| 	b := img.Bounds() |  | ||||||
| 	for { |  | ||||||
| 		for x := b.Min.X; x < b.Max.X; x++ { |  | ||||||
| 			for y := b.Min.Y; y < b.Max.Y; y++ { |  | ||||||
| 				// request pixel
 |  | ||||||
| 				fmt.Fprintf(conn, "PX %d %d\n", x, y) |  | ||||||
| 				if err != nil { |  | ||||||
| 					log.Fatal(err) |  | ||||||
| 				} |  | ||||||
| 
 |  | ||||||
| 				// read pixel
 |  | ||||||
| 				// @speed try to run this in a separate goroutine?
 |  | ||||||
| 				// we probably need to buffer the responses then
 |  | ||||||
| 				res, err := tp.ReadLine() |  | ||||||
| 				if err != nil { |  | ||||||
| 					log.Fatal(err) |  | ||||||
| 				} |  | ||||||
| 				res2 := strings.Split(res, " ") |  | ||||||
| 				col, _ := hex.DecodeString(res2[3]) |  | ||||||
| 				img.Set(x, y, color.NRGBA{ |  | ||||||
| 					uint8(col[0]), |  | ||||||
| 					uint8(col[1]), |  | ||||||
| 					uint8(col[2]), |  | ||||||
| 					255, |  | ||||||
| 				}) |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  | @ -0,0 +1,30 @@ | ||||||
|  | package pixelflut | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"math/rand" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | // Commands represent a list of messages to be sent to a pixelflut server.
 | ||||||
|  | type Commands [][]byte | ||||||
|  | 
 | ||||||
|  | // Chunk splits commands into equally sized chunks, while flattening each chunk
 | ||||||
|  | // so that all commands are concatenated as a single `[]byte`.
 | ||||||
|  | func (c Commands) Chunk(numChunks int) [][]byte { | ||||||
|  | 	chunks := make([][]byte, numChunks) | ||||||
|  | 	chunkLength := len(c) / numChunks | ||||||
|  | 	for i := 0; i < numChunks; i++ { | ||||||
|  | 		cmdOffset := i * chunkLength | ||||||
|  | 		for j := 0; j < chunkLength; j++ { | ||||||
|  | 			chunks[i] = append(chunks[i], c[cmdOffset+j]...) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return chunks | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Shuffle reorders commands randomly, in place.
 | ||||||
|  | func (c Commands) Shuffle() { | ||||||
|  | 	for i := range c { | ||||||
|  | 		j := rand.Intn(i + 1) | ||||||
|  | 		c[i], c[j] = c[j], c[i] | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | @ -0,0 +1,57 @@ | ||||||
|  | package pixelflut | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"bufio" | ||||||
|  | 	"encoding/hex" | ||||||
|  | 	"fmt" | ||||||
|  | 	"image" | ||||||
|  | 	"image/color" | ||||||
|  | 	"log" | ||||||
|  | 	"net" | ||||||
|  | 	"net/textproto" | ||||||
|  | 	"strings" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | func FetchImage(img *image.NRGBA, address string) { | ||||||
|  | 	// FIXME @speed: this is unusably s l o w w w
 | ||||||
|  | 	// bottleneck seems to be our pixel reading/parsing code. cpuprofile!
 | ||||||
|  | 	// -> should buffer it just as in bomb()
 | ||||||
|  | 
 | ||||||
|  | 	conn, err := net.Dial("tcp", address) | ||||||
|  | 	if err != nil { | ||||||
|  | 		log.Fatal(err) | ||||||
|  | 	} | ||||||
|  | 	defer conn.Close() | ||||||
|  | 
 | ||||||
|  | 	reader := bufio.NewReader(conn) | ||||||
|  | 	tp := textproto.NewReader(reader) | ||||||
|  | 
 | ||||||
|  | 	b := img.Bounds() | ||||||
|  | 	for { | ||||||
|  | 		for x := b.Min.X; x < b.Max.X; x++ { | ||||||
|  | 			for y := b.Min.Y; y < b.Max.Y; y++ { | ||||||
|  | 				// request pixel
 | ||||||
|  | 				fmt.Fprintf(conn, "PX %d %d\n", x, y) | ||||||
|  | 				if err != nil { | ||||||
|  | 					log.Fatal(err) | ||||||
|  | 				} | ||||||
|  | 
 | ||||||
|  | 				// read pixel
 | ||||||
|  | 				// @speed try to run this in a separate goroutine?
 | ||||||
|  | 				// we probably need to buffer the responses then
 | ||||||
|  | 				res, err := tp.ReadLine() | ||||||
|  | 				if err != nil { | ||||||
|  | 					log.Fatal(err) | ||||||
|  | 				} | ||||||
|  | 				res2 := strings.Split(res, " ") | ||||||
|  | 				col, _ := hex.DecodeString(res2[3]) | ||||||
|  | 				img.Set(x, y, color.NRGBA{ | ||||||
|  | 					uint8(col[0]), | ||||||
|  | 					uint8(col[1]), | ||||||
|  | 					uint8(col[2]), | ||||||
|  | 					255, | ||||||
|  | 				}) | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | @ -0,0 +1,23 @@ | ||||||
|  | package pixelflut | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"net" | ||||||
|  | 	"log" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | // Bomb writes the given message via plain TCP to the given address,
 | ||||||
|  | // forever, as fast as possible.
 | ||||||
|  | func Bomb(message []byte, address string) { | ||||||
|  | 	conn, err := net.Dial("tcp", address) | ||||||
|  | 	if err != nil { | ||||||
|  | 		log.Fatal(err) | ||||||
|  | 	} | ||||||
|  | 	defer conn.Close() | ||||||
|  | 
 | ||||||
|  | 	for { | ||||||
|  | 		_, err := conn.Write(message) | ||||||
|  | 		if err != nil { | ||||||
|  | 			log.Fatal(err) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | @ -0,0 +1,34 @@ | ||||||
|  | package pixelflut | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"fmt" | ||||||
|  | 	"image" | ||||||
|  | 	"image/color" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | // CommandsFromImage converts an image to the respective pixelflut commands
 | ||||||
|  | func CommandsFromImage(img image.Image, offset image.Point) (commands Commands) { | ||||||
|  | 	b := img.Bounds() | ||||||
|  | 	commands = make([][]byte, b.Size().X*b.Size().Y) | ||||||
|  | 	numCmds := 0 | ||||||
|  | 
 | ||||||
|  | 	for x := b.Min.X; x < b.Max.X; x++ { | ||||||
|  | 		for y := b.Min.Y; y < b.Max.Y; y++ { | ||||||
|  | 			// ensure we're working with RGBA colors (non-alpha-pre-multiplied)
 | ||||||
|  | 			c := color.NRGBAModel.Convert(img.At(x, y)).(color.NRGBA) | ||||||
|  | 
 | ||||||
|  | 			// ignore transparent pixels
 | ||||||
|  | 			if c.A == 0 { | ||||||
|  | 				continue | ||||||
|  | 			} | ||||||
|  | 			// @incomplete: also send alpha? -> bandwidth tradeoff
 | ||||||
|  | 			// @speed: this sprintf call is quite slow..
 | ||||||
|  | 			cmd := fmt.Sprintf("PX %d %d %.2x%.2x%.2x\n", | ||||||
|  | 				x + offset.X, y + offset.Y, c.R, c.G, c.B) | ||||||
|  | 			commands[numCmds] = []byte(cmd) | ||||||
|  | 			numCmds++ | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return commands[:numCmds] | ||||||
|  | } | ||||||
		Loading…
	
		Reference in New Issue