DataHouse/xmpp/xmpp.go

216 lines
5.6 KiB
Go
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package xmpp_manager
import (
"strconv"
"time"
"github.com/astaxie/beego"
"github.com/astaxie/beego/logs"
"git.kingpenguin.tk/chteufleur/datahouse.git/models/relay"
"git.kingpenguin.tk/chteufleur/datahouse.git/models/variables"
"git.kingpenguin.tk/chteufleur/go-xmpp.git/src/xmpp"
)
const (
Status_online = ""
Status_offline = ""
Status_away = "away"
Status_chat = "chat"
Status_do_not_disturb = "dnd"
Status_extended_away = "xa"
Type_available = ""
Type_unavailable = "unavailable"
Type_subscribe = "subscribe"
Type_subscribed = "subscribed"
Type_unsubscribe = "unsubscribe"
Type_unsubscribed = "unsubscribed"
Type_probe = "probe"
Type_error = "error"
)
var (
log = logs.NewLogger(10000)
JidStr = beego.AppConfig.String("JID")
passwdStr = beego.AppConfig.String("PWD")
serverPort = beego.AppConfig.String("PORT")
jid xmpp.JID
stream = new(xmpp.Stream)
client = new(xmpp.XMPP)
ping = false
pingId int64 = 0
timerDoPing, _ = beego.AppConfig.Int("TIMER_PING")
Debug = false
)
func init() {
log.SetLogger(variables.LogType, variables.LogParams)
Debug = beego.AppConfig.String("XMPP_DEBUG") == "true"
if timerDoPing < 30 {
timerDoPing = 30
}
go doPing()
}
func must(v interface{}, err error) interface{} {
if err != nil {
log.Error("Must error : ", err)
}
return v
}
func Run() {
// Create stream and configure it as a component connection.
log.Info("XMPP Run()")
jid = must(xmpp.ParseJID(JidStr)).(xmpp.JID)
addrs, err := xmpp.HomeServerAddrs(jid)
if err == nil && len(addrs) > 0 {
stream = must(xmpp.NewStream(addrs[0], &xmpp.StreamConfig{LogStanzas: Debug})).(*xmpp.Stream)
client = must(xmpp.NewClientXMPP(stream, jid, passwdStr, &xmpp.ClientConfig{InsecureSkipVerify: true})).(*xmpp.XMPP)
mainXMPP()
time.Sleep(1 * time.Second)
}
log.Debug("xmpp.Run Ended")
go Run()
}
func mainXMPP() {
defer func() {
ping = false
log.Debug("mainXMPP Ended")
}()
SendPresence(Status_online, Type_available, "DataHouse")
ping = true
for x := range client.In {
switch v := x.(type) {
case *xmpp.Iq:
// TODO check if the caller has privilege to ask
switch v.PayloadName().Space {
case xmpp.NSDiscoItems:
execDiscoCommand(v)
case xmpp.NodeAdHocCommand:
execCommandAdHoc(v)
}
default:
log.Info("recv: %v", x)
}
}
}
func doPing() {
for {
if ping {
iq := &xmpp.Iq{Id: strconv.FormatInt(pingId, 10), Type: xmpp.IQTypeGet, To: jid.Domain, From: jid.Full()}
iq.PayloadEncode(&xmpp.Ping{})
client.Out <- iq
pingId++
}
time.Sleep(time.Duration(timerDoPing) * time.Second)
}
}
func SendPresence(status, tpye, message string) {
client.Out <- xmpp.Presence{From: jid.Full(), Show: status, Type: tpye, Status: message}
}
func SendMessage(to, subject, message string) {
m := xmpp.Message{From: jid.Domain, To: to, Type: "chat"}
mBody := xmpp.MessageBody{Value: message}
m.Body = append(m.Body, mBody)
if subject != "" {
m.Subject = subject
}
client.Out <- m
}
func execDiscoCommand(iq *xmpp.Iq) {
log.Info("Discovery item iq received")
reply := iq.Response(xmpp.IQTypeResult)
discoItem := &xmpp.DiscoItems{Node: xmpp.NodeAdHocCommand}
relays := relay.GetAllRelay()
for _, r := range relays {
discoI := &xmpp.DiscoItem{JID: client.JID.Full(), Node: r.Mac, Name: "Relay : "}
if r.Description == "" {
discoI.Name += r.Mac
} else {
discoI.Name += r.Description
}
discoItem.Item = append(discoItem.Item, *discoI)
}
reply.PayloadEncode(discoItem)
client.Out <- reply
}
func execCommandAdHoc(iq *xmpp.Iq) {
adHoc := &xmpp.AdHocCommand{}
iq.PayloadDecode(adHoc)
log.Info("Commande Ad-Hoc reçut. Node : %s", adHoc.Node)
// For now, we know that the node is the Mac address for a relay
relais := relay.GetRelayByMac(adHoc.Node)
descriptionRelais := relais.Description
if descriptionRelais == "" {
descriptionRelais = relais.Mac
}
if adHoc.SessionID == "" && adHoc.Action == xmpp.ActionAdHocExecute {
// First step in the command
if relais.Id != 0 {
reply := iq.Response(xmpp.IQTypeResult)
cmd := &xmpp.AdHocCommand{Node: adHoc.Node, Status: xmpp.StatusAdHocExecute, SessionID: xmpp.SessionID() /*+";"+relais.Mac*/}
cmdXForm := &xmpp.AdHocXForm{Type: xmpp.TypeAdHocForm, Title: "Commande relais " + descriptionRelais}
field := &xmpp.AdHocField{Var: "command", Label: "Commande a executer", Type: "list-single"}
fieldOption := &xmpp.AdHocFieldOption{Value: "toggle"}
field.Options = append(field.Options, *fieldOption)
cmdXForm.Fields = append(cmdXForm.Fields, *field)
// TODO, ajouter des commandes pour allumer X seconde (par exemple)
cmd.XForm = *cmdXForm
reply.PayloadEncode(cmd)
client.Out <- reply
}
} else if adHoc.Action == xmpp.ActionAdHocExecute {
// Last step in the command
err := relais.Toggle()
reply := iq.Response(xmpp.IQTypeResult)
cmd := &xmpp.AdHocCommand{Node: adHoc.Node, Status: xmpp.StatusAdHocCompleted, SessionID: adHoc.SessionID}
cmdXForm := &xmpp.AdHocXForm{Type: xmpp.TypeAdHocResult, Title: "Commande relais " + descriptionRelais}
cmd.XForm = *cmdXForm
note := &xmpp.AdHocNote{Type: xmpp.TypeAdHocNoteInfo}
if err == nil {
note.Value = "Commande effectuée avec succes !"
} else {
note.Value = "Une erreur c'est produite à l'exécution de la commande…"
}
cmd.Note = *note
reply.PayloadEncode(cmd)
client.Out <- reply
} else if adHoc.Action == xmpp.ActionAdHocCancel {
// command canceled
reply := iq.Response(xmpp.IQTypeResult)
cmd := &xmpp.AdHocCommand{Node: adHoc.Node, Status: xmpp.StatusAdHocCanceled, SessionID: adHoc.SessionID}
reply.PayloadEncode(cmd)
client.Out <- reply
}
}