Highly efficient client for Pixelflut
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

main.go 3.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. package main
  2. import (
  3. "flag"
  4. "fmt"
  5. "image"
  6. _ "image/gif"
  7. _ "image/jpeg"
  8. _ "image/png"
  9. "log"
  10. "math/rand"
  11. "net"
  12. _ "net/http/pprof"
  13. "os"
  14. "runtime/pprof"
  15. "strconv"
  16. "time"
  17. )
  18. var err error
  19. var cpuprofile = flag.String("cpuprofile", "", "Destination file for CPU Profile")
  20. var image_path = flag.String("image", "", "Absolute Path to image")
  21. var image_offsetx = flag.Int("xoffset", 0, "Offset of posted image from left border")
  22. var image_offsety = flag.Int("yoffset", 0, "Offset of posted image from top border")
  23. var connections = flag.Int("connections", 4, "Number of simultaneous connections. Each connection posts a subimage")
  24. var address = flag.String("host", "127.0.0.1:1337", "Server address")
  25. var runtime = flag.String("runtime", "1", "Runtime in Minutes")
  26. var shuffle = flag.Bool("shuffle", false, "pixel send ordering")
  27. func main() {
  28. flag.Parse()
  29. if *image_path == "" {
  30. log.Fatal("No image provided")
  31. }
  32. // check connectivity by opening one test connection
  33. conn, err := net.Dial("tcp", *address)
  34. if err != nil {
  35. log.Fatal(err)
  36. }
  37. conn.Close()
  38. // Start cpu profiling if wanted
  39. if *cpuprofile != "" {
  40. f, err := os.Create(*cpuprofile)
  41. if err != nil {
  42. log.Fatal(err)
  43. }
  44. pprof.StartCPUProfile(f)
  45. defer pprof.StopCPUProfile()
  46. }
  47. // Generate and split messages into equal chunks
  48. commands := genCommands(readImage(*image_path), *image_offsetx, *image_offsety)
  49. if *shuffle {
  50. shuffleCommands(commands)
  51. }
  52. commandGroups := chunkCommands(commands, *connections)
  53. for _, messages := range commandGroups {
  54. go bomb(messages)
  55. }
  56. // Terminate after 1 Minute to save resources
  57. timer, err := time.ParseDuration(*runtime + "m")
  58. if err != nil {
  59. log.Fatal("Invalid runtime specified: " + err.Error())
  60. }
  61. time.Sleep(time.Minute * timer)
  62. }
  63. func bomb(messages []byte) {
  64. conn, err := net.Dial("tcp", *address)
  65. if err != nil {
  66. log.Fatal(err)
  67. }
  68. defer conn.Close()
  69. // Start bombardement
  70. for {
  71. _, err := conn.Write(messages)
  72. if err != nil {
  73. log.Fatal(err)
  74. }
  75. }
  76. }
  77. func readImage(path string) (img image.Image) {
  78. reader, err := os.Open(path)
  79. if err != nil {
  80. log.Fatal(err)
  81. }
  82. img, _, err2 := image.Decode(reader)
  83. if err2 != nil {
  84. log.Fatal(err2)
  85. }
  86. return img
  87. }
  88. func intToHex(x uint32) string {
  89. str := strconv.FormatInt(int64(x), 16)
  90. if len(str) == 1 {
  91. str = "0" + str
  92. }
  93. return str[0:2]
  94. }
  95. // Creates message based on given image
  96. func genCommands(img image.Image, offset_x, offset_y int) (commands [][]byte) {
  97. max_x := img.Bounds().Max.X
  98. max_y := img.Bounds().Max.Y
  99. commands = make([][]byte, max_x*max_y)
  100. for x := 0; x < max_x; x++ {
  101. for y := 0; y < max_y; y++ {
  102. r, g, b, _ := img.At(x, y).RGBA()
  103. colStr := intToHex(r) + intToHex(g) + intToHex(b)
  104. cmd := fmt.Sprintf("PX %d %d %s\n", x+offset_x, y+offset_y, colStr)
  105. commands[x*max_y+y] = []byte(cmd)
  106. }
  107. }
  108. return commands
  109. }
  110. // Splits messages into equally sized chunks
  111. func chunkCommands(commands [][]byte, numChunks int) [][]byte {
  112. chunks := make([][]byte, numChunks)
  113. chunkLength := len(commands) / numChunks
  114. for i := 0; i < numChunks; i++ {
  115. cmdOffset := i * chunkLength
  116. for j := 0; j < chunkLength; j++ {
  117. chunks[i] = append(chunks[i], commands[cmdOffset+j]...)
  118. }
  119. }
  120. return chunks
  121. }
  122. func shuffleCommands(slice [][]byte) {
  123. for i := range slice {
  124. j := rand.Intn(i + 1)
  125. slice[i], slice[j] = slice[j], slice[i]
  126. }
  127. }