Przeglądaj źródła

запилил архитектуру

kpmy 10 lat temu
rodzic
commit
1413b2aec7

+ 66 - 0
c2s/actors/act.go

@@ -0,0 +1,66 @@
+package actors
+
+import (
+	"sync"
+	"xep/c2s/stream"
+)
+
+type Continue interface {
+	Do(func(stream.Stream) error, ...func(error)) Continue
+	Run()
+}
+
+type step struct {
+	s   stream.Stream
+	act func(stream.Stream) error
+	err func(error)
+}
+
+type cont struct {
+	s     stream.Stream
+	steps []step
+}
+
+func With(s stream.Stream) Continue {
+	return &cont{s: s}
+}
+
+func (c *cont) Do(fn func(stream.Stream) error, err ...func(error)) Continue {
+	s := step{s: c.s}
+	s.act = fn
+	if len(err) > 0 {
+		s.err = err[0]
+	}
+	c.steps = append(c.steps, s)
+	return c
+}
+
+func (c *cont) Run() {
+	var next *cont
+	var this *step
+	if len(c.steps) > 0 {
+		this = &c.steps[0]
+	}
+	if len(c.steps) > 1 {
+		next = &cont{s: c.s}
+		next.steps = c.steps[1:]
+	}
+	if this != nil {
+		wg := &sync.WaitGroup{}
+		wg.Add(1)
+		go func(this *step, next *cont) {
+			if err := this.act(this.s); err == nil {
+				if next != nil {
+					next.Run()
+				}
+				wg.Done()
+			} else if this.err != nil {
+				this.err(err)
+				wg.Done()
+			} else {
+				panic(err)
+			}
+		}(this, next)
+		wg.Wait()
+	}
+}

+ 39 - 0
c2s/actors/steps/auth.go

@@ -0,0 +1,39 @@
+package steps
+
+import (
+	"bytes"
+	"log"
+	"reflect"
+	"xep/c2s/stream"
+	"xep/entity"
+	"xep/units"
+)
+
+type PlainAuth struct {
+	Client *units.Client
+	Pwd    string
+}
+
+func (p *PlainAuth) Act() func(stream.Stream) error {
+	return func(s stream.Stream) (err error) {
+		auth := &entity.PlainAuth{}
+		*auth = entity.PlainAuthPrototype
+		auth.Init(p.Client.Name, p.Pwd)
+		if err = s.Write(entity.Produce(auth)); err == nil {
+			s.Ring(func(b *bytes.Buffer) (ret *bytes.Buffer) {
+				var _e entity.Entity
+				if _e, err = entity.Consume(b); err == nil {
+					switch e := _e.(type) {
+					case *entity.Success:
+
+					default:
+						log.Println(reflect.TypeOf(e))
+						ret = b //pass
+					}
+				}
+				return
+			}, 0)
+		}
+		return
+	}
+}

+ 67 - 0
c2s/actors/steps/bind.go

@@ -0,0 +1,67 @@
+package steps
+
+import (
+	"bytes"
+	"log"
+	"reflect"
+	"xep/c2s/stream"
+	"xep/entity"
+)
+
+type Bind struct {
+	Rsrc string
+}
+
+func (b *Bind) Act() func(s stream.Stream) error {
+	return func(s stream.Stream) (err error) {
+		bind := &entity.Bind{}
+		*bind = entity.BindPrototype
+		bind.Resource = b.Rsrc
+		iq := entity.IQ(entity.SET, bind)
+		if err = s.Write(entity.Produce(iq)); err == nil {
+			s.Ring(func(b *bytes.Buffer) (ret *bytes.Buffer) {
+				var _e entity.Entity
+				if _e, err = entity.Consume(b); err == nil {
+					switch e := _e.(type) {
+					case *entity.Iq:
+						switch {
+						case e.Id == iq.Id && e.Type == entity.RESULT:
+							stream.Bind(s, e.Inner.(*entity.Bind).Jid)
+						default:
+							ret = b //pass
+						}
+					default:
+						log.Println(reflect.TypeOf(e))
+						ret = b //pass
+					}
+				}
+				return
+			}, 0)
+		}
+		return
+	}
+}
+
+func Session(s stream.Stream) (err error) {
+	iq := entity.IQ(entity.SET, &entity.SessionPrototype)
+	if err = s.Write(entity.Produce(iq)); err == nil {
+		s.Ring(func(b *bytes.Buffer) (ret *bytes.Buffer) {
+			var _e entity.Entity
+			if _e, err = entity.Consume(b); err == nil {
+				switch e := _e.(type) {
+				case *entity.Iq:
+					switch {
+					case e.Id == iq.Id && e.Type == entity.RESULT:
+					default:
+						ret = b
+					}
+				default:
+					log.Println(reflect.TypeOf(e))
+					ret = b //pass
+				}
+			}
+			return
+		}, 0)
+	}
+	return
+}

