216 lines
5.6 KiB
Go
216 lines
5.6 KiB
Go
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
|
||
}
|
||
}
|