소스 검색

Initial tries of getting d.Close/shutdown.

I'm not using the closeChannel -- that needs to be removed.
But, what I have currently seems to be working / telnet close
while nms/about in testdoor does "Ending testdoor" with Closing
and Closed.
Steve Thielemann 3 년 전
부모
커밋
1ab9c54941
10개의 변경된 파일144개의 추가작업 그리고 20개의 파일을 삭제
  1. 5 1
      Makefile
  2. 20 0
      door/door.go
  3. 3 1
      door/door_linux.go
  4. 1 0
      door/door_test.go
  5. 3 0
      door/input_linux.go
  6. 14 1
      door/input_test.go
  7. 1 0
      door/menu_test.go
  8. 4 1
      door/write.go
  9. 77 16
      door/write_linux.go
  10. 16 0
      testdoor/testdoor.go

+ 5 - 1
Makefile

@@ -1,6 +1,7 @@
 
-all: door32 testdoor/testdoor testdoor/art.go space-ace/space-ace
+all: door32 testdoor testdoor/art.go space-ace/space-ace
 
+testdoor: testdoor/testdoor testdoor/testdoor.exe
 
 font-out: font-out.go
 	go build font-out.go
@@ -34,6 +35,9 @@ space-ace/space.go: space.ans
 testdoor/testdoor: testdoor/art.go testdoor/fonts.go testdoor/rgfont.go testdoor/*.go door/*.go
 	cd testdoor; go build
 
+testdoor/testdoor.exe: testdoor/art.go testdoor/fonts.go testdoor/rgfont.go testdoor/*.go door/*.go
+	cd testdoor; GOOS=windows GOARCH=amd64 go build
+
 space-ace/space-ace: space-ace/*.go door/*.go space-ace/space.go
 	cd space-ace; go build -ldflags="-extldflags=-static" -tags sqlite_omit_load_extension
 

+ 20 - 0
door/door.go

@@ -30,6 +30,7 @@ import (
 	"strings"
 	"sync"
 	"time"
+	"runtime/debug"
 )
 
 const SavePos = "\x1b[s"              // Save Cursor Position
@@ -88,6 +89,8 @@ type Door struct {
 	LastColor     []int
 	readerChannel chan byte   // Reading from the User
 	writerChannel chan string // Writing to the User
+	closeChannel  chan bool   // Closing
+	wg            sync.WaitGroup
 	writerMutex   sync.Mutex
 }
 
@@ -268,6 +271,7 @@ func (d *Door) Init(doorname string) {
 
 	d.readerChannel = make(chan byte)
 	d.writerChannel = make(chan string)
+	d.closeChannel = make(chan bool,5)
 
 	d.setupChannels()
 
@@ -281,6 +285,22 @@ func (d *Door) Init(doorname string) {
 	}
 }
 
+func (d *Door) Close() {
+        defer func() {
+                if err := recover(); err != nil {
+                        log.Println("door.Close FAILURE:", err)
+                        // This displays stack trace stderr
+                        debug.PrintStack()
+                }
+        }()
+
+	log.Printf("Closing...")
+	d.closeChannel <- true
+	// close(d.closeChannel)
+	d.wg.Wait()
+	log.Printf("Closed.")
+}
+
 // Goto X, Y - Position the cursor using ANSI Escape Codes
 //
 // Example:

+ 3 - 1
door/door_linux.go

@@ -2,5 +2,7 @@ package door
 
 func (d *Door) setupChannels() {
 	go Reader(d.Config.Comm_handle, &d.readerChannel)
-	go Writer(d.Config.Comm_handle, &d.writerChannel)
+	// go Writer(d.Config.Comm_handle, &d.writerChannel)
+	go Writer2(d.Config.Comm_handle, d)
+	(*d).wg.Add(1)
 }

+ 1 - 0
door/door_test.go

@@ -190,6 +190,7 @@ func TestDetectFail(t *testing.T) {
 	os.Args = []string{"door", "-d", tmpFile.Name()}
 	d.Init("menu-test")
 
+        defer d.Close()
 	// clean up log file
 	// I don't need to.  Tests are run in /tmp/go-buildNNNN.
 	// defer os.Remove("menu-test-13.log")

+ 3 - 0
door/input_linux.go

@@ -31,3 +31,6 @@ func Reader(handle int, readerChannel *chan byte) {
 	}
 }
 
+func CloseReader(handle int) {
+	syscall.Close(handle)
+}

+ 14 - 1
door/input_test.go

@@ -58,6 +58,7 @@ func TestDoorInputConnection(t *testing.T) {
 	os.Args = []string{"door", "-d", tmpFile.Name()}
 	d.Init("input-test")
 
+	defer d.Close()
 	// clean up logfile
 	defer os.Remove("input-test-12.log")
 
@@ -111,15 +112,27 @@ func TestDoorInputConnection(t *testing.T) {
 		time.Sleep(time.Millisecond)
 
 		recv := make([]int, 0)
+		var retries int = 0
 		for {
 			// input := d.WaitKey(0, 50)
 			// running go test -count > 1 sometimes fails --
 			// not getting all of the data we Write above.
 			// data shows up on next read.
-			input := d.WaitKey(0, 100)
+			// input := d.WaitKey(0, 100) // because we are retrying, reduce the wait time
+			input := d.WaitKey(0, 50)
+
 			if input != -1 {
 				recv = append(recv, input)
 			} else {
+				// sometimes, running test using local loopback takes awhile for the characters
+				// to arrive.
+				if len(recv) != len(get) {
+					if retries < 5 {
+						retries++
+						t.Logf("Retry %d want %d got %d\n", retries, len(get), len(recv))
+						continue
+					}
+				}
 				break
 			}
 		}

+ 1 - 0
door/menu_test.go

@@ -86,6 +86,7 @@ func TestMenuConnection(t *testing.T) {
 	os.Args = []string{"door", "-d", tmpFile.Name()}
 	d.Init("menu-test")
 
+	defer d.Close()
 	// clean up log file - not needed in tests
 	defer os.Remove("menu-test-12.log")
 

+ 4 - 1
door/write.go

@@ -78,7 +78,7 @@ func ParseColorArray(colorarray []int) ANSIColorParts {
 }
 
 // Update the LastColor with the latest codes.
-func (d *Door) UpdateLastColor(output string, LastColor * []int) {
+func (d *Door) UpdateLastColor(output string, LastColor *[]int) {
 	// use the last color information + whatever is in the string to
 	// track the last color set
 	updated := ParseColorArray(*LastColor)
@@ -136,6 +136,9 @@ func (d *Door) Write(output string) {
 		return
 	}
 
+	d.writerChannel <- output
+	return
+
 	// There is a potential race condition here --
 	// We could be updating d.LastColor when called again.
 

+ 77 - 16
door/write_linux.go

@@ -1,16 +1,77 @@
-package door
-
-import (
-	"syscall"
-)
-
-func Writer(handle int, writerChannel *chan string) {
-	for output := range *writerChannel {
-		buffer := []byte(output)
-		n, err := syscall.Write(handle, buffer)
-		if (err != nil) || (n != len(buffer)) {
-			close(*writerChannel)
-			break
-		}
-	}
-}
+package door
+
+import (
+	"log"
+	"strings"
+	"syscall"
+)
+
+// https://go101.org/article/channel-closing.html
+func Writer2(handle int, d *Door) {
+	log.Println("Writer2")
+	defer d.wg.Done()
+	for {
+		select {
+		case <-d.closeChannel:
+			// close((*d).writerChannel)
+			log.Println("~Writer2")
+			return
+		default:
+		}
+
+		select {
+		case <-d.closeChannel:
+			// close((*d).writerChannel)
+			log.Println("~Writer2")
+			return
+
+		case output, ok := <-d.writerChannel:
+			if !ok {
+				// (*d).writerChannel = nil
+				log.Println("closeChannel")
+				// close(d.closeChannel)
+				d.Disconnected = true
+				close(d.writerChannel)
+				log.Println("~Writer2")
+				return
+
+//				d.closeChannel <- true
+//				continue
+			} else {
+				// log.Println("output")
+				if strings.HasSuffix(output, RestorePos) {
+					output += Color(d.LastColor...)
+
+				} else {
+					d.UpdateLastColor(output, &d.LastColor)
+				}
+				// log.Println("write output")
+				buffer := []byte(output)
+				n, err := syscall.Write(handle, buffer)
+				if (err != nil) || (n != len(buffer)) {
+					// close((*d).writerChannel)
+					// (*d).writerChannel = nil
+					log.Println("closeChannel")
+					// close(d.closeChannel)
+					d.Disconnected = true
+					close(d.writerChannel)
+					log.Println("~Writer2")
+					return
+//					d.closeChannel <- true
+//					continue
+				}
+			}
+		}
+	}
+}
+
+func Writer(handle int, writerChannel *chan string) {
+	for output := range *writerChannel {
+		buffer := []byte(output)
+		n, err := syscall.Write(handle, buffer)
+		if (err != nil) || (n != len(buffer)) {
+			close(*writerChannel)
+			break
+		}
+	}
+}

+ 16 - 0
testdoor/testdoor.go

@@ -525,6 +525,20 @@ func main() {
 		}
 	}()
 
+	defer d.Close()
+	ticker := time.NewTicker(time.Second)
+
+	go func() {
+		for t := range ticker.C {
+			const tf = "03:04:05 PM"
+			var timeinfo string = fmt.Sprintf("(%3.1f mins)", d.TimeLeft().Minutes())
+
+			// maxlen = 12 + 7 + 5 = 24
+			output := door.SavePos + door.Goto(door.Width-25, 0) + door.ColorText("BRI WHI ON BLUE") + " " + t.Format(tf) + " " + timeinfo + " " + door.RestorePos
+			d.Write(output)
+		}
+	}()
+
 	bold := door.Color(1, 37, 40)
 	bolder := door.ColorText("BLI BOLD YEL ON BLUE")
 	d.Write("Welcome to " + bolder + "door32.sys" + door.Reset + door.CRNL + "..." + door.CRNL)
@@ -606,6 +620,8 @@ func main() {
 	d.WaitKey(1, 0)
 	left = d.TimeLeft()
 
+	ticker.Stop()
+
 	message = fmt.Sprintf("You had %0.2f minutes / %0.2f seconds remaining!"+door.CRNL, left.Minutes(), left.Seconds())
 	d.Write(message)