+ 71 - 0
c2s/actors/steps/first.go

@@ -0,0 +1,71 @@
+package steps
+
+import (
+	"bytes"
+	"errors"
+	"fmt"
+	"log"
+	"reflect"
+	"strings"
+	"xep/c2s/stream"
+	"xep/entity"
+)
+
+func Starter(s stream.Stream) (err error) {
+	if err = s.Write(entity.Open(s.Server()).Produce()); err == nil {
+		s.Ring(func(b *bytes.Buffer) (ret *bytes.Buffer) {
+			_e, e := entity.Consume(b)
+			if _e != nil {
+				switch e := _e.(type) {
+				case *entity.Stream:
+					s.Id(e.Id)
+				default:
+					log.Println(reflect.TypeOf(e))
+					ret = b //pass
+				}
+			} else if e == nil {
+				ret = nil
+				err = errors.New(fmt.Sprint("unknown entity ", string(b.Bytes())))
+			} else {
+				err = e
+			}
+			return
+		}, 0)
+	}
+	return
+}
+
+type Negotiation struct {
+	AuthMechanisms []string
+}
+
+func (n *Negotiation) Act() func(stream.Stream) error {
+	return func(s stream.Stream) (err error) {
+		s.Ring(func(b *bytes.Buffer) (ret *bytes.Buffer) {
+			var _e entity.Entity
+			if _e, err = entity.Consume(b); err == nil {
+				switch e := _e.(type) {
+				case *entity.Features:
+					n.AuthMechanisms = e.Mechanisms
+				default:
+					log.Println(reflect.TypeOf(e))
+					ret = b //pass
+				}
+			}
+			return
+		}, 0)
+		return
+	}
+}
+
+func (n *Negotiation) HasMechanism(mech string) (ok bool) {
+	if n.AuthMechanisms != nil {
+		for _, v := range n.AuthMechanisms {
+			if strings.ToLower(v) == strings.ToLower(mech) {
+				ok = true
+				break
+			}
+		}
+	}
+	return
+}

+ 20 - 0
c2s/actors/steps/presence.go

@@ -0,0 +1,20 @@
+package steps
+
+import (
+	"xep/c2s/stream"
+	"xep/entity"
+)
+
+func InitialPresence(s stream.Stream) (err error) {
+	err = s.Write(entity.Produce(&entity.PresencePrototype))
+	return
+}
+
+func PresenceTo(jid string) func(stream.Stream) error {
+	return func(s stream.Stream) error {
+		pr := &entity.Presence{}
+		*pr = entity.PresencePrototype
+		pr.To = jid
+		return s.Write(entity.Produce(pr))
+	}
+}

+ 160 - 0
c2s/stream/stream.go

