package door import ( "bufio" "bytes" "log" "strings" "syscall" "time" ) var ReaderInterval = time.Duration(200) * time.Millisecond var ReaderTimeval syscall.Timeval = syscall.NsecToTimeval(int64(ReaderInterval)) // Output a nice string representation of the rune buffer. func extended_output(buffer []rune) string { var output string = string(buffer) output = strings.Replace(output, "\x1b", "^[", -1) return output } // syscall.FdSet clear all func clearAll(fdSetPtr *syscall.FdSet) { for index := range (*fdSetPtr).Bits { (*fdSetPtr).Bits[index] = 0 } } // syscall.FdSet set fd func set(fdSetPtr *syscall.FdSet, fd int) { (*fdSetPtr).Bits[fd/64] |= 1 << uint64(fd%64) } // go routine Reader for input // This "times out" every ReaderTimeval func Reader(d *Door) { // I need non-blocking reads here. /* ReaderTimeval = syscall.Timeval{Sec: int64(ReaderInterval.Seconds()), Usec: ReaderInterval.Microseconds() % time.Second.Microseconds()} */ log.Println(ReaderInterval, ReaderTimeval) readerBuffer = make([]rune, 0, READ_SIZE*2) defer func() { log.Printf("~Reader\n") //if d.ReaderCanClose { d.wg.Done() //} }() defer func() { if err := recover(); err != nil { log.Printf("Reader: %#v\n", err) } }() var fdset syscall.FdSet var readbuffer [READ_SIZE]byte var runebuffer bytes.Buffer var runeread = bufio.NewReaderSize(&runebuffer, 1) var selectTimeval syscall.Timeval for { clearAll(&fdset) set(&fdset, d.READFD) selectTimeval = ReaderTimeval v, err := syscall.Select(d.READFD+1, &fdset, nil, nil, &selectTimeval) if err == syscall.EINTR { continue } // log.Printf("Select: %#v / %#v\n", v, err) if v == -1 { log.Printf("Reader ERR: %#v\n", err) d.readerMutex.Lock() if !d.ReaderClosed { d.ReaderClosed = true close(d.readerChannel) } return } if v == 0 { // timeout ReadRune(d, runeread, true) // process(d, false) d.readerMutex.Lock() if d.ReaderEnd { if !d.ReaderClosed { d.ReaderClosed = true close(d.readerChannel) } d.readerMutex.Unlock() return } d.readerMutex.Unlock() continue } // The buffer used here must have len & cap to size you want to read. // use [BUFF_SIZE]byte for readone r, err := syscall.Read(d.READFD, readbuffer[:]) if r == -1 { log.Println("syscall.Read -1 (closed)") d.readerMutex.Lock() defer d.readerMutex.Unlock() if !d.ReaderClosed { d.ReaderClosed = true d.Disconnected = true close(d.readerChannel) } return } if r == 0 { log.Printf("Select said ready, but: %#v %#v\n", r, err) d.readerMutex.Lock() defer d.readerMutex.Unlock() if !d.ReaderClosed { d.ReaderClosed = true d.Disconnected = true close(d.readerChannel) } return } if DEBUG_INPUT { log.Printf("Reader << %d, %#v\n", r, readbuffer[:r]) } // write the received bytes into runebuffer. runebuffer.Write(readbuffer[:r]) ReadRune(d, runeread, false) // process(d, true) // buffer = append(buffer, readone[0]) /* Take2: input, size = utf8.DecodeRune(buffer) if input != utf8.RuneError { d.readerChannel <- input for size > 0 { ArrayDelete(&buffer, 0) size-- } if len(buffer) > 0 { goto Take2 } timeoutCount = 0 } else { // Not a valid rune continue } */ // d.readerChannel <- rune(buffer[0]) } }