// mautrix-whatsapp - A Matrix-WhatsApp puppeting bridge. // Copyright (C) 2022 Tulir Asokan, Sumner Evans // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . package main import ( "bytes" "encoding/json" "fmt" "net/http" "github.com/rs/zerolog" "maunium.net/go/mautrix/id" ) type AnalyticsClient struct { url string key string userID string log zerolog.Logger client http.Client } var Analytics AnalyticsClient func (sc *AnalyticsClient) trackSync(userID id.UserID, event string, properties map[string]interface{}) error { var buf bytes.Buffer var analyticsUserID string if Analytics.userID != "" { analyticsUserID = Analytics.userID } else { analyticsUserID = userID.String() } err := json.NewEncoder(&buf).Encode(map[string]interface{}{ "userId": analyticsUserID, "event": event, "properties": properties, }) if err != nil { return err } req, err := http.NewRequest(http.MethodPost, sc.url, &buf) if err != nil { return err } req.SetBasicAuth(sc.key, "") resp, err := sc.client.Do(req) if err != nil { return err } _ = resp.Body.Close() if resp.StatusCode != 200 { return fmt.Errorf("unexpected status code %d", resp.StatusCode) } return nil } func (sc *AnalyticsClient) IsEnabled() bool { return len(sc.key) > 0 } func (sc *AnalyticsClient) Track(userID id.UserID, event string, properties ...map[string]interface{}) { if !sc.IsEnabled() { return } else if len(properties) > 1 { panic("Track should be called with at most one property map") } go func() { props := map[string]interface{}{} if len(properties) > 0 { props = properties[0] } props["bridge"] = "whatsapp" err := sc.trackSync(userID, event, props) if err != nil { sc.log.Err(err).Str("event", event).Msg("Error tracking event") } else { sc.log.Debug().Str("event", event).Msg("Tracked event") } }() }