@@ -0,0 +1,160 @@
+package stream
+
+import (
+	"bytes"
+	"errors"
+	"github.com/kpmy/ypk/halt"
+	"hash/adler32"
+	"log"
+	"net"
+	"reflect"
+	"time"
+	"xep/tools/srv"
+	"xep/units"
+)
+
+type Stream interface {
+	Server() *units.Server
+	Write(*bytes.Buffer) error
+	Ring(func(*bytes.Buffer) *bytes.Buffer, time.Duration)
+	Id(...string) string
+}
+
+type wrapperStream struct {
+	base Stream
+}
+
+func (w *wrapperStream) Write(b *bytes.Buffer) error { return w.base.Write(b) }
+
+func (w *wrapperStream) Ring(fn func(*bytes.Buffer) *bytes.Buffer, t time.Duration) {
+	w.base.Ring(fn, t)
+}
+
+func (w *wrapperStream) Server() *units.Server { return w.base.Server() }
+
+func (w *wrapperStream) Id(s ...string) string { return w.base.Id(s...) }
+
+type dummyStream struct {
+	to *units.Server
+}
+
+func (d *dummyStream) Ring(func(*bytes.Buffer) *bytes.Buffer, time.Duration) { panic(126) }
+func (d *dummyStream) Write(b *bytes.Buffer) error                           { panic(126) }
+func (d *dummyStream) Server() *units.Server                                 { return d.to }
+func (d *dummyStream) Id(...string) string                                   { return "" }
+
+type xmppStream struct {
+	to   *units.Server
+	conn net.Conn
+	ctrl chan bool
+	data chan pack
+	id   string
+	jid  string
+}
+
+type pack struct {
+	data []byte
+	hash uint32
+}
+
+func (x *xmppStream) Id(s ...string) string {
+	if len(s) > 0 {
+		x.id = s[0]
+	}
+	return x.id
+}
+func (x *xmppStream) Server() *units.Server { return x.to }
+
+func (x *xmppStream) Write(b *bytes.Buffer) (err error) {
+	log.Println("OUT")
+	log.Println(string(b.Bytes()))
+	log.Println()
+	_, err = x.conn.Write(b.Bytes())
+	return
+}
+
+func (x *xmppStream) Ring(fn func(*bytes.Buffer) *bytes.Buffer, timeout time.Duration) {
+	log.Println("ring")
+	timed := make(chan bool)
+	if timeout > 0 {
+		go func() {
+			<-time.NewTimer(timeout).C
+			timed <- true
+		}()
+	}
+	for stop := false; !stop; {
+		select {
+		case p := <-x.data:
+			log.Println("try ", p.hash)
+			res := fn(bytes.NewBuffer(p.data))
+			if res != nil {
+				log.Println("passed", p.hash)
+				x.data <- pack{data: p.data, hash: p.hash}
+			} else {
+				log.Println("done", p.hash)
+				stop = true
+			}
+		case <-timed:
+			stop = true
+		}
+	}
+}
+
+func New(to *units.Server) Stream {
+	return &wrapperStream{base: &dummyStream{to: to}}
+}
+
+func Bind(_s Stream, jid string) {
+	switch w := _s.(type) {
+	case *wrapperStream:
+		switch s := w.base.(type) {
+		case *xmppStream:
+			s.jid = jid
+		}
+	}
+}
+
+func Dial(_s Stream) (err error) {
+	switch w := _s.(type) {
+	case *wrapperStream:
+		switch s := w.base.(type) {
+		case *dummyStream:
+			x := &xmppStream{to: s.to}
+			var (
+				host, port string
+			)
+			if host, port, err = srv.Resolve(x.to); err == nil {
+				if x.conn, err = net.Dial("tcp", host+":"+port); err == nil {
+					x.ctrl = make(chan bool)
+					x.data = make(chan pack, 256)
+					go func(stream *xmppStream) {
+						<-stream.ctrl
+						stream.conn.Close()
+					}(x)
+					go func(stream *xmppStream) {
+						var err error
+						buf := make([]byte, 65535)
+						for err == nil {
+							n := 0
+							n, err = stream.conn.Read(buf)
+							if n > 0 && err == nil {
+								data := make([]byte, n)
+								copy(data, buf)
+								log.Println("IN", len(data), adler32.Checksum(data))
+								log.Println(string(data))
+								log.Println()
+								stream.data <- pack{data: data, hash: adler32.Checksum(data)}
+							}
+						}
+					}(x)
+					w.base = x
+				}
+			}
+		default:
+			err = errors.New("already connected")
+		}
+	default:
+		halt.As(100, reflect.TypeOf(_s))
+	}
+	return
+}

+ 64 - 0
client/main.go

