commit 1ac8367a507578902091de0c5808ab2db607e042 Author: ptrcnull Date: Thu Mar 25 13:03:08 2021 +0100 feat: Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d9f3900 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +uber-tracker diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..41e80b4 --- /dev/null +++ b/go.mod @@ -0,0 +1,5 @@ +module uber-tracker + +go 1.15 + +require git.ddd.rip/ptrcnull/telegram v0.0.4 diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..041b70f --- /dev/null +++ b/go.sum @@ -0,0 +1,2 @@ +git.ddd.rip/ptrcnull/telegram v0.0.4 h1:b4VaLAdIUuEFG5DRM+JzfLEVoe4tdHhrgxtmoF2UJOQ= +git.ddd.rip/ptrcnull/telegram v0.0.4/go.mod h1:SSSKvfhw7mDx/8UPoLdtP9J74z2/pXccHnKzdi16nLA= diff --git a/main.go b/main.go new file mode 100644 index 0000000..67068b6 --- /dev/null +++ b/main.go @@ -0,0 +1,145 @@ +package main + +import ( + "bytes" + "encoding/json" + "fmt" + "git.ddd.rip/ptrcnull/telegram" + "io/ioutil" + "log" + "net/http" + "os" + "strconv" + "strings" + "time" +) + +func GetUberData(uuid string) (*UberDataOrder, error) { + requestBody := []byte(fmt.Sprintf("{\"orderUuid\":\"%s\"}", uuid)) + req, err := http.NewRequest("POST", "https://www.ubereats.com/api/getActiveOrdersV1", bytes.NewBuffer(requestBody)) + if err != nil { + return nil, err + } + req.Header.Set("Content-Type", "application/json") + req.Header.Set("x-csrf-token", "x") + + res, err := http.DefaultClient.Do(req) + if err != nil { + return nil, err + } + + if res.StatusCode != 200 { + body, err := ioutil.ReadAll(res.Body) + log.Println(string(body), err) + return nil, fmt.Errorf("unexpected status code: %d", res.StatusCode) + } + + var data UberResponse + err = json.NewDecoder(res.Body).Decode(&data) + if err != nil { + return nil, err + } + + for _, order := range data.Data.Orders { + if order.UUID == uuid { + return &order, nil + } + } + + return nil, fmt.Errorf("order not found: %s", uuid) +} + +type Order struct { + ChatID string + UberData *UberDataOrder + MessageID string +} + +func main() { + c := telegram.Client{ + Token: os.Getenv("TELEGRAM_TOKEN"), + } + sendMessage := func(chatId, body string) *telegram.SendMessageResponse { + res, err := c.SendMessage(chatId, body) + if err != nil { + log.Println("error sending message:", err) + return nil + } + return res + } + var orders []*Order + go func() { + for { + time.Sleep(1 * time.Second) + for i, order := range orders { + log.Println("Getting data for order", order.UberData.UUID) + newData, err := GetUberData(order.UberData.UUID) + if err != nil { + log.Println(err) + sendMessage(order.ChatID, "order completed: "+order.UberData.UUID) + orders = append(orders[:i], orders[i+1:]...) + continue + } + oldStatus := order.UberData.Status() + newStatus := newData.Status() + if oldStatus != newStatus { + _, err := c.EditMessageText(order.ChatID, order.MessageID, newStatus) + if err != nil { + log.Println(err) + } + } + order.UberData = newData + } + } + }() + for { + time.Sleep(5 * time.Second) + + log.Println("Getting updates...") + upd, err := c.GetUpdates() + if err != nil { + log.Println(err) + continue + } + + log.Println("updates:", len(upd.Result)) + for _, update := range upd.Result { + if update.Message != nil && strings.HasPrefix(update.Message.Text, "/add") { + chatId := strconv.FormatInt(update.Message.Chat.ID, 10) + + orderId := strings.Split(update.Message.Text, " ")[1] + data, err := GetUberData(orderId) + if err != nil { + log.Println(err) + sendMessage(chatId, "error: "+err.Error()) + continue + } + log.Printf("%#v\n", data) + sendMessage(chatId, "added new order: "+data.OrderInfo.StoreInfo.Name) + status := data.Status() + res := sendMessage(chatId, status) + if res != nil { + orders = append(orders, &Order{ + ChatID: chatId, + UberData: data, + MessageID: strconv.FormatInt(res.Result.MessageID, 10), + }) + } + } + if update.Message != nil && strings.HasPrefix(update.Message.Text, "/contact") { + chatId := strconv.FormatInt(update.Message.Chat.ID, 10) + + orderId := strings.Split(update.Message.Text, " ")[1] + data, err := GetUberData(orderId) + if err != nil { + log.Println(err) + sendMessage(chatId, "error: "+err.Error()) + continue + } + for _, contact := range data.Contacts { + sendMessage(chatId, contact.Title + ": " + contact.FormattedPhoneNumber) + } + } + } + } +} diff --git a/types.go b/types.go new file mode 100644 index 0000000..9b800a2 --- /dev/null +++ b/types.go @@ -0,0 +1,154 @@ +package main + +type UberResponse struct { + Status string `json:"status"` + Data UberData `json:"data"` +} + +type UberData struct { + Orders []UberDataOrder `json:"orders"` +} + +type Contact struct { + Type string `json:"type"` + Title string `json:"title"` + PhoneNumber string `json:"phoneNumber"` + FormattedPhoneNumber string `json:"formattedPhoneNumber"` +} + +type ActiveOrderOverview struct { + Title string `json:"title"` + Subtitle string `json:"subtitle"` + BackgroundImageURL string `json:"backgroundImageUrl"` + Items []struct { + ShoppingCartItemUUID string `json:"shoppingCartItemUUID"` + Title string `json:"title"` + Quantity int `json:"quantity"` + Subtitle string `json:"subtitle"` + } `json:"items"` + Actions interface{} `json:"actions"` +} + +type InAppNotification struct { + Title string `json:"title"` + Subtitle string `json:"subtitle"` +} + +type FeedCardStatus struct { + Title string `json:"title"` + Subtitle string `json:"subtitle"` + TimelineSummary string `json:"timelineSummary"` + StatusSummary struct { + Text string `json:"text"` + InfoText string `json:"infoText"` + InfoBody string `json:"infoBody"` + } `json:"statusSummary"` + CurrentProgress int `json:"currentProgress"` + TotalProgressSegments int `json:"totalProgressSegments"` + AnimateCurrentProgressSegment bool `json:"animateCurrentProgressSegment"` + Actions interface{} `json:"actions"` +} + +type FeedCard struct { + Status FeedCardStatus `json:"status,omitempty"` + MapEntity interface{} `json:"mapEntity"` + Courier interface{} `json:"courier"` + Type string `json:"type"` + Savings struct { + Title string `json:"title"` + IconImageURL string `json:"iconImageUrl"` + } `json:"savings,omitempty"` + Delivery struct { + FormattedAddress string `json:"formattedAddress"` + DeliveryTypeDescription string `json:"deliveryTypeDescription"` + SpecialInstructions string `json:"specialInstructions"` + Title string `json:"title"` + Paragraphs []struct { + Title string `json:"title"` + Subtitle string `json:"subtitle,omitempty"` + } `json:"paragraphs"` + } `json:"delivery,omitempty"` + OrderSummary struct { + RestaurantName string `json:"restaurantName"` + Items []struct { + ShoppingCartItemUUID string `json:"shoppingCartItemUUID"` + Title string `json:"title"` + Quantity int `json:"quantity"` + Subtitle string `json:"subtitle"` + } `json:"items"` + Total string `json:"total"` + Sections []interface{} `json:"sections"` + TotalLabel string `json:"totalLabel"` + } `json:"orderSummary,omitempty"` +} + +type BackgroundFeedCard struct { + MapEntity []struct { + UUID string `json:"uuid"` + Type string `json:"type"` + Latitude float64 `json:"latitude"` + Longitude float64 `json:"longitude"` + Course float64 `json:"course,omitempty"` + Subtitle interface{} `json:"subtitle"` + PathPoints []struct { + Epoch int64 `json:"epoch"` + Latitude float64 `json:"latitude"` + Longitude float64 `json:"longitude"` + Course float64 `json:"course"` + } `json:"pathPoints"` + IconURL string `json:"iconUrl,omitempty"` + SpriteCount int `json:"spriteCount,omitempty"` + SpriteSize int `json:"spriteSize,omitempty"` + Title string `json:"title,omitempty"` + } `json:"mapEntity"` + Courier interface{} `json:"courier"` + Type string `json:"type"` +} + +type UberDataOrder struct { + UUID string `json:"uuid"` + Contacts []Contact `json:"contacts"` + Actions interface{} `json:"actions"` + BottomSheets interface{} `json:"bottomSheets"` + OrderInfo OrderInfo `json:"orderInfo"` + ActiveOrderOverview ActiveOrderOverview `json:"activeOrderOverview"` + InAppNotification InAppNotification `json:"inAppNotification"` + FeedCards []FeedCard `json:"feedCards"` + BackgroundFeedCards []BackgroundFeedCard `json:"backgroundFeedCards"` + Layout string `json:"layout"` +} + +func (o *UberDataOrder) Status() string { + for _, feedCard := range o.FeedCards { + if feedCard.Type == "status" { + c := feedCard.Status + return c.Subtitle + " " + c.Title + "\n" + c.TimelineSummary + } + } + return "" +} + +type OrderInfo struct { + OrderPhase string `json:"orderPhase"` + StoreInfo struct { + StoreUUID string `json:"storeUUID"` + TerritoryUUID string `json:"territoryUUID"` + Location struct { + Address struct { + Address1 string `json:"address1"` + City string `json:"city"` + Country string `json:"country"` + PostalCode string `json:"postalCode"` + Region string `json:"region"` + UUID string `json:"uuid"` + } `json:"address"` + Latitude float64 `json:"latitude"` + Longitude float64 `json:"longitude"` + } `json:"location"` + WebURL string `json:"webURL"` + HeroImageURL string `json:"heroImageURL"` + Name string `json:"name"` + } `json:"storeInfo"` + OrderCategory string `json:"orderCategory"` + CustomerInfos interface{} `json:"customerInfos"` +}