firmware/user workaround: send open if user opens door after timeout_after_open
[svn42.git] / go / r3-netstatus / r3xmppbot / ping.go
1 // (c) Bernhard Tittelbach, 2013
2
3 package r3xmppbot
4
5 import (
6         xmpp "code.google.com/p/goexmpp"
7     "time"
8     "encoding/xml"    
9 )
10
11 // XMPP Ping
12 type XMPPPing struct {
13         XMLName xml.Name     `xml:"urn:xmpp:ping ping"`
14 }
15
16 func HandleServerToClientPing(iq *xmpp.Iq, xmppout chan<- xmpp.Stanza) bool {
17     ///<iq from='juliet@capulet.lit/balcony' to='capulet.lit' id='s2c1' type='result'/>
18     if iq.Type != "get" { return false}
19     for _, ele := range iq.Nested {
20         if _, ok := ele.(*XMPPPing); ok {
21             xmppout <- &xmpp.Iq{Header: xmpp.Header{To: iq.From, From: iq.To, Id: iq.Id, Type: "result" }}
22             return true
23         }
24     }
25     return false
26 }
27
28 func (botdata *XmppBot) PingServer(timeout_ms time.Duration) (is_up bool) {
29 ///<iq from='juliet@capulet.lit/balcony' to='capulet.lit' id='c2s1' type='get'>
30 ///  <ping xmlns='urn:xmpp:ping'/>
31 ///</iq>
32     server_jid := new(xmpp.JID)
33     server_jid.Set(botdata.my_jid_)
34     iqping := &xmpp.Iq{Header: xmpp.Header{To: server_jid.Domain,
35                                                             From: botdata.my_jid_,
36                                                             Id: <-xmpp.Id,
37                                                             Type: "get",
38                                                             Nested: []interface{}{XMPPPing{}}   }   }
39     pong := make(chan bool, 1)
40     defer close(pong)
41     f := func(v xmpp.Stanza) bool {
42         defer recover() //recover from writing to possibly already closed chan
43         let_others_handle_stanza := false
44         iq, ok := v.(*xmpp.Iq)
45         if !ok {
46             Syslog_.Printf("response to iq ping wasn't iq: %s", v)
47             pong <- false
48             return true //let other handlers process reply
49         }
50         if iq.Type == "error" && iq.Error != nil && iq.Error.Type == "cancel"{
51             Debug_.Printf("response to iq ping was cancel, server does not support ping")
52             //server does not support ping, but at least we know server is still there
53         } else if iq.Type != "result" {
54             Syslog_.Printf("response to iq ping was not pong: %s", v)
55             let_others_handle_stanza = true //let other handlers process reply
56         }
57         pong <- true
58         return let_others_handle_stanza // return false so that Stanza v will not be appear in xmppclient_.Out()
59     }
60     botdata.xmppclient_.HandleStanza(iqping.Id, f)
61     botdata.xmppclient_.Out <- iqping    
62     go func() {
63         defer func() {if x:= recover(); x == nil { Syslog_.Printf("response to iq ping timed out !!") }}() //recover from writing to possibly already closed chan. If we did not need to recover, then Handler did not receive reply
64         time.Sleep(timeout_ms * time.Millisecond)
65         pong <- false   //xmpp ping timed out
66     }()
67     return <- pong
68 }