2023-03-12 15:00:57 +00:00
|
|
|
// GoToSocial
|
|
|
|
// Copyright (C) GoToSocial Authors admin@gotosocial.org
|
|
|
|
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
|
|
//
|
|
|
|
// 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 <http://www.gnu.org/licenses/>.
|
2021-08-25 14:34:33 +01:00
|
|
|
|
2021-06-27 15:52:18 +01:00
|
|
|
package transport
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
2022-04-18 16:17:05 +01:00
|
|
|
"fmt"
|
2022-05-15 10:16:43 +01:00
|
|
|
"net/http"
|
2021-06-27 15:52:18 +01:00
|
|
|
"net/url"
|
2022-04-18 16:17:05 +01:00
|
|
|
"sync"
|
2021-12-20 17:42:19 +00:00
|
|
|
|
2023-02-18 16:02:19 +00:00
|
|
|
"codeberg.org/gruf/go-byteutil"
|
2023-01-02 12:10:50 +00:00
|
|
|
apiutil "github.com/superseriousbusiness/gotosocial/internal/api/util"
|
2022-03-15 14:01:19 +00:00
|
|
|
"github.com/superseriousbusiness/gotosocial/internal/config"
|
2023-03-06 09:38:43 +00:00
|
|
|
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
|
2021-06-27 15:52:18 +01:00
|
|
|
)
|
|
|
|
|
2021-08-25 14:34:33 +01:00
|
|
|
func (t *transport) BatchDeliver(ctx context.Context, b []byte, recipients []*url.URL) error {
|
2023-04-28 16:45:21 +01:00
|
|
|
var (
|
|
|
|
// errs accumulates errors received during
|
|
|
|
// attempted delivery by deliverer routines.
|
|
|
|
errs gtserror.MultiError
|
|
|
|
|
|
|
|
// wait blocks until all sender
|
|
|
|
// routines have returned.
|
|
|
|
wait sync.WaitGroup
|
|
|
|
|
|
|
|
// mutex protects 'recipients' and
|
|
|
|
// 'errs' for concurrent access.
|
|
|
|
mutex sync.Mutex
|
|
|
|
|
|
|
|
// Get current instance host info.
|
|
|
|
domain = config.GetAccountDomain()
|
|
|
|
host = config.GetHost()
|
|
|
|
)
|
|
|
|
|
|
|
|
// Block on expect no. senders.
|
|
|
|
wait.Add(t.controller.senders)
|
|
|
|
|
|
|
|
for i := 0; i < t.controller.senders; i++ {
|
|
|
|
go func() {
|
|
|
|
// Mark returned.
|
|
|
|
defer wait.Done()
|
|
|
|
|
|
|
|
for {
|
|
|
|
// Acquire lock.
|
|
|
|
mutex.Lock()
|
|
|
|
|
|
|
|
if len(recipients) == 0 {
|
|
|
|
// Reached end.
|
|
|
|
mutex.Unlock()
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// Pop next recipient.
|
|
|
|
i := len(recipients) - 1
|
|
|
|
to := recipients[i]
|
|
|
|
recipients = recipients[:i]
|
|
|
|
|
|
|
|
// Done with lock.
|
|
|
|
mutex.Unlock()
|
|
|
|
|
|
|
|
// Skip delivery to recipient if it is "us".
|
|
|
|
if to.Host == host || to.Host == domain {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
// Attempt to deliver data to recipient.
|
|
|
|
if err := t.deliver(ctx, b, to); err != nil {
|
|
|
|
mutex.Lock() // safely append err to accumulator.
|
|
|
|
errs.Appendf("error delivering to %s: %v", to, err)
|
|
|
|
mutex.Unlock()
|
|
|
|
}
|
2022-04-18 16:17:05 +01:00
|
|
|
}
|
2023-04-28 16:45:21 +01:00
|
|
|
}()
|
2022-04-18 16:17:05 +01:00
|
|
|
}
|
|
|
|
|
2023-04-28 16:45:21 +01:00
|
|
|
// Wait for finish.
|
|
|
|
wait.Wait()
|
2022-04-18 16:17:05 +01:00
|
|
|
|
2023-04-28 16:45:21 +01:00
|
|
|
// Return combined err.
|
|
|
|
return errs.Combine()
|
2021-06-27 15:52:18 +01:00
|
|
|
}
|
|
|
|
|
2021-08-25 14:34:33 +01:00
|
|
|
func (t *transport) Deliver(ctx context.Context, b []byte, to *url.URL) error {
|
2023-04-28 16:45:21 +01:00
|
|
|
// if 'to' host is our own, skip as we don't need to deliver to ourselves...
|
2022-05-30 13:41:24 +01:00
|
|
|
if to.Host == config.GetHost() || to.Host == config.GetAccountDomain() {
|
2022-03-15 14:01:19 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2023-04-28 16:45:21 +01:00
|
|
|
// Deliver data to recipient.
|
|
|
|
return t.deliver(ctx, b, to)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (t *transport) deliver(ctx context.Context, b []byte, to *url.URL) error {
|
|
|
|
url := to.String()
|
2022-05-15 10:16:43 +01:00
|
|
|
|
2023-02-18 16:02:19 +00:00
|
|
|
// Use rewindable bytes reader for body.
|
|
|
|
var body byteutil.ReadNopCloser
|
|
|
|
body.Reset(b)
|
|
|
|
|
2023-04-28 16:45:21 +01:00
|
|
|
req, err := http.NewRequestWithContext(ctx, "POST", url, &body)
|
2022-05-15 10:16:43 +01:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2023-01-02 12:10:50 +00:00
|
|
|
req.Header.Add("Content-Type", string(apiutil.AppActivityLDJSON))
|
2022-05-15 10:16:43 +01:00
|
|
|
req.Header.Add("Accept-Charset", "utf-8")
|
|
|
|
req.Header.Set("Host", to.Host)
|
|
|
|
|
2023-04-28 16:45:21 +01:00
|
|
|
rsp, err := t.POST(req, b)
|
2022-05-15 10:16:43 +01:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2023-04-28 16:45:21 +01:00
|
|
|
defer rsp.Body.Close()
|
2022-05-15 10:16:43 +01:00
|
|
|
|
2023-04-28 16:45:21 +01:00
|
|
|
if code := rsp.StatusCode; code != http.StatusOK &&
|
2022-05-15 10:16:43 +01:00
|
|
|
code != http.StatusCreated && code != http.StatusAccepted {
|
2023-04-28 16:45:21 +01:00
|
|
|
err := fmt.Errorf("POST request to %s failed: %s", url, rsp.Status)
|
|
|
|
return gtserror.WithStatusCode(err, rsp.StatusCode)
|
2022-05-15 10:16:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
2021-06-27 15:52:18 +01:00
|
|
|
}
|