@@ -0,0 +1,64 @@
+package main
+
+import (
+	"bytes"
+	"flag"
+	"log"
+	"xep/c2s/actors"
+	"xep/c2s/actors/steps"
+	"xep/c2s/stream"
+	"xep/entity"
+	"xep/units"
+)
+
+var user string
+var pwd string
+var server string
+var resource string
+
+func init() {
+	flag.StringVar(&user, "u", "goxep", "-u=user")
+	flag.StringVar(&server, "s", "xmpp.ru", "-s=server")
+	flag.StringVar(&resource, "r", "go", "-r=resource")
+	flag.StringVar(&pwd, "p", "GogogOg0", "-p=password")
+	log.SetFlags(0)
+}
+
+func conv(fn func(entity.Entity) entity.Entity) func(*bytes.Buffer) *bytes.Buffer {
+	return func(in *bytes.Buffer) (out *bytes.Buffer) {
+
+		return
+	}
+}
+
+func main() {
+	flag.Parse()
+	s := &units.Server{Name: server}
+	c := &units.Client{Name: user, Server: s}
+	st := stream.New(s)
+	if err := stream.Dial(st); err == nil {
+		errHandler := func(err error) {
+			log.Fatal(err)
+		}
+		neg := &steps.Negotiation{}
+		actors.With(st).Do(steps.Starter, errHandler).Do(neg.Act(), errHandler).Run()
+		if neg.HasMechanism("PLAIN") {
+			auth := &steps.PlainAuth{Client: c, Pwd: pwd}
+			neg := &steps.Negotiation{}
+			bind := &steps.Bind{Rsrc: resource}
+			actors.With(st).Do(auth.Act(), errHandler).Do(steps.Starter).Do(neg.Act()).Do(bind.Act()).Do(steps.Session).Run()
+			actors.With(st).Do(steps.InitialPresence).Run()
+			actors.With(st).Do(func(st stream.Stream) error {
+				actors.With(st).Do(steps.PresenceTo("golang@conference.jabber.ru/xep")).Run()
+				for {
+					st.Ring(conv(func(entity.Entity) entity.Entity {
+
+						return nil
+					}), 0)
+				}
+			}).Run()
+		}
+	} else {
+		log.Fatal(err)
+	}
+}

+ 25 - 0
entity/bind-session.go

@@ -0,0 +1,25 @@
+package entity
+
+import (
+	"encoding/xml"
+)
+
+type Bind struct {
+	XMLName  xml.Name
+	Xmlns    string `xml:"xmlns,attr"`
+	Resource string `xml:"resource"`
+	Jid      string `xml:"jid"`
+}
+
+func (b *Bind) Init(rsrc string) {
+	b.Resource = rsrc
+}
+
+var BindPrototype = Bind{XMLName: xml.Name{Local: "bind"}, Xmlns: "urn:ietf:params:xml:ns:xmpp-bind"}
+
+type Session struct {
+	XMLName xml.Name
+	Xmlns   string `xml:"xmlns,attr"`
+}
+
+var SessionPrototype = Session{XMLName: xml.Name{Local: "session"}, Xmlns: "urn:ietf:params:xml:ns:xmpp-session"}

+ 80 - 0
entity/entity.go

@@ -0,0 +1,80 @@
+package entity
+
+import (
+	"bytes"
+	"encoding/xml"
+	"errors"
+	"fmt"
+	"github.com/kpmy/ypk/halt"
+	"io"
+	"strings"
+	"xep/units"
+)
+
+func Produce(i interface{}) *bytes.Buffer {
+	if data, err := xml.Marshal(i); err == nil {
+		return bytes.NewBuffer(data)
+	} else {
+		panic(err)
+	}
+}
+
+func Consume(b *bytes.Buffer) (ret Entity, err error) {
+	d := &dumb{buf: b}
+	if err = xml.NewDecoder(d.buf).Decode(d); err == nil {
+		ret = d.x
+	}
+	return
+}
+
+type Entity interface {
+	Produce() *bytes.Buffer
+}
+
+type dumb struct {
+	buf *bytes.Buffer
+	x   Entity
+}
+
+func (x *dumb) UnmarshalXML(d *xml.Decoder, start xml.StartElement) (err error) {
+	if fact, ok := ns[start.Name]; ok {
+		x.x = fact(x.buf)
+		d.DecodeElement(x.x, &start)
+	} else {
+		err = errors.New(fmt.Sprint("unknown entity ", start.Name))
+		halt.As(100, start.Name)
+	}
+	return
+}
+
+func (d *dumb) Produce() *bytes.Buffer {
+	return d.buf
+}
+
+func Open(s *units.Server) Entity {
+	buf := bytes.NewBuffer([]byte(xml.Header))
+	st := stream
+	st.To = s.Name
+	data := Produce(st)
+	pre := strings.TrimSuffix(string(data.Bytes()), "</stream:stream>")
+	io.Copy(buf, bytes.NewBufferString(pre))
+	return &dumb{buf: buf}
+}
+
+var ns map[xml.Name]func(*bytes.Buffer) Entity
+
+func init() {
+	ns = make(map[xml.Name]func(*bytes.Buffer) Entity)
+
+	ns[xml.Name{Space: "http://etherx.jabber.org/streams", Local: "stream"}] = func(buf *bytes.Buffer) Entity {
+		s := stream
+		buf.WriteString("</stream:stream>")
+		return &s
+	}
+
+	ns[xml.Name{Space: "stream", Local: "features"}] = func(*bytes.Buffer) Entity { return &Features{} }
+
+	ns[xml.Name{Space: "urn:ietf:params:xml:ns:xmpp-sasl", Local: "success"}] = func(*bytes.Buffer) Entity { return &Success{} }
+
+	ns[xml.Name{Local: "iq"}] = func(*bytes.Buffer) Entity { return &Iq{} }
+}

