feat: Initial commit

This commit is contained in:
ptrcnull 2021-03-25 13:03:08 +01:00
commit 1ac8367a50
5 changed files with 307 additions and 0 deletions

1
.gitignore vendored Normal file
View file

@ -0,0 +1 @@
uber-tracker

5
go.mod Normal file
View file

@ -0,0 +1,5 @@
module uber-tracker
go 1.15
require git.ddd.rip/ptrcnull/telegram v0.0.4

2
go.sum Normal file
View file

@ -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=

145
main.go Normal file
View file

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

154
types.go Normal file
View file

@ -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"`
}