package fcm /* const ( // Batch Send API BatchSendEndpoint = "https://fcm.googleapis.com/batch" // Requests to the endpoint will start failing after 6/21/2024. // Migrate to the standard HTTP v1 API send method, which supports HTTP/2 for multiplexing. ) type ClientConfig struct { SendEndpoint string //BatchSendEndpoint string } // Deprecated: Use SendEach instead. func (c *Client) SendMessages(messages []Message) (MultiSendResponse, error) { return c.doSendMessages(messages, false) } func (c *Client) ValidateMessages(messages []Message) (MultiSendResponse, error) { return c.doSendMessages(messages, true) } func (c *Client) doSendMessages(messages []Message, validateOnly bool) (MultiSendResponse, error) { messageCount := len(messages) if messageCount == 0 { return MultiSendResponse{}, nil } if messageCount > maxMessages { return MultiSendResponse{}, errors.New(fmt.Sprintf("messages limit (%d) exceeded: %d", maxMessages, messageCount)) } accessToken, err := c.ts.Token() if err != nil { return MultiSendResponse{}, err } var body bytes.Buffer w := multipart.NewWriter(&body) w.SetBoundary(multipartBoundary) for index, msg := range messages { req := SendRequest{ ValidateOnly: validateOnly, Message: msg, } body, err := c.makeMessageRequest(req) if err != nil { return MultiSendResponse{}, err } if err := writePartTo(w, body, index); err != nil { return MultiSendResponse{}, err } } if err := w.Close(); err != nil { return MultiSendResponse{}, errors.WithStack(err) } request, err := http.NewRequest(http.MethodPost, c.cfg.BatchSendEndpoint, &body) if err != nil { return MultiSendResponse{}, errors.WithStack(err) } accessToken.SetAuthHeader(request) request.Header.Set("Content-Type", fmt.Sprintf(`multipart/mixed; boundary="%s"`, multipartBoundary)) response, err := c.hc.Do(request) if err != nil { return MultiSendResponse{}, errors.WithStack(err) } defer response.Body.Close() return c.makeMultiSendResponse(response, messageCount) } func (c *Client) makeMessageRequest(req SendRequest) ([]byte, error) { reqJson, err := json.Marshal(req) if err != nil { return nil, errors.WithStack(err) } request, err := http.NewRequest(http.MethodPost, c.cfg.SendEndpoint, bytes.NewBuffer(reqJson)) if err != nil { return nil, errors.WithStack(err) } request.Header.Set("Content-Type", "application/json; charset=UTF-8") request.Header.Set("User-Agent", "") var body bytes.Buffer if err := request.Write(&body); err != nil { return nil, errors.WithStack(err) } return body.Bytes(), nil } func writePartTo(w *multipart.Writer, bytes []byte, index int) error { header := make(textproto.MIMEHeader) header.Set("Content-Type", "application/http") header.Set("Content-Transfer-Encoding", "binary") header.Set("Content-ID", fmt.Sprintf("%d", index+1)) part, err := w.CreatePart(header) if err != nil { return errors.WithStack(err) } if _, err := part.Write(bytes); err != nil { return errors.WithStack(err) } return nil } func (c *Client) makeMultiSendResponse(response *http.Response, totalCount int) (MultiSendResponse, error) { responses := make([]SendResponse, 0, totalCount) var fails int _, params, err := mime.ParseMediaType(response.Header.Get("Content-Type")) if err != nil { return MultiSendResponse{}, errors.WithStack(err) } reader := multipart.NewReader(response.Body, params["boundary"]) for { part, err := reader.NextPart() if err == io.EOF { break } else if err != nil { return MultiSendResponse{}, errors.WithStack(err) } resp, err := makeSendResponseFromPart(part) if err != nil { return MultiSendResponse{}, err } responses = append(responses, resp) if resp.HasError() { c.logger.Info("fail", "error", fmt.Sprintf("%+v", *resp.Error)) fails++ } } return MultiSendResponse{ Responses: responses, Sent: totalCount - fails, Failed: fails, }, nil } func makeSendResponseFromPart(part *multipart.Part) (SendResponse, error) { response, err := http.ReadResponse(bufio.NewReader(part), nil) if err != nil { return SendResponse{}, errors.WithStack(err) } defer response.Body.Close() body, err := ioutil.ReadAll(response.Body) if err != nil { return SendResponse{}, errors.WithStack(err) } var resp SendResponse if err := json.Unmarshal(body, &resp); err != nil { return SendResponse{}, errors.WithMessagef(err, "response body: %s", body) } return resp, nil } */