+ 28 - 0
entity/misc.go

@@ -0,0 +1,28 @@
+package entity
+
+import (
+	"bytes"
+	"encoding/xml"
+	"strings"
+)
+
+func setAttr(start *xml.StartElement, name, value string) {
+	a := xml.Attr{}
+	a.Name.Local = name
+	a.Value = value
+	start.Attr = append(start.Attr, a)
+}
+
+func getAttr(start *xml.StartElement, name string) (value string) {
+	for _, v := range start.Attr {
+		if strings.ToLower(v.Name.Local) == strings.ToLower(name) {
+			value = v.Value
+			break
+		}
+	}
+	return
+}
+
+type dumbProducer struct{}
+
+func (d *dumbProducer) Produce() *bytes.Buffer { panic(126) }

+ 29 - 0
entity/sasl-auth.go

@@ -0,0 +1,29 @@
+package entity
+
+import (
+	"bytes"
+	"encoding/base64"
+	"encoding/xml"
+)
+
+type PlainAuth struct {
+	XMLName   xml.Name
+	Xmlns     string `xml:"xmlns,attr"`
+	Mechanism string `xml:"mechanism,attr"`
+	Data      string `xml:",chardata"`
+}
+
+type Success struct {
+	dumbProducer
+}
+
+func (p *PlainAuth) Init(user, pwd string) {
+	data := bytes.NewBuffer([]byte(user + ":" + pwd))
+	data.WriteByte(0)
+	data.Write([]byte(user))
+	data.WriteByte(0)
+	data.Write([]byte(pwd))
+	p.Data = base64.StdEncoding.EncodeToString(data.Bytes())
+}
+
+var PlainAuthPrototype = PlainAuth{XMLName: xml.Name{Local: "auth"}, Xmlns: "urn:ietf:params:xml:ns:xmpp-sasl", Mechanism: "PLAIN"}

+ 6 - 0
entity/stream-features.go

@@ -0,0 +1,6 @@
+package entity
+
+type Features struct {
+	Mechanisms []string `xml:"mechanisms>mechanism"`
+	dumbProducer
+}

+ 35 - 0
entity/stream-stream.go

@@ -0,0 +1,35 @@
+package entity
+
+import (
+	"encoding/xml"
+	"errors"
+	"fmt"
+)
+
+type Stream struct {
+	XMLName xml.Name
+	Xmlns   string `xml:"xmlns,attr,omitempty"`
+	Version string `xml:"version,attr,omitempty"`
+	Stream  string `xml:"xmlns:stream,attr,omitempty"`
+	To      string `xml:"to,attr,omitempty"`
+	Id      string `xml:"-"`
+	dumbProducer
+}
+
+var stream Stream = Stream{XMLName: xml.Name{Local: "stream:stream"}, Version: "1.0", Xmlns: "jabber:client", Stream: "http://etherx.jabber.org/streams"}
+
+func (s *Stream) UnmarshalXML(d *xml.Decoder, start xml.StartElement) (err error) {
+	s.Id = getAttr(&start, "id")
+	var _t xml.Token
+	for stop := false; err == nil && !stop; {
+		if _t, err = d.Token(); err == nil {
+			switch t := _t.(type) {
+			case xml.EndElement:
+				stop = (start.Name == t.Name)
+			default:
+				err = errors.New(fmt.Sprint("unhandled ", t))
+			}
+		}
+	}
+	return
+}

+ 78 - 0
entity/xmpp-stanza.go

