11 "github.com/Sirupsen/logrus"
16 MonitorTime time.Duration
22 cbArr map[string][]cbMap
26 Type string `json:"type"`
27 Time time.Time `json:"time"`
28 Data map[string]string `json:"data"`
31 type EventsCBData map[string]interface{}
32 type EventsCB func(ev Event, cbData *EventsCBData)
35 EventFolderCompletion string = "FolderCompletion"
36 EventFolderSummary string = "FolderSummary"
37 EventFolderPaused string = "FolderPaused"
38 EventFolderResumed string = "FolderResumed"
39 EventFolderErrors string = "FolderErrors"
40 EventStateChanged string = "StateChanged"
43 var EventsAll string = EventFolderCompletion + "|" +
44 EventFolderSummary + "|" +
45 EventFolderPaused + "|" +
46 EventFolderResumed + "|" +
47 EventFolderErrors + "|" +
51 // Per-subscription sequential event ID. Named "id" for backwards compatibility with the REST API
52 SubscriptionID int `json:"id"`
53 // Global ID of the event across all subscriptions
54 GlobalID int `json:"globalID"`
55 Time time.Time `json:"time"`
56 Type string `json:"type"`
57 Data map[string]interface{} `json:"data"`
67 // NewEventListener Create a new instance of Event listener
68 func (s *SyncThing) NewEventListener() *Events {
69 _, dbg := os.LookupEnv("XDS_DEBUG_STEVENTS") // set to add more debug log
71 MonitorTime: 100, // in Milliseconds
73 stop: make(chan bool, 1),
76 cbArr: make(map[string][]cbMap),
80 // Start starts event monitoring loop
81 func (e *Events) Start() error {
86 // Stop stops event monitoring loop
87 func (e *Events) Stop() {
91 // Register Add a listener on an event
92 func (e *Events) Register(evName string, cb EventsCB, filterID string, data *EventsCBData) (int, error) {
93 if evName == "" || !strings.Contains(EventsAll, evName) {
94 return -1, fmt.Errorf("Unknown event name")
97 data = &EventsCBData{}
101 if _, ok := e.cbArr[evName]; ok {
102 cbList = e.cbArr[evName]
106 (*data)["id"] = strconv.Itoa(id)
108 e.cbArr[evName] = append(cbList, cbMap{id: id, cb: cb, filterID: filterID, data: data})
113 // UnRegister Remove a listener event
114 func (e *Events) UnRegister(evName string, id int) error {
115 cbKey, ok := e.cbArr[evName]
117 return fmt.Errorf("No event registered to such name")
120 // FIXME - NOT TESTED
121 if id >= len(cbKey) {
122 return fmt.Errorf("Invalid id")
123 } else if id == len(cbKey) {
124 e.cbArr[evName] = cbKey[:id-1]
126 e.cbArr[evName] = cbKey[id : id+1]
132 // GetEvents returns the Syncthing events
133 func (e *Events) getEvents(since int) ([]STEvent, error) {
138 url += "?since=" + strconv.Itoa(since)
140 if err := e.st.client.HTTPGet(url, &data); err != nil {
143 err := json.Unmarshal(data, &ev)
147 // Loop to monitor Syncthing events
148 func (e *Events) monitorLoop() {
149 e.log.Infof("Event monitoring running...")
154 e.log.Infof("Event monitoring exited")
157 case <-time.After(e.MonitorTime * time.Millisecond):
158 stEvArr, err := e.getEvents(since)
160 e.log.Errorf("Syncthing Get Events: %v", err)
164 for _, stEv := range stEvArr {
165 since = stEv.SubscriptionID
167 e.log.Warnf("ST EVENT: %d %s\n %v", stEv.GlobalID, stEv.Type, stEv)
170 cbKey, ok := e.cbArr[stEv.Type]
181 // FIXME: re-define data struct for each events
182 // instead of map of string and use JSON marshing/unmarshing
184 evData.Data = make(map[string]string)
187 case EventFolderCompletion:
188 fID = convString(stEv.Data["folder"])
189 evData.Data["completion"] = convFloat64(stEv.Data["completion"])
191 case EventFolderSummary:
192 fID = convString(stEv.Data["folder"])
193 evData.Data["needBytes"] = convInt64(stEv.Data["needBytes"])
194 evData.Data["state"] = convString(stEv.Data["state"])
196 case EventFolderPaused, EventFolderResumed:
197 fID = convString(stEv.Data["id"])
198 evData.Data["label"] = convString(stEv.Data["label"])
200 case EventFolderErrors:
201 fID = convString(stEv.Data["folder"])
202 // TODO decode array evData.Data["errors"] = convString(stEv.Data["errors"])
204 case EventStateChanged:
205 fID = convString(stEv.Data["folder"])
206 evData.Data["from"] = convString(stEv.Data["from"])
207 evData.Data["to"] = convString(stEv.Data["to"])
210 e.log.Warnf("Unsupported event type")
214 evData.Data["id"] = fID
217 // Call all registered callbacks
218 for _, c := range cbKey {
220 e.log.Warnf("EVENT CB fID=%s, filterID=%s", fID, c.filterID)
222 // Call when filterID is not set or when it matches
223 if c.filterID == "" || (fID != "" && fID == c.filterID) {
232 func convString(d interface{}) string {
236 func convFloat64(d interface{}) string {
237 return strconv.FormatFloat(d.(float64), 'f', -1, 64)
240 func convInt64(d interface{}) string {
241 return strconv.FormatInt(d.(int64), 10)