-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Initial commit of XEP-0114 implementation
- Loading branch information
0 parents
commit b17c2ef
Showing
11 changed files
with
470 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
The MIT License (MIT) | ||
|
||
Copyright (c) 2016 Sheena Artrip | ||
|
||
Permission is hereby granted, free of charge, to any person obtaining a copy | ||
of this software and associated documentation files (the "Software"), to deal | ||
in the Software without restriction, including without limitation the rights | ||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
copies of the Software, and to permit persons to whom the Software is | ||
furnished to do so, subject to the following conditions: | ||
|
||
The above copyright notice and this permission notice shall be included in all | ||
copies or substantial portions of the Software. | ||
|
||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
SOFTWARE. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
# go-xco | ||
|
||
Library for building XMPP/Jabber ( XEP-0114 ) components in golang. | ||
|
||
## Usage: | ||
|
||
import ( | ||
"github.com/sheenobu/go-xco" | ||
) | ||
|
||
func main(){ | ||
|
||
opts := &xco.Options{ | ||
Name: Name, | ||
SharedSecret: SharedSecret, | ||
Address: Address, | ||
} | ||
|
||
c, err := opts.NewComponent() | ||
if err != nil { | ||
panic(err) | ||
} | ||
|
||
// Uppercase Echo Component | ||
c.MessageHandler = func(c *xco.Component, msg *xco.Message) error { | ||
m := xco.Message{ | ||
Header: xco.Header{ | ||
From: msg.To, | ||
To: msg.From, | ||
ID: msg.ID, | ||
}, | ||
Subject: msg.Subject, | ||
Thread: msg.Thread, | ||
Type: msg.Type, | ||
Body: strings.ToUpper(msg.Body), | ||
XMLName: msg.XMLName, | ||
} | ||
|
||
return c.Send(m) | ||
} | ||
|
||
c.Run() | ||
} | ||
|
||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
package main | ||
|
||
import ( | ||
"flag" | ||
"os" | ||
"strings" | ||
|
||
"github.com/sheenobu/go-xco" | ||
) | ||
|
||
var Name string | ||
var SharedSecret string | ||
var Address string | ||
|
||
func init() { | ||
flag.StringVar(&Name, "name", "", "Name of Component") | ||
flag.StringVar(&SharedSecret, "secret", "", "Shared Secret between server and component") | ||
flag.StringVar(&Address, "address", "", "Hostname:port address of XMPP component listener") | ||
} | ||
|
||
func main() { | ||
|
||
flag.Parse() | ||
|
||
if Name == "" || SharedSecret == "" || Address == "" { | ||
flag.Usage() | ||
os.Exit(-1) | ||
return | ||
} | ||
|
||
opts := &xco.Options{ | ||
Name: Name, | ||
SharedSecret: SharedSecret, | ||
Address: Address, | ||
} | ||
|
||
c, err := opts.NewComponent() | ||
if err != nil { | ||
panic(err) | ||
} | ||
|
||
// Uppercase Echo Component | ||
c.MessageHandler = func(c *xco.Component, msg *xco.Message) error { | ||
m := xco.Message{ | ||
Header: xco.Header{ | ||
From: msg.To, | ||
To: msg.From, | ||
ID: msg.ID, | ||
}, | ||
Subject: msg.Subject, | ||
Thread: msg.Thread, | ||
Type: msg.Type, | ||
Body: strings.ToUpper(msg.Body), | ||
XMLName: msg.XMLName, | ||
} | ||
|
||
return c.Send(m) | ||
} | ||
|
||
c.Run() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
package xco | ||
|
||
import ( | ||
"encoding/xml" | ||
"fmt" | ||
"net" | ||
"os" | ||
|
||
"golang.org/x/net/context" | ||
) | ||
|
||
type stateFn func() (stateFn, error) | ||
|
||
// A Component is an instance of a Jabber Component (XEP-0114) | ||
type Component struct { | ||
MessageHandler MessageHandler | ||
PresenceHandler PresenceHandler | ||
IqHandler IqHandler | ||
|
||
ctx context.Context | ||
cancelFn context.CancelFunc | ||
|
||
conn net.Conn | ||
dec *xml.Decoder | ||
enc *xml.Encoder | ||
|
||
stateFn stateFn | ||
|
||
sharedSecret string | ||
name string | ||
} | ||
|
||
func (c *Component) dial(o *Options) error { | ||
conn, err := net.Dial("tcp", o.Address) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
c.MessageHandler = noOpMessageHandler | ||
c.PresenceHandler = noOpPresenceHandler | ||
c.IqHandler = noOpIqHandler | ||
|
||
c.conn = conn | ||
c.name = o.Name | ||
c.sharedSecret = o.SharedSecret | ||
c.dec = xml.NewDecoder(conn) | ||
c.enc = xml.NewEncoder(conn) | ||
c.stateFn = c.handshakeState | ||
|
||
return nil | ||
} | ||
|
||
func (c *Component) Close() { | ||
c.cancelFn() | ||
} | ||
|
||
func (c *Component) Run() { | ||
|
||
defer func() { | ||
c.conn.Close() | ||
}() | ||
|
||
var err error | ||
|
||
for { | ||
if c.stateFn == nil { | ||
return | ||
} | ||
c.stateFn, err = c.stateFn() | ||
if err != nil { | ||
fmt.Fprintf(os.Stderr, "Error: %s\n", err) | ||
} | ||
} | ||
} | ||
|
||
func (c *Component) Send(i interface{}) error { | ||
return c.enc.Encode(i) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
package xco | ||
|
||
import ( | ||
"crypto/sha1" | ||
"encoding/hex" | ||
"encoding/xml" | ||
"errors" | ||
"fmt" | ||
) | ||
|
||
func (c *Component) handshakeState() (stateFn, error) { | ||
|
||
if _, err := c.conn.Write([]byte(fmt.Sprintf(` | ||
<stream:stream | ||
xmlns='jabber:component:accept' | ||
xmlns:stream='http://etherx.jabber.org/streams' | ||
to='%s'>`, c.name))); err != nil { | ||
return nil, err | ||
} | ||
|
||
for { | ||
t, err := c.dec.Token() | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
stream, ok := t.(xml.StartElement) | ||
if !ok { | ||
continue | ||
} | ||
|
||
var id string | ||
|
||
for _, a := range stream.Attr { | ||
if a.Name.Local == "id" { | ||
id = a.Value | ||
} | ||
} | ||
|
||
if id == "" { | ||
return nil, errors.New("Unable to find ID in stream response") | ||
} | ||
|
||
handshakeInput := id + c.sharedSecret | ||
handshake := sha1.Sum([]byte(handshakeInput)) | ||
hexHandshake := hex.EncodeToString(handshake[:]) | ||
if _, err := c.conn.Write([]byte(fmt.Sprintf("<handshake>%s</handshake>", hexHandshake))); err != nil { | ||
return nil, err | ||
} | ||
|
||
//TODO: separate each step into a state | ||
|
||
// get handshake response | ||
t, err = c.dec.Token() | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
t, err = c.dec.Token() | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
return c.readLoopState, nil | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
package xco | ||
|
||
type Header struct { | ||
ID string `xml:"id,attr"` | ||
From string `xml:"from,attr"` //TODO: make address type | ||
To string `xml:"to,attr"` //TODO: make address type | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
package xco | ||
|
||
type Iq struct { | ||
Header | ||
|
||
Type string `xml:"type,attr"` | ||
|
||
Content string `xml:",innerxml"` | ||
|
||
XMLName string `xml:"iq"` | ||
} | ||
|
||
type IqHandler func(c *Component, iq *Iq) error | ||
|
||
func noOpIqHandler(c *Component, iq *Iq) error { | ||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
package xco | ||
|
||
import "encoding/xml" | ||
|
||
// MessageType defines the constants for the types of messages within XEP-0114 | ||
type MessageType string | ||
|
||
const ( | ||
|
||
// CHAT defines the chat message type | ||
CHAT = MessageType("chat") | ||
|
||
// ERROR defines the error message type | ||
ERROR = MessageType("error") | ||
|
||
// GROUPCHAT defines the group chat message type | ||
GROUPCHAT = MessageType("groupchat") | ||
|
||
// HEADLINE defines the headline message type | ||
HEADLINE = MessageType("headline") | ||
|
||
// NORMAL defines the normal message type | ||
NORMAL = MessageType("normal") | ||
) | ||
|
||
// A Message is an incoming or outgoing Component message | ||
type Message struct { | ||
Header | ||
Type MessageType `xml:"type,attr,omitempty"` | ||
|
||
Subject string `xml:"subject,omitempty"` | ||
Body string `xml:"body"` | ||
Thread string `xml:"thread,omitempty"` | ||
|
||
XMLName xml.Name | ||
} | ||
|
||
// A MessageHandler handles a message | ||
type MessageHandler func(*Component, *Message) error | ||
|
||
func noOpMessageHandler(c *Component, m *Message) error { | ||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
package xco | ||
|
||
import "golang.org/x/net/context" | ||
|
||
// Options define the series of options required to build a component | ||
type Options struct { | ||
|
||
// Name defines the component name | ||
Name string | ||
|
||
// SharedSecret is the secret shared between the server and component | ||
SharedSecret string | ||
|
||
// Address is the address of the XMPP server | ||
Address string | ||
|
||
// The (optional) parent context | ||
Context context.Context | ||
} | ||
|
||
// NewComponent creates a new component from the given options | ||
func (opts *Options) NewComponent() (*Component, error) { | ||
|
||
if opts.Context == nil { | ||
opts.Context = context.Background() | ||
} | ||
|
||
var c Component | ||
c.ctx, c.cancelFn = context.WithCancel(opts.Context) | ||
|
||
if err := c.dial(opts); err != nil { | ||
return nil, err | ||
} | ||
|
||
return &c, nil | ||
} |
Oops, something went wrong.