@@ -0,0 +1,78 @@
+package entity
+
+import (
+	"encoding/xml"
+	"github.com/kpmy/ypk/fn"
+	"github.com/kpmy/ypk/halt"
+	"math/rand"
+	"reflect"
+	"strconv"
+)
+
+type Type string
+
+const (
+	SET    Type = "set"
+	RESULT Type = "result"
+)
+
+type Stanza interface {
+}
+
+type Iq struct {
+	XMLName xml.Name
+	Id      string      `xml:"id,attr,omitempty"`
+	Type    Type        `xml:"type,attr"`
+	Inner   interface{} `xml:"iq"`
+	dumbProducer
+}
+
+func (i *Iq) UnmarshalXML(d *xml.Decoder, start xml.StartElement) (err error) {
+	i.Id = getAttr(&start, "id")
+	i.Type = Type(getAttr(&start, "type"))
+	var _t xml.Token
+	for stop := false; !stop && err == nil; {
+		_t, err = d.Token()
+		switch t := _t.(type) {
+		case xml.StartElement:
+			if fact, ok := us[t.Name]; ok {
+				i.Inner = fact()
+			}
+			if !fn.IsNil(i.Inner) {
+				d.DecodeElement(i.Inner, &t)
+			} else {
+				halt.As(100, t.Name)
+			}
+		case xml.EndElement:
+			stop = t.Name == start.Name
+		default:
+			halt.As(100, reflect.TypeOf(t))
+		}
+	}
+	return
+}
+
+var iq = Iq{XMLName: xml.Name{Local: "iq"}}
+
+func IQ(typ Type, user interface{}) *Iq {
+	i := &Iq{}
+	*i = iq
+	i.Type = typ
+	i.Inner = user
+	i.Id = strconv.FormatInt(int64(rand.Intn(0xffffff)), 16)
+	return i
+}
+
+type Presence struct {
+	XMLName xml.Name
+	To      string `xml:"to,attr,omitempty"`
+}
+
+var PresencePrototype = Presence{XMLName: xml.Name{Local: "presence"}}
+
+var us map[xml.Name]func() interface{}
+
+func init() {
+	us = make(map[xml.Name]func() interface{})
+	us[xml.Name{Space: "urn:ietf:params:xml:ns:xmpp-bind", Local: "bind"}] = func() interface{} { return &Bind{} }
+}

+ 0 - 154
stream/client.go

@@ -1,154 +0,0 @@
-package stream
-
-import (
-	"bytes"
-	"encoding/xml"
-	"errors"
-	"log"
-	"net"
-	"strings"
-)
-
-type Client struct {
-	User, Server, Resource, Pwd string
-	conn                        net.Conn
-	buffer                      []byte
-}
-
-func resolve(server string) (addr, port string) {
-	return server, "5222"
-}
-
-func (c *Client) Bare() string {
-	return c.User + "@" + c.Server
-}
-
-func write(c net.Conn, b []byte) (int, error) {
-	log.Println(string(b))
-	return c.Write(b)
-}
-
-func read(c net.Conn, b []byte) (ret []byte, err error) {
-	n := 0
-	if n, err = c.Read(b); err == nil && n > 0 {
-		ret = b[0:n]
-		log.Println(string(ret))
-	}
-	return
-}
-
-func (c *Client) Status() {
-	data, _ := xml.Marshal(&presence)
-	write(c.conn, data)
-}
-
-func (c *Client) start2(next func() error) (err error) {
-	s := &Stream{to: c.Server, from: c.Bare()}
-	buf := bytes.NewBuffer([]byte(xml.Header))
-	data, _ := xml.Marshal(s)
-	pre := string(data)
-	pre = strings.TrimSuffix(pre, "</stream:stream>")
-	buf.Write([]byte(pre))
-	write(c.conn, buf.Bytes())
-	if data, err = read(c.conn, c.buffer); err == nil {
-		post := string(data) + "</stream:stream>"
-		data = []byte(post)
-		xml.Unmarshal(data, s)
-		read(c.conn, c.buffer) //blabla features
-		b := &Bind{}
-		*b = bind
-		b.Init(c.Resource)
-		biq := &Iq{}
-		*biq = iq
-		biq.Id = "0001"
-		biq.Type = SET
-		biq.Inner = b
-		data, _ = xml.Marshal(biq)
-		write(c.conn, data)
-		if data, err = read(c.conn, c.buffer); err == nil {
-			xml.Unmarshal(data, biq)
-			log.Println(b.Jid)
-			if b.Jid == "" {
-				err = errors.New("resource not binded")
-				return
-			}
-			siq := &Iq{}
-			*siq = iq
-			siq.Id = "0002"
-			siq.Type = SET
-			siq.Inner = &session
-			data, _ = xml.Marshal(siq)
-			write(c.conn, data)
-			if data, err = read(c.conn, c.buffer); err == nil {
-				xml.Unmarshal(data, siq)
-				next()
-			}
-		}
-	}
-	return
-}
-
-func (c *Client) Start(next func() error) (err error) {
-	s := &Stream{to: c.Server, from: c.Bare()}
-	buf := bytes.NewBuffer([]byte(xml.Header))
-	data, _ := xml.Marshal(s)
-	pre := string(data)
-	pre = strings.TrimSuffix(pre, "</stream:stream>")
-	buf.Write([]byte(pre))
-	write(c.conn, buf.Bytes())
-	if data, err = read(c.conn, c.buffer); err == nil {
-		post := string(data) + "</stream:stream>"
-		data = []byte(post)
-		xml.Unmarshal(data, s)
-		s.features = &Features{}
-		if data, err = read(c.conn, c.buffer); err == nil {
-			xml.Unmarshal(data, s.features)
-			if s.HasMechanism("PLAIN") {
-				a := &PlainAuth{}
-				*a = plainAuth
-				a.Init(c.User, c.Pwd)
-				data, _ = xml.Marshal(a)
-				write(c.conn, data)
-				if data, err = read(c.conn, c.buffer); err == nil {
-					xml.Unmarshal(data, a)
-					if a.Success {
-						log.Println("success")
-						return c.start2(next)
-					} else {
-						err = errors.New("failed")
-					}
-				}
-			}
-		}
-	}
-	return
-}
-
-func (c *Client) Do(s Stanza) (err error) {
-	if data, e := xml.Marshal(s); e == nil {
-		_, err = write(c.conn, data)
-	} else {
-		err = e
-	}
-	return
-}
-
-func (c *Client) Process() (err error) {
-	read(c.conn, c.buffer)
-	return
-}
-
-func (c *Client) Stop() (err error) {
-	write(c.conn, []byte("</stream:stream>"))
-	read(c.conn, c.buffer)
-	return
-}
-
-func Dial(cli *Client) (ret *Client, err error) {
-	host, port := resolve(cli.Server)
-	if cli.conn, err = net.Dial("tcp", host+":"+port); err == nil {
-		cli.buffer = make([]byte, 4096)
-		ret = cli
-	}
-	return
-}

