(ctx context.Context, before int64)
| 102 | } |
| 103 | |
| 104 | func (c *ChannelClient) FetchMessages(ctx context.Context, before int64) ([]Message, error) { |
| 105 | messages := []Message{} |
| 106 | url := fmt.Sprintf(URLPattern, c.channel) |
| 107 | |
| 108 | if before != 0 { |
| 109 | url = fmt.Sprintf("%s?before=%d", url, before) |
| 110 | } |
| 111 | |
| 112 | req, err := http.NewRequestWithContext(ctx, "POST", url, nil) |
| 113 | if err != nil { |
| 114 | return nil, fmt.Errorf("telegram: create request: %w", err) |
| 115 | } |
| 116 | |
| 117 | req.Header.Add("X-Requested-With", "XMLHttpRequest") |
| 118 | |
| 119 | log.Tracef("POST %s", req.URL) |
| 120 | |
| 121 | attempts := 5 |
| 122 | |
| 123 | var root *html.Node |
| 124 | |
| 125 | for { |
| 126 | if root, err = c.fetchAndParse(req); err == nil { |
| 127 | break |
| 128 | } |
| 129 | |
| 130 | if errors.Is(err, context.Canceled) { |
| 131 | return nil, err |
| 132 | } |
| 133 | |
| 134 | log.Warnf("%v, will retry after 10s", err) |
| 135 | <-time.After(time.Second * 10) |
| 136 | |
| 137 | attempts-- |
| 138 | if attempts == 0 { |
| 139 | return nil, err |
| 140 | } |
| 141 | } |
| 142 | |
| 143 | nodes := MessagesSel.MatchAll(root) |
| 144 | for _, node := range nodes { |
| 145 | authorNode := AuthorSel.MatchFirst(node) |
| 146 | textNode := TextSel.MatchFirst(node) |
| 147 | dateNode := DateSel.MatchFirst(node) |
| 148 | dateTimeNode := getAttr(dateNode, "datetime") |
| 149 | dataPost := getAttr(node, "data-post") |
| 150 | parts := strings.Split(dataPost, "/") |
| 151 | |
| 152 | id, err := strconv.ParseInt(parts[len(parts)-1], 10, 64) |
| 153 | if err != nil { |
| 154 | return nil, fmt.Errorf("telegram: parse message ID: %w", err) |
| 155 | } |
| 156 | |
| 157 | datetime, err := time.Parse(time.RFC3339, dateTimeNode) |
| 158 | if err != nil { |
| 159 | return nil, fmt.Errorf("telegram: parse message time: %w", err) |
| 160 | } |
| 161 | // Note: datetime is in UTC without timezone here |
no test coverage detected