write.go 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. package door
  2. import (
  3. "log"
  4. "regexp"
  5. "strconv"
  6. "strings"
  7. )
  8. var FindANSIColor *regexp.Regexp
  9. func init() {
  10. FindANSIColor = regexp.MustCompile("\x1b\\[([0-9;]*)m")
  11. }
  12. /*
  13. find \x1b[0;1;37;40m codes.
  14. return array of start/end positions in the given string.
  15. */
  16. func find_ansicolor(text string) [][]int {
  17. var color_codes [][]int
  18. // word, _ := regexp.Compile("\x1b\\[([0-9;]+)m")
  19. var colors [][]int = FindANSIColor.FindAllStringIndex(text, -1)
  20. // regexp seems to be ignoring the capture groups.
  21. // colors := word.FindAllSubmatchIndex([]byte(text), len(text))
  22. for _, pos := range colors {
  23. var txt string = text[pos[0]+2 : pos[1]-1]
  24. if txt == "" {
  25. txt = "0"
  26. }
  27. // log.Printf("Text: [%s]\n", txt)
  28. var codes []string = strings.Split(txt, ";")
  29. // log.Printf("Codes: [%#v]\n", codes)
  30. var code []int = make([]int, len(codes))
  31. for idx, c := range codes {
  32. var err error
  33. code[idx], err = strconv.Atoi(c)
  34. if err != nil {
  35. log.Printf("Atoi: %#v [%s]\n", err, c)
  36. }
  37. color_codes = append(color_codes, code)
  38. }
  39. }
  40. return color_codes
  41. }
  42. type ANSIColorParts struct {
  43. Bold bool
  44. Blink bool
  45. FG int
  46. BG int
  47. }
  48. // Parse an array of codes into their ANSIColorParts.
  49. func ParseColorArray(colorarray []int) ANSIColorParts {
  50. var acp ANSIColorParts
  51. acp.FG = -1
  52. acp.BG = -1
  53. for _, c := range colorarray {
  54. switch c {
  55. case 0:
  56. acp.FG = 7
  57. acp.BG = 0
  58. case 1:
  59. acp.Bold = true
  60. case 5:
  61. acp.Blink = true
  62. case 30, 31, 32, 33, 34, 35, 36, 37:
  63. acp.FG = c - 30
  64. case 40, 41, 42, 43, 44, 45, 46, 47:
  65. acp.BG = c - 40
  66. }
  67. }
  68. return acp
  69. }
  70. // Update the LastColor with the latest codes.
  71. func (d *Door) UpdateLastColor(output string, LastColor *[]int) {
  72. // use the last color information + whatever is in the string to
  73. // track the last color set
  74. var updated ANSIColorParts = ParseColorArray(*LastColor)
  75. var colors [][]int = find_ansicolor(output)
  76. for _, codes := range colors {
  77. if codes[0] == 0 {
  78. updated = ParseColorArray(codes)
  79. } else {
  80. newCode := ParseColorArray(codes)
  81. if newCode.Bold {
  82. updated.Bold = true
  83. }
  84. if newCode.Blink {
  85. updated.Blink = true
  86. }
  87. if (newCode.FG != -1) && (newCode.FG != updated.FG) {
  88. updated.FG = newCode.FG
  89. }
  90. if (newCode.BG != -1) && (newCode.BG != updated.BG) {
  91. updated.BG = newCode.BG
  92. }
  93. }
  94. }
  95. *LastColor = make([]int, 1)
  96. (*LastColor)[0] = 0
  97. if updated.Blink {
  98. *LastColor = append(*LastColor, 5)
  99. }
  100. if updated.Bold {
  101. *LastColor = append(*LastColor, 1)
  102. }
  103. if updated.FG != -1 {
  104. *LastColor = append(*LastColor, updated.FG+30)
  105. }
  106. if updated.BG != -1 {
  107. *LastColor = append(*LastColor, updated.BG+40)
  108. }
  109. }
  110. /*
  111. reading from a closed channel is easy to detect.
  112. res, ok := <-channel
  113. ok == false
  114. writing to a closed channel is a panic.
  115. Have the Write manage itself.
  116. if
  117. */
  118. // Write string to client.
  119. func (d *Door) Write(output string) {
  120. if output == "" {
  121. return
  122. }
  123. /*
  124. if d.Disconnect() {
  125. return
  126. }
  127. defer func() {
  128. if err := recover(); err != nil {
  129. log.Println("Write FAILURE:", err)
  130. // Display error to user
  131. // This displays stack trace stderr
  132. // debug.PrintStack()
  133. }
  134. }()
  135. if d.Disconnect() {
  136. return
  137. }
  138. */
  139. // DATA RACE. Because WriterClosed is getting changed by
  140. // the closeChannel ... this isn't synchronized/safe.
  141. // DATA RACE. If I just close the writerChannel, there's
  142. // a data race on the channel. (writing to and closing)
  143. // DATA RACE. Sending a "" to the channel for a "close"
  144. // signal doesn't work either ... (called from go routine)
  145. // The channel <- is synced, the access to the bool isn't. :(
  146. //if !d.WriterClosed {
  147. // Apparently, when I get to the next line, there's
  148. // already a data race here...
  149. /*
  150. if !d.WriterIsClosed() {
  151. d.writerChannel <- output
  152. }
  153. */
  154. defer func() {
  155. if err := recover(); err != nil {
  156. log.Println("Write failed.", err)
  157. }
  158. }()
  159. //if !d.WriterIsClosed() {
  160. d.writerChannel <- output
  161. //}
  162. /*
  163. d.writerMutex.Lock()
  164. defer d.writerMutex.Unlock()
  165. if d.WriterClosed {
  166. return
  167. }
  168. d.writerChannel <- output
  169. */
  170. }