浏览代码

Working tests.

Learning about channels (buffered/unbuffered).
Learning about syscall.Read().
Steve Thielemann 2 年之前
父节点
当前提交
06112c7872
共有 5 个文件被更改,包括 146 次插入93 次删除
  1. 6 1
      door/door.go
  2. 4 0
      door/door_test.go
  3. 6 6
      door/input.go
  4. 111 79
      door/input_linux.go
  5. 19 7
      door/input_test.go

+ 6 - 1
door/door.go

@@ -445,7 +445,12 @@ func (d *Door) Init(doorname string) {
 	log.Printf("Loading dropfile %s\n", dropfile)
 	log.Printf("BBS %s, User %s / Handle %s / File %d\n", d.Config.BBSID, d.Config.Real_name, d.Config.Handle, d.Config.Comm_handle)
 
-	d.readerChannel = make(chan rune, 8)
+	d.readerChannel = make(chan rune) // was 8 ?
+	/*
+		Ok, here's the issue.  This blocks the go reader when this is full.
+		It seems like it would be better to have a channel that receives
+		rune, Extended instead.
+	*/
 	d.writerChannel = make(chan string) // unbuffered
 
 	// changing this to unbound/sync hangs tests.

+ 4 - 0
door/door_test.go

@@ -9,6 +9,10 @@ import (
 	"time"
 )
 
+// Should tests not delete the logfiles?
+const KEEP_LOGS bool = true
+const VERBOSE_TEST bool = true
+
 func TestGoto(t *testing.T) {
 	GotoMap := map[string][]int{"\x1b[10;20H": {20, 10},
 		"\x1b[20;10H":  {10, 20},

+ 6 - 6
door/input.go

@@ -214,12 +214,12 @@ func (d *Door) GetKey() (rune, Extended, error) {
 			return r, F9, nil
 		case 0x44:
 			return r, F10, nil
-		/*
-			case 0x45:
-				return F11
-			case 0x46:
-				return F12
-		*/
+
+		case 0x45:
+			return r, F11, nil
+		case 0x46:
+			return r, F12, nil
+
 		case 0x52:
 			return r, INSERT, nil
 		case 0x53:

+ 111 - 79
door/input_linux.go

@@ -1,24 +1,58 @@
 package door
 
 import (
+	"bufio"
+	"bytes"
 	"log"
 	"syscall"
 	"time"
+	"unicode"
 )
 
 var ReaderInterval = time.Duration(200) * time.Millisecond
 var ReaderTimeval syscall.Timeval = syscall.Timeval{0, 200}
 
+// 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)
 }
 
+/*
+	func main() {
+		var text string = "\x1b\u2415\xff"
+		var buffer []byte = []byte(text)
+		var readbuffer = bytes.NewBuffer(buffer)
+		// bytes.Buffer{}
+		// readbuffer.Write(buffer)
+
+		var runeread = bufio.NewReaderSize(readbuffer, 1)
+
+		//for readbuffer.Len() > 0 {
+		for {
+			r, _, err := runeread.ReadRune()
+			if err != nil {
+				break
+			}
+			if r == unicode.ReplacementChar {
+				runeread.UnreadRune()
+				b, _ := runeread.ReadByte()
+				fmt.Printf("BYTE %#v\n", b)
+			} else {
+				fmt.Printf("%#v\n", r)
+			}
+		}
+*/
+const READ_SIZE = 16
+
+// go routine Reader for input
+// This "times out" every ReaderTimeval
 func Reader(d *Door) {
 	// I need non-blocking reads here.
 
@@ -40,6 +74,12 @@ func Reader(d *Door) {
 	}()
 
 	var fdset syscall.FdSet
+	var readone []byte = make([]byte, READ_SIZE) //make([]byte, 0, READ_SIZE)
+	// read 1 byte
+	var readbuffer bytes.Buffer // NewBuffer(readone)
+	var runeread = bufio.NewReaderSize(&readbuffer, 1)
+
+	// var buffer []byte = make([]byte, 0)  // unicode read buffer
 
 	for {
 		clearAll(&fdset)
@@ -65,16 +105,34 @@ func Reader(d *Door) {
 
 		if v == 0 {
 			// timeout
+			/*
+				if len(buffer) > 0 {
+					timeoutCount++
+
+					input, size = utf8.DecodeRune(buffer)
+					if input != utf8.RuneError {
+						d.readerChannel <- input
+						for size > 0 {
+							ArrayDelete(&buffer, 0)
+							size--
+						}
+						timeoutCount = 0
+
+					} else {
+						b, _ := ArrayDelete(&buffer, 0)
+						d.readerChannel <- rune(b)
+					}
+				} else {
+					timeoutCount = 0
+				}
+			*/
 			continue
 		}
 
-		// d.readerFile.SetReadDeadline(time.Now().Add(ReaderInterval))
-		// not on a os.File you won't. :P
-
-		// r, _, err := d.runereader.ReadRune()
+		log.Println("syscall.Read:", len(readone), cap(readone))
+		// The buffer used here must have len & cap to size you want to read.
 
-		buffer := make([]byte, 1)
-		r, err := syscall.Read(d.READFD, buffer)
+		r, err := syscall.Read(d.READFD, readone)
 		if r == -1 {
 			log.Println("Read -1 (closed)")
 			d.readerMutex.Lock()
@@ -86,7 +144,7 @@ func Reader(d *Door) {
 			}
 			return
 		}
-		if r != 1 {
+		if r == 0 {
 			log.Printf("Select said ready, but: %#v %#v\n", r, err)
 			d.readerMutex.Lock()
 			defer d.readerMutex.Unlock()
@@ -97,89 +155,63 @@ func Reader(d *Door) {
 			}
 			return
 		}
+		// readone = readone[:r]
 
 		if DEBUG_INPUT {
-			log.Printf("Reader (byte): %#v\n", buffer[0])
+			log.Printf("Reader << %d, %#v\n", r, readone[:r])
 		}
 
-		d.readerChannel <- rune(buffer[0])
+		// Is this unicode?
+		readbuffer.Write(readone[:r])
+		// reset
+		// readone = readone[0:0]
+		log.Println("readone:", len(readone), cap(readone))
+		var input rune
 
-		/*
-			if r == unicode.ReplacementChar {
-				_ = d.runereader.UnreadRune()
-				b, _ := d.runereader.ReadByte()
-				if DEBUG_INPUT {
-					log.Printf("Reader (byte): %#v\n", b)
-				}
-				d.readerChannel <- rune(b)
-				continue
-			}
+	RuneRead:
 
-			if err == nil {
-				if DEBUG_INPUT {
-					log.Printf("Reader (rune): %#v\n", r)
-				}
-				d.readerChannel <- r
-				continue
+		input, _, err = runeread.ReadRune()
+		if err != nil {
+			log.Printf("ReadRune: %#v\n", err)
+			// errors EOF
+			continue
+		}
+		if input == unicode.ReplacementChar {
+			runeread.UnreadRune()
+			b, _ := runeread.ReadByte()
+			if DEBUG_INPUT {
+				log.Printf("Reader (byte) >> %x\n", b)
 			}
-		*/
-
-		// I'm not sure I care what the error is we're getting here...
-
-		/*
-			if e, ok := err.(net.Error); ok && e.Timeout() {
-
-			} else {
-
+			d.readerChannel <- rune(b)
+		} else {
+			if DEBUG_INPUT {
+				log.Printf("Reader >> %x\n", input)
 			}
-		*/
+			d.readerChannel <- input
+		}
+		goto RuneRead
+
+		// buffer = append(buffer, readone[0])
 
 		/*
-			log.Printf("Reader ERR: %#v\n", err)
-			d.ReaderClosed = true
-			close(d.readerChannel)
-			return
+			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
+				}
 		*/
-	}
-}
-
-/*
-func Reader(handle int, readerChannel *chan byte) {
-	// I don't need the select anymore.  Let the read block.
-	defer func() {
-		if err := recover(); err != nil {
-			log.Printf("Reader: %#v\n", err)
-		}
-	}()
+		// d.readerChannel <- rune(buffer[0])
 
-	buffer := make([]byte, 1)
-	for {
-		// blocking read in go routine
-		// why doesn't this end when I close the handle?
-		read, err := syscall.Read(handle, buffer)
-		if err != nil {
-			log.Printf("Reader ERR: %#v\n", err)
-			close(*readerChannel)
-			break
-		}
-		if read == 1 {
-			*readerChannel <- buffer[0]
-		} else {
-			log.Printf("READ FAILED %d\n", read)
-			close(*readerChannel)
-			break
-		}
 	}
 }
-
-// This doesn't work.  Closing the handle does not unblock the syscall.Read above.
-func CloseReader(handle int) {
-	defer func() {
-		if err := recover(); err != nil {
-			log.Printf("CloseReader: %#v\n", err)
-		}
-	}()
-
-	syscall.Close(handle)
-}
-*/

+ 19 - 7
door/input_test.go

@@ -11,8 +11,6 @@ import (
 	"time"
 )
 
-const KEEP_LOGS = true
-
 func clear_socket(socket net.Conn, t *testing.T) string {
 	// Clear out the data that's pending in the socket.
 
@@ -164,12 +162,26 @@ func TestDoorInputConnection(t *testing.T) {
 		"\x1b[20~\x1b[21~\x1b[23~\x1b[24~": []Extended{F9, F10, F11, F12},
 	}
 
+	keyWait := time.Duration(50 * time.Millisecond)
+
+	// Verify input is empty
+	for {
+		input, ex, err := d.WaitKey(keyWait)
+		if err == nil {
+			t.Errorf("Keys: %#v, %#v\n", input, ex)
+		} else {
+			break
+		}
+	}
+
 	t.Logf("Starting keytest\n")
 
-	keyWait := time.Duration(50 * time.Millisecond)
 	// 5 * time.Second) //50 * time.Millisecond)
 
 	for send, get := range keytest {
+		if VERBOSE_TEST {
+			t.Logf("Sending %#v: Expect: %#v\n", send, get)
+		}
 		var buffer []byte = []byte(send)
 		_, err = server.Write(buffer)
 		if err != nil {
@@ -218,7 +230,7 @@ func TestDoorInputConnection(t *testing.T) {
 		}
 
 		if len(recv) != len(get) {
-			t.Errorf("Send %#v, LEN expected %#v, got %#v", send, get, recv)
+			t.Errorf("Sent %#v, LEN expected %#v, got %#v", send, get, recv)
 		} else {
 			matches := true
 			for idx, i := range get {
@@ -228,7 +240,7 @@ func TestDoorInputConnection(t *testing.T) {
 				}
 			}
 			if !matches {
-				t.Errorf("Send %#v, MATCH expected %#v, got %#v", send, get, recv)
+				t.Errorf("Sent %#v, MATCH expected %#v, got %#v", send, get, recv)
 			}
 		}
 	}
@@ -285,7 +297,7 @@ func TestDoorInputConnection(t *testing.T) {
 		}
 
 		if len(recv) != len(get) {
-			t.Errorf("Send %#v, LEN expected %#v, got %#v", send, get, recv)
+			t.Errorf("Sent %#v, LEN expected %#v, got %#v", send, get, recv)
 		} else {
 			matches := true
 			for idx, i := range get {
@@ -295,7 +307,7 @@ func TestDoorInputConnection(t *testing.T) {
 				}
 			}
 			if !matches {
-				t.Errorf("Send %#v, MATCH expected %#v, got %#v", send, get, recv)
+				t.Errorf("Sent %#v, MATCH expected %#v, got %#v", send, get, recv)
 			}
 		}
 	}