summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorxengineering <me@xengineering.eu>2023-06-29 21:39:54 +0200
committerxengineering <me@xengineering.eu>2023-06-29 21:39:54 +0200
commitc8544b19df055235b9106ff296f0a5fe7cb1fe91 (patch)
treeb3da91a3d41746620ca67891797b55df8edfdc09
parent9afa580f3f3207ac449be86c1a305cb716b77f76 (diff)
parent3df1a88c726c08704e8b71c467bd8e11c9a52db6 (diff)
downloadlimox-c8544b19df055235b9106ff296f0a5fe7cb1fe91.tar
limox-c8544b19df055235b9106ff296f0a5fe7cb1fe91.tar.zst
limox-c8544b19df055235b9106ff296f0a5fe7cb1fe91.zip
Merge branch 'element-buffer'
This adds xengineering.eu/limox/xmpp/elementBuffer which is a buffer for a collection of XML tokens which are further processed after a full XML element is collected.
-rw-r--r--Makefile2
-rw-r--r--xmpp/element_buffer.go61
-rw-r--r--xmpp/element_buffer_test.go55
-rw-r--r--xmpp/stream_pair.go20
4 files changed, 135 insertions, 3 deletions
diff --git a/Makefile b/Makefile
index 7db9cae..5e8f23e 100644
--- a/Makefile
+++ b/Makefile
@@ -48,6 +48,6 @@ install: $(LIMOX)
install -Dm 644 $(DESKTOP) $(DESKTOP_INSTALL)
tests:
- go test $(LIMOX_GO_PACKAGE)/...
+ go test -test.v $(LIMOX_GO_PACKAGE)/...
imgs: $(IMGS)
diff --git a/xmpp/element_buffer.go b/xmpp/element_buffer.go
new file mode 100644
index 0000000..7792db2
--- /dev/null
+++ b/xmpp/element_buffer.go
@@ -0,0 +1,61 @@
+package xmpp
+
+import (
+ "encoding/xml"
+)
+
+// elementBuffer is a struct to store multiple values of type xml.Token until
+// they form a complete XML element with opening and closing tag which is
+// suitable to be passed to an appropriate handler function.
+type elementBuffer struct {
+ tokens []xml.Token
+ end xml.EndElement
+ level int
+}
+
+// newElementBuffer returns a new initialized elementBuffer struct.
+func newElementBuffer() elementBuffer {
+ buf := elementBuffer{}
+ buf.reset()
+ return buf
+}
+
+// FIXME this function needs essential error handling for corner cases!
+//
+// add is able to add a new xml.Token to the buffer. There are some rules
+// checked to ensure a correct and consistent elementBuffer which are checked.
+// If one of these checks fail the token is not added and a corresponding error
+// is returned.
+func (e *elementBuffer) add(t xml.Token) error {
+ switch t.(type) {
+ case xml.StartElement:
+ e.level += 1
+ case xml.EndElement:
+ e.level -= 1
+ }
+ e.tokens = append(e.tokens, t)
+ return nil
+}
+
+// FIXME isComplete would be true if a stream with only one XML comment is
+// passed to the buffer. This might be unexpected behaviour.
+//
+// isComplete returns true if the buffer contains a slice of XML tokens which
+// form a complete XML element starting with an xml.StartElement and closing
+// with the corresponding xml.EndElement.
+func (e *elementBuffer) isComplete() bool {
+ return (len(e.tokens) > 0 && e.level == 0)
+}
+
+// reset returns the content of the buffer as a slice of XML tokens and resets
+// the buffer to the initial state. This function can be used to initialize the
+// elementBuffer struct. In that case the return value can be ignored.
+func (e *elementBuffer) reset() (buf []xml.Token) {
+ retval := e.tokens
+
+ e.tokens = make([]xml.Token, 0)
+ e.end = xml.EndElement{}
+ e.level = 0
+
+ return retval
+}
diff --git a/xmpp/element_buffer_test.go b/xmpp/element_buffer_test.go
new file mode 100644
index 0000000..113a2c4
--- /dev/null
+++ b/xmpp/element_buffer_test.go
@@ -0,0 +1,55 @@
+package xmpp
+
+import (
+ "encoding/xml"
+ "strings"
+ "testing"
+)
+
+// bufTest is a struct containing a test point for the
+// xengineering.eu/limox/xmpp.elementBuffer. It contains a test XML string
+// which has to be exactly one XML element and an array of indentation levels
+// which have to be checked after each token which is parsed.
+type bufTest struct {
+ xml string
+ levels []int
+}
+
+func TestElementBuffer(t *testing.T) {
+ tests := []bufTest{
+ bufTest{`<stream></stream>`, []int{1, 0}},
+ bufTest{`<stream/>`, []int{1, 0}},
+ bufTest{`<a><b>testing</b></a>`, []int{1, 2, 2, 1, 0}},
+ bufTest{`<a><!-- comment --><b>testing</b></a>`, []int{1, 1, 2, 2, 1, 0}},
+ bufTest{`<!-- comment --><a><b>testing</b></a>`, []int{0, 1, 2, 2, 1, 0}},
+ }
+
+ for _, v := range tests {
+ r := strings.NewReader(v.xml)
+ d := xml.NewDecoder(r)
+ b := newElementBuffer()
+
+ i := 0
+
+ for {
+ token, err := d.Token()
+ if err != nil {
+ if i != len(v.levels) {
+ t.Fatalf("Stopped parsing at unexpected index due to error `%v`!\n", err)
+ }
+ break
+ }
+
+ err = b.add(token)
+ if err != nil {
+ t.Fatalf("add(token) failed with error `%v`!\n", err)
+ }
+
+ if b.level != v.levels[i] {
+ t.Fatalf("Indent level of xmpp.elementBuffer %d does not match value given by test data %d!\n", b.level, v.levels[i])
+ }
+
+ i += 1
+ }
+ }
+}
diff --git a/xmpp/stream_pair.go b/xmpp/stream_pair.go
index e02cca6..b13d8a3 100644
--- a/xmpp/stream_pair.go
+++ b/xmpp/stream_pair.go
@@ -9,6 +9,8 @@ func runStreamPair(s *session) {
openStream(s)
defer closeStream(s)
+ buf := newElementBuffer()
+
for {
select {
case data := <-s.in:
@@ -18,8 +20,22 @@ func runStreamPair(s *session) {
default:
log.Printf("Unknown data '%d'!\n", data)
}
- case _ = <-s.rx:
- // TODO route received XML token here
+ case t := <-s.rx:
+ err := buf.add(t)
+ if err != nil {
+ log.Printf("Could not add XML token to buffer: %v\n", err)
+ return
+ }
+ if buf.isComplete() {
+ element := buf.reset()
+ // TODO handle XML element here - this is just a dummy:
+ switch start := element[0].(type) {
+ case xml.StartElement:
+ log.Printf("Got XML element `%s`\n", start.Name.Local)
+ default:
+ log.Println("No xml.StartElement at start of element buffer!")
+ }
+ }
}
}
}