+ 0 - 55
stream/stanza.go

@@ -1,55 +0,0 @@
-package stream
-
-import (
-	"encoding/xml"
-	"fmt"
-	"reflect"
-)
-
-const (
-	SET = "set"
-)
-
-type Stanza interface {
-	Prepare()
-}
-
-type Iq struct {
-	XMLName xml.Name
-	Id      string      `xml:"id,attr"`
-	Type    string      `xml:"type,attr"`
-	Inner   interface{} `xml:"iq"`
-}
-
-func (i *Iq) UnmarshalXML(d *xml.Decoder, start xml.StartElement) (err error) {
-	var _t xml.Token
-	for stop := false; !stop && err == nil; {
-		_t, err = d.Token()
-		switch t := _t.(type) {
-		case xml.StartElement:
-			d.DecodeElement(i.Inner, &t)
-		case xml.EndElement:
-			stop = t.Name == start.Name
-		default:
-			panic(fmt.Sprintln(reflect.TypeOf(t)))
-		}
-	}
-	return
-}
-
-func (i *Iq) Prepare() {
-	*i = iq
-}
-
-var iq = Iq{XMLName: xml.Name{Local: "iq"}}
-
-type Presence struct {
-	XMLName xml.Name
-	To      string `xml:"to,attr,omitempty"`
-}
-
-func (p *Presence) Prepare() {
-	*p = presence
-}
-
-var presence = Presence{XMLName: xml.Name{Local: "presence"}}

+ 0 - 109
stream/xml.go

