From 7a88cd52b3c9a61f6c413f5cff2383a62113974d Mon Sep 17 00:00:00 2001 From: devlights Date: Mon, 16 Sep 2024 14:53:11 +0000 Subject: [PATCH] Add examples/singleapp/cancel_reader --- examples/singleapp/cancel_reader/Taskfile.yml | 8 ++ examples/singleapp/cancel_reader/main.go | 81 +++++++++++++++++++ go.mod | 2 + go.sum | 2 + 4 files changed, 93 insertions(+) create mode 100644 examples/singleapp/cancel_reader/Taskfile.yml create mode 100644 examples/singleapp/cancel_reader/main.go diff --git a/examples/singleapp/cancel_reader/Taskfile.yml b/examples/singleapp/cancel_reader/Taskfile.yml new file mode 100644 index 00000000..de4e69df --- /dev/null +++ b/examples/singleapp/cancel_reader/Taskfile.yml @@ -0,0 +1,8 @@ +# https://taskfile.dev + +version: '3' + +tasks: + default: + cmds: + - echo -n helloworld | go run main.go diff --git a/examples/singleapp/cancel_reader/main.go b/examples/singleapp/cancel_reader/main.go new file mode 100644 index 00000000..e1472905 --- /dev/null +++ b/examples/singleapp/cancel_reader/main.go @@ -0,0 +1,81 @@ +package main + +import ( + "errors" + "fmt" + "log" + "os" + "time" + + "github.com/muesli/cancelreader" +) + +func main() { + log.SetFlags(log.Lmicroseconds) + log.SetOutput(os.Stdout) + + if err := run(); err != nil { + log.Panic(err) + } +} + +func run() error { + // + // 標準入力をキャンセル可能なReaderにする + // + // cancelreader.CancelReaderは、Linuxの場合 + // 内部で epoll を利用して制御を行っている。 + // + // なので、非ブロッキングI/Oが可能なファイルディスクリプタに対してのみ + // キャンセル可能となっている。非ブロッキングI/Oが可能なものは例えば以下のもの。 + // - ソケット + // - パイプ + // - FIFO + // + // 通常のファイルは非ブロッキングI/O可能なファイルディスクリプタでは無いことに注意。 + // 通常のファイルをepollで利用すると epoll_ctl() で EPERM が返ってくる。 + // 通常のファイルをキャンセル可能にしたい場合は io_uring などを検討する。 + // + + var ( + reader cancelreader.CancelReader + err error + ) + reader, err = cancelreader.NewReader(os.Stdin) + if err != nil { + return fmt.Errorf("cancelreader.NewReader() failed: %w", err) + } + defer reader.Close() + + // + // 3秒後にキャンセル + // + go func() { + time.Sleep(3 * time.Second) + reader.Cancel() + }() + + // + // 500ms毎に1文字読み込み + // + var ( + buf [1]byte + ) + for { + clear(buf[:]) + + if _, err = reader.Read(buf[:]); err != nil { + if errors.Is(err, cancelreader.ErrCanceled) { + log.Println("CANCELED") + break + } + + return fmt.Errorf("reader.Read() failed: %w", err) + } + + log.Print(string(buf[:])) + time.Sleep(500 * time.Millisecond) + } + + return nil +} diff --git a/go.mod b/go.mod index 9b657716..d716c779 100644 --- a/go.mod +++ b/go.mod @@ -17,3 +17,5 @@ require ( gopkg.in/natefinch/lumberjack.v2 v2.2.1 gopkg.in/yaml.v3 v3.0.1 ) + +require github.com/muesli/cancelreader v0.2.2 diff --git a/go.sum b/go.sum index 61654777..42c873b3 100644 --- a/go.sum +++ b/go.sum @@ -7,6 +7,8 @@ github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/integrii/flaggy v1.5.2 h1:bWV20MQEngo4hWhno3i5Z9ISPxLPKj9NOGNwTWb/8IQ= github.com/integrii/flaggy v1.5.2/go.mod h1:dO13u7SYuhk910nayCJ+s1DeAAGC1THCMj1uSFmwtQ8= +github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA= +github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo= github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M= github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=