diff options
Diffstat (limited to 'xA/xA.go')
-rw-r--r-- | xA/xA.go | 137 |
1 files changed, 137 insertions, 0 deletions
diff --git a/xA/xA.go b/xA/xA.go new file mode 100644 index 0000000..192265f --- /dev/null +++ b/xA/xA.go @@ -0,0 +1,137 @@ +// Copyright (c) 2024, Přemysl Eric Janouch <p@janouch.name> +// SPDX-License-Identifier: 0BSD + +package main + +import ( + "bufio" + "context" + "encoding/binary" + "flag" + "fmt" + "io" + "log" + "net" + "net/url" + "os" + + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/app" + "fyne.io/fyne/v2/container" + "fyne.io/fyne/v2/widget" +) + +var ( + debug = flag.Bool("debug", false, "enable debug output") + projectName = "xA" + projectVersion = "?" + addressConnect string +) + +// ----------------------------------------------------------------------------- + +func relayReadFrame(r io.Reader) []byte { + var length uint32 + if err := binary.Read(r, binary.BigEndian, &length); err != nil { + log.Println("Event receive failed: " + err.Error()) + return nil + } + b := make([]byte, length) + if _, err := io.ReadFull(r, b); err != nil { + log.Println("Event receive failed: " + err.Error()) + return nil + } + + if *debug { + log.Printf("<? %v\n", b) + + var m RelayEventMessage + if after, ok := m.ConsumeFrom(b); !ok { + log.Println("Event deserialization failed") + return nil + } else if len(after) != 0 { + log.Println("Event deserialization failed: trailing data") + return nil + } + + j, err := m.MarshalJSON() + if err != nil { + log.Println("Event marshalling failed: " + err.Error()) + return nil + } + + log.Printf("<- %s\n", j) + } + return b +} + +func relayMakeReceiver(ctx context.Context, conn net.Conn) <-chan []byte { + // The usual event message rarely gets above 1 kilobyte, + // thus this is set to buffer up at most 1 megabyte or so. + p := make(chan []byte, 1000) + r := bufio.NewReaderSize(conn, 65536) + go func() { + defer close(p) + for { + j := relayReadFrame(r) + if j == nil { + return + } + select { + case p <- j: + case <-ctx.Done(): + return + } + } + }() + return p +} + +func main() { + flag.Usage = func() { + fmt.Fprintf(flag.CommandLine.Output(), + "Usage: %s [OPTION...] CONNECT\n\n", os.Args[0]) + flag.PrintDefaults() + } + + flag.Parse() + if flag.NArg() < 1 || flag.NArg() > 1 { + flag.Usage() + os.Exit(1) + } + + addressConnect = flag.Arg(0) + + // TODO(p): First, test Fyne's GUI capabilities. + + a := app.New() + w := a.NewWindow(projectName) + + // TODO(p): There should also be a widget.NewLabel() next to the entry. + // - Probably another Border, even though this seems odd. + var ( + richtext = widget.NewRichText() + richscroll = container.NewVScroll(richtext) + entry = widget.NewMultiLineEntry() + ) + w.SetContent(container.NewBorder(nil, entry, nil, nil, richscroll)) + + testURL, _ := url.Parse("https://x.com") + richtext.Segments = []widget.RichTextSegment{ + &widget.ParagraphSegment{Texts: []widget.RichTextSegment{ + &widget.TextSegment{Text: "Test"}, + &widget.HyperlinkSegment{Text: "X", URL: testURL}, + &widget.TextSegment{ + Text: " is a website, certainly", + Style: widget.RichTextStyleInline, + }, + }}, + &widget.TextSegment{Style: widget.RichTextStyleParagraph}, + &widget.SeparatorSegment{}, + &widget.TextSegment{Text: "Paragraph"}, + } + richtext.Wrapping = fyne.TextWrapWord + richtext.Refresh() + + w.ShowAndRun() +} |