diff --git a/ws/common.go b/ws/common.go new file mode 100644 index 0000000..fe8a586 --- /dev/null +++ b/ws/common.go @@ -0,0 +1,24 @@ +package ws + +import ( + "fmt" + "os" +) + +func checkFile(fileNa string) error { + var ( + err error + stat os.FileInfo + ) + + if stat, err = os.Stat(fileNa); err != nil { + return fmt.Errorf("unable to check metadata for file '%s': %v", fileNa, err) + } + if !stat.Mode().IsRegular() { + return fmt.Errorf("file '%s' is not regular") + } + if stat.Mode()&0444 == 0 { + return fmt.Errorf("file '%s' is not readable") + } + return nil +} diff --git a/ws/file_interval.go b/ws/file_interval.go new file mode 100644 index 0000000..369d546 --- /dev/null +++ b/ws/file_interval.go @@ -0,0 +1,89 @@ +package ws + +import ( + "context" + "fmt" + "io" + "os" + "time" + "wssrv/log" + + "github.com/gorilla/websocket" +) + +func readMessage(ctx context.Context, cancel context.CancelCauseFunc, con *websocket.Conn) { + var ( + err error + msg []byte + ) + for err != io.EOF { + select { + case <-ctx.Done(): + return + default: + if _, msg, err = con.ReadMessage(); err != nil { + // chErr <- fmt.Errorf("unable to read from websocket on '%s': %v", con.RemoteAddr(), err) + cancel(fmt.Errorf("unable to read from websocket on '%s': %v", con.RemoteAddr(), err)) + return + } + fmt.Printf("(%s): %s\n", con.RemoteAddr(), msg) + } + } +} + +func sendFile(ctx context.Context, cancel context.CancelCauseFunc, con *websocket.Conn, fileNa string, data []byte, interv time.Duration) { + var err error + for { + select { + case <-ctx.Done(): + return + default: + log.Info.Printf("sending file '%s'", fileNa) + if err = con.WriteMessage(websocket.TextMessage, data); err != nil { + // chErr <- fmt.Errorf("unable write on websocket on '%s': %v", con.RemoteAddr(), err) + cancel(fmt.Errorf("unable write on websocket on '%s': %v", con.RemoteAddr(), err)) + return + } + log.Info.Printf("sleeping for '%v'", interv) + time.Sleep(interv) + } + } + +} + +func sendFileByInterval(con *websocket.Conn, fileNa string, interv time.Duration) error { + var ( + err error + data []byte + + ctx, cancel = context.WithCancelCause(context.Background()) + ) + + if data, err = os.ReadFile(fileNa); err != nil { + return fmt.Errorf("unable to read file '%s': %v", fileNa, err) + } + + go readMessage(ctx, cancel, con) + go sendFile(ctx, cancel, con, fileNa, data, interv) + + <-ctx.Done() + return context.Cause(ctx) +} + +// SendFileByInterval repeatedly sends a given file in the websocket according +// to an interval. +func SendFileByInterval(con *websocket.Conn, fileNa string, interv time.Duration) error { + switch { + case con == nil: + return fmt.Errorf("nil connection parameter") + case len(fileNa) == 0: + return fmt.Errorf("empty file parameter") + case interv < 1: + return fmt.Errorf("non positive interval parameter") + } + if err := checkFile(fileNa); err != nil { + return err + } + + return sendFileByInterval(con, fileNa, interv) +} diff --git a/ws/file_reply.go b/ws/file_reply.go index e76cc71..b5d985f 100644 --- a/ws/file_reply.go +++ b/ws/file_reply.go @@ -3,7 +3,6 @@ package ws import ( "fmt" "io" - "io/fs" "os" "wssrv/log" @@ -44,19 +43,8 @@ func SendFileReply(con *websocket.Conn, fileNa string) error { case len(fileNa) == 0: return fmt.Errorf("empty file parameter") } - var ( - err error - stat fs.FileInfo - ) - - if stat, err = os.Stat(fileNa); err != nil { - return fmt.Errorf("unable to check metadata for file '%s': %v", fileNa, err) - } - if !stat.Mode().IsRegular() { - return fmt.Errorf("file '%s' is not regular") - } - if stat.Mode()&0444 == 0 { - return fmt.Errorf("file '%s' is not readable") + if err := checkFile(fileNa); err != nil { + return err } return sendFileReply(con, fileNa)