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 } }