@@ -1,109 +0,0 @@
-package stream
-
-import (
-	"bytes"
-	"encoding/base64"
-	"encoding/xml"
-	"strings"
-)
-
-func setAttr(start *xml.StartElement, name, value string) {
-	a := xml.Attr{}
-	a.Name.Local = name
-	a.Value = value
-	start.Attr = append(start.Attr, a)
-}
-
-func getAttr(start *xml.StartElement, name string) (value string) {
-	for _, v := range start.Attr {
-		if strings.ToLower(v.Name.Local) == strings.ToLower(name) {
-			value = v.Value
-			break
-		}
-	}
-	return
-}
-
-type Stream struct {
-	to, from string
-	id       string
-	features *Features
-}
-
-func (s *Stream) MarshalXML(e *xml.Encoder, start xml.StartElement) (err error) {
-	start.Name = xml.Name{Local: "stream:stream"}
-	setAttr(&start, "version", "1.0")
-	setAttr(&start, "xmlns", "jabber:client")
-	setAttr(&start, "xml:lang", "en")
-	setAttr(&start, "xmlns:stream", "http://etherx.jabber.org/streams")
-	setAttr(&start, "to", s.to)
-	setAttr(&start, "from", s.from)
-	e.EncodeToken(start)
-	e.EncodeToken(start.End())
-	return
-}
-
-func (s *Stream) UnmarshalXML(d *xml.Decoder, start xml.StartElement) (err error) {
-	s.id = getAttr(&start, "id")
-	return
-}
-
-func (s *Stream) HasMechanism(mech string) (ok bool) {
-	if s.features != nil {
-		for _, v := range s.features.Mechanisms {
-			if strings.ToLower(v) == strings.ToLower(mech) {
-				ok = true
-				break
-			}
-		}
-	}
-	return
-}
-
-type Features struct {
-	Mechanisms []string `xml:"mechanisms>mechanism"`
-}
-
-type PlainAuth struct {
-	XMLName   xml.Name
-	Xmlns     string `xml:"xmlns,attr"`
-	Mechanism string `xml:"mechanism,attr"`
-	Data      string `xml:",chardata"`
-	Success   bool
-}
-
-func (p *PlainAuth) Init(user, pwd string) {
-	data := bytes.NewBuffer([]byte(user + "@" + pwd))
-	data.WriteByte(0)
-	data.Write([]byte(user))
-	data.WriteByte(0)
-	data.Write([]byte(pwd))
-	p.Data = base64.StdEncoding.EncodeToString(data.Bytes())
-}
-
-func (p *PlainAuth) UnmarshalXML(d *xml.Decoder, start xml.StartElement) (err error) {
-	p.Success = start.Name.Local == "success"
-	return
-}
-
-var plainAuth = PlainAuth{XMLName: xml.Name{Local: "auth"}, Xmlns: "urn:ietf:params:xml:ns:xmpp-sasl", Mechanism: "PLAIN"}
-
-type Bind struct {
-	XMLName  xml.Name
-	Xmlns    string `xml:"xmlns,attr"`
-	Resource string `xml:"resource"`
-	Jid      string `xml:"jid"`
-}
-
-func (b *Bind) Init(rsrc string) {
-	b.Resource = rsrc
-}
-
-var bind = Bind{XMLName: xml.Name{Local: "bind"}, Xmlns: "urn:ietf:params:xml:ns:xmpp-bind"}
-
-type Session struct {
-	XMLName xml.Name
-	Xmlns   string `xml:"xmlns,attr"`
-}
-
-var session = Session{XMLName: xml.Name{Local: "session"}, Xmlns: "urn:ietf:params:xml:ns:xmpp-session"}

+ 9 - 0
tools/srv/srv.go

@@ -0,0 +1,9 @@
+package srv
+
+import (
+	"xep/units"
+)
+
+func Resolve(s *units.Server) (host, port string, err error) {
+	return s.Name, "5222", nil
+}

+ 10 - 0
units/units.go

@@ -0,0 +1,10 @@
+package units
+
+type Server struct {
+	Name string
+}
+
+type Client struct {
+	Name   string
+	Server *Server
+}

+ 0 - 29
xep.go

@@ -1,29 +0,0 @@
-package main
-
-import (
-	"log"
-	"xep/stream"
-)
-
-func init() {
-	log.SetFlags(0)
-}
-
-func main() {
-	if cli, err := stream.Dial(&stream.Client{User: "goxep", Server: "xmpp.ru", Resource: "go", Pwd: "GogogOg0"}); err == nil {
-		log.Println("connected")
-		for err := cli.Start(func() error {
-			cli.Status()
-			p := &stream.Presence{}
-			p.Prepare()
-			p.To = "golang@conference.jabber.ru/xep"
-			cli.Do(p)
-			return nil
-		}); err == nil; {
-			err = cli.Process()
-		}
-		defer cli.Stop()
-	} else {
-		log.Fatal(err)
-	}
-}