[feature] Add a request ID and include it in logs (#1476)
This adds a lightweight form of tracing to GTS. Each incoming request is assigned a Request ID which we then pass on and log in all our log lines. Any function that gets called downstream from an HTTP handler should now emit a requestID=value pair whenever it logs something. Co-authored-by: kim <grufwub@gmail.com>
This commit is contained in:
parent
b5993095fa
commit
68e6d08c76
|
@ -14,7 +14,6 @@ run:
|
||||||
linters:
|
linters:
|
||||||
# enable some extra linters, see here for the list: https://golangci-lint.run/usage/linters/
|
# enable some extra linters, see here for the list: https://golangci-lint.run/usage/linters/
|
||||||
enable:
|
enable:
|
||||||
- contextcheck
|
|
||||||
- forcetypeassert
|
- forcetypeassert
|
||||||
- goconst
|
- goconst
|
||||||
- gocritic
|
- gocritic
|
||||||
|
@ -27,3 +26,8 @@ linters-settings:
|
||||||
govet:
|
govet:
|
||||||
disable:
|
disable:
|
||||||
- composites
|
- composites
|
||||||
|
staticcheck:
|
||||||
|
# Enable all checks
|
||||||
|
# Disable:
|
||||||
|
# - SA1012: nil context passing
|
||||||
|
checks: ["all", "-SA1012"]
|
||||||
|
|
|
@ -42,9 +42,9 @@ var Orphaned action.GTSAction = func(ctx context.Context) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
if dry /* dick heyyoooooo */ {
|
if dry /* dick heyyoooooo */ {
|
||||||
log.Infof("DRY RUN: %d items are orphaned and eligible to be pruned", pruned)
|
log.Infof(ctx, "DRY RUN: %d items are orphaned and eligible to be pruned", pruned)
|
||||||
} else {
|
} else {
|
||||||
log.Infof("%d orphaned items were pruned", pruned)
|
log.Infof(ctx, "%d orphaned items were pruned", pruned)
|
||||||
}
|
}
|
||||||
|
|
||||||
return prune.shutdown(ctx)
|
return prune.shutdown(ctx)
|
||||||
|
|
|
@ -49,9 +49,9 @@ var Remote action.GTSAction = func(ctx context.Context) error {
|
||||||
total := pruned + uncached
|
total := pruned + uncached
|
||||||
|
|
||||||
if dry /* dick heyyoooooo */ {
|
if dry /* dick heyyoooooo */ {
|
||||||
log.Infof("DRY RUN: %d remote items are unused/stale and eligible to be pruned", total)
|
log.Infof(ctx, "DRY RUN: %d remote items are unused/stale and eligible to be pruned", total)
|
||||||
} else {
|
} else {
|
||||||
log.Infof("%d unused/stale remote items were pruned", pruned)
|
log.Infof(ctx, "%d unused/stale remote items were pruned", pruned)
|
||||||
}
|
}
|
||||||
|
|
||||||
return prune.shutdown(ctx)
|
return prune.shutdown(ctx)
|
||||||
|
|
|
@ -62,7 +62,7 @@ import (
|
||||||
|
|
||||||
// Start creates and starts a gotosocial server
|
// Start creates and starts a gotosocial server
|
||||||
var Start action.GTSAction = func(ctx context.Context) error {
|
var Start action.GTSAction = func(ctx context.Context) error {
|
||||||
_, err := maxprocs.Set(maxprocs.Logger(log.Debugf))
|
_, err := maxprocs.Set(nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to set CPU limits from cgroup: %s", err)
|
return fmt.Errorf("failed to set CPU limits from cgroup: %s", err)
|
||||||
}
|
}
|
||||||
|
@ -156,6 +156,9 @@ var Start action.GTSAction = func(ctx context.Context) error {
|
||||||
|
|
||||||
// attach global middlewares which are used for every request
|
// attach global middlewares which are used for every request
|
||||||
router.AttachGlobalMiddleware(
|
router.AttachGlobalMiddleware(
|
||||||
|
middleware.AddRequestID(config.GetRequestIDHeader()),
|
||||||
|
// note: hooks adding ctx fields must be ABOVE
|
||||||
|
// the logger, otherwise won't be accessible.
|
||||||
middleware.Logger(),
|
middleware.Logger(),
|
||||||
middleware.UserAgent(),
|
middleware.UserAgent(),
|
||||||
middleware.CORS(),
|
middleware.CORS(),
|
||||||
|
@ -237,13 +240,13 @@ var Start action.GTSAction = func(ctx context.Context) error {
|
||||||
sigs := make(chan os.Signal, 1)
|
sigs := make(chan os.Signal, 1)
|
||||||
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
|
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
|
||||||
sig := <-sigs // block until signal received
|
sig := <-sigs // block until signal received
|
||||||
log.Infof("received signal %s, shutting down", sig)
|
log.Infof(ctx, "received signal %s, shutting down", sig)
|
||||||
|
|
||||||
// close down all running services in order
|
// close down all running services in order
|
||||||
if err := gts.Stop(ctx); err != nil {
|
if err := gts.Stop(ctx); err != nil {
|
||||||
return fmt.Errorf("error closing gotosocial service: %s", err)
|
return fmt.Errorf("error closing gotosocial service: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Info("done! exiting...")
|
log.Info(ctx, "done! exiting...")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -155,7 +155,7 @@ var Start action.GTSAction = func(ctx context.Context) error {
|
||||||
sigs := make(chan os.Signal, 1)
|
sigs := make(chan os.Signal, 1)
|
||||||
signal.Notify(sigs, os.Interrupt, syscall.SIGTERM)
|
signal.Notify(sigs, os.Interrupt, syscall.SIGTERM)
|
||||||
sig := <-sigs
|
sig := <-sigs
|
||||||
log.Infof("received signal %s, shutting down", sig)
|
log.Infof(ctx, "received signal %s, shutting down", sig)
|
||||||
|
|
||||||
testrig.StandardDBTeardown(dbService)
|
testrig.StandardDBTeardown(dbService)
|
||||||
testrig.StandardStorageTeardown(storageBackend)
|
testrig.StandardStorageTeardown(storageBackend)
|
||||||
|
@ -165,6 +165,6 @@ var Start action.GTSAction = func(ctx context.Context) error {
|
||||||
return fmt.Errorf("error closing gotosocial service: %s", err)
|
return fmt.Errorf("error closing gotosocial service: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Info("done! exiting...")
|
log.Info(ctx, "done! exiting...")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
# Observability
|
||||||
|
|
||||||
|
These settings let you tune and configure certain observability related behaviours.
|
||||||
|
|
||||||
|
## Settings
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
##################################
|
||||||
|
##### OBSERVABILITY SETTINGS #####
|
||||||
|
##################################
|
||||||
|
|
||||||
|
# String. Header name to use to extract a request or trace ID from. Typically set by a
|
||||||
|
# loadbalancer or proxy.
|
||||||
|
# Default: "X-Request-Id"
|
||||||
|
request-id-header: "X-Request-Id"
|
||||||
|
```
|
|
@ -692,6 +692,15 @@ syslog-protocol: "udp"
|
||||||
# Default: "localhost:514"
|
# Default: "localhost:514"
|
||||||
syslog-address: "localhost:514"
|
syslog-address: "localhost:514"
|
||||||
|
|
||||||
|
##################################
|
||||||
|
##### OBSERVABILITY SETTINGS #####
|
||||||
|
##################################
|
||||||
|
|
||||||
|
# String. Header name to use to extract a request or trace ID from. Typically set by a
|
||||||
|
# loadbalancer or proxy.
|
||||||
|
# Default: "X-Request-Id"
|
||||||
|
request-id-header: "X-Request-Id"
|
||||||
|
|
||||||
#############################
|
#############################
|
||||||
##### ADVANCED SETTINGS #####
|
##### ADVANCED SETTINGS #####
|
||||||
#############################
|
#############################
|
||||||
|
|
|
@ -100,7 +100,7 @@ func (suite *MediaCreateTestSuite) SetupSuite() {
|
||||||
|
|
||||||
func (suite *MediaCreateTestSuite) TearDownSuite() {
|
func (suite *MediaCreateTestSuite) TearDownSuite() {
|
||||||
if err := suite.db.Stop(context.Background()); err != nil {
|
if err := suite.db.Stop(context.Background()); err != nil {
|
||||||
log.Panicf("error closing db connection: %s", err)
|
log.Panicf(nil, "error closing db connection: %s", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -98,7 +98,7 @@ func (suite *MediaUpdateTestSuite) SetupSuite() {
|
||||||
|
|
||||||
func (suite *MediaUpdateTestSuite) TearDownSuite() {
|
func (suite *MediaUpdateTestSuite) TearDownSuite() {
|
||||||
if err := suite.db.Stop(context.Background()); err != nil {
|
if err := suite.db.Stop(context.Background()); err != nil {
|
||||||
log.Panicf("error closing db connection: %s", err)
|
log.Panicf(nil, "error closing db connection: %s", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -166,11 +166,12 @@ func (m *Module) StreamGETHandler(c *gin.Context) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
l := log.WithFields(kv.Fields{
|
l := log.WithContext(c.Request.Context()).
|
||||||
{"account", account.Username},
|
WithFields(kv.Fields{
|
||||||
{"streamID", stream.ID},
|
{"account", account.Username},
|
||||||
{"streamType", streamType},
|
{"streamID", stream.ID},
|
||||||
}...)
|
{"streamType", streamType},
|
||||||
|
}...)
|
||||||
|
|
||||||
// Upgrade the incoming HTTP request, which hijacks the underlying
|
// Upgrade the incoming HTTP request, which hijacks the underlying
|
||||||
// connection and reuses it for the websocket (non-http) protocol.
|
// connection and reuses it for the websocket (non-http) protocol.
|
||||||
|
|
|
@ -99,7 +99,7 @@ func (suite *FileserverTestSuite) SetupTest() {
|
||||||
|
|
||||||
func (suite *FileserverTestSuite) TearDownSuite() {
|
func (suite *FileserverTestSuite) TearDownSuite() {
|
||||||
if err := suite.db.Stop(context.Background()); err != nil {
|
if err := suite.db.Stop(context.Background()); err != nil {
|
||||||
log.Panicf("error closing db connection: %s", err)
|
log.Panicf(nil, "error closing db connection: %s", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -77,7 +77,10 @@ func (m *Module) ServeFile(c *gin.Context) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
content, errWithCode := m.processor.FileGet(c.Request.Context(), authed, &apimodel.GetContentRequestForm{
|
// Acquire context from gin request.
|
||||||
|
ctx := c.Request.Context()
|
||||||
|
|
||||||
|
content, errWithCode := m.processor.FileGet(ctx, authed, &apimodel.GetContentRequestForm{
|
||||||
AccountID: accountID,
|
AccountID: accountID,
|
||||||
MediaType: mediaType,
|
MediaType: mediaType,
|
||||||
MediaSize: mediaSize,
|
MediaSize: mediaSize,
|
||||||
|
@ -101,7 +104,7 @@ func (m *Module) ServeFile(c *gin.Context) {
|
||||||
defer func() {
|
defer func() {
|
||||||
// Close content when we're done, catch errors.
|
// Close content when we're done, catch errors.
|
||||||
if err := content.Content.Close(); err != nil {
|
if err := content.Content.Close(); err != nil {
|
||||||
log.Errorf("ServeFile: error closing readcloser: %s", err)
|
log.Errorf(ctx, "ServeFile: error closing readcloser: %s", err)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
@ -130,15 +133,21 @@ func (m *Module) ServeFile(c *gin.Context) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set known content-type and serve this file range.
|
// Set known content-type and serve range.
|
||||||
c.Header("Content-Type", format)
|
c.Header("Content-Type", format)
|
||||||
serveFileRange(c.Writer, content.Content, rng, content.ContentLength)
|
serveFileRange(
|
||||||
|
c.Writer,
|
||||||
|
c.Request,
|
||||||
|
content.Content,
|
||||||
|
rng,
|
||||||
|
content.ContentLength,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// serveFileRange serves the range of a file from a given source reader, without the
|
// serveFileRange serves the range of a file from a given source reader, without the
|
||||||
// need for implementation of io.Seeker. Instead we read the first 'start' many bytes
|
// need for implementation of io.Seeker. Instead we read the first 'start' many bytes
|
||||||
// into a discard reader. Code is adapted from https://codeberg.org/gruf/simplehttp.
|
// into a discard reader. Code is adapted from https://codeberg.org/gruf/simplehttp.
|
||||||
func serveFileRange(rw http.ResponseWriter, src io.Reader, rng string, size int64) {
|
func serveFileRange(rw http.ResponseWriter, r *http.Request, src io.Reader, rng string, size int64) {
|
||||||
var i int
|
var i int
|
||||||
|
|
||||||
if i = strings.IndexByte(rng, '='); i < 0 {
|
if i = strings.IndexByte(rng, '='); i < 0 {
|
||||||
|
@ -219,7 +228,7 @@ func serveFileRange(rw http.ResponseWriter, src io.Reader, rng string, size int6
|
||||||
|
|
||||||
// Dump the first 'start' many bytes into the void...
|
// Dump the first 'start' many bytes into the void...
|
||||||
if _, err := fastcopy.CopyN(io.Discard, src, start); err != nil {
|
if _, err := fastcopy.CopyN(io.Discard, src, start); err != nil {
|
||||||
log.Errorf("error reading from source: %v", err)
|
log.Errorf(r.Context(), "error reading from source: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -239,7 +248,7 @@ func serveFileRange(rw http.ResponseWriter, src io.Reader, rng string, size int6
|
||||||
|
|
||||||
// Read the "seeked" source reader into destination writer.
|
// Read the "seeked" source reader into destination writer.
|
||||||
if _, err := fastcopy.Copy(rw, src); err != nil {
|
if _, err := fastcopy.Copy(rw, src); err != nil {
|
||||||
log.Errorf("error reading from source: %v", err)
|
log.Errorf(r.Context(), "error reading from source: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,7 @@ import (
|
||||||
apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model"
|
apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model"
|
||||||
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
|
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
|
||||||
"github.com/superseriousbusiness/gotosocial/internal/log"
|
"github.com/superseriousbusiness/gotosocial/internal/log"
|
||||||
|
"github.com/superseriousbusiness/gotosocial/internal/middleware"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TODO: add more templated html pages here for different error types
|
// TODO: add more templated html pages here for different error types
|
||||||
|
@ -43,16 +44,20 @@ import (
|
||||||
func NotFoundHandler(c *gin.Context, instanceGet func(ctx context.Context) (*apimodel.InstanceV1, gtserror.WithCode), accept string) {
|
func NotFoundHandler(c *gin.Context, instanceGet func(ctx context.Context) (*apimodel.InstanceV1, gtserror.WithCode), accept string) {
|
||||||
switch accept {
|
switch accept {
|
||||||
case string(TextHTML):
|
case string(TextHTML):
|
||||||
instance, err := instanceGet(c.Request.Context())
|
ctx := c.Request.Context()
|
||||||
|
instance, err := instanceGet(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
c.HTML(http.StatusNotFound, "404.tmpl", gin.H{
|
c.HTML(http.StatusNotFound, "404.tmpl", gin.H{
|
||||||
"instance": instance,
|
"instance": instance,
|
||||||
|
"requestID": middleware.RequestID(ctx),
|
||||||
})
|
})
|
||||||
default:
|
default:
|
||||||
c.JSON(http.StatusNotFound, gin.H{"error": http.StatusText(http.StatusNotFound)})
|
c.JSON(http.StatusNotFound, gin.H{
|
||||||
|
"error": http.StatusText(http.StatusNotFound),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,15 +67,17 @@ func NotFoundHandler(c *gin.Context, instanceGet func(ctx context.Context) (*api
|
||||||
func genericErrorHandler(c *gin.Context, instanceGet func(ctx context.Context) (*apimodel.InstanceV1, gtserror.WithCode), accept string, errWithCode gtserror.WithCode) {
|
func genericErrorHandler(c *gin.Context, instanceGet func(ctx context.Context) (*apimodel.InstanceV1, gtserror.WithCode), accept string, errWithCode gtserror.WithCode) {
|
||||||
switch accept {
|
switch accept {
|
||||||
case string(TextHTML):
|
case string(TextHTML):
|
||||||
instance, err := instanceGet(c.Request.Context())
|
ctx := c.Request.Context()
|
||||||
|
instance, err := instanceGet(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
c.HTML(errWithCode.Code(), "error.tmpl", gin.H{
|
c.HTML(errWithCode.Code(), "error.tmpl", gin.H{
|
||||||
"instance": instance,
|
"instance": instance,
|
||||||
"code": errWithCode.Code(),
|
"code": errWithCode.Code(),
|
||||||
"error": errWithCode.Safe(),
|
"error": errWithCode.Safe(),
|
||||||
|
"requestID": middleware.RequestID(ctx),
|
||||||
})
|
})
|
||||||
default:
|
default:
|
||||||
c.JSON(errWithCode.Code(), gin.H{"error": errWithCode.Safe()})
|
c.JSON(errWithCode.Code(), gin.H{"error": errWithCode.Safe()})
|
||||||
|
@ -108,11 +115,12 @@ func ErrorHandler(c *gin.Context, errWithCode gtserror.WithCode, instanceGet fun
|
||||||
// to pass any detailed errors (that might contain sensitive information) into the
|
// to pass any detailed errors (that might contain sensitive information) into the
|
||||||
// errWithCode.Error() field, since the client will see this. Use your noggin!
|
// errWithCode.Error() field, since the client will see this. Use your noggin!
|
||||||
func OAuthErrorHandler(c *gin.Context, errWithCode gtserror.WithCode) {
|
func OAuthErrorHandler(c *gin.Context, errWithCode gtserror.WithCode) {
|
||||||
l := log.WithFields(kv.Fields{
|
l := log.WithContext(c.Request.Context()).
|
||||||
{"path", c.Request.URL.Path},
|
WithFields(kv.Fields{
|
||||||
{"error", errWithCode.Error()},
|
{"path", c.Request.URL.Path},
|
||||||
{"help", errWithCode.Safe()},
|
{"error", errWithCode.Error()},
|
||||||
}...)
|
{"help", errWithCode.Safe()},
|
||||||
|
}...)
|
||||||
|
|
||||||
statusCode := errWithCode.Code()
|
statusCode := errWithCode.Code()
|
||||||
|
|
||||||
|
|
|
@ -35,5 +35,5 @@ func tryUntil(msg string, count int, do func() bool) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
log.Panicf("failed %s after %d tries", msg, count)
|
log.Panicf(nil, "failed %s after %d tries", msg, count)
|
||||||
}
|
}
|
||||||
|
|
|
@ -66,7 +66,7 @@ func NewWorkerPool[MsgType any](workers int, queueRatio int) *WorkerPool[MsgType
|
||||||
}
|
}
|
||||||
|
|
||||||
// Log new worker creation with worker type prefix
|
// Log new worker creation with worker type prefix
|
||||||
log.Infof("%s created with workers=%d queue=%d",
|
log.Infof(nil, "%s created with workers=%d queue=%d",
|
||||||
w.wtype,
|
w.wtype,
|
||||||
workers,
|
workers,
|
||||||
workers*queueRatio,
|
workers*queueRatio,
|
||||||
|
@ -77,7 +77,7 @@ func NewWorkerPool[MsgType any](workers int, queueRatio int) *WorkerPool[MsgType
|
||||||
|
|
||||||
// Start will attempt to start the underlying worker pool, or return error.
|
// Start will attempt to start the underlying worker pool, or return error.
|
||||||
func (w *WorkerPool[MsgType]) Start() error {
|
func (w *WorkerPool[MsgType]) Start() error {
|
||||||
log.Infof("%s starting", w.wtype)
|
log.Infof(nil, "%s starting", w.wtype)
|
||||||
|
|
||||||
// Check processor was set
|
// Check processor was set
|
||||||
if w.process == nil {
|
if w.process == nil {
|
||||||
|
@ -94,7 +94,7 @@ func (w *WorkerPool[MsgType]) Start() error {
|
||||||
|
|
||||||
// Stop will attempt to stop the underlying worker pool, or return error.
|
// Stop will attempt to stop the underlying worker pool, or return error.
|
||||||
func (w *WorkerPool[MsgType]) Stop() error {
|
func (w *WorkerPool[MsgType]) Stop() error {
|
||||||
log.Infof("%s stopping", w.wtype)
|
log.Infof(nil, "%s stopping", w.wtype)
|
||||||
|
|
||||||
// Attempt to stop pool
|
// Attempt to stop pool
|
||||||
if !w.workers.Stop() {
|
if !w.workers.Stop() {
|
||||||
|
@ -107,14 +107,14 @@ func (w *WorkerPool[MsgType]) Stop() error {
|
||||||
// SetProcessor will set the Worker's processor function, which is called for each queued message.
|
// SetProcessor will set the Worker's processor function, which is called for each queued message.
|
||||||
func (w *WorkerPool[MsgType]) SetProcessor(fn func(context.Context, MsgType) error) {
|
func (w *WorkerPool[MsgType]) SetProcessor(fn func(context.Context, MsgType) error) {
|
||||||
if w.process != nil {
|
if w.process != nil {
|
||||||
log.Panicf("%s Worker.process is already set", w.wtype)
|
log.Panicf(nil, "%s Worker.process is already set", w.wtype)
|
||||||
}
|
}
|
||||||
w.process = fn
|
w.process = fn
|
||||||
}
|
}
|
||||||
|
|
||||||
// Queue will queue provided message to be processed with there's a free worker.
|
// Queue will queue provided message to be processed with there's a free worker.
|
||||||
func (w *WorkerPool[MsgType]) Queue(msg MsgType) {
|
func (w *WorkerPool[MsgType]) Queue(msg MsgType) {
|
||||||
log.Tracef("%s queueing message: %+v", w.wtype, msg)
|
log.Tracef(nil, "%s queueing message: %+v", w.wtype, msg)
|
||||||
|
|
||||||
// Create new process function for msg
|
// Create new process function for msg
|
||||||
process := func(ctx context.Context) {
|
process := func(ctx context.Context) {
|
||||||
|
|
|
@ -147,6 +147,8 @@ type Configuration struct {
|
||||||
AdminAccountPassword string `name:"password" usage:"the password to set for this account"`
|
AdminAccountPassword string `name:"password" usage:"the password to set for this account"`
|
||||||
AdminTransPath string `name:"path" usage:"the path of the file to import from/export to"`
|
AdminTransPath string `name:"path" usage:"the path of the file to import from/export to"`
|
||||||
AdminMediaPruneDryRun bool `name:"dry-run" usage:"perform a dry run and only log number of items eligible for pruning"`
|
AdminMediaPruneDryRun bool `name:"dry-run" usage:"perform a dry run and only log number of items eligible for pruning"`
|
||||||
|
|
||||||
|
RequestIDHeader string `name:"request-id-header" usage:"Header to extract the Request ID from. Eg.,'X-Request-Id'"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type CacheConfiguration struct {
|
type CacheConfiguration struct {
|
||||||
|
|
|
@ -163,4 +163,6 @@ var Defaults = Configuration{
|
||||||
},
|
},
|
||||||
|
|
||||||
AdminMediaPruneDryRun: true,
|
AdminMediaPruneDryRun: true,
|
||||||
|
|
||||||
|
RequestIDHeader: "X-Request-Id",
|
||||||
}
|
}
|
||||||
|
|
|
@ -140,6 +140,8 @@ func (s *ConfigState) AddServerFlags(cmd *cobra.Command) {
|
||||||
cmd.Flags().Int(AdvancedRateLimitRequestsFlag(), cfg.AdvancedRateLimitRequests, fieldtag("AdvancedRateLimitRequests", "usage"))
|
cmd.Flags().Int(AdvancedRateLimitRequestsFlag(), cfg.AdvancedRateLimitRequests, fieldtag("AdvancedRateLimitRequests", "usage"))
|
||||||
cmd.Flags().Int(AdvancedThrottlingMultiplierFlag(), cfg.AdvancedThrottlingMultiplier, fieldtag("AdvancedThrottlingMultiplier", "usage"))
|
cmd.Flags().Int(AdvancedThrottlingMultiplierFlag(), cfg.AdvancedThrottlingMultiplier, fieldtag("AdvancedThrottlingMultiplier", "usage"))
|
||||||
cmd.Flags().Duration(AdvancedThrottlingRetryAfterFlag(), cfg.AdvancedThrottlingRetryAfter, fieldtag("AdvancedThrottlingRetryAfter", "usage"))
|
cmd.Flags().Duration(AdvancedThrottlingRetryAfterFlag(), cfg.AdvancedThrottlingRetryAfter, fieldtag("AdvancedThrottlingRetryAfter", "usage"))
|
||||||
|
|
||||||
|
cmd.Flags().String(RequestIDHeaderFlag(), cfg.RequestIDHeader, fieldtag("RequestIDHeader", "usage"))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2977,3 +2977,28 @@ func GetAdminMediaPruneDryRun() bool { return global.GetAdminMediaPruneDryRun()
|
||||||
|
|
||||||
// SetAdminMediaPruneDryRun safely sets the value for global configuration 'AdminMediaPruneDryRun' field
|
// SetAdminMediaPruneDryRun safely sets the value for global configuration 'AdminMediaPruneDryRun' field
|
||||||
func SetAdminMediaPruneDryRun(v bool) { global.SetAdminMediaPruneDryRun(v) }
|
func SetAdminMediaPruneDryRun(v bool) { global.SetAdminMediaPruneDryRun(v) }
|
||||||
|
|
||||||
|
// GetRequestIDHeader safely fetches the Configuration value for state's 'RequestIDHeader' field
|
||||||
|
func (st *ConfigState) GetRequestIDHeader() (v string) {
|
||||||
|
st.mutex.Lock()
|
||||||
|
v = st.config.RequestIDHeader
|
||||||
|
st.mutex.Unlock()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetRequestIDHeader safely sets the Configuration value for state's 'RequestIDHeader' field
|
||||||
|
func (st *ConfigState) SetRequestIDHeader(v string) {
|
||||||
|
st.mutex.Lock()
|
||||||
|
defer st.mutex.Unlock()
|
||||||
|
st.config.RequestIDHeader = v
|
||||||
|
st.reloadToViper()
|
||||||
|
}
|
||||||
|
|
||||||
|
// RequestIDHeaderFlag returns the flag name for the 'RequestIDHeader' field
|
||||||
|
func RequestIDHeaderFlag() string { return "request-id-header" }
|
||||||
|
|
||||||
|
// GetRequestIDHeader safely fetches the value for global configuration 'RequestIDHeader' field
|
||||||
|
func GetRequestIDHeader() string { return global.GetRequestIDHeader() }
|
||||||
|
|
||||||
|
// SetRequestIDHeader safely sets the value for global configuration 'RequestIDHeader' field
|
||||||
|
func SetRequestIDHeader(v string) { global.SetRequestIDHeader(v) }
|
||||||
|
|
|
@ -416,3 +416,12 @@ cache:
|
||||||
account-max-size: 99
|
account-max-size: 99
|
||||||
account-ttl: "3h"
|
account-ttl: "3h"
|
||||||
account-sweep-freq: "1s"
|
account-sweep-freq: "1s"
|
||||||
|
|
||||||
|
##################################
|
||||||
|
##### OBSERVABILITY SETTINGS #####
|
||||||
|
##################################
|
||||||
|
|
||||||
|
# String. Header name to use to extract a request or trace ID from. Typically set by a
|
||||||
|
# loadbalancer or proxy.
|
||||||
|
# Default: "X-Request-Id"
|
||||||
|
request-id-header: "X-Trace-Id"
|
||||||
|
|
|
@ -55,7 +55,7 @@ func Validate() error {
|
||||||
// no problem
|
// no problem
|
||||||
break
|
break
|
||||||
case "http":
|
case "http":
|
||||||
log.Warnf("%s was set to 'http'; this should *only* be used for debugging and tests!", ProtocolFlag())
|
log.Warnf(nil, "%s was set to 'http'; this should *only* be used for debugging and tests!", ProtocolFlag())
|
||||||
case "":
|
case "":
|
||||||
errs = append(errs, fmt.Errorf("%s must be set", ProtocolFlag()))
|
errs = append(errs, fmt.Errorf("%s must be set", ProtocolFlag()))
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -146,7 +146,7 @@ func (a *accountDB) getAccount(ctx context.Context, lookup string, dbQuery func(
|
||||||
// Set the account's related avatar
|
// Set the account's related avatar
|
||||||
account.AvatarMediaAttachment, err = a.state.DB.GetAttachmentByID(ctx, account.AvatarMediaAttachmentID)
|
account.AvatarMediaAttachment, err = a.state.DB.GetAttachmentByID(ctx, account.AvatarMediaAttachmentID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("error getting account %s avatar: %v", account.ID, err)
|
log.Errorf(ctx, "error getting account %s avatar: %v", account.ID, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -154,7 +154,7 @@ func (a *accountDB) getAccount(ctx context.Context, lookup string, dbQuery func(
|
||||||
// Set the account's related header
|
// Set the account's related header
|
||||||
account.HeaderMediaAttachment, err = a.state.DB.GetAttachmentByID(ctx, account.HeaderMediaAttachmentID)
|
account.HeaderMediaAttachment, err = a.state.DB.GetAttachmentByID(ctx, account.HeaderMediaAttachmentID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("error getting account %s header: %v", account.ID, err)
|
log.Errorf(ctx, "error getting account %s header: %v", account.ID, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -162,7 +162,7 @@ func (a *accountDB) getAccount(ctx context.Context, lookup string, dbQuery func(
|
||||||
// Set the account's related emojis
|
// Set the account's related emojis
|
||||||
account.Emojis, err = a.state.DB.GetEmojisByIDs(ctx, account.EmojiIDs)
|
account.Emojis, err = a.state.DB.GetEmojisByIDs(ctx, account.EmojiIDs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("error getting account %s emojis: %v", account.ID, err)
|
log.Errorf(ctx, "error getting account %s emojis: %v", account.ID, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -412,7 +412,7 @@ func (a *accountDB) GetAccountStatuses(ctx context.Context, accountID string, li
|
||||||
Where("? != '{}'", bun.Ident("status.attachments")).
|
Where("? != '{}'", bun.Ident("status.attachments")).
|
||||||
Where("? != '[]'", bun.Ident("status.attachments"))
|
Where("? != '[]'", bun.Ident("status.attachments"))
|
||||||
default:
|
default:
|
||||||
log.Panic("db dialect was neither pg nor sqlite")
|
log.Panic(ctx, "db dialect was neither pg nor sqlite")
|
||||||
return q
|
return q
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -540,7 +540,7 @@ func (a *accountDB) statusesFromIDs(ctx context.Context, statusIDs []string) ([]
|
||||||
// Fetch from status from database by ID
|
// Fetch from status from database by ID
|
||||||
status, err := a.state.DB.GetStatusByID(ctx, id)
|
status, err := a.state.DB.GetStatusByID(ctx, id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("statusesFromIDs: error getting status %q: %v", id, err)
|
log.Errorf(ctx, "error getting status %q: %v", id, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -93,7 +93,7 @@ func (a *adminDB) IsEmailAvailable(ctx context.Context, email string) (bool, db.
|
||||||
func (a *adminDB) NewSignup(ctx context.Context, username string, reason string, requireApproval bool, email string, password string, signUpIP net.IP, locale string, appID string, emailVerified bool, externalID string, admin bool) (*gtsmodel.User, db.Error) {
|
func (a *adminDB) NewSignup(ctx context.Context, username string, reason string, requireApproval bool, email string, password string, signUpIP net.IP, locale string, appID string, emailVerified bool, externalID string, admin bool) (*gtsmodel.User, db.Error) {
|
||||||
key, err := rsa.GenerateKey(rand.Reader, rsaKeyBits)
|
key, err := rsa.GenerateKey(rand.Reader, rsaKeyBits)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("error creating new rsa key: %s", err)
|
log.Errorf(ctx, "error creating new rsa key: %s", err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -107,7 +107,7 @@ func (a *adminDB) NewSignup(ctx context.Context, username string, reason string,
|
||||||
Scan(ctx); err != nil {
|
Scan(ctx); err != nil {
|
||||||
err = a.conn.ProcessError(err)
|
err = a.conn.ProcessError(err)
|
||||||
if err != db.ErrNoEntries {
|
if err != db.ErrNoEntries {
|
||||||
log.Errorf("error checking for existing account: %s", err)
|
log.Errorf(ctx, "error checking for existing account: %s", err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -207,13 +207,13 @@ func (a *adminDB) CreateInstanceAccount(ctx context.Context) db.Error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if exists {
|
if exists {
|
||||||
log.Infof("instance account %s already exists", username)
|
log.Infof(ctx, "instance account %s already exists", username)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
key, err := rsa.GenerateKey(rand.Reader, rsaKeyBits)
|
key, err := rsa.GenerateKey(rand.Reader, rsaKeyBits)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("error creating new rsa key: %s", err)
|
log.Errorf(ctx, "error creating new rsa key: %s", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -245,7 +245,7 @@ func (a *adminDB) CreateInstanceAccount(ctx context.Context) db.Error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Infof("instance account %s CREATED with id %s", username, acct.ID)
|
log.Infof(ctx, "instance account %s CREATED with id %s", username, acct.ID)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -265,7 +265,7 @@ func (a *adminDB) CreateInstanceInstance(ctx context.Context) db.Error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if exists {
|
if exists {
|
||||||
log.Infof("instance entry already exists")
|
log.Infof(ctx, "instance entry already exists")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -290,6 +290,6 @@ func (a *adminDB) CreateInstanceInstance(ctx context.Context) db.Error {
|
||||||
return a.conn.ProcessError(err)
|
return a.conn.ProcessError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Infof("created instance instance %s with id %s", host, i.ID)
|
log.Infof(ctx, "created instance instance %s with id %s", host, i.ID)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -165,6 +165,6 @@ func (b *basicDB) IsHealthy(ctx context.Context) db.Error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *basicDB) Stop(ctx context.Context) db.Error {
|
func (b *basicDB) Stop(ctx context.Context) db.Error {
|
||||||
log.Info("closing db connection")
|
log.Info(ctx, "closing db connection")
|
||||||
return b.conn.Close()
|
return b.conn.Close()
|
||||||
}
|
}
|
||||||
|
|
|
@ -100,11 +100,11 @@ func doMigration(ctx context.Context, db *bun.DB) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
if group.ID == 0 {
|
if group.ID == 0 {
|
||||||
log.Info("there are no new migrations to run")
|
log.Info(ctx, "there are no new migrations to run")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Infof("MIGRATED DATABASE TO %s", group)
|
log.Infof(ctx, "MIGRATED DATABASE TO %s", group)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -245,7 +245,7 @@ func pgConn(ctx context.Context) (*DBConn, error) {
|
||||||
return nil, fmt.Errorf("postgres ping: %s", err)
|
return nil, fmt.Errorf("postgres ping: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Info("connected to POSTGRES database")
|
log.Info(ctx, "connected to POSTGRES database")
|
||||||
return conn, nil
|
return conn, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -268,7 +268,7 @@ func sqliteConn(ctx context.Context) (*DBConn, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if address == ":memory:" {
|
if address == ":memory:" {
|
||||||
log.Warn("using sqlite in-memory mode; all data will be deleted when gts shuts down; this mode should only be used for debugging or running tests")
|
log.Warn(ctx, "using sqlite in-memory mode; all data will be deleted when gts shuts down; this mode should only be used for debugging or running tests")
|
||||||
|
|
||||||
// Use random name for in-memory instead of ':memory:', so
|
// Use random name for in-memory instead of ':memory:', so
|
||||||
// multiple in-mem databases can be created without conflict.
|
// multiple in-mem databases can be created without conflict.
|
||||||
|
@ -319,7 +319,7 @@ func sqliteConn(ctx context.Context) (*DBConn, error) {
|
||||||
}
|
}
|
||||||
return nil, fmt.Errorf("sqlite ping: %s", err)
|
return nil, fmt.Errorf("sqlite ping: %s", err)
|
||||||
}
|
}
|
||||||
log.Infof("connected to SQLITE database with address %s", address)
|
log.Infof(ctx, "connected to SQLITE database with address %s", address)
|
||||||
|
|
||||||
return conn, nil
|
return conn, nil
|
||||||
}
|
}
|
||||||
|
@ -464,7 +464,7 @@ func sqlitePragmas(ctx context.Context, conn *DBConn) error {
|
||||||
return fmt.Errorf("error scanning sqlite pragma %s: %w", pv, err)
|
return fmt.Errorf("error scanning sqlite pragma %s: %w", pv, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Infof("sqlite pragma %s set to %s", pk, res)
|
log.Infof(ctx, "sqlite pragma %s set to %s", pk, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -372,7 +372,7 @@ func (e *emojiDB) GetEmojisByIDs(ctx context.Context, emojiIDs []string) ([]*gts
|
||||||
for _, id := range emojiIDs {
|
for _, id := range emojiIDs {
|
||||||
emoji, err := e.GetEmojiByID(ctx, id)
|
emoji, err := e.GetEmojiByID(ctx, id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("emojisFromIDs: error getting emoji %q: %v", id, err)
|
log.Errorf(ctx, "emojisFromIDs: error getting emoji %q: %v", id, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -405,7 +405,7 @@ func (e *emojiDB) GetEmojiCategoriesByIDs(ctx context.Context, emojiCategoryIDs
|
||||||
for _, id := range emojiCategoryIDs {
|
for _, id := range emojiCategoryIDs {
|
||||||
emojiCategory, err := e.GetEmojiCategory(ctx, id)
|
emojiCategory, err := e.GetEmojiCategory(ctx, id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("emojiCategoriesFromIDs: error getting emoji category %q: %v", id, err)
|
log.Errorf(ctx, "error getting emoji category %q: %v", id, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -36,17 +36,18 @@ func (queryHook) BeforeQuery(ctx context.Context, _ *bun.QueryEvent) context.Con
|
||||||
}
|
}
|
||||||
|
|
||||||
// AfterQuery logs the time taken to query, the operation (select, update, etc), and the query itself as translated by bun.
|
// AfterQuery logs the time taken to query, the operation (select, update, etc), and the query itself as translated by bun.
|
||||||
func (queryHook) AfterQuery(_ context.Context, event *bun.QueryEvent) {
|
func (queryHook) AfterQuery(ctx context.Context, event *bun.QueryEvent) {
|
||||||
// Get the DB query duration
|
// Get the DB query duration
|
||||||
dur := time.Since(event.StartTime)
|
dur := time.Since(event.StartTime)
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
// Warn on slow database queries
|
// Warn on slow database queries
|
||||||
case dur > time.Second:
|
case dur > time.Second:
|
||||||
log.WithFields(kv.Fields{
|
log.WithContext(ctx).
|
||||||
{"duration", dur},
|
WithFields(kv.Fields{
|
||||||
{"query", event.Query},
|
{"duration", dur},
|
||||||
}...).Warn("SLOW DATABASE QUERY")
|
{"query", event.Query},
|
||||||
|
}...).Warn("SLOW DATABASE QUERY")
|
||||||
|
|
||||||
// On trace, we log query information,
|
// On trace, we log query information,
|
||||||
// manually crafting so DB query not escaped.
|
// manually crafting so DB query not escaped.
|
||||||
|
|
|
@ -58,7 +58,7 @@ func (m *mediaDB) getAttachments(ctx context.Context, ids []string) ([]*gtsmodel
|
||||||
// Attempt fetch from DB
|
// Attempt fetch from DB
|
||||||
attachment, err := m.GetAttachmentByID(ctx, id)
|
attachment, err := m.GetAttachmentByID(ctx, id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("error getting attachment %q: %v", id, err)
|
log.Errorf(ctx, "error getting attachment %q: %v", id, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -64,7 +64,7 @@ func (m *mentionDB) GetMentions(ctx context.Context, ids []string) ([]*gtsmodel.
|
||||||
// Attempt fetch from DB
|
// Attempt fetch from DB
|
||||||
mention, err := m.GetMention(ctx, id)
|
mention, err := m.GetMention(ctx, id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("GetMentions: error getting mention %q: %v", id, err)
|
log.Errorf(ctx, "error getting mention %q: %v", id, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -38,7 +38,7 @@ func init() {
|
||||||
case dialect.SQLite:
|
case dialect.SQLite:
|
||||||
q = q.ColumnExpr("? VARCHAR", bun.Ident("emojis"))
|
q = q.ColumnExpr("? VARCHAR", bun.Ident("emojis"))
|
||||||
default:
|
default:
|
||||||
log.Panic("db dialect was neither pg nor sqlite")
|
log.Panic(ctx, "db dialect was neither pg nor sqlite")
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := q.Exec(ctx); err != nil {
|
if _, err := q.Exec(ctx); err != nil {
|
||||||
|
|
|
@ -94,7 +94,7 @@ func (n *notificationDB) GetNotifications(ctx context.Context, accountID string,
|
||||||
// Attempt fetch from DB
|
// Attempt fetch from DB
|
||||||
notif, err := n.GetNotification(ctx, id)
|
notif, err := n.GetNotification(ctx, id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("GetNotifications: error getting notification %q: %v", id, err)
|
log.Errorf(ctx, "error getting notification %q: %v", id, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -106,7 +106,7 @@ func (r *reportDB) GetReports(ctx context.Context, resolved *bool, accountID str
|
||||||
for _, id := range reportIDs {
|
for _, id := range reportIDs {
|
||||||
report, err := r.GetReportByID(ctx, id)
|
report, err := r.GetReportByID(ctx, id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("GetReports: error getting report %q: %v", id, err)
|
log.Errorf(ctx, "error getting report %q: %v", id, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -74,7 +74,7 @@ func (s *statusDB) GetStatuses(ctx context.Context, ids []string) ([]*gtsmodel.S
|
||||||
// Attempt fetch from DB
|
// Attempt fetch from DB
|
||||||
status, err := s.GetStatusByID(ctx, id)
|
status, err := s.GetStatusByID(ctx, id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("GetStatuses: error getting status %q: %v", id, err)
|
log.Errorf(ctx, "error getting status %q: %v", id, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -387,7 +387,7 @@ func (s *statusDB) GetStatusChildren(ctx context.Context, status *gtsmodel.Statu
|
||||||
// only append children, not the overall parent status
|
// only append children, not the overall parent status
|
||||||
entry, ok := e.Value.(*gtsmodel.Status)
|
entry, ok := e.Value.(*gtsmodel.Status)
|
||||||
if !ok {
|
if !ok {
|
||||||
log.Panic("GetStatusChildren: found status could not be asserted to *gtsmodel.Status")
|
log.Panic(ctx, "found status could not be asserted to *gtsmodel.Status")
|
||||||
}
|
}
|
||||||
|
|
||||||
if entry.ID != status.ID {
|
if entry.ID != status.ID {
|
||||||
|
@ -412,7 +412,7 @@ func (s *statusDB) statusChildren(ctx context.Context, status *gtsmodel.Status,
|
||||||
|
|
||||||
if err := q.Scan(ctx, &childIDs); err != nil {
|
if err := q.Scan(ctx, &childIDs); err != nil {
|
||||||
if err != sql.ErrNoRows {
|
if err != sql.ErrNoRows {
|
||||||
log.Errorf("statusChildren: error getting children for %q: %v", status.ID, err)
|
log.Errorf(ctx, "error getting children for %q: %v", status.ID, err)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -421,7 +421,7 @@ func (s *statusDB) statusChildren(ctx context.Context, status *gtsmodel.Status,
|
||||||
// Fetch child with ID from database
|
// Fetch child with ID from database
|
||||||
child, err := s.GetStatusByID(ctx, id)
|
child, err := s.GetStatusByID(ctx, id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("statusChildren: error getting child status %q: %v", id, err)
|
log.Errorf(ctx, "error getting child status %q: %v", id, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -429,7 +429,7 @@ func (s *statusDB) statusChildren(ctx context.Context, status *gtsmodel.Status,
|
||||||
for e := foundStatuses.Front(); e != nil; e = e.Next() {
|
for e := foundStatuses.Front(); e != nil; e = e.Next() {
|
||||||
entry, ok := e.Value.(*gtsmodel.Status)
|
entry, ok := e.Value.(*gtsmodel.Status)
|
||||||
if !ok {
|
if !ok {
|
||||||
log.Panic("statusChildren: found status could not be asserted to *gtsmodel.Status")
|
log.Panic(ctx, "found status could not be asserted to *gtsmodel.Status")
|
||||||
}
|
}
|
||||||
|
|
||||||
if child.InReplyToAccountID != "" && entry.ID == child.InReplyToID {
|
if child.InReplyToAccountID != "" && entry.ID == child.InReplyToID {
|
||||||
|
|
|
@ -114,7 +114,7 @@ func (t *timelineDB) GetHomeTimeline(ctx context.Context, accountID string, maxI
|
||||||
// Fetch status from db for ID
|
// Fetch status from db for ID
|
||||||
status, err := t.state.DB.GetStatusByID(ctx, id)
|
status, err := t.state.DB.GetStatusByID(ctx, id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("GetHomeTimeline: error fetching status %q: %v", id, err)
|
log.Errorf(ctx, "error fetching status %q: %v", id, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -182,7 +182,7 @@ func (t *timelineDB) GetPublicTimeline(ctx context.Context, maxID string, sinceI
|
||||||
// Fetch status from db for ID
|
// Fetch status from db for ID
|
||||||
status, err := t.state.DB.GetStatusByID(ctx, id)
|
status, err := t.state.DB.GetStatusByID(ctx, id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("GetPublicTimeline: error fetching status %q: %v", id, err)
|
log.Errorf(ctx, "error fetching status %q: %v", id, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -242,7 +242,7 @@ func (t *timelineDB) GetFavedTimeline(ctx context.Context, accountID string, max
|
||||||
// Fetch status from db for corresponding favourite
|
// Fetch status from db for corresponding favourite
|
||||||
status, err := t.state.DB.GetStatusByID(ctx, fave.StatusID)
|
status, err := t.state.DB.GetStatusByID(ctx, fave.StatusID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("GetFavedTimeline: error fetching status for fave %q: %v", fave.ID, err)
|
log.Errorf(ctx, "error fetching status for fave %q: %v", fave.ID, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -42,7 +42,7 @@ func (s *sender) SendConfirmEmail(toAddress string, data ConfirmData) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
log.Trace(s.hostAddress + "\n" + config.GetSMTPUsername() + ":password" + "\n" + s.from + "\n" + toAddress + "\n\n" + string(msg) + "\n")
|
log.Trace(nil, s.hostAddress+"\n"+config.GetSMTPUsername()+":password"+"\n"+s.from+"\n"+toAddress+"\n\n"+string(msg)+"\n")
|
||||||
return smtp.SendMail(s.hostAddress, s.auth, s.from, []string{toAddress}, msg)
|
return smtp.SendMail(s.hostAddress, s.auth, s.from, []string{toAddress}, msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -61,7 +61,7 @@ func (s *noopSender) SendConfirmEmail(toAddress string, data ConfirmData) error
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Tracef("NOT SENDING confirmation email to %s with contents: %s", toAddress, msg)
|
log.Tracef(nil, "NOT SENDING confirmation email to %s with contents: %s", toAddress, msg)
|
||||||
|
|
||||||
if s.sendCallback != nil {
|
if s.sendCallback != nil {
|
||||||
s.sendCallback(toAddress, string(msg))
|
s.sendCallback(toAddress, string(msg))
|
||||||
|
@ -81,7 +81,7 @@ func (s *noopSender) SendResetEmail(toAddress string, data ResetData) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Tracef("NOT SENDING reset email to %s with contents: %s", toAddress, msg)
|
log.Tracef(nil, "NOT SENDING reset email to %s with contents: %s", toAddress, msg)
|
||||||
|
|
||||||
if s.sendCallback != nil {
|
if s.sendCallback != nil {
|
||||||
s.sendCallback(toAddress, string(msg))
|
s.sendCallback(toAddress, string(msg))
|
||||||
|
|
|
@ -124,7 +124,7 @@ func (f *federator) AuthenticateFederatedRequest(ctx context.Context, requestedU
|
||||||
if vi == nil {
|
if vi == nil {
|
||||||
err := errors.New("http request wasn't signed or http signature was invalid")
|
err := errors.New("http request wasn't signed or http signature was invalid")
|
||||||
errWithCode := gtserror.NewErrorUnauthorized(err, err.Error())
|
errWithCode := gtserror.NewErrorUnauthorized(err, err.Error())
|
||||||
log.Debug(errWithCode)
|
log.Debug(ctx, errWithCode)
|
||||||
return nil, errWithCode
|
return nil, errWithCode
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -132,7 +132,7 @@ func (f *federator) AuthenticateFederatedRequest(ctx context.Context, requestedU
|
||||||
if !ok {
|
if !ok {
|
||||||
err := errors.New("http request wasn't signed or http signature was invalid")
|
err := errors.New("http request wasn't signed or http signature was invalid")
|
||||||
errWithCode := gtserror.NewErrorUnauthorized(err, err.Error())
|
errWithCode := gtserror.NewErrorUnauthorized(err, err.Error())
|
||||||
log.Debug(errWithCode)
|
log.Debug(ctx, errWithCode)
|
||||||
return nil, errWithCode
|
return nil, errWithCode
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -141,7 +141,7 @@ func (f *federator) AuthenticateFederatedRequest(ctx context.Context, requestedU
|
||||||
if si == nil {
|
if si == nil {
|
||||||
err := errors.New("http request wasn't signed or http signature was invalid")
|
err := errors.New("http request wasn't signed or http signature was invalid")
|
||||||
errWithCode := gtserror.NewErrorUnauthorized(err, err.Error())
|
errWithCode := gtserror.NewErrorUnauthorized(err, err.Error())
|
||||||
log.Debug(errWithCode)
|
log.Debug(ctx, errWithCode)
|
||||||
return nil, errWithCode
|
return nil, errWithCode
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -149,7 +149,7 @@ func (f *federator) AuthenticateFederatedRequest(ctx context.Context, requestedU
|
||||||
if !ok {
|
if !ok {
|
||||||
err := errors.New("http request wasn't signed or http signature was invalid")
|
err := errors.New("http request wasn't signed or http signature was invalid")
|
||||||
errWithCode := gtserror.NewErrorUnauthorized(err, err.Error())
|
errWithCode := gtserror.NewErrorUnauthorized(err, err.Error())
|
||||||
log.Debug(errWithCode)
|
log.Debug(ctx, errWithCode)
|
||||||
return nil, errWithCode
|
return nil, errWithCode
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -157,7 +157,7 @@ func (f *federator) AuthenticateFederatedRequest(ctx context.Context, requestedU
|
||||||
requestingPublicKeyID, err := url.Parse(verifier.KeyId())
|
requestingPublicKeyID, err := url.Parse(verifier.KeyId())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errWithCode := gtserror.NewErrorBadRequest(err, fmt.Sprintf("couldn't parse public key URL %s", verifier.KeyId()))
|
errWithCode := gtserror.NewErrorBadRequest(err, fmt.Sprintf("couldn't parse public key URL %s", verifier.KeyId()))
|
||||||
log.Debug(errWithCode)
|
log.Debug(ctx, errWithCode)
|
||||||
return nil, errWithCode
|
return nil, errWithCode
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -170,12 +170,12 @@ func (f *federator) AuthenticateFederatedRequest(ctx context.Context, requestedU
|
||||||
if host := config.GetHost(); strings.EqualFold(requestingHost, host) {
|
if host := config.GetHost(); strings.EqualFold(requestingHost, host) {
|
||||||
// LOCAL ACCOUNT REQUEST
|
// LOCAL ACCOUNT REQUEST
|
||||||
// the request is coming from INSIDE THE HOUSE so skip the remote dereferencing
|
// the request is coming from INSIDE THE HOUSE so skip the remote dereferencing
|
||||||
log.Tracef("proceeding without dereference for local public key %s", requestingPublicKeyID)
|
log.Tracef(ctx, "proceeding without dereference for local public key %s", requestingPublicKeyID)
|
||||||
|
|
||||||
requestingLocalAccount, err = f.db.GetAccountByPubkeyID(ctx, requestingPublicKeyID.String())
|
requestingLocalAccount, err = f.db.GetAccountByPubkeyID(ctx, requestingPublicKeyID.String())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errWithCode := gtserror.NewErrorInternalError(fmt.Errorf("couldn't get account with public key uri %s from the database: %s", requestingPublicKeyID.String(), err))
|
errWithCode := gtserror.NewErrorInternalError(fmt.Errorf("couldn't get account with public key uri %s from the database: %s", requestingPublicKeyID.String(), err))
|
||||||
log.Debug(errWithCode)
|
log.Debug(ctx, errWithCode)
|
||||||
return nil, errWithCode
|
return nil, errWithCode
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -184,18 +184,18 @@ func (f *federator) AuthenticateFederatedRequest(ctx context.Context, requestedU
|
||||||
pkOwnerURI, err = url.Parse(requestingLocalAccount.URI)
|
pkOwnerURI, err = url.Parse(requestingLocalAccount.URI)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errWithCode := gtserror.NewErrorBadRequest(err, fmt.Sprintf("couldn't parse public key owner URL %s", requestingLocalAccount.URI))
|
errWithCode := gtserror.NewErrorBadRequest(err, fmt.Sprintf("couldn't parse public key owner URL %s", requestingLocalAccount.URI))
|
||||||
log.Debug(errWithCode)
|
log.Debug(ctx, errWithCode)
|
||||||
return nil, errWithCode
|
return nil, errWithCode
|
||||||
}
|
}
|
||||||
} else if requestingRemoteAccount, err = f.db.GetAccountByPubkeyID(ctx, requestingPublicKeyID.String()); err == nil {
|
} else if requestingRemoteAccount, err = f.db.GetAccountByPubkeyID(ctx, requestingPublicKeyID.String()); err == nil {
|
||||||
// REMOTE ACCOUNT REQUEST WITH KEY CACHED LOCALLY
|
// REMOTE ACCOUNT REQUEST WITH KEY CACHED LOCALLY
|
||||||
// this is a remote account and we already have the public key for it so use that
|
// this is a remote account and we already have the public key for it so use that
|
||||||
log.Tracef("proceeding without dereference for cached public key %s", requestingPublicKeyID)
|
log.Tracef(ctx, "proceeding without dereference for cached public key %s", requestingPublicKeyID)
|
||||||
publicKey = requestingRemoteAccount.PublicKey
|
publicKey = requestingRemoteAccount.PublicKey
|
||||||
pkOwnerURI, err = url.Parse(requestingRemoteAccount.URI)
|
pkOwnerURI, err = url.Parse(requestingRemoteAccount.URI)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errWithCode := gtserror.NewErrorBadRequest(err, fmt.Sprintf("couldn't parse public key owner URL %s", requestingRemoteAccount.URI))
|
errWithCode := gtserror.NewErrorBadRequest(err, fmt.Sprintf("couldn't parse public key owner URL %s", requestingRemoteAccount.URI))
|
||||||
log.Debug(errWithCode)
|
log.Debug(ctx, errWithCode)
|
||||||
return nil, errWithCode
|
return nil, errWithCode
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -205,21 +205,21 @@ func (f *federator) AuthenticateFederatedRequest(ctx context.Context, requestedU
|
||||||
gone, err := f.CheckGone(ctx, requestingPublicKeyID)
|
gone, err := f.CheckGone(ctx, requestingPublicKeyID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errWithCode := gtserror.NewErrorInternalError(fmt.Errorf("error checking for tombstone for %s: %s", requestingPublicKeyID, err))
|
errWithCode := gtserror.NewErrorInternalError(fmt.Errorf("error checking for tombstone for %s: %s", requestingPublicKeyID, err))
|
||||||
log.Debug(errWithCode)
|
log.Debug(ctx, errWithCode)
|
||||||
return nil, errWithCode
|
return nil, errWithCode
|
||||||
}
|
}
|
||||||
|
|
||||||
if gone {
|
if gone {
|
||||||
errWithCode := gtserror.NewErrorGone(fmt.Errorf("account with public key %s is gone", requestingPublicKeyID))
|
errWithCode := gtserror.NewErrorGone(fmt.Errorf("account with public key %s is gone", requestingPublicKeyID))
|
||||||
log.Debug(errWithCode)
|
log.Debug(ctx, errWithCode)
|
||||||
return nil, errWithCode
|
return nil, errWithCode
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Tracef("proceeding with dereference for uncached public key %s", requestingPublicKeyID)
|
log.Tracef(ctx, "proceeding with dereference for uncached public key %s", requestingPublicKeyID)
|
||||||
trans, err := f.transportController.NewTransportForUsername(transport.WithFastfail(ctx), requestedUsername)
|
trans, err := f.transportController.NewTransportForUsername(transport.WithFastfail(ctx), requestedUsername)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errWithCode := gtserror.NewErrorInternalError(fmt.Errorf("error creating transport for %s: %s", requestedUsername, err))
|
errWithCode := gtserror.NewErrorInternalError(fmt.Errorf("error creating transport for %s: %s", requestedUsername, err))
|
||||||
log.Debug(errWithCode)
|
log.Debug(ctx, errWithCode)
|
||||||
return nil, errWithCode
|
return nil, errWithCode
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -231,16 +231,16 @@ func (f *federator) AuthenticateFederatedRequest(ctx context.Context, requestedU
|
||||||
// we should add a tombstone to our database so that we can avoid trying to deref it in future
|
// we should add a tombstone to our database so that we can avoid trying to deref it in future
|
||||||
if err := f.HandleGone(ctx, requestingPublicKeyID); err != nil {
|
if err := f.HandleGone(ctx, requestingPublicKeyID); err != nil {
|
||||||
errWithCode := gtserror.NewErrorInternalError(fmt.Errorf("error marking account with public key %s as gone: %s", requestingPublicKeyID, err))
|
errWithCode := gtserror.NewErrorInternalError(fmt.Errorf("error marking account with public key %s as gone: %s", requestingPublicKeyID, err))
|
||||||
log.Debug(errWithCode)
|
log.Debug(ctx, errWithCode)
|
||||||
return nil, errWithCode
|
return nil, errWithCode
|
||||||
}
|
}
|
||||||
errWithCode := gtserror.NewErrorGone(fmt.Errorf("account with public key %s is gone", requestingPublicKeyID))
|
errWithCode := gtserror.NewErrorGone(fmt.Errorf("account with public key %s is gone", requestingPublicKeyID))
|
||||||
log.Debug(errWithCode)
|
log.Debug(ctx, errWithCode)
|
||||||
return nil, errWithCode
|
return nil, errWithCode
|
||||||
}
|
}
|
||||||
|
|
||||||
errWithCode := gtserror.NewErrorUnauthorized(fmt.Errorf("error dereferencing public key %s: %s", requestingPublicKeyID, err))
|
errWithCode := gtserror.NewErrorUnauthorized(fmt.Errorf("error dereferencing public key %s: %s", requestingPublicKeyID, err))
|
||||||
log.Debug(errWithCode)
|
log.Debug(ctx, errWithCode)
|
||||||
return nil, errWithCode
|
return nil, errWithCode
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -248,7 +248,7 @@ func (f *federator) AuthenticateFederatedRequest(ctx context.Context, requestedU
|
||||||
requestingPublicKey, err := getPublicKeyFromResponse(ctx, b, requestingPublicKeyID)
|
requestingPublicKey, err := getPublicKeyFromResponse(ctx, b, requestingPublicKeyID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errWithCode := gtserror.NewErrorUnauthorized(fmt.Errorf("error parsing public key %s: %s", requestingPublicKeyID, err))
|
errWithCode := gtserror.NewErrorUnauthorized(fmt.Errorf("error parsing public key %s: %s", requestingPublicKeyID, err))
|
||||||
log.Debug(errWithCode)
|
log.Debug(ctx, errWithCode)
|
||||||
return nil, errWithCode
|
return nil, errWithCode
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -256,7 +256,7 @@ func (f *federator) AuthenticateFederatedRequest(ctx context.Context, requestedU
|
||||||
pkPemProp := requestingPublicKey.GetW3IDSecurityV1PublicKeyPem()
|
pkPemProp := requestingPublicKey.GetW3IDSecurityV1PublicKeyPem()
|
||||||
if pkPemProp == nil || !pkPemProp.IsXMLSchemaString() {
|
if pkPemProp == nil || !pkPemProp.IsXMLSchemaString() {
|
||||||
errWithCode := gtserror.NewErrorUnauthorized(errors.New("publicKeyPem property is not provided or it is not embedded as a value"))
|
errWithCode := gtserror.NewErrorUnauthorized(errors.New("publicKeyPem property is not provided or it is not embedded as a value"))
|
||||||
log.Debug(errWithCode)
|
log.Debug(ctx, errWithCode)
|
||||||
return nil, errWithCode
|
return nil, errWithCode
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -265,14 +265,14 @@ func (f *federator) AuthenticateFederatedRequest(ctx context.Context, requestedU
|
||||||
block, _ := pem.Decode([]byte(pubKeyPem))
|
block, _ := pem.Decode([]byte(pubKeyPem))
|
||||||
if block == nil || block.Type != "PUBLIC KEY" {
|
if block == nil || block.Type != "PUBLIC KEY" {
|
||||||
errWithCode := gtserror.NewErrorUnauthorized(errors.New("could not decode publicKeyPem to PUBLIC KEY pem block type"))
|
errWithCode := gtserror.NewErrorUnauthorized(errors.New("could not decode publicKeyPem to PUBLIC KEY pem block type"))
|
||||||
log.Debug(errWithCode)
|
log.Debug(ctx, errWithCode)
|
||||||
return nil, errWithCode
|
return nil, errWithCode
|
||||||
}
|
}
|
||||||
|
|
||||||
publicKey, err = x509.ParsePKIXPublicKey(block.Bytes)
|
publicKey, err = x509.ParsePKIXPublicKey(block.Bytes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errWithCode := gtserror.NewErrorUnauthorized(fmt.Errorf("could not parse public key %s from block bytes: %s", requestingPublicKeyID, err))
|
errWithCode := gtserror.NewErrorUnauthorized(fmt.Errorf("could not parse public key %s from block bytes: %s", requestingPublicKeyID, err))
|
||||||
log.Debug(errWithCode)
|
log.Debug(ctx, errWithCode)
|
||||||
return nil, errWithCode
|
return nil, errWithCode
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -280,7 +280,7 @@ func (f *federator) AuthenticateFederatedRequest(ctx context.Context, requestedU
|
||||||
pkOwnerProp := requestingPublicKey.GetW3IDSecurityV1Owner()
|
pkOwnerProp := requestingPublicKey.GetW3IDSecurityV1Owner()
|
||||||
if pkOwnerProp == nil || !pkOwnerProp.IsIRI() {
|
if pkOwnerProp == nil || !pkOwnerProp.IsIRI() {
|
||||||
errWithCode := gtserror.NewErrorUnauthorized(errors.New("publicKeyOwner property is not provided or it is not embedded as a value"))
|
errWithCode := gtserror.NewErrorUnauthorized(errors.New("publicKeyOwner property is not provided or it is not embedded as a value"))
|
||||||
log.Debug(errWithCode)
|
log.Debug(ctx, errWithCode)
|
||||||
return nil, errWithCode
|
return nil, errWithCode
|
||||||
}
|
}
|
||||||
pkOwnerURI = pkOwnerProp.GetIRI()
|
pkOwnerURI = pkOwnerProp.GetIRI()
|
||||||
|
@ -289,7 +289,7 @@ func (f *federator) AuthenticateFederatedRequest(ctx context.Context, requestedU
|
||||||
// after all that, public key should be defined
|
// after all that, public key should be defined
|
||||||
if publicKey == nil {
|
if publicKey == nil {
|
||||||
errWithCode := gtserror.NewErrorInternalError(errors.New("returned public key was empty"))
|
errWithCode := gtserror.NewErrorInternalError(errors.New("returned public key was empty"))
|
||||||
log.Debug(errWithCode)
|
log.Debug(ctx, errWithCode)
|
||||||
return nil, errWithCode
|
return nil, errWithCode
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -301,16 +301,16 @@ func (f *federator) AuthenticateFederatedRequest(ctx context.Context, requestedU
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, algo := range algos {
|
for _, algo := range algos {
|
||||||
log.Tracef("trying algo: %s", algo)
|
log.Tracef(ctx, "trying algo: %s", algo)
|
||||||
err := verifier.Verify(publicKey, algo)
|
err := verifier.Verify(publicKey, algo)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
log.Tracef("authentication for %s PASSED with algorithm %s", pkOwnerURI, algo)
|
log.Tracef(ctx, "authentication for %s PASSED with algorithm %s", pkOwnerURI, algo)
|
||||||
return pkOwnerURI, nil
|
return pkOwnerURI, nil
|
||||||
}
|
}
|
||||||
log.Tracef("authentication for %s NOT PASSED with algorithm %s: %s", pkOwnerURI, algo, err)
|
log.Tracef(ctx, "authentication for %s NOT PASSED with algorithm %s: %s", pkOwnerURI, algo, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
errWithCode := gtserror.NewErrorUnauthorized(fmt.Errorf("authentication not passed for public key owner %s; signature value was '%s'", pkOwnerURI, signature))
|
errWithCode := gtserror.NewErrorUnauthorized(fmt.Errorf("authentication not passed for public key owner %s; signature value was '%s'", pkOwnerURI, signature))
|
||||||
log.Debug(errWithCode)
|
log.Debug(ctx, errWithCode)
|
||||||
return nil, errWithCode
|
return nil, errWithCode
|
||||||
}
|
}
|
||||||
|
|
|
@ -77,7 +77,7 @@ func (d *deref) GetAccountByURI(ctx context.Context, requestUser string, uri *ur
|
||||||
// Try to update existing account model
|
// Try to update existing account model
|
||||||
enriched, err := d.enrichAccount(ctx, requestUser, uri, account, false, block)
|
enriched, err := d.enrichAccount(ctx, requestUser, uri, account, false, block)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("error enriching remote account: %v", err)
|
log.Errorf(ctx, "error enriching remote account: %v", err)
|
||||||
return account, nil // fall back to returning existing
|
return account, nil // fall back to returning existing
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,7 +114,7 @@ func (d *deref) GetAccountByUsernameDomain(ctx context.Context, requestUser stri
|
||||||
// Try to update existing account model
|
// Try to update existing account model
|
||||||
enriched, err := d.enrichAccount(ctx, requestUser, nil, account, false, block)
|
enriched, err := d.enrichAccount(ctx, requestUser, nil, account, false, block)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("GetAccountByUsernameDomain: error enriching account from remote: %v", err)
|
log.Errorf(ctx, "error enriching account from remote: %v", err)
|
||||||
return account, nil // fall back to returning unchanged existing account model
|
return account, nil // fall back to returning unchanged existing account model
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -250,7 +250,7 @@ func (d *deref) enrichAccount(ctx context.Context, requestUser string, uri *url.
|
||||||
latestAcc.ID,
|
latestAcc.ID,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("error fetching remote avatar for account %s: %v", uri, err)
|
log.Errorf(ctx, "error fetching remote avatar for account %s: %v", uri, err)
|
||||||
|
|
||||||
// Keep old avatar for now, we'll try again in $interval.
|
// Keep old avatar for now, we'll try again in $interval.
|
||||||
latestAcc.AvatarMediaAttachmentID = account.AvatarMediaAttachmentID
|
latestAcc.AvatarMediaAttachmentID = account.AvatarMediaAttachmentID
|
||||||
|
@ -271,7 +271,7 @@ func (d *deref) enrichAccount(ctx context.Context, requestUser string, uri *url.
|
||||||
latestAcc.ID,
|
latestAcc.ID,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("error fetching remote header for account %s: %v", uri, err)
|
log.Errorf(ctx, "error fetching remote header for account %s: %v", uri, err)
|
||||||
|
|
||||||
// Keep old header for now, we'll try again in $interval.
|
// Keep old header for now, we'll try again in $interval.
|
||||||
latestAcc.HeaderMediaAttachmentID = account.HeaderMediaAttachmentID
|
latestAcc.HeaderMediaAttachmentID = account.HeaderMediaAttachmentID
|
||||||
|
@ -283,7 +283,7 @@ func (d *deref) enrichAccount(ctx context.Context, requestUser string, uri *url.
|
||||||
// Fetch the latest remote account emoji IDs used in account display name/bio.
|
// Fetch the latest remote account emoji IDs used in account display name/bio.
|
||||||
_, err = d.fetchRemoteAccountEmojis(ctx, latestAcc, requestUser)
|
_, err = d.fetchRemoteAccountEmojis(ctx, latestAcc, requestUser)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("error fetching remote emojis for account %s: %v", uri, err)
|
log.Errorf(ctx, "error fetching remote emojis for account %s: %v", uri, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if account.CreatedAt.IsZero() {
|
if account.CreatedAt.IsZero() {
|
||||||
|
|
|
@ -111,7 +111,7 @@ func (d *deref) populateEmojis(ctx context.Context, rawEmojis []*gtsmodel.Emoji,
|
||||||
// have to get it from the database again
|
// have to get it from the database again
|
||||||
gotEmoji = e
|
gotEmoji = e
|
||||||
} else if gotEmoji, err = d.db.GetEmojiByShortcodeDomain(ctx, e.Shortcode, e.Domain); err != nil && err != db.ErrNoEntries {
|
} else if gotEmoji, err = d.db.GetEmojiByShortcodeDomain(ctx, e.Shortcode, e.Domain); err != nil && err != db.ErrNoEntries {
|
||||||
log.Errorf("populateEmojis: error checking database for emoji %s: %s", shortcodeDomain, err)
|
log.Errorf(ctx, "error checking database for emoji %s: %s", shortcodeDomain, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -120,24 +120,24 @@ func (d *deref) populateEmojis(ctx context.Context, rawEmojis []*gtsmodel.Emoji,
|
||||||
if gotEmoji != nil {
|
if gotEmoji != nil {
|
||||||
// we had the emoji already, but refresh it if necessary
|
// we had the emoji already, but refresh it if necessary
|
||||||
if e.UpdatedAt.Unix() > gotEmoji.ImageUpdatedAt.Unix() {
|
if e.UpdatedAt.Unix() > gotEmoji.ImageUpdatedAt.Unix() {
|
||||||
log.Tracef("populateEmojis: emoji %s was updated since we last saw it, will refresh", shortcodeDomain)
|
log.Tracef(ctx, "emoji %s was updated since we last saw it, will refresh", shortcodeDomain)
|
||||||
refresh = true
|
refresh = true
|
||||||
}
|
}
|
||||||
|
|
||||||
if !refresh && (e.URI != gotEmoji.URI) {
|
if !refresh && (e.URI != gotEmoji.URI) {
|
||||||
log.Tracef("populateEmojis: emoji %s changed URI since we last saw it, will refresh", shortcodeDomain)
|
log.Tracef(ctx, "emoji %s changed URI since we last saw it, will refresh", shortcodeDomain)
|
||||||
refresh = true
|
refresh = true
|
||||||
}
|
}
|
||||||
|
|
||||||
if !refresh && (e.ImageRemoteURL != gotEmoji.ImageRemoteURL) {
|
if !refresh && (e.ImageRemoteURL != gotEmoji.ImageRemoteURL) {
|
||||||
log.Tracef("populateEmojis: emoji %s changed image URL since we last saw it, will refresh", shortcodeDomain)
|
log.Tracef(ctx, "emoji %s changed image URL since we last saw it, will refresh", shortcodeDomain)
|
||||||
refresh = true
|
refresh = true
|
||||||
}
|
}
|
||||||
|
|
||||||
if !refresh {
|
if !refresh {
|
||||||
log.Tracef("populateEmojis: emoji %s is up to date, will not refresh", shortcodeDomain)
|
log.Tracef(ctx, "emoji %s is up to date, will not refresh", shortcodeDomain)
|
||||||
} else {
|
} else {
|
||||||
log.Tracef("populateEmojis: refreshing emoji %s", shortcodeDomain)
|
log.Tracef(ctx, "refreshing emoji %s", shortcodeDomain)
|
||||||
emojiID := gotEmoji.ID // use existing ID
|
emojiID := gotEmoji.ID // use existing ID
|
||||||
processingEmoji, err := d.GetRemoteEmoji(ctx, requestingUsername, e.ImageRemoteURL, e.Shortcode, e.Domain, emojiID, e.URI, &media.AdditionalEmojiInfo{
|
processingEmoji, err := d.GetRemoteEmoji(ctx, requestingUsername, e.ImageRemoteURL, e.Shortcode, e.Domain, emojiID, e.URI, &media.AdditionalEmojiInfo{
|
||||||
Domain: &e.Domain,
|
Domain: &e.Domain,
|
||||||
|
@ -147,12 +147,12 @@ func (d *deref) populateEmojis(ctx context.Context, rawEmojis []*gtsmodel.Emoji,
|
||||||
VisibleInPicker: gotEmoji.VisibleInPicker,
|
VisibleInPicker: gotEmoji.VisibleInPicker,
|
||||||
}, refresh)
|
}, refresh)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("populateEmojis: couldn't refresh remote emoji %s: %s", shortcodeDomain, err)
|
log.Errorf(ctx, "couldn't refresh remote emoji %s: %s", shortcodeDomain, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if gotEmoji, err = processingEmoji.LoadEmoji(ctx); err != nil {
|
if gotEmoji, err = processingEmoji.LoadEmoji(ctx); err != nil {
|
||||||
log.Errorf("populateEmojis: couldn't load refreshed remote emoji %s: %s", shortcodeDomain, err)
|
log.Errorf(ctx, "couldn't load refreshed remote emoji %s: %s", shortcodeDomain, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -160,7 +160,7 @@ func (d *deref) populateEmojis(ctx context.Context, rawEmojis []*gtsmodel.Emoji,
|
||||||
// it's new! go get it!
|
// it's new! go get it!
|
||||||
newEmojiID, err := id.NewRandomULID()
|
newEmojiID, err := id.NewRandomULID()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("populateEmojis: error generating id for remote emoji %s: %s", shortcodeDomain, err)
|
log.Errorf(ctx, "error generating id for remote emoji %s: %s", shortcodeDomain, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -172,12 +172,12 @@ func (d *deref) populateEmojis(ctx context.Context, rawEmojis []*gtsmodel.Emoji,
|
||||||
VisibleInPicker: e.VisibleInPicker,
|
VisibleInPicker: e.VisibleInPicker,
|
||||||
}, refresh)
|
}, refresh)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("populateEmojis: couldn't get remote emoji %s: %s", shortcodeDomain, err)
|
log.Errorf(ctx, "couldn't get remote emoji %s: %s", shortcodeDomain, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if gotEmoji, err = processingEmoji.LoadEmoji(ctx); err != nil {
|
if gotEmoji, err = processingEmoji.LoadEmoji(ctx); err != nil {
|
||||||
log.Errorf("populateEmojis: couldn't load remote emoji %s: %s", shortcodeDomain, err)
|
log.Errorf(ctx, "couldn't load remote emoji %s: %s", shortcodeDomain, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -318,20 +318,20 @@ func (d *deref) populateStatusMentions(ctx context.Context, status *gtsmodel.Sta
|
||||||
for _, m := range status.Mentions {
|
for _, m := range status.Mentions {
|
||||||
if m.ID != "" {
|
if m.ID != "" {
|
||||||
// we've already populated this mention, since it has an ID
|
// we've already populated this mention, since it has an ID
|
||||||
log.Debug("populateStatusMentions: mention already populated")
|
log.Debug(ctx, "mention already populated")
|
||||||
mentionIDs = append(mentionIDs, m.ID)
|
mentionIDs = append(mentionIDs, m.ID)
|
||||||
newMentions = append(newMentions, m)
|
newMentions = append(newMentions, m)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if m.TargetAccountURI == "" {
|
if m.TargetAccountURI == "" {
|
||||||
log.Debug("populateStatusMentions: target URI not set on mention")
|
log.Debug(ctx, "target URI not set on mention")
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
targetAccountURI, err := url.Parse(m.TargetAccountURI)
|
targetAccountURI, err := url.Parse(m.TargetAccountURI)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debugf("populateStatusMentions: error parsing mentioned account uri %s: %s", m.TargetAccountURI, err)
|
log.Debugf(ctx, "error parsing mentioned account uri %s: %s", m.TargetAccountURI, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -342,7 +342,7 @@ func (d *deref) populateStatusMentions(ctx context.Context, status *gtsmodel.Sta
|
||||||
if a, err := d.db.GetAccountByURI(ctx, targetAccountURI.String()); err != nil {
|
if a, err := d.db.GetAccountByURI(ctx, targetAccountURI.String()); err != nil {
|
||||||
errs = append(errs, err.Error())
|
errs = append(errs, err.Error())
|
||||||
} else {
|
} else {
|
||||||
log.Debugf("populateStatusMentions: got target account %s with id %s through GetAccountByURI", targetAccountURI, a.ID)
|
log.Debugf(ctx, "got target account %s with id %s through GetAccountByURI", targetAccountURI, a.ID)
|
||||||
targetAccount = a
|
targetAccount = a
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -352,13 +352,13 @@ func (d *deref) populateStatusMentions(ctx context.Context, status *gtsmodel.Sta
|
||||||
if a, err := d.GetAccountByURI(ctx, requestingUsername, targetAccountURI, false); err != nil {
|
if a, err := d.GetAccountByURI(ctx, requestingUsername, targetAccountURI, false); err != nil {
|
||||||
errs = append(errs, err.Error())
|
errs = append(errs, err.Error())
|
||||||
} else {
|
} else {
|
||||||
log.Debugf("populateStatusMentions: got target account %s with id %s through GetRemoteAccount", targetAccountURI, a.ID)
|
log.Debugf(ctx, "got target account %s with id %s through GetRemoteAccount", targetAccountURI, a.ID)
|
||||||
targetAccount = a
|
targetAccount = a
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if targetAccount == nil {
|
if targetAccount == nil {
|
||||||
log.Debugf("populateStatusMentions: couldn't get target account %s: %s", m.TargetAccountURI, strings.Join(errs, " : "))
|
log.Debugf(ctx, "couldn't get target account %s: %s", m.TargetAccountURI, strings.Join(errs, " : "))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -419,13 +419,13 @@ func (d *deref) populateStatusAttachments(ctx context.Context, status *gtsmodel.
|
||||||
Blurhash: &a.Blurhash,
|
Blurhash: &a.Blurhash,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("populateStatusAttachments: couldn't get remote media %s: %s", a.RemoteURL, err)
|
log.Errorf(ctx, "couldn't get remote media %s: %s", a.RemoteURL, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
attachment, err := processingMedia.LoadAttachment(ctx)
|
attachment, err := processingMedia.LoadAttachment(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("populateStatusAttachments: couldn't load remote attachment %s: %s", a.RemoteURL, err)
|
log.Errorf(ctx, "couldn't load remote attachment %s: %s", a.RemoteURL, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -45,10 +45,11 @@ const maxIter = 1000
|
||||||
//
|
//
|
||||||
// This does not return error, as for robustness we do not want to error-out on a status because another further up / down has issues.
|
// This does not return error, as for robustness we do not want to error-out on a status because another further up / down has issues.
|
||||||
func (d *deref) DereferenceThread(ctx context.Context, username string, statusIRI *url.URL, status *gtsmodel.Status, statusable ap.Statusable) {
|
func (d *deref) DereferenceThread(ctx context.Context, username string, statusIRI *url.URL, status *gtsmodel.Status, statusable ap.Statusable) {
|
||||||
l := log.WithFields(kv.Fields{
|
l := log.WithContext(ctx).
|
||||||
{"username", username},
|
WithFields(kv.Fields{
|
||||||
{"statusIRI", status.URI},
|
{"username", username},
|
||||||
}...)
|
{"statusIRI", status.URI},
|
||||||
|
}...)
|
||||||
|
|
||||||
// Log function start
|
// Log function start
|
||||||
l.Trace("beginning")
|
l.Trace("beginning")
|
||||||
|
@ -72,10 +73,11 @@ func (d *deref) dereferenceStatusAncestors(ctx context.Context, username string,
|
||||||
ogIRI := status.URI
|
ogIRI := status.URI
|
||||||
|
|
||||||
// Start log entry with fields
|
// Start log entry with fields
|
||||||
l := log.WithFields(kv.Fields{
|
l := log.WithContext(ctx).
|
||||||
{"username", username},
|
WithFields(kv.Fields{
|
||||||
{"statusIRI", ogIRI},
|
{"username", username},
|
||||||
}...)
|
{"statusIRI", ogIRI},
|
||||||
|
}...)
|
||||||
|
|
||||||
// Log function start
|
// Log function start
|
||||||
l.Trace("beginning")
|
l.Trace("beginning")
|
||||||
|
@ -132,10 +134,11 @@ func (d *deref) dereferenceStatusDescendants(ctx context.Context, username strin
|
||||||
ogIRI := statusIRI
|
ogIRI := statusIRI
|
||||||
|
|
||||||
// Start log entry with fields
|
// Start log entry with fields
|
||||||
l := log.WithFields(kv.Fields{
|
l := log.WithContext(ctx).
|
||||||
{"username", username},
|
WithFields(kv.Fields{
|
||||||
{"statusIRI", ogIRI},
|
{"username", username},
|
||||||
}...)
|
{"statusIRI", ogIRI},
|
||||||
|
}...)
|
||||||
|
|
||||||
// Log function start
|
// Log function start
|
||||||
l.Trace("beginning")
|
l.Trace("beginning")
|
||||||
|
|
|
@ -56,7 +56,7 @@ func newFederatingActor(c pub.CommonBehavior, s2s pub.FederatingProtocol, db pub
|
||||||
// method will guaranteed work for non-custom Actors. For custom actors,
|
// method will guaranteed work for non-custom Actors. For custom actors,
|
||||||
// care should be used to not call this method if only C2S is supported.
|
// care should be used to not call this method if only C2S is supported.
|
||||||
func (f *federatingActor) Send(c context.Context, outbox *url.URL, t vocab.Type) (pub.Activity, error) {
|
func (f *federatingActor) Send(c context.Context, outbox *url.URL, t vocab.Type) (pub.Activity, error) {
|
||||||
log.Infof("federating actor: send activity %s via outbox %s", t.GetTypeName(), outbox)
|
log.Infof(c, "send activity %s via outbox %s", t.GetTypeName(), outbox)
|
||||||
return f.actor.Send(c, outbox, t)
|
return f.actor.Send(c, outbox, t)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -53,8 +53,9 @@ func (f *federatingDB) Create(ctx context.Context, asType vocab.Type) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
l := log.WithField("create", i)
|
l := log.WithContext(ctx).
|
||||||
l.Debug("entering Create")
|
WithField("create", i)
|
||||||
|
l.Trace("entering Create")
|
||||||
}
|
}
|
||||||
|
|
||||||
receivingAccount, requestingAccount := extractFromCtx(ctx)
|
receivingAccount, requestingAccount := extractFromCtx(ctx)
|
||||||
|
@ -164,10 +165,11 @@ func (f *federatingDB) activityCreate(ctx context.Context, asType vocab.Type, re
|
||||||
|
|
||||||
// createNote handles a Create activity with a Note type.
|
// createNote handles a Create activity with a Note type.
|
||||||
func (f *federatingDB) createNote(ctx context.Context, note vocab.ActivityStreamsNote, receivingAccount *gtsmodel.Account, requestingAccount *gtsmodel.Account) error {
|
func (f *federatingDB) createNote(ctx context.Context, note vocab.ActivityStreamsNote, receivingAccount *gtsmodel.Account, requestingAccount *gtsmodel.Account) error {
|
||||||
l := log.WithFields(kv.Fields{
|
l := log.WithContext(ctx).
|
||||||
{"receivingAccount", receivingAccount.URI},
|
WithFields(kv.Fields{
|
||||||
{"requestingAccount", requestingAccount.URI},
|
{"receivingAccount", receivingAccount.URI},
|
||||||
}...)
|
{"requestingAccount", requestingAccount.URI},
|
||||||
|
}...)
|
||||||
|
|
||||||
// Check if we have a forward.
|
// Check if we have a forward.
|
||||||
// In other words, was the note posted to our inbox by at least one actor who actually created the note, or are they just forwarding it?
|
// In other words, was the note posted to our inbox by at least one actor who actually created the note, or are they just forwarding it?
|
||||||
|
|
|
@ -35,9 +35,10 @@ import (
|
||||||
//
|
//
|
||||||
// The library makes this call only after acquiring a lock first.
|
// The library makes this call only after acquiring a lock first.
|
||||||
func (f *federatingDB) Delete(ctx context.Context, id *url.URL) error {
|
func (f *federatingDB) Delete(ctx context.Context, id *url.URL) error {
|
||||||
l := log.WithFields(kv.Fields{
|
l := log.WithContext(ctx).
|
||||||
{"id", id},
|
WithFields(kv.Fields{
|
||||||
}...)
|
{"id", id},
|
||||||
|
}...)
|
||||||
l.Debug("entering Delete")
|
l.Debug("entering Delete")
|
||||||
|
|
||||||
receivingAccount, requestingAccount := extractFromCtx(ctx)
|
receivingAccount, requestingAccount := extractFromCtx(ctx)
|
||||||
|
|
|
@ -32,10 +32,11 @@ import (
|
||||||
// The library makes this call only after acquiring a lock first.
|
// The library makes this call only after acquiring a lock first.
|
||||||
//
|
//
|
||||||
// Implementation note: this just straight up isn't implemented, and doesn't *really* need to be either.
|
// Implementation note: this just straight up isn't implemented, and doesn't *really* need to be either.
|
||||||
func (f *federatingDB) Exists(c context.Context, id *url.URL) (exists bool, err error) {
|
func (f *federatingDB) Exists(ctx context.Context, id *url.URL) (exists bool, err error) {
|
||||||
l := log.WithFields(kv.Fields{
|
l := log.WithContext(ctx).
|
||||||
{"id", id},
|
WithFields(kv.Fields{
|
||||||
}...)
|
{"id", id},
|
||||||
|
}...)
|
||||||
l.Debug("entering Exists")
|
l.Debug("entering Exists")
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,9 +18,10 @@ import (
|
||||||
//
|
//
|
||||||
// The library makes this call only after acquiring a lock first.
|
// The library makes this call only after acquiring a lock first.
|
||||||
func (f *federatingDB) Followers(ctx context.Context, actorIRI *url.URL) (followers vocab.ActivityStreamsCollection, err error) {
|
func (f *federatingDB) Followers(ctx context.Context, actorIRI *url.URL) (followers vocab.ActivityStreamsCollection, err error) {
|
||||||
l := log.WithFields(kv.Fields{
|
l := log.WithContext(ctx).
|
||||||
{"id", actorIRI},
|
WithFields(kv.Fields{
|
||||||
}...)
|
{"id", actorIRI},
|
||||||
|
}...)
|
||||||
l.Debug("entering Followers")
|
l.Debug("entering Followers")
|
||||||
|
|
||||||
acct, err := f.getAccountForIRI(ctx, actorIRI)
|
acct, err := f.getAccountForIRI(ctx, actorIRI)
|
||||||
|
|
|
@ -36,9 +36,10 @@ import (
|
||||||
//
|
//
|
||||||
// The library makes this call only after acquiring a lock first.
|
// The library makes this call only after acquiring a lock first.
|
||||||
func (f *federatingDB) Following(ctx context.Context, actorIRI *url.URL) (following vocab.ActivityStreamsCollection, err error) {
|
func (f *federatingDB) Following(ctx context.Context, actorIRI *url.URL) (following vocab.ActivityStreamsCollection, err error) {
|
||||||
l := log.WithFields(kv.Fields{
|
l := log.WithContext(ctx).
|
||||||
{"id", actorIRI},
|
WithFields(kv.Fields{
|
||||||
}...)
|
{"id", actorIRI},
|
||||||
|
}...)
|
||||||
l.Debug("entering Following")
|
l.Debug("entering Following")
|
||||||
|
|
||||||
acct, err := f.getAccountForIRI(ctx, actorIRI)
|
acct, err := f.getAccountForIRI(ctx, actorIRI)
|
||||||
|
|
|
@ -33,7 +33,8 @@ import (
|
||||||
//
|
//
|
||||||
// The library makes this call only after acquiring a lock first.
|
// The library makes this call only after acquiring a lock first.
|
||||||
func (f *federatingDB) Get(ctx context.Context, id *url.URL) (value vocab.Type, err error) {
|
func (f *federatingDB) Get(ctx context.Context, id *url.URL) (value vocab.Type, err error) {
|
||||||
l := log.WithFields(kv.Fields{{"id", id}}...)
|
l := log.WithContext(ctx).
|
||||||
|
WithFields(kv.Fields{{"id", id}}...)
|
||||||
l.Debug("entering Get")
|
l.Debug("entering Get")
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
|
|
|
@ -35,9 +35,10 @@ import (
|
||||||
// the database has an entry for the IRI.
|
// the database has an entry for the IRI.
|
||||||
// The library makes this call only after acquiring a lock first.
|
// The library makes this call only after acquiring a lock first.
|
||||||
func (f *federatingDB) Owns(ctx context.Context, id *url.URL) (bool, error) {
|
func (f *federatingDB) Owns(ctx context.Context, id *url.URL) (bool, error) {
|
||||||
l := log.WithFields(kv.Fields{
|
l := log.WithContext(ctx).
|
||||||
{"id", id},
|
WithFields(kv.Fields{
|
||||||
}...)
|
{"id", id},
|
||||||
|
}...)
|
||||||
l.Debug("entering Owns")
|
l.Debug("entering Owns")
|
||||||
|
|
||||||
// if the id host isn't this instance host, we don't own this IRI
|
// if the id host isn't this instance host, we don't own this IRI
|
||||||
|
|
|
@ -304,7 +304,7 @@ func extractFromCtx(ctx context.Context) (receivingAccount, requestingAccount *g
|
||||||
var ok bool
|
var ok bool
|
||||||
receivingAccount, ok = receivingAccountI.(*gtsmodel.Account)
|
receivingAccount, ok = receivingAccountI.(*gtsmodel.Account)
|
||||||
if !ok {
|
if !ok {
|
||||||
log.Panicf("extractFromCtx: context entry with key %s could not be asserted to *gtsmodel.Account", ap.ContextReceivingAccount)
|
log.Panicf(ctx, "context entry with key %s could not be asserted to *gtsmodel.Account", ap.ContextReceivingAccount)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -313,7 +313,7 @@ func extractFromCtx(ctx context.Context) (receivingAccount, requestingAccount *g
|
||||||
var ok bool
|
var ok bool
|
||||||
requestingAccount, ok = requestingAcctI.(*gtsmodel.Account)
|
requestingAccount, ok = requestingAcctI.(*gtsmodel.Account)
|
||||||
if !ok {
|
if !ok {
|
||||||
log.Panicf("extractFromCtx: context entry with key %s could not be asserted to *gtsmodel.Account", ap.ContextRequestingAccount)
|
log.Panicf(ctx, "context entry with key %s could not be asserted to *gtsmodel.Account", ap.ContextRequestingAccount)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -138,10 +138,11 @@ func (f *federator) PostInboxRequestBodyHook(ctx context.Context, r *http.Reques
|
||||||
// authenticated must be true and error nil. The request will continue
|
// authenticated must be true and error nil. The request will continue
|
||||||
// to be processed.
|
// to be processed.
|
||||||
func (f *federator) AuthenticatePostInbox(ctx context.Context, w http.ResponseWriter, r *http.Request) (context.Context, bool, error) {
|
func (f *federator) AuthenticatePostInbox(ctx context.Context, w http.ResponseWriter, r *http.Request) (context.Context, bool, error) {
|
||||||
l := log.WithFields(kv.Fields{
|
l := log.WithContext(ctx).
|
||||||
{"useragent", r.UserAgent()},
|
WithFields(kv.Fields{
|
||||||
{"url", r.URL.String()},
|
{"useragent", r.UserAgent()},
|
||||||
}...)
|
{"url", r.URL.String()},
|
||||||
|
}...)
|
||||||
l.Trace("received request to authenticate")
|
l.Trace("received request to authenticate")
|
||||||
|
|
||||||
if !uris.IsInboxPath(r.URL) {
|
if !uris.IsInboxPath(r.URL) {
|
||||||
|
@ -242,7 +243,7 @@ func (f *federator) AuthenticatePostInbox(ctx context.Context, w http.ResponseWr
|
||||||
// blocked must be false and error nil. The request will continue
|
// blocked must be false and error nil. The request will continue
|
||||||
// to be processed.
|
// to be processed.
|
||||||
func (f *federator) Blocked(ctx context.Context, actorIRIs []*url.URL) (bool, error) {
|
func (f *federator) Blocked(ctx context.Context, actorIRIs []*url.URL) (bool, error) {
|
||||||
log.Debugf("entering BLOCKED function with IRI list: %+v", actorIRIs)
|
log.Tracef(ctx, "entering BLOCKED function with IRI list: %+v", actorIRIs)
|
||||||
|
|
||||||
// check domain blocks first for the given actor IRIs
|
// check domain blocks first for the given actor IRIs
|
||||||
blocked, err := f.db.AreURIsBlocked(ctx, actorIRIs)
|
blocked, err := f.db.AreURIsBlocked(ctx, actorIRIs)
|
||||||
|
@ -257,7 +258,7 @@ func (f *federator) Blocked(ctx context.Context, actorIRIs []*url.URL) (bool, er
|
||||||
otherInvolvedIRIsI := ctx.Value(ap.ContextOtherInvolvedIRIs)
|
otherInvolvedIRIsI := ctx.Value(ap.ContextOtherInvolvedIRIs)
|
||||||
otherInvolvedIRIs, ok := otherInvolvedIRIsI.([]*url.URL)
|
otherInvolvedIRIs, ok := otherInvolvedIRIsI.([]*url.URL)
|
||||||
if !ok {
|
if !ok {
|
||||||
log.Error("other involved IRIs not set on request context")
|
log.Error(ctx, "other involved IRIs not set on request context")
|
||||||
return false, errors.New("other involved IRIs not set on request context, so couldn't determine blocks")
|
return false, errors.New("other involved IRIs not set on request context, so couldn't determine blocks")
|
||||||
}
|
}
|
||||||
blocked, err = f.db.AreURIsBlocked(ctx, otherInvolvedIRIs)
|
blocked, err = f.db.AreURIsBlocked(ctx, otherInvolvedIRIs)
|
||||||
|
@ -272,13 +273,13 @@ func (f *federator) Blocked(ctx context.Context, actorIRIs []*url.URL) (bool, er
|
||||||
receivingAccountI := ctx.Value(ap.ContextReceivingAccount)
|
receivingAccountI := ctx.Value(ap.ContextReceivingAccount)
|
||||||
receivingAccount, ok := receivingAccountI.(*gtsmodel.Account)
|
receivingAccount, ok := receivingAccountI.(*gtsmodel.Account)
|
||||||
if !ok {
|
if !ok {
|
||||||
log.Error("receiving account not set on request context")
|
log.Error(ctx, "receiving account not set on request context")
|
||||||
return false, errors.New("receiving account not set on request context, so couldn't determine blocks")
|
return false, errors.New("receiving account not set on request context, so couldn't determine blocks")
|
||||||
}
|
}
|
||||||
requestingAccountI := ctx.Value(ap.ContextRequestingAccount)
|
requestingAccountI := ctx.Value(ap.ContextRequestingAccount)
|
||||||
requestingAccount, ok := requestingAccountI.(*gtsmodel.Account)
|
requestingAccount, ok := requestingAccountI.(*gtsmodel.Account)
|
||||||
if !ok {
|
if !ok {
|
||||||
log.Error("requesting account not set on request context")
|
log.Error(ctx, "requesting account not set on request context")
|
||||||
return false, errors.New("requesting account not set on request context, so couldn't determine blocks")
|
return false, errors.New("requesting account not set on request context, so couldn't determine blocks")
|
||||||
}
|
}
|
||||||
// the receiver shouldn't block the sender
|
// the receiver shouldn't block the sender
|
||||||
|
@ -384,10 +385,11 @@ func (f *federator) FederatingCallbacks(ctx context.Context) (wrapped pub.Federa
|
||||||
// type and extension, so the unhandled ones are passed to
|
// type and extension, so the unhandled ones are passed to
|
||||||
// DefaultCallback.
|
// DefaultCallback.
|
||||||
func (f *federator) DefaultCallback(ctx context.Context, activity pub.Activity) error {
|
func (f *federator) DefaultCallback(ctx context.Context, activity pub.Activity) error {
|
||||||
l := log.WithFields(kv.Fields{
|
l := log.WithContext(ctx).
|
||||||
{"aptype", activity.GetTypeName()},
|
WithFields(kv.Fields{
|
||||||
}...)
|
{"aptype", activity.GetTypeName()},
|
||||||
l.Debugf("received unhandle-able activity type so ignoring it")
|
}...)
|
||||||
|
l.Debug("received unhandle-able activity type so ignoring it")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -180,12 +180,13 @@ func (c *Client) Do(req *http.Request) (*http.Response, error) {
|
||||||
|
|
||||||
if !ok {
|
if !ok {
|
||||||
// No spot acquired, log warning
|
// No spot acquired, log warning
|
||||||
log.WithFields(kv.Fields{
|
log.WithContext(req.Context()).
|
||||||
{K: "queue", V: len(wait)},
|
WithFields(kv.Fields{
|
||||||
{K: "method", V: req.Method},
|
{K: "queue", V: len(wait)},
|
||||||
{K: "host", V: req.Host},
|
{K: "method", V: req.Method},
|
||||||
{K: "uri", V: req.URL.RequestURI()},
|
{K: "host", V: req.Host},
|
||||||
}...).Warn("full request queue")
|
{K: "uri", V: req.URL.RequestURI()},
|
||||||
|
}...).Warn("full request queue")
|
||||||
|
|
||||||
select {
|
select {
|
||||||
case <-req.Context().Done():
|
case <-req.Context().Done():
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
package log
|
package log
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
|
@ -27,91 +28,97 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type Entry struct {
|
type Entry struct {
|
||||||
fields []kv.Field
|
ctx context.Context
|
||||||
|
kvs []kv.Field
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e Entry) WithField(key string, value interface{}) Entry {
|
func (e Entry) WithContext(ctx context.Context) Entry {
|
||||||
e.fields = append(e.fields, kv.Field{K: key, V: value})
|
e.ctx = ctx
|
||||||
return e
|
return e
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e Entry) WithFields(fields ...kv.Field) Entry {
|
func (e Entry) WithField(key string, value interface{}) Entry {
|
||||||
e.fields = append(e.fields, fields...)
|
e.kvs = append(e.kvs, kv.Field{K: key, V: value})
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e Entry) WithFields(kvs ...kv.Field) Entry {
|
||||||
|
e.kvs = append(e.kvs, kvs...)
|
||||||
return e
|
return e
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e Entry) Trace(a ...interface{}) {
|
func (e Entry) Trace(a ...interface{}) {
|
||||||
logf(3, level.TRACE, e.fields, args(len(a)), a...)
|
logf(e.ctx, 3, level.TRACE, e.kvs, args(len(a)), a...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e Entry) Tracef(s string, a ...interface{}) {
|
func (e Entry) Tracef(s string, a ...interface{}) {
|
||||||
logf(3, level.TRACE, e.fields, s, a...)
|
logf(e.ctx, 3, level.TRACE, e.kvs, s, a...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e Entry) Debug(a ...interface{}) {
|
func (e Entry) Debug(a ...interface{}) {
|
||||||
logf(3, level.DEBUG, e.fields, args(len(a)), a...)
|
logf(e.ctx, 3, level.DEBUG, e.kvs, args(len(a)), a...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e Entry) Debugf(s string, a ...interface{}) {
|
func (e Entry) Debugf(s string, a ...interface{}) {
|
||||||
logf(3, level.DEBUG, e.fields, s, a...)
|
logf(e.ctx, 3, level.DEBUG, e.kvs, s, a...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e Entry) Info(a ...interface{}) {
|
func (e Entry) Info(a ...interface{}) {
|
||||||
logf(3, level.INFO, e.fields, args(len(a)), a...)
|
logf(e.ctx, 3, level.INFO, e.kvs, args(len(a)), a...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e Entry) Infof(s string, a ...interface{}) {
|
func (e Entry) Infof(s string, a ...interface{}) {
|
||||||
logf(3, level.INFO, e.fields, s, a...)
|
logf(e.ctx, 3, level.INFO, e.kvs, s, a...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e Entry) Warn(a ...interface{}) {
|
func (e Entry) Warn(a ...interface{}) {
|
||||||
logf(3, level.WARN, e.fields, args(len(a)), a...)
|
logf(e.ctx, 3, level.WARN, e.kvs, args(len(a)), a...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e Entry) Warnf(s string, a ...interface{}) {
|
func (e Entry) Warnf(s string, a ...interface{}) {
|
||||||
logf(3, level.WARN, e.fields, s, a...)
|
logf(e.ctx, 3, level.WARN, e.kvs, s, a...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e Entry) Error(a ...interface{}) {
|
func (e Entry) Error(a ...interface{}) {
|
||||||
logf(3, level.ERROR, e.fields, args(len(a)), a...)
|
logf(e.ctx, 3, level.ERROR, e.kvs, args(len(a)), a...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e Entry) Errorf(s string, a ...interface{}) {
|
func (e Entry) Errorf(s string, a ...interface{}) {
|
||||||
logf(3, level.ERROR, e.fields, s, a...)
|
logf(e.ctx, 3, level.ERROR, e.kvs, s, a...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e Entry) Fatal(a ...interface{}) {
|
func (e Entry) Fatal(a ...interface{}) {
|
||||||
defer syscall.Exit(1)
|
defer syscall.Exit(1)
|
||||||
logf(3, level.FATAL, e.fields, args(len(a)), a...)
|
logf(e.ctx, 3, level.FATAL, e.kvs, args(len(a)), a...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e Entry) Fatalf(s string, a ...interface{}) {
|
func (e Entry) Fatalf(s string, a ...interface{}) {
|
||||||
defer syscall.Exit(1)
|
defer syscall.Exit(1)
|
||||||
logf(3, level.FATAL, e.fields, s, a...)
|
logf(e.ctx, 3, level.FATAL, e.kvs, s, a...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e Entry) Panic(a ...interface{}) {
|
func (e Entry) Panic(a ...interface{}) {
|
||||||
defer panic(fmt.Sprint(a...))
|
defer panic(fmt.Sprint(a...))
|
||||||
logf(3, level.PANIC, e.fields, args(len(a)), a...)
|
logf(e.ctx, 3, level.PANIC, e.kvs, args(len(a)), a...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e Entry) Panicf(s string, a ...interface{}) {
|
func (e Entry) Panicf(s string, a ...interface{}) {
|
||||||
defer panic(fmt.Sprintf(s, a...))
|
defer panic(fmt.Sprintf(s, a...))
|
||||||
logf(3, level.PANIC, e.fields, s, a...)
|
logf(e.ctx, 3, level.PANIC, e.kvs, s, a...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e Entry) Log(lvl level.LEVEL, a ...interface{}) {
|
func (e Entry) Log(lvl level.LEVEL, a ...interface{}) {
|
||||||
logf(3, lvl, e.fields, args(len(a)), a...)
|
logf(e.ctx, 3, lvl, e.kvs, args(len(a)), a...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e Entry) Logf(lvl level.LEVEL, s string, a ...interface{}) {
|
func (e Entry) Logf(lvl level.LEVEL, s string, a ...interface{}) {
|
||||||
logf(3, lvl, e.fields, s, a...)
|
logf(e.ctx, 3, lvl, e.kvs, s, a...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e Entry) Print(a ...interface{}) {
|
func (e Entry) Print(a ...interface{}) {
|
||||||
printf(3, e.fields, args(len(a)), a...)
|
printf(3, e.kvs, args(len(a)), a...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e Entry) Printf(s string, a ...interface{}) {
|
func (e Entry) Printf(s string, a ...interface{}) {
|
||||||
printf(3, e.fields, s, a...)
|
printf(3, e.kvs, s, a...)
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
package log
|
package log
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log/syslog"
|
"log/syslog"
|
||||||
"os"
|
"os"
|
||||||
|
@ -38,13 +39,21 @@ var (
|
||||||
// lvlstrs is the lookup table of log levels to strings.
|
// lvlstrs is the lookup table of log levels to strings.
|
||||||
lvlstrs = level.Default()
|
lvlstrs = level.Default()
|
||||||
|
|
||||||
// Syslog output, only set if enabled.
|
// syslog output, only set if enabled.
|
||||||
sysout *syslog.Writer
|
sysout *syslog.Writer
|
||||||
|
|
||||||
// timefmt is the logging time format used.
|
// timefmt is the logging time format used.
|
||||||
timefmt = "02/01/2006 15:04:05.000"
|
timefmt = "02/01/2006 15:04:05.000"
|
||||||
|
|
||||||
|
// ctxhooks allows modifying log content based on context.
|
||||||
|
ctxhooks []func(context.Context, []kv.Field) []kv.Field
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Hook adds the given hook to the global logger context hooks stack.
|
||||||
|
func Hook(hook func(ctx context.Context, kvs []kv.Field) []kv.Field) {
|
||||||
|
ctxhooks = append(ctxhooks, hook)
|
||||||
|
}
|
||||||
|
|
||||||
// Level returns the currently set log level.
|
// Level returns the currently set log level.
|
||||||
func Level() level.LEVEL {
|
func Level() level.LEVEL {
|
||||||
return level.LEVEL(loglvl.Load())
|
return level.LEVEL(loglvl.Load())
|
||||||
|
@ -60,82 +69,86 @@ func New() Entry {
|
||||||
return Entry{}
|
return Entry{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func WithContext(ctx context.Context) Entry {
|
||||||
|
return Entry{ctx: ctx}
|
||||||
|
}
|
||||||
|
|
||||||
func WithField(key string, value interface{}) Entry {
|
func WithField(key string, value interface{}) Entry {
|
||||||
return Entry{fields: []kv.Field{{K: key, V: value}}}
|
return New().WithField(key, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
func WithFields(fields ...kv.Field) Entry {
|
func WithFields(fields ...kv.Field) Entry {
|
||||||
return Entry{fields: fields}
|
return New().WithFields(fields...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Trace(a ...interface{}) {
|
func Trace(ctx context.Context, a ...interface{}) {
|
||||||
logf(3, level.TRACE, nil, args(len(a)), a...)
|
logf(ctx, 3, level.TRACE, nil, args(len(a)), a...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Tracef(s string, a ...interface{}) {
|
func Tracef(ctx context.Context, s string, a ...interface{}) {
|
||||||
logf(3, level.TRACE, nil, s, a...)
|
logf(ctx, 3, level.TRACE, nil, s, a...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Debug(a ...interface{}) {
|
func Debug(ctx context.Context, a ...interface{}) {
|
||||||
logf(3, level.DEBUG, nil, args(len(a)), a...)
|
logf(ctx, 3, level.DEBUG, nil, args(len(a)), a...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Debugf(s string, a ...interface{}) {
|
func Debugf(ctx context.Context, s string, a ...interface{}) {
|
||||||
logf(3, level.DEBUG, nil, s, a...)
|
logf(ctx, 3, level.DEBUG, nil, s, a...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Info(a ...interface{}) {
|
func Info(ctx context.Context, a ...interface{}) {
|
||||||
logf(3, level.INFO, nil, args(len(a)), a...)
|
logf(ctx, 3, level.INFO, nil, args(len(a)), a...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Infof(s string, a ...interface{}) {
|
func Infof(ctx context.Context, s string, a ...interface{}) {
|
||||||
logf(3, level.INFO, nil, s, a...)
|
logf(ctx, 3, level.INFO, nil, s, a...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Warn(a ...interface{}) {
|
func Warn(ctx context.Context, a ...interface{}) {
|
||||||
logf(3, level.WARN, nil, args(len(a)), a...)
|
logf(ctx, 3, level.WARN, nil, args(len(a)), a...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Warnf(s string, a ...interface{}) {
|
func Warnf(ctx context.Context, s string, a ...interface{}) {
|
||||||
logf(3, level.WARN, nil, s, a...)
|
logf(ctx, 3, level.WARN, nil, s, a...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Error(a ...interface{}) {
|
func Error(ctx context.Context, a ...interface{}) {
|
||||||
logf(3, level.ERROR, nil, args(len(a)), a...)
|
logf(ctx, 3, level.ERROR, nil, args(len(a)), a...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Errorf(s string, a ...interface{}) {
|
func Errorf(ctx context.Context, s string, a ...interface{}) {
|
||||||
logf(3, level.ERROR, nil, s, a...)
|
logf(ctx, 3, level.ERROR, nil, s, a...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Fatal(a ...interface{}) {
|
func Fatal(ctx context.Context, a ...interface{}) {
|
||||||
defer syscall.Exit(1)
|
defer syscall.Exit(1)
|
||||||
logf(3, level.FATAL, nil, args(len(a)), a...)
|
logf(ctx, 3, level.FATAL, nil, args(len(a)), a...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Fatalf(s string, a ...interface{}) {
|
func Fatalf(ctx context.Context, s string, a ...interface{}) {
|
||||||
defer syscall.Exit(1)
|
defer syscall.Exit(1)
|
||||||
logf(3, level.FATAL, nil, s, a...)
|
logf(ctx, 3, level.FATAL, nil, s, a...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Panic(a ...interface{}) {
|
func Panic(ctx context.Context, a ...interface{}) {
|
||||||
defer panic(fmt.Sprint(a...))
|
defer panic(fmt.Sprint(a...))
|
||||||
logf(3, level.PANIC, nil, args(len(a)), a...)
|
logf(ctx, 3, level.PANIC, nil, args(len(a)), a...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Panicf(s string, a ...interface{}) {
|
func Panicf(ctx context.Context, s string, a ...interface{}) {
|
||||||
defer panic(fmt.Sprintf(s, a...))
|
defer panic(fmt.Sprintf(s, a...))
|
||||||
logf(3, level.PANIC, nil, s, a...)
|
logf(ctx, 3, level.PANIC, nil, s, a...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Log will log formatted args as 'msg' field to the log at given level.
|
// Log will log formatted args as 'msg' field to the log at given level.
|
||||||
func Log(lvl level.LEVEL, a ...interface{}) {
|
func Log(ctx context.Context, lvl level.LEVEL, a ...interface{}) {
|
||||||
logf(3, lvl, nil, args(len(a)), a...)
|
logf(ctx, 3, lvl, nil, args(len(a)), a...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Logf will log format string as 'msg' field to the log at given level.
|
// Logf will log format string as 'msg' field to the log at given level.
|
||||||
func Logf(lvl level.LEVEL, s string, a ...interface{}) {
|
func Logf(ctx context.Context, lvl level.LEVEL, s string, a ...interface{}) {
|
||||||
logf(3, lvl, nil, s, a...)
|
logf(ctx, 3, lvl, nil, s, a...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Print will log formatted args to the stdout log output.
|
// Print will log formatted args to the stdout log output.
|
||||||
|
@ -186,7 +199,7 @@ func printf(depth int, fields []kv.Field, s string, a ...interface{}) {
|
||||||
putBuf(buf)
|
putBuf(buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
func logf(depth int, lvl level.LEVEL, fields []kv.Field, s string, a ...interface{}) {
|
func logf(ctx context.Context, depth int, lvl level.LEVEL, fields []kv.Field, s string, a ...interface{}) {
|
||||||
var out *os.File
|
var out *os.File
|
||||||
|
|
||||||
// Check if enabled.
|
// Check if enabled.
|
||||||
|
@ -220,6 +233,13 @@ func logf(depth int, lvl level.LEVEL, fields []kv.Field, s string, a ...interfac
|
||||||
buf.B = append(buf.B, lvlstrs[lvl]...)
|
buf.B = append(buf.B, lvlstrs[lvl]...)
|
||||||
buf.B = append(buf.B, ' ')
|
buf.B = append(buf.B, ' ')
|
||||||
|
|
||||||
|
if ctx != nil {
|
||||||
|
// Pass context through hooks.
|
||||||
|
for _, hook := range ctxhooks {
|
||||||
|
fields = hook(ctx, fields)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Append formatted fields with msg
|
// Append formatted fields with msg
|
||||||
kv.Fields(append(fields, kv.Field{
|
kv.Fields(append(fields, kv.Field{
|
||||||
K: "msg", V: fmt.Sprintf(s, a...),
|
K: "msg", V: fmt.Sprintf(s, a...),
|
||||||
|
|
|
@ -66,14 +66,14 @@ func (suite *SyslogTestSuite) TearDownTest() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (suite *SyslogTestSuite) TestSyslog() {
|
func (suite *SyslogTestSuite) TestSyslog() {
|
||||||
log.Info("this is a test of the emergency broadcast system!")
|
log.Info(nil, "this is a test of the emergency broadcast system!")
|
||||||
|
|
||||||
entry := <-suite.syslogChannel
|
entry := <-suite.syslogChannel
|
||||||
suite.Regexp(regexp.MustCompile(`timestamp=.* func=.* level=INFO msg="this is a test of the emergency broadcast system!"`), entry["content"])
|
suite.Regexp(regexp.MustCompile(`timestamp=.* func=.* level=INFO msg="this is a test of the emergency broadcast system!"`), entry["content"])
|
||||||
}
|
}
|
||||||
|
|
||||||
func (suite *SyslogTestSuite) TestSyslogLongMessage() {
|
func (suite *SyslogTestSuite) TestSyslogLongMessage() {
|
||||||
log.Warn(longMessage)
|
log.Warn(nil, longMessage)
|
||||||
|
|
||||||
funcName := log.Caller(2)
|
funcName := log.Caller(2)
|
||||||
prefix := fmt.Sprintf(`timestamp="02/01/2006 15:04:05.000" func=%s level=WARN msg="`, funcName)
|
prefix := fmt.Sprintf(`timestamp="02/01/2006 15:04:05.000" func=%s level=WARN msg="`, funcName)
|
||||||
|
@ -104,7 +104,7 @@ func (suite *SyslogTestSuite) TestSyslogLongMessageUnixgram() {
|
||||||
|
|
||||||
testrig.InitTestLog()
|
testrig.InitTestLog()
|
||||||
|
|
||||||
log.Warn(longMessage)
|
log.Warn(nil, longMessage)
|
||||||
|
|
||||||
funcName := log.Caller(2)
|
funcName := log.Caller(2)
|
||||||
prefix := fmt.Sprintf(`timestamp="02/01/2006 15:04:05.000" func=%s level=WARN msg="`, funcName)
|
prefix := fmt.Sprintf(`timestamp="02/01/2006 15:04:05.000" func=%s level=WARN msg="`, funcName)
|
||||||
|
|
|
@ -454,8 +454,8 @@ func scheduleCleanupJobs(m *manager) {
|
||||||
m.state.Workers.Scheduler.Schedule(sched.NewJob(func(now time.Time) {
|
m.state.Workers.Scheduler.Schedule(sched.NewJob(func(now time.Time) {
|
||||||
err := m.PruneAll(doneCtx, config.GetMediaRemoteCacheDays(), true)
|
err := m.PruneAll(doneCtx, config.GetMediaRemoteCacheDays(), true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("error during prune: %v", err)
|
log.Errorf(nil, "error during prune: %v", err)
|
||||||
}
|
}
|
||||||
log.Infof("finished pruning all in %s", time.Since(now))
|
log.Infof(nil, "finished pruning all in %s", time.Since(now))
|
||||||
}).EveryAt(midnight, day))
|
}).EveryAt(midnight, day))
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,7 +67,7 @@ func (p *ProcessingEmoji) LoadEmoji(ctx context.Context) (*gtsmodel.Emoji, error
|
||||||
if !done {
|
if !done {
|
||||||
// Provided context was cancelled, e.g. request cancelled
|
// Provided context was cancelled, e.g. request cancelled
|
||||||
// early. Queue this item for asynchronous processing.
|
// early. Queue this item for asynchronous processing.
|
||||||
log.Warnf("reprocessing emoji %s after canceled ctx", p.emoji.ID)
|
log.Warnf(ctx, "reprocessing emoji %s after canceled ctx", p.emoji.ID)
|
||||||
go p.mgr.state.Workers.Media.Enqueue(p.Process)
|
go p.mgr.state.Workers.Media.Enqueue(p.Process)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,7 +77,7 @@ func (p *ProcessingEmoji) LoadEmoji(ctx context.Context) (*gtsmodel.Emoji, error
|
||||||
// Process allows the receiving object to fit the runners.WorkerFunc signature. It performs a (blocking) load and logs on error.
|
// Process allows the receiving object to fit the runners.WorkerFunc signature. It performs a (blocking) load and logs on error.
|
||||||
func (p *ProcessingEmoji) Process(ctx context.Context) {
|
func (p *ProcessingEmoji) Process(ctx context.Context) {
|
||||||
if _, _, err := p.load(ctx); err != nil {
|
if _, _, err := p.load(ctx); err != nil {
|
||||||
log.Errorf("error processing emoji: %v", err)
|
log.Errorf(ctx, "error processing emoji: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -167,7 +167,7 @@ func (p *ProcessingEmoji) store(ctx context.Context) error {
|
||||||
|
|
||||||
// Ensure post callback gets called.
|
// Ensure post callback gets called.
|
||||||
if err := p.postFn(ctx); err != nil {
|
if err := p.postFn(ctx); err != nil {
|
||||||
log.Errorf("error executing postdata function: %v", err)
|
log.Errorf(ctx, "error executing postdata function: %v", err)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
@ -180,7 +180,7 @@ func (p *ProcessingEmoji) store(ctx context.Context) error {
|
||||||
defer func() {
|
defer func() {
|
||||||
// Ensure data reader gets closed on return.
|
// Ensure data reader gets closed on return.
|
||||||
if err := rc.Close(); err != nil {
|
if err := rc.Close(); err != nil {
|
||||||
log.Errorf("error closing data reader: %v", err)
|
log.Errorf(ctx, "error closing data reader: %v", err)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
@ -251,7 +251,7 @@ func (p *ProcessingEmoji) store(ctx context.Context) error {
|
||||||
|
|
||||||
// This shouldn't already exist, but we do a check as it's worth logging.
|
// This shouldn't already exist, but we do a check as it's worth logging.
|
||||||
if have, _ := p.mgr.state.Storage.Has(ctx, p.emoji.ImagePath); have {
|
if have, _ := p.mgr.state.Storage.Has(ctx, p.emoji.ImagePath); have {
|
||||||
log.Warnf("emoji already exists at storage path: %s", p.emoji.ImagePath)
|
log.Warnf(ctx, "emoji already exists at storage path: %s", p.emoji.ImagePath)
|
||||||
|
|
||||||
// Attempt to remove existing emoji at storage path (might be broken / out-of-date)
|
// Attempt to remove existing emoji at storage path (might be broken / out-of-date)
|
||||||
if err := p.mgr.state.Storage.Delete(ctx, p.emoji.ImagePath); err != nil {
|
if err := p.mgr.state.Storage.Delete(ctx, p.emoji.ImagePath); err != nil {
|
||||||
|
@ -267,8 +267,9 @@ func (p *ProcessingEmoji) store(ctx context.Context) error {
|
||||||
|
|
||||||
// Once again check size in case none was provided previously.
|
// Once again check size in case none was provided previously.
|
||||||
if size := bytesize.Size(sz); size > maxSize {
|
if size := bytesize.Size(sz); size > maxSize {
|
||||||
|
|
||||||
if err := p.mgr.state.Storage.Delete(ctx, p.emoji.ImagePath); err != nil {
|
if err := p.mgr.state.Storage.Delete(ctx, p.emoji.ImagePath); err != nil {
|
||||||
log.Errorf("error removing too-large-emoji from storage: %v", err)
|
log.Errorf(ctx, "error removing too-large-emoji from storage: %v", err)
|
||||||
}
|
}
|
||||||
return fmt.Errorf("calculated emoji size %s greater than max allowed %s", size, maxSize)
|
return fmt.Errorf("calculated emoji size %s greater than max allowed %s", size, maxSize)
|
||||||
}
|
}
|
||||||
|
@ -308,8 +309,7 @@ func (p *ProcessingEmoji) finish(ctx context.Context) error {
|
||||||
|
|
||||||
// This shouldn't already exist, but we do a check as it's worth logging.
|
// This shouldn't already exist, but we do a check as it's worth logging.
|
||||||
if have, _ := p.mgr.state.Storage.Has(ctx, p.emoji.ImageStaticPath); have {
|
if have, _ := p.mgr.state.Storage.Has(ctx, p.emoji.ImageStaticPath); have {
|
||||||
log.Warnf("static emoji already exists at storage path: %s", p.emoji.ImagePath)
|
log.Warnf(ctx, "static emoji already exists at storage path: %s", p.emoji.ImagePath)
|
||||||
|
|
||||||
// Attempt to remove static existing emoji at storage path (might be broken / out-of-date)
|
// Attempt to remove static existing emoji at storage path (might be broken / out-of-date)
|
||||||
if err := p.mgr.state.Storage.Delete(ctx, p.emoji.ImageStaticPath); err != nil {
|
if err := p.mgr.state.Storage.Delete(ctx, p.emoji.ImageStaticPath); err != nil {
|
||||||
return fmt.Errorf("error removing static emoji from storage: %v", err)
|
return fmt.Errorf("error removing static emoji from storage: %v", err)
|
||||||
|
|
|
@ -67,7 +67,7 @@ func (p *ProcessingMedia) LoadAttachment(ctx context.Context) (*gtsmodel.MediaAt
|
||||||
if !done {
|
if !done {
|
||||||
// Provided context was cancelled, e.g. request cancelled
|
// Provided context was cancelled, e.g. request cancelled
|
||||||
// early. Queue this item for asynchronous processing.
|
// early. Queue this item for asynchronous processing.
|
||||||
log.Warnf("reprocessing media %s after canceled ctx", p.media.ID)
|
log.Warnf(ctx, "reprocessing media %s after canceled ctx", p.media.ID)
|
||||||
go p.mgr.state.Workers.Media.Enqueue(p.Process)
|
go p.mgr.state.Workers.Media.Enqueue(p.Process)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,7 +77,7 @@ func (p *ProcessingMedia) LoadAttachment(ctx context.Context) (*gtsmodel.MediaAt
|
||||||
// Process allows the receiving object to fit the runners.WorkerFunc signature. It performs a (blocking) load and logs on error.
|
// Process allows the receiving object to fit the runners.WorkerFunc signature. It performs a (blocking) load and logs on error.
|
||||||
func (p *ProcessingMedia) Process(ctx context.Context) {
|
func (p *ProcessingMedia) Process(ctx context.Context) {
|
||||||
if _, _, err := p.load(ctx); err != nil {
|
if _, _, err := p.load(ctx); err != nil {
|
||||||
log.Errorf("error processing media: %v", err)
|
log.Errorf(ctx, "error processing media: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -151,7 +151,7 @@ func (p *ProcessingMedia) store(ctx context.Context) error {
|
||||||
|
|
||||||
// ensure post callback gets called.
|
// ensure post callback gets called.
|
||||||
if err := p.postFn(ctx); err != nil {
|
if err := p.postFn(ctx); err != nil {
|
||||||
log.Errorf("error executing postdata function: %v", err)
|
log.Errorf(ctx, "error executing postdata function: %v", err)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
@ -164,7 +164,7 @@ func (p *ProcessingMedia) store(ctx context.Context) error {
|
||||||
defer func() {
|
defer func() {
|
||||||
// Ensure data reader gets closed on return.
|
// Ensure data reader gets closed on return.
|
||||||
if err := rc.Close(); err != nil {
|
if err := rc.Close(); err != nil {
|
||||||
log.Errorf("error closing data reader: %v", err)
|
log.Errorf(ctx, "error closing data reader: %v", err)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
@ -220,7 +220,7 @@ func (p *ProcessingMedia) store(ctx context.Context) error {
|
||||||
|
|
||||||
// This shouldn't already exist, but we do a check as it's worth logging.
|
// This shouldn't already exist, but we do a check as it's worth logging.
|
||||||
if have, _ := p.mgr.state.Storage.Has(ctx, p.media.File.Path); have {
|
if have, _ := p.mgr.state.Storage.Has(ctx, p.media.File.Path); have {
|
||||||
log.Warnf("media already exists at storage path: %s", p.media.File.Path)
|
log.Warnf(ctx, "media already exists at storage path: %s", p.media.File.Path)
|
||||||
|
|
||||||
// Attempt to remove existing media at storage path (might be broken / out-of-date)
|
// Attempt to remove existing media at storage path (might be broken / out-of-date)
|
||||||
if err := p.mgr.state.Storage.Delete(ctx, p.media.File.Path); err != nil {
|
if err := p.mgr.state.Storage.Delete(ctx, p.media.File.Path); err != nil {
|
||||||
|
@ -333,7 +333,7 @@ func (p *ProcessingMedia) finish(ctx context.Context) error {
|
||||||
|
|
||||||
// This shouldn't already exist, but we do a check as it's worth logging.
|
// This shouldn't already exist, but we do a check as it's worth logging.
|
||||||
if have, _ := p.mgr.state.Storage.Has(ctx, p.media.Thumbnail.Path); have {
|
if have, _ := p.mgr.state.Storage.Has(ctx, p.media.Thumbnail.Path); have {
|
||||||
log.Warnf("thumbnail already exists at storage path: %s", p.media.Thumbnail.Path)
|
log.Warnf(ctx, "thumbnail already exists at storage path: %s", p.media.Thumbnail.Path)
|
||||||
|
|
||||||
// Attempt to remove existing thumbnail at storage path (might be broken / out-of-date)
|
// Attempt to remove existing thumbnail at storage path (might be broken / out-of-date)
|
||||||
if err := p.mgr.state.Storage.Delete(ctx, p.media.Thumbnail.Path); err != nil {
|
if err := p.mgr.state.Storage.Delete(ctx, p.media.Thumbnail.Path); err != nil {
|
||||||
|
|
|
@ -48,34 +48,34 @@ func (m *manager) PruneAll(ctx context.Context, mediaCacheRemoteDays int, blocki
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errs = append(errs, fmt.Sprintf("error pruning unused local media (%s)", err))
|
errs = append(errs, fmt.Sprintf("error pruning unused local media (%s)", err))
|
||||||
} else {
|
} else {
|
||||||
log.Infof("pruned %d unused local media", pruned)
|
log.Infof(ctx, "pruned %d unused local media", pruned)
|
||||||
}
|
}
|
||||||
|
|
||||||
pruned, err = m.PruneUnusedRemote(innerCtx, dry)
|
pruned, err = m.PruneUnusedRemote(innerCtx, dry)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errs = append(errs, fmt.Sprintf("error pruning unused remote media: (%s)", err))
|
errs = append(errs, fmt.Sprintf("error pruning unused remote media: (%s)", err))
|
||||||
} else {
|
} else {
|
||||||
log.Infof("pruned %d unused remote media", pruned)
|
log.Infof(ctx, "pruned %d unused remote media", pruned)
|
||||||
}
|
}
|
||||||
|
|
||||||
pruned, err = m.UncacheRemote(innerCtx, mediaCacheRemoteDays, dry)
|
pruned, err = m.UncacheRemote(innerCtx, mediaCacheRemoteDays, dry)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errs = append(errs, fmt.Sprintf("error uncacheing remote media older than %d day(s): (%s)", mediaCacheRemoteDays, err))
|
errs = append(errs, fmt.Sprintf("error uncacheing remote media older than %d day(s): (%s)", mediaCacheRemoteDays, err))
|
||||||
} else {
|
} else {
|
||||||
log.Infof("uncached %d remote media older than %d day(s)", pruned, mediaCacheRemoteDays)
|
log.Infof(ctx, "uncached %d remote media older than %d day(s)", pruned, mediaCacheRemoteDays)
|
||||||
}
|
}
|
||||||
|
|
||||||
pruned, err = m.PruneOrphaned(innerCtx, dry)
|
pruned, err = m.PruneOrphaned(innerCtx, dry)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errs = append(errs, fmt.Sprintf("error pruning orphaned media: (%s)", err))
|
errs = append(errs, fmt.Sprintf("error pruning orphaned media: (%s)", err))
|
||||||
} else {
|
} else {
|
||||||
log.Infof("pruned %d orphaned media", pruned)
|
log.Infof(ctx, "pruned %d orphaned media", pruned)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := m.state.Storage.Storage.Clean(innerCtx); err != nil {
|
if err := m.state.Storage.Storage.Clean(innerCtx); err != nil {
|
||||||
errs = append(errs, fmt.Sprintf("error cleaning storage: (%s)", err))
|
errs = append(errs, fmt.Sprintf("error cleaning storage: (%s)", err))
|
||||||
} else {
|
} else {
|
||||||
log.Info("cleaned storage")
|
log.Info(ctx, "cleaned storage")
|
||||||
}
|
}
|
||||||
|
|
||||||
return errs.Combine()
|
return errs.Combine()
|
||||||
|
@ -87,7 +87,7 @@ func (m *manager) PruneAll(ctx context.Context, mediaCacheRemoteDays int, blocki
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
if err := f(context.Background()); err != nil {
|
if err := f(context.Background()); err != nil {
|
||||||
log.Error(err)
|
log.Error(ctx, err)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
|
|
@ -51,7 +51,7 @@ func (m *manager) RefetchEmojis(ctx context.Context, domain string, dereferenceM
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if !errors.Is(err, db.ErrNoEntries) {
|
if !errors.Is(err, db.ErrNoEntries) {
|
||||||
// an actual error has occurred
|
// an actual error has occurred
|
||||||
log.Errorf("error fetching emojis from database: %s", err)
|
log.Errorf(ctx, "error fetching emojis from database: %s", err)
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
@ -79,10 +79,10 @@ func (m *manager) RefetchEmojis(ctx context.Context, domain string, dereferenceM
|
||||||
// bail early if we've got nothing to do
|
// bail early if we've got nothing to do
|
||||||
toRefetchCount := len(refetchIDs)
|
toRefetchCount := len(refetchIDs)
|
||||||
if toRefetchCount == 0 {
|
if toRefetchCount == 0 {
|
||||||
log.Debug("no remote emojis require a refetch")
|
log.Debug(ctx, "no remote emojis require a refetch")
|
||||||
return 0, nil
|
return 0, nil
|
||||||
}
|
}
|
||||||
log.Debugf("%d remote emoji(s) require a refetch, doing that now...", toRefetchCount)
|
log.Debugf(ctx, "%d remote emoji(s) require a refetch, doing that now...", toRefetchCount)
|
||||||
|
|
||||||
var totalRefetched int
|
var totalRefetched int
|
||||||
for _, emojiID := range refetchIDs {
|
for _, emojiID := range refetchIDs {
|
||||||
|
@ -94,13 +94,13 @@ func (m *manager) RefetchEmojis(ctx context.Context, domain string, dereferenceM
|
||||||
shortcodeDomain := util.ShortcodeDomain(emoji)
|
shortcodeDomain := util.ShortcodeDomain(emoji)
|
||||||
|
|
||||||
if emoji.ImageRemoteURL == "" {
|
if emoji.ImageRemoteURL == "" {
|
||||||
log.Errorf("remote emoji %s could not be refreshed because it has no ImageRemoteURL set", shortcodeDomain)
|
log.Errorf(ctx, "remote emoji %s could not be refreshed because it has no ImageRemoteURL set", shortcodeDomain)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
emojiImageIRI, err := url.Parse(emoji.ImageRemoteURL)
|
emojiImageIRI, err := url.Parse(emoji.ImageRemoteURL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("remote emoji %s could not be refreshed because its ImageRemoteURL (%s) is not a valid uri: %s", shortcodeDomain, emoji.ImageRemoteURL, err)
|
log.Errorf(ctx, "remote emoji %s could not be refreshed because its ImageRemoteURL (%s) is not a valid uri: %s", shortcodeDomain, emoji.ImageRemoteURL, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -116,16 +116,16 @@ func (m *manager) RefetchEmojis(ctx context.Context, domain string, dereferenceM
|
||||||
VisibleInPicker: emoji.VisibleInPicker,
|
VisibleInPicker: emoji.VisibleInPicker,
|
||||||
}, true)
|
}, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("emoji %s could not be refreshed because of an error during processing: %s", shortcodeDomain, err)
|
log.Errorf(ctx, "emoji %s could not be refreshed because of an error during processing: %s", shortcodeDomain, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := processingEmoji.LoadEmoji(ctx); err != nil {
|
if _, err := processingEmoji.LoadEmoji(ctx); err != nil {
|
||||||
log.Errorf("emoji %s could not be refreshed because of an error during loading: %s", shortcodeDomain, err)
|
log.Errorf(ctx, "emoji %s could not be refreshed because of an error during loading: %s", shortcodeDomain, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Tracef("refetched emoji %s successfully from remote", shortcodeDomain)
|
log.Tracef(ctx, "refetched emoji %s successfully from remote", shortcodeDomain)
|
||||||
totalRefetched++
|
totalRefetched++
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -44,7 +44,7 @@ func decodeVideoFrame(r io.Reader) (*gtsVideo, error) {
|
||||||
}
|
}
|
||||||
defer func() {
|
defer func() {
|
||||||
if err := tfs.Close(); err != nil {
|
if err := tfs.Close(); err != nil {
|
||||||
log.Errorf("error closing temp file seeker: %s", err)
|
log.Errorf(nil, "error closing temp file seeker: %s", err)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,111 @@
|
||||||
|
/*
|
||||||
|
GoToSocial
|
||||||
|
Copyright (C) 2021-2023 GoToSocial Authors admin@gotosocial.org
|
||||||
|
|
||||||
|
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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package middleware
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"context"
|
||||||
|
"crypto/rand"
|
||||||
|
"encoding/base32"
|
||||||
|
"encoding/binary"
|
||||||
|
"io"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"codeberg.org/gruf/go-kv"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/superseriousbusiness/gotosocial/internal/log"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ctxType string
|
||||||
|
|
||||||
|
var (
|
||||||
|
// ridCtxKey is the key underwhich we store request IDs in a context.
|
||||||
|
ridCtxKey ctxType = "id"
|
||||||
|
|
||||||
|
// crand provides buffered reads of random input.
|
||||||
|
crand = bufio.NewReader(rand.Reader)
|
||||||
|
mrand sync.Mutex
|
||||||
|
|
||||||
|
// base32enc is a base 32 encoding based on a human-readable character set (no padding).
|
||||||
|
base32enc = base32.NewEncoding("0123456789abcdefghjkmnpqrstvwxyz").WithPadding(-1)
|
||||||
|
)
|
||||||
|
|
||||||
|
// generateID generates a new ID string.
|
||||||
|
func generateID() string {
|
||||||
|
// 0:8 = timestamp
|
||||||
|
// 8:12 = entropy
|
||||||
|
//
|
||||||
|
// inspired by ULID.
|
||||||
|
b := make([]byte, 12)
|
||||||
|
|
||||||
|
// Get current time in milliseconds.
|
||||||
|
ms := uint64(time.Now().UnixMilli())
|
||||||
|
|
||||||
|
// Store binary time data in byte buffer.
|
||||||
|
binary.LittleEndian.PutUint64(b[0:8], ms)
|
||||||
|
|
||||||
|
mrand.Lock()
|
||||||
|
// Read random bits into buffer end.
|
||||||
|
_, _ = io.ReadFull(crand, b[8:12])
|
||||||
|
mrand.Unlock()
|
||||||
|
|
||||||
|
// Encode the binary time+entropy ID.
|
||||||
|
return base32enc.EncodeToString(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RequestID fetches the stored request ID from context.
|
||||||
|
func RequestID(ctx context.Context) string {
|
||||||
|
id, _ := ctx.Value(ridCtxKey).(string)
|
||||||
|
return id
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddRequestID returns a gin middleware which adds a unique ID to each request (both response header and context).
|
||||||
|
func AddRequestID(header string) gin.HandlerFunc {
|
||||||
|
log.Hook(func(ctx context.Context, kvs []kv.Field) []kv.Field {
|
||||||
|
if id, _ := ctx.Value(ridCtxKey).(string); id != "" {
|
||||||
|
// Add stored request ID to log entry fields.
|
||||||
|
return append(kvs, kv.Field{K: "requestID", V: id})
|
||||||
|
}
|
||||||
|
return kvs
|
||||||
|
})
|
||||||
|
|
||||||
|
return func(c *gin.Context) {
|
||||||
|
// Look for existing ID.
|
||||||
|
id := c.GetHeader(header)
|
||||||
|
|
||||||
|
if id == "" {
|
||||||
|
// Generate new ID.
|
||||||
|
//
|
||||||
|
// 0:8 = timestamp
|
||||||
|
// 8:12 = entropy
|
||||||
|
id = generateID()
|
||||||
|
// Set the request ID in the req header in case we pass the request along
|
||||||
|
// to another service
|
||||||
|
c.Request.Header.Set(header, id)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store request ID in new request ctx and set new gin request obj.
|
||||||
|
ctx := context.WithValue(c.Request.Context(), ridCtxKey, id)
|
||||||
|
c.Request = c.Request.WithContext(ctx)
|
||||||
|
|
||||||
|
// Set the request ID in the rsp header.
|
||||||
|
c.Writer.Header().Set(header, id)
|
||||||
|
}
|
||||||
|
}
|
|
@ -41,7 +41,7 @@ func SessionOptions() sessions.Options {
|
||||||
case "strict":
|
case "strict":
|
||||||
samesite = http.SameSiteStrictMode
|
samesite = http.SameSiteStrictMode
|
||||||
default:
|
default:
|
||||||
log.Warnf("%s set to %s which is not recognized, defaulting to 'lax'", config.AdvancedCookiesSamesiteFlag(), config.GetAdvancedCookiesSamesite())
|
log.Warnf(nil, "%s set to %s which is not recognized, defaulting to 'lax'", config.AdvancedCookiesSamesiteFlag(), config.GetAdvancedCookiesSamesite())
|
||||||
samesite = http.SameSiteLaxMode
|
samesite = http.SameSiteLaxMode
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -36,13 +36,16 @@ var (
|
||||||
// In case of an error, the request will be aborted with http code 500 internal server error.
|
// In case of an error, the request will be aborted with http code 500 internal server error.
|
||||||
func SignatureCheck(isURIBlocked func(context.Context, *url.URL) (bool, db.Error)) func(*gin.Context) {
|
func SignatureCheck(isURIBlocked func(context.Context, *url.URL) (bool, db.Error)) func(*gin.Context) {
|
||||||
return func(c *gin.Context) {
|
return func(c *gin.Context) {
|
||||||
|
// Acquire ctx from gin request.
|
||||||
|
ctx := c.Request.Context()
|
||||||
|
|
||||||
// create the verifier from the request, this will error if the request wasn't signed
|
// create the verifier from the request, this will error if the request wasn't signed
|
||||||
verifier, err := httpsig.NewVerifier(c.Request)
|
verifier, err := httpsig.NewVerifier(c.Request)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// Something went wrong, so we need to return regardless, but only actually
|
// Something went wrong, so we need to return regardless, but only actually
|
||||||
// *abort* the request with 401 if a signature was present but malformed
|
// *abort* the request with 401 if a signature was present but malformed
|
||||||
if err.Error() != noSignatureError {
|
if err.Error() != noSignatureError {
|
||||||
log.Debugf("http signature was present but invalid: %s", err)
|
log.Debugf(ctx, "http signature was present but invalid: %s", err)
|
||||||
c.AbortWithStatus(http.StatusUnauthorized)
|
c.AbortWithStatus(http.StatusUnauthorized)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
|
@ -54,13 +57,13 @@ func SignatureCheck(isURIBlocked func(context.Context, *url.URL) (bool, db.Error
|
||||||
requestingPublicKeyIDString := verifier.KeyId()
|
requestingPublicKeyIDString := verifier.KeyId()
|
||||||
requestingPublicKeyID, err := url.Parse(requestingPublicKeyIDString)
|
requestingPublicKeyID, err := url.Parse(requestingPublicKeyIDString)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debugf("http signature requesting public key id %s could not be parsed as a url: %s", requestingPublicKeyIDString, err)
|
log.Debugf(ctx, "http signature requesting public key id %s could not be parsed as a url: %s", requestingPublicKeyIDString, err)
|
||||||
c.AbortWithStatus(http.StatusUnauthorized)
|
c.AbortWithStatus(http.StatusUnauthorized)
|
||||||
return
|
return
|
||||||
} else if requestingPublicKeyID == nil {
|
} else if requestingPublicKeyID == nil {
|
||||||
// Key can sometimes be nil, according to url parse function:
|
// Key can sometimes be nil, according to url parse function:
|
||||||
// 'Trying to parse a hostname and path without a scheme is invalid but may not necessarily return an error, due to parsing ambiguities'
|
// 'Trying to parse a hostname and path without a scheme is invalid but may not necessarily return an error, due to parsing ambiguities'
|
||||||
log.Debugf("http signature requesting public key id %s was nil after parsing as a url", requestingPublicKeyIDString)
|
log.Debugf(ctx, "http signature requesting public key id %s was nil after parsing as a url", requestingPublicKeyIDString)
|
||||||
c.AbortWithStatus(http.StatusUnauthorized)
|
c.AbortWithStatus(http.StatusUnauthorized)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -68,11 +71,11 @@ func SignatureCheck(isURIBlocked func(context.Context, *url.URL) (bool, db.Error
|
||||||
// we managed to parse the url!
|
// we managed to parse the url!
|
||||||
// if the domain is blocked we want to bail as early as possible
|
// if the domain is blocked we want to bail as early as possible
|
||||||
if blocked, err := isURIBlocked(c.Request.Context(), requestingPublicKeyID); err != nil {
|
if blocked, err := isURIBlocked(c.Request.Context(), requestingPublicKeyID); err != nil {
|
||||||
log.Errorf("could not tell if domain %s was blocked or not: %s", requestingPublicKeyID.Host, err)
|
log.Errorf(ctx, "could not tell if domain %s was blocked or not: %s", requestingPublicKeyID.Host, err)
|
||||||
c.AbortWithStatus(http.StatusInternalServerError)
|
c.AbortWithStatus(http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
} else if blocked {
|
} else if blocked {
|
||||||
log.Infof("domain %s is blocked", requestingPublicKeyID.Host)
|
log.Infof(ctx, "domain %s is blocked", requestingPublicKeyID.Host)
|
||||||
c.AbortWithStatus(http.StatusForbidden)
|
c.AbortWithStatus(http.StatusForbidden)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,6 +52,7 @@ import (
|
||||||
// Bearer token set (eg., for public instance information and so on).
|
// Bearer token set (eg., for public instance information and so on).
|
||||||
func TokenCheck(dbConn db.DB, validateBearerToken func(r *http.Request) (oauth2.TokenInfo, error)) func(*gin.Context) {
|
func TokenCheck(dbConn db.DB, validateBearerToken func(r *http.Request) (oauth2.TokenInfo, error)) func(*gin.Context) {
|
||||||
return func(c *gin.Context) {
|
return func(c *gin.Context) {
|
||||||
|
// Acquire context from gin request.
|
||||||
ctx := c.Request.Context()
|
ctx := c.Request.Context()
|
||||||
|
|
||||||
if c.Request.Header.Get("Authorization") == "" {
|
if c.Request.Header.Get("Authorization") == "" {
|
||||||
|
@ -61,38 +62,38 @@ func TokenCheck(dbConn db.DB, validateBearerToken func(r *http.Request) (oauth2.
|
||||||
|
|
||||||
ti, err := validateBearerToken(c.Copy().Request)
|
ti, err := validateBearerToken(c.Copy().Request)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debugf("token was passed in Authorization header but we could not validate it: %s", err)
|
log.Debugf(ctx, "token was passed in Authorization header but we could not validate it: %s", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
c.Set(oauth.SessionAuthorizedToken, ti)
|
c.Set(oauth.SessionAuthorizedToken, ti)
|
||||||
|
|
||||||
// check for user-level token
|
// check for user-level token
|
||||||
if userID := ti.GetUserID(); userID != "" {
|
if userID := ti.GetUserID(); userID != "" {
|
||||||
log.Tracef("authenticated user %s with bearer token, scope is %s", userID, ti.GetScope())
|
log.Tracef(ctx, "authenticated user %s with bearer token, scope is %s", userID, ti.GetScope())
|
||||||
|
|
||||||
// fetch user for this token
|
// fetch user for this token
|
||||||
user, err := dbConn.GetUserByID(ctx, userID)
|
user, err := dbConn.GetUserByID(ctx, userID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err != db.ErrNoEntries {
|
if err != db.ErrNoEntries {
|
||||||
log.Errorf("database error looking for user with id %s: %s", userID, err)
|
log.Errorf(ctx, "database error looking for user with id %s: %s", userID, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
log.Warnf("no user found for userID %s", userID)
|
log.Warnf(ctx, "no user found for userID %s", userID)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if user.ConfirmedAt.IsZero() {
|
if user.ConfirmedAt.IsZero() {
|
||||||
log.Warnf("authenticated user %s has never confirmed thier email address", userID)
|
log.Warnf(ctx, "authenticated user %s has never confirmed thier email address", userID)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if !*user.Approved {
|
if !*user.Approved {
|
||||||
log.Warnf("authenticated user %s's account was never approved by an admin", userID)
|
log.Warnf(ctx, "authenticated user %s's account was never approved by an admin", userID)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if *user.Disabled {
|
if *user.Disabled {
|
||||||
log.Warnf("authenticated user %s's account was disabled'", userID)
|
log.Warnf(ctx, "authenticated user %s's account was disabled'", userID)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -103,17 +104,17 @@ func TokenCheck(dbConn db.DB, validateBearerToken func(r *http.Request) (oauth2.
|
||||||
acct, err := dbConn.GetAccountByID(ctx, user.AccountID)
|
acct, err := dbConn.GetAccountByID(ctx, user.AccountID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err != db.ErrNoEntries {
|
if err != db.ErrNoEntries {
|
||||||
log.Errorf("database error looking for account with id %s: %s", user.AccountID, err)
|
log.Errorf(ctx, "database error looking for account with id %s: %s", user.AccountID, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
log.Warnf("no account found for userID %s", userID)
|
log.Warnf(ctx, "no account found for userID %s", userID)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
user.Account = acct
|
user.Account = acct
|
||||||
}
|
}
|
||||||
|
|
||||||
if !user.Account.SuspendedAt.IsZero() {
|
if !user.Account.SuspendedAt.IsZero() {
|
||||||
log.Warnf("authenticated user %s's account (accountId=%s) has been suspended", userID, user.AccountID)
|
log.Warnf(ctx, "authenticated user %s's account (accountId=%s) has been suspended", userID, user.AccountID)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -122,16 +123,16 @@ func TokenCheck(dbConn db.DB, validateBearerToken func(r *http.Request) (oauth2.
|
||||||
|
|
||||||
// check for application token
|
// check for application token
|
||||||
if clientID := ti.GetClientID(); clientID != "" {
|
if clientID := ti.GetClientID(); clientID != "" {
|
||||||
log.Tracef("authenticated client %s with bearer token, scope is %s", clientID, ti.GetScope())
|
log.Tracef(ctx, "authenticated client %s with bearer token, scope is %s", clientID, ti.GetScope())
|
||||||
|
|
||||||
// fetch app for this token
|
// fetch app for this token
|
||||||
app := >smodel.Application{}
|
app := >smodel.Application{}
|
||||||
if err := dbConn.GetWhere(ctx, []db.Where{{Key: "client_id", Value: clientID}}, app); err != nil {
|
if err := dbConn.GetWhere(ctx, []db.Where{{Key: "client_id", Value: clientID}}, app); err != nil {
|
||||||
if err != db.ErrNoEntries {
|
if err != db.ErrNoEntries {
|
||||||
log.Errorf("database error looking for application with clientID %s: %s", clientID, err)
|
log.Errorf(ctx, "database error looking for application with clientID %s: %s", clientID, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
log.Warnf("no app found for client %s", clientID)
|
log.Warnf(ctx, "no app found for client %s", clientID)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
c.Set(oauth.SessionAuthorizedApplication, app)
|
c.Set(oauth.SessionAuthorizedApplication, app)
|
||||||
|
|
|
@ -103,12 +103,12 @@ func New(ctx context.Context, database db.Basic) Server {
|
||||||
|
|
||||||
srv := server.NewServer(sc, manager)
|
srv := server.NewServer(sc, manager)
|
||||||
srv.SetInternalErrorHandler(func(err error) *errors.Response {
|
srv.SetInternalErrorHandler(func(err error) *errors.Response {
|
||||||
log.Errorf("internal oauth error: %s", err)
|
log.Errorf(nil, "internal oauth error: %s", err)
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
|
||||||
srv.SetResponseErrorHandler(func(re *errors.Response) {
|
srv.SetResponseErrorHandler(func(re *errors.Response) {
|
||||||
log.Errorf("internal response error: %s", re.Error)
|
log.Errorf(nil, "internal response error: %s", re.Error)
|
||||||
})
|
})
|
||||||
|
|
||||||
srv.SetUserAuthorizationHandler(func(w http.ResponseWriter, r *http.Request) (string, error) {
|
srv.SetUserAuthorizationHandler(func(w http.ResponseWriter, r *http.Request) (string, error) {
|
||||||
|
@ -272,7 +272,7 @@ func (s *s) GenerateUserAccessToken(ctx context.Context, ti oauth2.TokenInfo, cl
|
||||||
if authToken == nil {
|
if authToken == nil {
|
||||||
return nil, errors.New("generated auth token was empty")
|
return nil, errors.New("generated auth token was empty")
|
||||||
}
|
}
|
||||||
log.Tracef("obtained auth token: %+v", authToken)
|
log.Tracef(ctx, "obtained auth token: %+v", authToken)
|
||||||
|
|
||||||
accessToken, err := s.server.Manager.GenerateAccessToken(ctx, oauth2.AuthorizationCode, &oauth2.TokenGenerateRequest{
|
accessToken, err := s.server.Manager.GenerateAccessToken(ctx, oauth2.AuthorizationCode, &oauth2.TokenGenerateRequest{
|
||||||
ClientID: authToken.GetClientID(),
|
ClientID: authToken.GetClientID(),
|
||||||
|
@ -287,7 +287,7 @@ func (s *s) GenerateUserAccessToken(ctx context.Context, ti oauth2.TokenInfo, cl
|
||||||
if accessToken == nil {
|
if accessToken == nil {
|
||||||
return nil, errors.New("generated user-level access token was empty")
|
return nil, errors.New("generated user-level access token was empty")
|
||||||
}
|
}
|
||||||
log.Tracef("obtained user-level access token: %+v", accessToken)
|
log.Tracef(ctx, "obtained user-level access token: %+v", accessToken)
|
||||||
return accessToken, nil
|
return accessToken, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -53,12 +53,12 @@ func newTokenStore(ctx context.Context, db db.Basic) oauth2.TokenStore {
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
log.Info("breaking cleanloop")
|
log.Info(ctx, "breaking cleanloop")
|
||||||
break cleanloop
|
break cleanloop
|
||||||
case <-time.After(1 * time.Minute):
|
case <-time.After(1 * time.Minute):
|
||||||
log.Trace("sweeping out old oauth entries broom broom")
|
log.Trace(ctx, "sweeping out old oauth entries broom broom")
|
||||||
if err := ts.sweep(ctx); err != nil {
|
if err := ts.sweep(ctx); err != nil {
|
||||||
log.Errorf("error while sweeping oauth entries: %s", err)
|
log.Errorf(ctx, "error while sweeping oauth entries: %s", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,23 +33,23 @@ func (i *idp) HandleCallback(ctx context.Context, code string) (*Claims, gtserro
|
||||||
return nil, gtserror.NewErrorBadRequest(err, err.Error())
|
return nil, gtserror.NewErrorBadRequest(err, err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Debug("exchanging code for oauth2token")
|
log.Debug(ctx, "exchanging code for oauth2token")
|
||||||
oauth2Token, err := i.oauth2Config.Exchange(ctx, code)
|
oauth2Token, err := i.oauth2Config.Exchange(ctx, code)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err := fmt.Errorf("error exchanging code for oauth2token: %s", err)
|
err := fmt.Errorf("error exchanging code for oauth2token: %s", err)
|
||||||
return nil, gtserror.NewErrorInternalError(err)
|
return nil, gtserror.NewErrorInternalError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Debug("extracting id_token")
|
log.Debug(ctx, "extracting id_token")
|
||||||
rawIDToken, ok := oauth2Token.Extra("id_token").(string)
|
rawIDToken, ok := oauth2Token.Extra("id_token").(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
err := errors.New("no id_token in oauth2token")
|
err := errors.New("no id_token in oauth2token")
|
||||||
return nil, gtserror.NewErrorBadRequest(err, err.Error())
|
return nil, gtserror.NewErrorBadRequest(err, err.Error())
|
||||||
}
|
}
|
||||||
log.Debugf("raw id token: %s", rawIDToken)
|
log.Debugf(ctx, "raw id token: %s", rawIDToken)
|
||||||
|
|
||||||
// Parse and verify ID Token payload.
|
// Parse and verify ID Token payload.
|
||||||
log.Debug("verifying id_token")
|
log.Debug(ctx, "verifying id_token")
|
||||||
idTokenVerifier := i.provider.Verifier(i.oidcConf)
|
idTokenVerifier := i.provider.Verifier(i.oidcConf)
|
||||||
idToken, err := idTokenVerifier.Verify(ctx, rawIDToken)
|
idToken, err := idTokenVerifier.Verify(ctx, rawIDToken)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -57,7 +57,7 @@ func (i *idp) HandleCallback(ctx context.Context, code string) (*Claims, gtserro
|
||||||
return nil, gtserror.NewErrorUnauthorized(err, err.Error())
|
return nil, gtserror.NewErrorUnauthorized(err, err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Debug("extracting claims from id_token")
|
log.Debug(ctx, "extracting claims from id_token")
|
||||||
claims := &Claims{}
|
claims := &Claims{}
|
||||||
if err := idToken.Claims(claims); err != nil {
|
if err := idToken.Claims(claims); err != nil {
|
||||||
err := fmt.Errorf("could not parse claims from idToken: %s", err)
|
err := fmt.Errorf("could not parse claims from idToken: %s", err)
|
||||||
|
|
|
@ -59,13 +59,13 @@ func (p *processor) Create(ctx context.Context, applicationToken oauth2.TokenInf
|
||||||
reason = ""
|
reason = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Trace("creating new username and account")
|
log.Trace(ctx, "creating new username and account")
|
||||||
user, err := p.db.NewSignup(ctx, form.Username, text.SanitizePlaintext(reason), approvalRequired, form.Email, form.Password, form.IP, form.Locale, application.ID, false, "", false)
|
user, err := p.db.NewSignup(ctx, form.Username, text.SanitizePlaintext(reason), approvalRequired, form.Email, form.Password, form.IP, form.Locale, application.ID, false, "", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, gtserror.NewErrorInternalError(fmt.Errorf("error creating new signup in the database: %s", err))
|
return nil, gtserror.NewErrorInternalError(fmt.Errorf("error creating new signup in the database: %s", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Tracef("generating a token for user %s with account %s and application %s", user.ID, user.AccountID, application.ID)
|
log.Tracef(ctx, "generating a token for user %s with account %s and application %s", user.ID, user.AccountID, application.ID)
|
||||||
accessToken, err := p.oauthServer.GenerateUserAccessToken(ctx, applicationToken, application.ClientSecret, user.ID)
|
accessToken, err := p.oauthServer.GenerateUserAccessToken(ctx, applicationToken, application.ClientSecret, user.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, gtserror.NewErrorInternalError(fmt.Errorf("error creating new access token for user %s: %s", user.ID, err))
|
return nil, gtserror.NewErrorInternalError(fmt.Errorf("error creating new access token for user %s: %s", user.ID, err))
|
||||||
|
|
|
@ -64,7 +64,7 @@ func (p *processor) Delete(ctx context.Context, account *gtsmodel.Account, origi
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
l := log.WithFields(fields...)
|
l := log.WithContext(ctx).WithFields(fields...)
|
||||||
l.Trace("beginning account delete process")
|
l.Trace("beginning account delete process")
|
||||||
|
|
||||||
// 1. Delete account's application(s), clients, and oauth tokens
|
// 1. Delete account's application(s), clients, and oauth tokens
|
||||||
|
|
|
@ -97,7 +97,7 @@ func (p *processor) Update(ctx context.Context, account *gtsmodel.Account, form
|
||||||
}
|
}
|
||||||
account.AvatarMediaAttachmentID = avatarInfo.ID
|
account.AvatarMediaAttachmentID = avatarInfo.ID
|
||||||
account.AvatarMediaAttachment = avatarInfo
|
account.AvatarMediaAttachment = avatarInfo
|
||||||
log.Tracef("new avatar info for account %s is %+v", account.ID, avatarInfo)
|
log.Tracef(ctx, "new avatar info for account %s is %+v", account.ID, avatarInfo)
|
||||||
}
|
}
|
||||||
|
|
||||||
if form.Header != nil && form.Header.Size != 0 {
|
if form.Header != nil && form.Header.Size != 0 {
|
||||||
|
@ -107,7 +107,7 @@ func (p *processor) Update(ctx context.Context, account *gtsmodel.Account, form
|
||||||
}
|
}
|
||||||
account.HeaderMediaAttachmentID = headerInfo.ID
|
account.HeaderMediaAttachmentID = headerInfo.ID
|
||||||
account.HeaderMediaAttachment = headerInfo
|
account.HeaderMediaAttachment = headerInfo
|
||||||
log.Tracef("new header info for account %s is %+v", account.ID, headerInfo)
|
log.Tracef(ctx, "new header info for account %s is %+v", account.ID, headerInfo)
|
||||||
}
|
}
|
||||||
|
|
||||||
if form.Locked != nil {
|
if form.Locked != nil {
|
||||||
|
|
|
@ -89,9 +89,10 @@ func (p *processor) DomainBlockCreate(ctx context.Context, account *gtsmodel.Acc
|
||||||
// 2. Delete the instance account for that instance if it exists.
|
// 2. Delete the instance account for that instance if it exists.
|
||||||
// 3. Select all accounts from this instance and pass them through the delete functionality of the processor.
|
// 3. Select all accounts from this instance and pass them through the delete functionality of the processor.
|
||||||
func (p *processor) initiateDomainBlockSideEffects(ctx context.Context, account *gtsmodel.Account, block *gtsmodel.DomainBlock) {
|
func (p *processor) initiateDomainBlockSideEffects(ctx context.Context, account *gtsmodel.Account, block *gtsmodel.DomainBlock) {
|
||||||
l := log.WithFields(kv.Fields{
|
l := log.WithContext(ctx).
|
||||||
{"domain", block.Domain},
|
WithFields(kv.Fields{
|
||||||
}...)
|
{"domain", block.Domain},
|
||||||
|
}...)
|
||||||
|
|
||||||
l.Debug("processing domain block side effects")
|
l.Debug("processing domain block side effects")
|
||||||
|
|
||||||
|
|
|
@ -35,12 +35,12 @@ func (p *processor) MediaRefetch(ctx context.Context, requestingAccount *gtsmode
|
||||||
}
|
}
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
log.Info("starting emoji refetch")
|
log.Info(ctx, "starting emoji refetch")
|
||||||
refetched, err := p.mediaManager.RefetchEmojis(context.Background(), domain, transport.DereferenceMedia)
|
refetched, err := p.mediaManager.RefetchEmojis(context.Background(), domain, transport.DereferenceMedia)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("error refetching emojis: %s", err)
|
log.Errorf(ctx, "error refetching emojis: %s", err)
|
||||||
} else {
|
} else {
|
||||||
log.Infof("refetched %d emojis from remote", refetched)
|
log.Infof(ctx, "refetched %d emojis from remote", refetched)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
|
|
@ -50,7 +50,7 @@ func (p *processor) ProcessFromClientAPI(ctx context.Context, clientMsg messages
|
||||||
}
|
}
|
||||||
|
|
||||||
// Log this federated message
|
// Log this federated message
|
||||||
l := log.WithFields(fields...)
|
l := log.WithContext(ctx).WithFields(fields...)
|
||||||
l.Info("processing from client")
|
l.Info("processing from client")
|
||||||
|
|
||||||
switch clientMsg.APActivityType {
|
switch clientMsg.APActivityType {
|
||||||
|
|
|
@ -59,7 +59,7 @@ func (p *processor) ProcessFromFederator(ctx context.Context, federatorMsg messa
|
||||||
}
|
}
|
||||||
|
|
||||||
// Log this federated message
|
// Log this federated message
|
||||||
l := log.WithFields(fields...)
|
l := log.WithContext(ctx).WithFields(fields...)
|
||||||
l.Info("processing from federator")
|
l.Info("processing from federator")
|
||||||
|
|
||||||
switch federatorMsg.APActivityType {
|
switch federatorMsg.APActivityType {
|
||||||
|
|
|
@ -40,7 +40,7 @@ func (p *processor) GetCustomEmojis(ctx context.Context) ([]*apimodel.Emoji, gts
|
||||||
for _, gtsEmoji := range emojis {
|
for _, gtsEmoji := range emojis {
|
||||||
apiEmoji, err := p.tc.EmojiToAPIEmoji(ctx, gtsEmoji)
|
apiEmoji, err := p.tc.EmojiToAPIEmoji(ctx, gtsEmoji)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("error converting emoji with id %s: %s", gtsEmoji.ID, err)
|
log.Errorf(ctx, "error converting emoji with id %s: %s", gtsEmoji.ID, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
apiEmojis = append(apiEmojis, &apiEmoji)
|
apiEmojis = append(apiEmojis, &apiEmoji)
|
||||||
|
|
|
@ -46,7 +46,7 @@ func (p *processor) NotificationsGet(ctx context.Context, authed *oauth.Auth, ex
|
||||||
for i, n := range notifs {
|
for i, n := range notifs {
|
||||||
item, err := p.tc.NotificationToAPINotification(ctx, n)
|
item, err := p.tc.NotificationToAPINotification(ctx, n)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debugf("got an error converting a notification to api, will skip it: %s", err)
|
log.Debugf(ctx, "got an error converting a notification to api, will skip it: %s", err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -57,7 +57,8 @@ func (p *processor) SearchGet(ctx context.Context, authed *oauth.Auth, search *a
|
||||||
return nil, gtserror.NewErrorBadRequest(err, err.Error())
|
return nil, gtserror.NewErrorBadRequest(err, err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
l := log.WithFields(kv.Fields{{"query", query}}...)
|
l := log.WithContext(ctx).
|
||||||
|
WithFields(kv.Fields{{"query", query}}...)
|
||||||
|
|
||||||
searchResult := &apimodel.SearchResult{
|
searchResult := &apimodel.SearchResult{
|
||||||
Accounts: []apimodel.Account{},
|
Accounts: []apimodel.Account{},
|
||||||
|
|
|
@ -72,7 +72,7 @@ func StatusFilterFunction(database db.DB, filter visibility.Filter) timeline.Fil
|
||||||
|
|
||||||
timelineable, err := filter.StatusHometimelineable(ctx, status, requestingAccount)
|
timelineable, err := filter.StatusHometimelineable(ctx, status, requestingAccount)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warnf("error checking hometimelineability of status %s for account %s: %s", status.ID, timelineAccountID, err)
|
log.Warnf(ctx, "error checking hometimelineability of status %s for account %s: %s", status.ID, timelineAccountID, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return timelineable, nil // we don't return the error here because we want to just skip this item if something goes wrong
|
return timelineable, nil // we don't return the error here because we want to just skip this item if something goes wrong
|
||||||
|
@ -257,7 +257,7 @@ func (p *processor) filterPublicStatuses(ctx context.Context, authed *oauth.Auth
|
||||||
targetAccount := >smodel.Account{}
|
targetAccount := >smodel.Account{}
|
||||||
if err := p.db.GetByID(ctx, s.AccountID, targetAccount); err != nil {
|
if err := p.db.GetByID(ctx, s.AccountID, targetAccount); err != nil {
|
||||||
if err == db.ErrNoEntries {
|
if err == db.ErrNoEntries {
|
||||||
log.Debugf("filterPublicStatuses: skipping status %s because account %s can't be found in the db", s.ID, s.AccountID)
|
log.Debugf(ctx, "skipping status %s because account %s can't be found in the db", s.ID, s.AccountID)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
return nil, gtserror.NewErrorInternalError(fmt.Errorf("filterPublicStatuses: error getting status author: %s", err))
|
return nil, gtserror.NewErrorInternalError(fmt.Errorf("filterPublicStatuses: error getting status author: %s", err))
|
||||||
|
@ -265,7 +265,7 @@ func (p *processor) filterPublicStatuses(ctx context.Context, authed *oauth.Auth
|
||||||
|
|
||||||
timelineable, err := p.filter.StatusPublictimelineable(ctx, s, authed.Account)
|
timelineable, err := p.filter.StatusPublictimelineable(ctx, s, authed.Account)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debugf("filterPublicStatuses: skipping status %s because of an error checking status visibility: %s", s.ID, err)
|
log.Debugf(ctx, "skipping status %s because of an error checking status visibility: %s", s.ID, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if !timelineable {
|
if !timelineable {
|
||||||
|
@ -274,7 +274,7 @@ func (p *processor) filterPublicStatuses(ctx context.Context, authed *oauth.Auth
|
||||||
|
|
||||||
apiStatus, err := p.tc.StatusToAPIStatus(ctx, s, authed.Account)
|
apiStatus, err := p.tc.StatusToAPIStatus(ctx, s, authed.Account)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debugf("filterPublicStatuses: skipping status %s because it couldn't be converted to its api representation: %s", s.ID, err)
|
log.Debugf(ctx, "skipping status %s because it couldn't be converted to its api representation: %s", s.ID, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -290,7 +290,7 @@ func (p *processor) filterFavedStatuses(ctx context.Context, authed *oauth.Auth,
|
||||||
targetAccount := >smodel.Account{}
|
targetAccount := >smodel.Account{}
|
||||||
if err := p.db.GetByID(ctx, s.AccountID, targetAccount); err != nil {
|
if err := p.db.GetByID(ctx, s.AccountID, targetAccount); err != nil {
|
||||||
if err == db.ErrNoEntries {
|
if err == db.ErrNoEntries {
|
||||||
log.Debugf("filterFavedStatuses: skipping status %s because account %s can't be found in the db", s.ID, s.AccountID)
|
log.Debugf(ctx, "skipping status %s because account %s can't be found in the db", s.ID, s.AccountID)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
return nil, gtserror.NewErrorInternalError(fmt.Errorf("filterPublicStatuses: error getting status author: %s", err))
|
return nil, gtserror.NewErrorInternalError(fmt.Errorf("filterPublicStatuses: error getting status author: %s", err))
|
||||||
|
@ -298,7 +298,7 @@ func (p *processor) filterFavedStatuses(ctx context.Context, authed *oauth.Auth,
|
||||||
|
|
||||||
timelineable, err := p.filter.StatusVisible(ctx, s, authed.Account)
|
timelineable, err := p.filter.StatusVisible(ctx, s, authed.Account)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debugf("filterFavedStatuses: skipping status %s because of an error checking status visibility: %s", s.ID, err)
|
log.Debugf(ctx, "skipping status %s because of an error checking status visibility: %s", s.ID, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if !timelineable {
|
if !timelineable {
|
||||||
|
@ -307,7 +307,7 @@ func (p *processor) filterFavedStatuses(ctx context.Context, authed *oauth.Auth,
|
||||||
|
|
||||||
apiStatus, err := p.tc.StatusToAPIStatus(ctx, s, authed.Account)
|
apiStatus, err := p.tc.StatusToAPIStatus(ctx, s, authed.Account)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debugf("filterFavedStatuses: skipping status %s because it couldn't be converted to its api representation: %s", s.ID, err)
|
log.Debugf(ctx, "skipping status %s because it couldn't be converted to its api representation: %s", s.ID, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -32,11 +32,11 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func (p *processor) OpenStreamForAccount(ctx context.Context, account *gtsmodel.Account, streamTimeline string) (*stream.Stream, gtserror.WithCode) {
|
func (p *processor) OpenStreamForAccount(ctx context.Context, account *gtsmodel.Account, streamTimeline string) (*stream.Stream, gtserror.WithCode) {
|
||||||
l := log.WithFields(kv.Fields{
|
l := log.WithContext(ctx).
|
||||||
|
WithFields(kv.Fields{
|
||||||
{"account", account.ID},
|
{"account", account.ID},
|
||||||
{"streamType", streamTimeline},
|
{"streamType", streamTimeline},
|
||||||
}...)
|
}...)
|
||||||
l.Debug("received open stream request")
|
l.Debug("received open stream request")
|
||||||
|
|
||||||
// each stream needs a unique ID so we know to close it
|
// each stream needs a unique ID so we know to close it
|
||||||
|
|
|
@ -101,10 +101,10 @@ func (r *router) Start() {
|
||||||
)
|
)
|
||||||
|
|
||||||
// Start the LetsEncrypt autocert manager HTTP server.
|
// Start the LetsEncrypt autocert manager HTTP server.
|
||||||
log.Infof("letsencrypt listening on %s", srv.Addr)
|
log.Infof(nil, "letsencrypt listening on %s", srv.Addr)
|
||||||
if err := srv.ListenAndServe(); err != nil &&
|
if err := srv.ListenAndServe(); err != nil &&
|
||||||
err != http.ErrServerClosed {
|
err != http.ErrServerClosed {
|
||||||
log.Fatalf("letsencrypt: listen: %s", err)
|
log.Fatalf(nil, "letsencrypt: listen: %s", err)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
@ -119,23 +119,23 @@ func (r *router) Start() {
|
||||||
r.srv.Handler = debug.WithPprof(r.srv.Handler)
|
r.srv.Handler = debug.WithPprof(r.srv.Handler)
|
||||||
if debug.DEBUG {
|
if debug.DEBUG {
|
||||||
// Profiling requires timeouts longer than 30s, so reset these.
|
// Profiling requires timeouts longer than 30s, so reset these.
|
||||||
log.Warn("resetting http.Server{} timeout to support profiling")
|
log.Warn(nil, "resetting http.Server{} timeout to support profiling")
|
||||||
r.srv.ReadTimeout = 0
|
r.srv.ReadTimeout = 0
|
||||||
r.srv.WriteTimeout = 0
|
r.srv.WriteTimeout = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start the main listener.
|
// Start the main listener.
|
||||||
go func() {
|
go func() {
|
||||||
log.Infof("listening on %s", r.srv.Addr)
|
log.Infof(nil, "listening on %s", r.srv.Addr)
|
||||||
if err := listen(); err != nil && err != http.ErrServerClosed {
|
if err := listen(); err != nil && err != http.ErrServerClosed {
|
||||||
log.Fatalf("listen: %s", err)
|
log.Fatalf(nil, "listen: %s", err)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stop shuts down the router nicely
|
// Stop shuts down the router nicely
|
||||||
func (r *router) Stop(ctx context.Context) error {
|
func (r *router) Stop(ctx context.Context) error {
|
||||||
log.Infof("shutting down http router with %s grace period", shutdownTimeout)
|
log.Infof(nil, "shutting down http router with %s grace period", shutdownTimeout)
|
||||||
timeout, cancel := context.WithTimeout(ctx, shutdownTimeout)
|
timeout, cancel := context.WithTimeout(ctx, shutdownTimeout)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
|
@ -143,7 +143,7 @@ func (r *router) Stop(ctx context.Context) error {
|
||||||
return fmt.Errorf("error shutting down http router: %s", err)
|
return fmt.Errorf("error shutting down http router: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Info("http router closed connections and shut down gracefully")
|
log.Info(nil, "http router closed connections and shut down gracefully")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -87,7 +87,7 @@ func noescapeAttr(str string) template.HTMLAttr {
|
||||||
func timestamp(stamp string) string {
|
func timestamp(stamp string) string {
|
||||||
t, err := util.ParseISO8601(stamp)
|
t, err := util.ParseISO8601(stamp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("error parsing timestamp %s: %s", stamp, err)
|
log.Errorf(nil, "error parsing timestamp %s: %s", stamp, err)
|
||||||
return badTimestamp
|
return badTimestamp
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -110,7 +110,7 @@ func timestamp(stamp string) string {
|
||||||
func timestampPrecise(stamp string) string {
|
func timestampPrecise(stamp string) string {
|
||||||
t, err := util.ParseISO8601(stamp)
|
t, err := util.ParseISO8601(stamp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("error parsing timestamp %s: %s", stamp, err)
|
log.Errorf(nil, "error parsing timestamp %s: %s", stamp, err)
|
||||||
return badTimestamp
|
return badTimestamp
|
||||||
}
|
}
|
||||||
return t.Local().Format(dateYearTime)
|
return t.Local().Format(dateYearTime)
|
||||||
|
@ -119,7 +119,7 @@ func timestampPrecise(stamp string) string {
|
||||||
func timestampVague(stamp string) string {
|
func timestampVague(stamp string) string {
|
||||||
t, err := util.ParseISO8601(stamp)
|
t, err := util.ParseISO8601(stamp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("error parsing timestamp %s: %s", stamp, err)
|
log.Errorf(nil, "error parsing timestamp %s: %s", stamp, err)
|
||||||
return badTimestamp
|
return badTimestamp
|
||||||
}
|
}
|
||||||
return t.Format(monthYear)
|
return t.Format(monthYear)
|
||||||
|
|
|
@ -128,8 +128,9 @@ func NewFileStorage() (*Driver, error) {
|
||||||
return nil, fmt.Errorf("error opening disk storage: %w", err)
|
return nil, fmt.Errorf("error opening disk storage: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Perform an initial storage clean to delete old dirs.
|
||||||
if err := disk.Clean(context.Background()); err != nil {
|
if err := disk.Clean(context.Background()); err != nil {
|
||||||
log.Errorf("error performing storage cleanup: %v", err)
|
log.Errorf(nil, "error performing storage cleanup: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return &Driver{
|
return &Driver{
|
||||||
|
|
|
@ -57,7 +57,7 @@ func (f *formatter) FromPlainEmojiOnly(ctx context.Context, pmf gtsmodel.ParseMe
|
||||||
var htmlContentBytes bytes.Buffer
|
var htmlContentBytes bytes.Buffer
|
||||||
err := md.Convert([]byte(plain), &htmlContentBytes)
|
err := md.Convert([]byte(plain), &htmlContentBytes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("error formatting plaintext to HTML: %s", err)
|
log.Errorf(ctx, "error formatting plaintext to HTML: %s", err)
|
||||||
}
|
}
|
||||||
result.HTML = htmlContentBytes.String()
|
result.HTML = htmlContentBytes.String()
|
||||||
|
|
||||||
|
@ -65,7 +65,10 @@ func (f *formatter) FromPlainEmojiOnly(ctx context.Context, pmf gtsmodel.ParseMe
|
||||||
result.HTML = SanitizeHTML(result.HTML)
|
result.HTML = SanitizeHTML(result.HTML)
|
||||||
|
|
||||||
// shrink ray
|
// shrink ray
|
||||||
result.HTML = minifyHTML(result.HTML)
|
result.HTML, err = m.String("text/html", result.HTML)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf(ctx, "error minifying HTML: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,9 +53,11 @@ type emoji struct {
|
||||||
Segment text.Segment
|
Segment text.Segment
|
||||||
}
|
}
|
||||||
|
|
||||||
var kindMention = ast.NewNodeKind("Mention")
|
var (
|
||||||
var kindHashtag = ast.NewNodeKind("Hashtag")
|
kindMention = ast.NewNodeKind("Mention")
|
||||||
var kindEmoji = ast.NewNodeKind("Emoji")
|
kindHashtag = ast.NewNodeKind("Hashtag")
|
||||||
|
kindEmoji = ast.NewNodeKind("Emoji")
|
||||||
|
)
|
||||||
|
|
||||||
func (n *mention) Kind() ast.NodeKind {
|
func (n *mention) Kind() ast.NodeKind {
|
||||||
return kindMention
|
return kindMention
|
||||||
|
@ -106,14 +108,11 @@ func newEmoji(s text.Segment) *emoji {
|
||||||
}
|
}
|
||||||
|
|
||||||
// mentionParser and hashtagParser fulfil the goldmark parser.InlineParser interface.
|
// mentionParser and hashtagParser fulfil the goldmark parser.InlineParser interface.
|
||||||
type mentionParser struct {
|
type mentionParser struct{}
|
||||||
}
|
|
||||||
|
|
||||||
type hashtagParser struct {
|
type hashtagParser struct{}
|
||||||
}
|
|
||||||
|
|
||||||
type emojiParser struct {
|
type emojiParser struct{}
|
||||||
}
|
|
||||||
|
|
||||||
func (p *mentionParser) Trigger() []byte {
|
func (p *mentionParser) Trigger() []byte {
|
||||||
return []byte{'@'}
|
return []byte{'@'}
|
||||||
|
@ -239,7 +238,7 @@ func (r *customRenderer) renderMention(w mdutil.BufWriter, source []byte, node a
|
||||||
|
|
||||||
n, ok := node.(*mention) // this function is only registered for kindMention
|
n, ok := node.(*mention) // this function is only registered for kindMention
|
||||||
if !ok {
|
if !ok {
|
||||||
log.Errorf("type assertion failed")
|
log.Panic(nil, "type assertion failed")
|
||||||
}
|
}
|
||||||
text := string(n.Segment.Value(source))
|
text := string(n.Segment.Value(source))
|
||||||
|
|
||||||
|
@ -247,7 +246,7 @@ func (r *customRenderer) renderMention(w mdutil.BufWriter, source []byte, node a
|
||||||
|
|
||||||
// we don't have much recourse if this fails
|
// we don't have much recourse if this fails
|
||||||
if _, err := w.WriteString(html); err != nil {
|
if _, err := w.WriteString(html); err != nil {
|
||||||
log.Errorf("error writing HTML: %s", err)
|
log.Errorf(nil, "error writing HTML: %s", err)
|
||||||
}
|
}
|
||||||
return ast.WalkSkipChildren, nil
|
return ast.WalkSkipChildren, nil
|
||||||
}
|
}
|
||||||
|
@ -259,7 +258,7 @@ func (r *customRenderer) renderHashtag(w mdutil.BufWriter, source []byte, node a
|
||||||
|
|
||||||
n, ok := node.(*hashtag) // this function is only registered for kindHashtag
|
n, ok := node.(*hashtag) // this function is only registered for kindHashtag
|
||||||
if !ok {
|
if !ok {
|
||||||
log.Errorf("type assertion failed")
|
log.Panic(nil, "type assertion failed")
|
||||||
}
|
}
|
||||||
text := string(n.Segment.Value(source))
|
text := string(n.Segment.Value(source))
|
||||||
|
|
||||||
|
@ -268,7 +267,7 @@ func (r *customRenderer) renderHashtag(w mdutil.BufWriter, source []byte, node a
|
||||||
_, err := w.WriteString(html)
|
_, err := w.WriteString(html)
|
||||||
// we don't have much recourse if this fails
|
// we don't have much recourse if this fails
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("error writing HTML: %s", err)
|
log.Errorf(nil, "error writing HTML: %s", err)
|
||||||
}
|
}
|
||||||
return ast.WalkSkipChildren, nil
|
return ast.WalkSkipChildren, nil
|
||||||
}
|
}
|
||||||
|
@ -281,7 +280,7 @@ func (r *customRenderer) renderEmoji(w mdutil.BufWriter, source []byte, node ast
|
||||||
|
|
||||||
n, ok := node.(*emoji) // this function is only registered for kindEmoji
|
n, ok := node.(*emoji) // this function is only registered for kindEmoji
|
||||||
if !ok {
|
if !ok {
|
||||||
log.Errorf("type assertion failed")
|
log.Panic(nil, "type assertion failed")
|
||||||
}
|
}
|
||||||
text := string(n.Segment.Value(source))
|
text := string(n.Segment.Value(source))
|
||||||
shortcode := text[1 : len(text)-1]
|
shortcode := text[1 : len(text)-1]
|
||||||
|
@ -289,7 +288,7 @@ func (r *customRenderer) renderEmoji(w mdutil.BufWriter, source []byte, node ast
|
||||||
emoji, err := r.f.db.GetEmojiByShortcodeDomain(r.ctx, shortcode, "")
|
emoji, err := r.f.db.GetEmojiByShortcodeDomain(r.ctx, shortcode, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err != db.ErrNoEntries {
|
if err != db.ErrNoEntries {
|
||||||
log.Errorf("error getting local emoji with shortcode %s: %s", shortcode, err)
|
log.Errorf(nil, "error getting local emoji with shortcode %s: %s", shortcode, err)
|
||||||
}
|
}
|
||||||
} else if *emoji.VisibleInPicker && !*emoji.Disabled {
|
} else if *emoji.VisibleInPicker && !*emoji.Disabled {
|
||||||
listed := false
|
listed := false
|
||||||
|
@ -306,7 +305,7 @@ func (r *customRenderer) renderEmoji(w mdutil.BufWriter, source []byte, node ast
|
||||||
|
|
||||||
// we don't have much recourse if this fails
|
// we don't have much recourse if this fails
|
||||||
if _, err := w.WriteString(text); err != nil {
|
if _, err := w.WriteString(text); err != nil {
|
||||||
log.Errorf("error writing HTML: %s", err)
|
log.Errorf(nil, "error writing HTML: %s", err)
|
||||||
}
|
}
|
||||||
return ast.WalkSkipChildren, nil
|
return ast.WalkSkipChildren, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,7 +53,7 @@ func (f *formatter) FromMarkdown(ctx context.Context, pmf gtsmodel.ParseMentionF
|
||||||
var htmlContentBytes bytes.Buffer
|
var htmlContentBytes bytes.Buffer
|
||||||
err := md.Convert([]byte(markdownText), &htmlContentBytes)
|
err := md.Convert([]byte(markdownText), &htmlContentBytes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("error formatting markdown to HTML: %s", err)
|
log.Errorf(ctx, "error formatting markdown to HTML: %s", err)
|
||||||
}
|
}
|
||||||
result.HTML = htmlContentBytes.String()
|
result.HTML = htmlContentBytes.String()
|
||||||
|
|
||||||
|
@ -61,7 +61,10 @@ func (f *formatter) FromMarkdown(ctx context.Context, pmf gtsmodel.ParseMentionF
|
||||||
result.HTML = SanitizeHTML(result.HTML)
|
result.HTML = SanitizeHTML(result.HTML)
|
||||||
|
|
||||||
// shrink ray
|
// shrink ray
|
||||||
result.HTML = minifyHTML(result.HTML)
|
result.HTML, err = m.String("text/html", result.HTML)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf(ctx, "error minifying HTML: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,27 +19,16 @@
|
||||||
package text
|
package text
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/superseriousbusiness/gotosocial/internal/log"
|
|
||||||
"github.com/tdewolff/minify/v2"
|
"github.com/tdewolff/minify/v2"
|
||||||
"github.com/tdewolff/minify/v2/html"
|
"github.com/tdewolff/minify/v2/html"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
// m is the global minify instance.
|
||||||
m *minify.M
|
var m = func() *minify.M {
|
||||||
)
|
m := minify.New()
|
||||||
|
m.Add("text/html", &html.Minifier{
|
||||||
func minifyHTML(content string) string {
|
KeepEndTags: true,
|
||||||
if m == nil {
|
KeepQuotes: true,
|
||||||
m = minify.New()
|
})
|
||||||
m.Add("text/html", &html.Minifier{
|
return m
|
||||||
KeepEndTags: true,
|
}()
|
||||||
KeepQuotes: true,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
minified, err := m.String("text/html", content)
|
|
||||||
if err != nil {
|
|
||||||
log.Errorf("error minifying HTML: %s", err)
|
|
||||||
}
|
|
||||||
return minified
|
|
||||||
}
|
|
||||||
|
|
|
@ -60,7 +60,7 @@ func (f *formatter) FromPlain(ctx context.Context, pmf gtsmodel.ParseMentionFunc
|
||||||
var htmlContentBytes bytes.Buffer
|
var htmlContentBytes bytes.Buffer
|
||||||
err := md.Convert([]byte(plain), &htmlContentBytes)
|
err := md.Convert([]byte(plain), &htmlContentBytes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("error formatting plaintext to HTML: %s", err)
|
log.Errorf(ctx, "error formatting plaintext to HTML: %s", err)
|
||||||
}
|
}
|
||||||
result.HTML = htmlContentBytes.String()
|
result.HTML = htmlContentBytes.String()
|
||||||
|
|
||||||
|
@ -68,7 +68,10 @@ func (f *formatter) FromPlain(ctx context.Context, pmf gtsmodel.ParseMentionFunc
|
||||||
result.HTML = SanitizeHTML(result.HTML)
|
result.HTML = SanitizeHTML(result.HTML)
|
||||||
|
|
||||||
// shrink ray
|
// shrink ray
|
||||||
result.HTML = minifyHTML(result.HTML)
|
result.HTML, err = m.String("text/html", result.HTML)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf(ctx, "error minifying HTML: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,11 +20,12 @@ package text
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/superseriousbusiness/gotosocial/internal/db"
|
"github.com/superseriousbusiness/gotosocial/internal/db"
|
||||||
"github.com/superseriousbusiness/gotosocial/internal/log"
|
"github.com/superseriousbusiness/gotosocial/internal/log"
|
||||||
"github.com/superseriousbusiness/gotosocial/internal/util"
|
"github.com/superseriousbusiness/gotosocial/internal/util"
|
||||||
"golang.org/x/text/unicode/norm"
|
"golang.org/x/text/unicode/norm"
|
||||||
"strings"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -39,13 +40,13 @@ const (
|
||||||
func (r *customRenderer) replaceMention(text string) string {
|
func (r *customRenderer) replaceMention(text string) string {
|
||||||
menchie, err := r.parseMention(r.ctx, text, r.accountID, r.statusID)
|
menchie, err := r.parseMention(r.ctx, text, r.accountID, r.statusID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("error parsing mention %s from status: %s", text, err)
|
log.Errorf(nil, "error parsing mention %s from status: %s", text, err)
|
||||||
return text
|
return text
|
||||||
}
|
}
|
||||||
|
|
||||||
if r.statusID != "" {
|
if r.statusID != "" {
|
||||||
if err := r.f.db.Put(r.ctx, menchie); err != nil {
|
if err := r.f.db.Put(r.ctx, menchie); err != nil {
|
||||||
log.Errorf("error putting mention in db: %s", err)
|
log.Errorf(nil, "error putting mention in db: %s", err)
|
||||||
return text
|
return text
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -66,7 +67,7 @@ func (r *customRenderer) replaceMention(text string) string {
|
||||||
if menchie.TargetAccount == nil {
|
if menchie.TargetAccount == nil {
|
||||||
a, err := r.f.db.GetAccountByID(r.ctx, menchie.TargetAccountID)
|
a, err := r.f.db.GetAccountByID(r.ctx, menchie.TargetAccountID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("error getting account with id %s from the db: %s", menchie.TargetAccountID, err)
|
log.Errorf(nil, "error getting account with id %s from the db: %s", menchie.TargetAccountID, err)
|
||||||
return text
|
return text
|
||||||
}
|
}
|
||||||
menchie.TargetAccount = a
|
menchie.TargetAccount = a
|
||||||
|
@ -105,7 +106,7 @@ func (r *customRenderer) replaceHashtag(text string) string {
|
||||||
|
|
||||||
tag, err := r.f.db.TagStringToTag(r.ctx, normalized, r.accountID)
|
tag, err := r.f.db.TagStringToTag(r.ctx, normalized, r.accountID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("error generating hashtags from status: %s", err)
|
log.Errorf(nil, "error generating hashtags from status: %s", err)
|
||||||
return text
|
return text
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -121,7 +122,7 @@ func (r *customRenderer) replaceHashtag(text string) string {
|
||||||
err = r.f.db.Put(r.ctx, tag)
|
err = r.f.db.Put(r.ctx, tag)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if !errors.Is(err, db.ErrAlreadyExists) {
|
if !errors.Is(err, db.ErrAlreadyExists) {
|
||||||
log.Errorf("error putting tags in db: %s", err)
|
log.Errorf(nil, "error putting tags in db: %s", err)
|
||||||
return text
|
return text
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,14 +38,15 @@ func (t *timeline) LastGot() time.Time {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *timeline) Get(ctx context.Context, amount int, maxID string, sinceID string, minID string, prepareNext bool) ([]Preparable, error) {
|
func (t *timeline) Get(ctx context.Context, amount int, maxID string, sinceID string, minID string, prepareNext bool) ([]Preparable, error) {
|
||||||
l := log.WithFields(kv.Fields{
|
l := log.WithContext(ctx).
|
||||||
{"accountID", t.accountID},
|
WithFields(kv.Fields{
|
||||||
{"amount", amount},
|
{"accountID", t.accountID},
|
||||||
{"maxID", maxID},
|
{"amount", amount},
|
||||||
{"sinceID", sinceID},
|
{"maxID", maxID},
|
||||||
{"minID", minID},
|
{"sinceID", sinceID},
|
||||||
}...)
|
{"minID", minID},
|
||||||
l.Debug("entering get and updating t.lastGot")
|
}...)
|
||||||
|
l.Trace("entering get and updating t.lastGot")
|
||||||
|
|
||||||
// regardless of what happens below, update the
|
// regardless of what happens below, update the
|
||||||
// last time Get was called for this timeline
|
// last time Get was called for this timeline
|
||||||
|
@ -154,11 +155,12 @@ func (t *timeline) getXFromTop(ctx context.Context, amount int) ([]Preparable, e
|
||||||
//
|
//
|
||||||
// This corresponds to an api call to /timelines/home?max_id=WHATEVER
|
// This corresponds to an api call to /timelines/home?max_id=WHATEVER
|
||||||
func (t *timeline) getXBehindID(ctx context.Context, amount int, behindID string, attempts *int) ([]Preparable, error) {
|
func (t *timeline) getXBehindID(ctx context.Context, amount int, behindID string, attempts *int) ([]Preparable, error) {
|
||||||
l := log.WithFields(kv.Fields{
|
l := log.WithContext(ctx).
|
||||||
{"amount", amount},
|
WithFields(kv.Fields{
|
||||||
{"behindID", behindID},
|
{"amount", amount},
|
||||||
{"attempts", attempts},
|
{"behindID", behindID},
|
||||||
}...)
|
{"attempts", attempts},
|
||||||
|
}...)
|
||||||
|
|
||||||
newAttempts := *attempts
|
newAttempts := *attempts
|
||||||
newAttempts++
|
newAttempts++
|
||||||
|
|
|
@ -35,58 +35,9 @@ func (t *timeline) ItemIndexLength(ctx context.Context) int {
|
||||||
return t.indexedItems.data.Len()
|
return t.indexedItems.data.Len()
|
||||||
}
|
}
|
||||||
|
|
||||||
// func (t *timeline) indexBefore(ctx context.Context, itemID string, amount int) error {
|
|
||||||
// l := log.WithFields(kv.Fields{{"amount", amount}}...)
|
|
||||||
|
|
||||||
// // lazily initialize index if it hasn't been done already
|
|
||||||
// if t.indexedItems.data == nil {
|
|
||||||
// t.indexedItems.data = &list.List{}
|
|
||||||
// t.indexedItems.data.Init()
|
|
||||||
// }
|
|
||||||
|
|
||||||
// toIndex := []Timelineable{}
|
|
||||||
// offsetID := itemID
|
|
||||||
|
|
||||||
// l.Trace("entering grabloop")
|
|
||||||
// grabloop:
|
|
||||||
// for i := 0; len(toIndex) < amount && i < 5; i++ { // try the grabloop 5 times only
|
|
||||||
// // first grab items using the caller-provided grab function
|
|
||||||
// l.Trace("grabbing...")
|
|
||||||
// items, stop, err := t.grabFunction(ctx, t.accountID, "", "", offsetID, amount)
|
|
||||||
// if err != nil {
|
|
||||||
// return err
|
|
||||||
// }
|
|
||||||
// if stop {
|
|
||||||
// break grabloop
|
|
||||||
// }
|
|
||||||
|
|
||||||
// l.Trace("filtering...")
|
|
||||||
// // now filter each item using the caller-provided filter function
|
|
||||||
// for _, item := range items {
|
|
||||||
// shouldIndex, err := t.filterFunction(ctx, t.accountID, item)
|
|
||||||
// if err != nil {
|
|
||||||
// return err
|
|
||||||
// }
|
|
||||||
// if shouldIndex {
|
|
||||||
// toIndex = append(toIndex, item)
|
|
||||||
// }
|
|
||||||
// offsetID = item.GetID()
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// l.Trace("left grabloop")
|
|
||||||
|
|
||||||
// // index the items we got
|
|
||||||
// for _, s := range toIndex {
|
|
||||||
// if _, err := t.IndexOne(ctx, s.GetID(), s.GetBoostOfID(), s.GetAccountID(), s.GetBoostOfAccountID()); err != nil {
|
|
||||||
// return fmt.Errorf("indexBefore: error indexing item with id %s: %s", s.GetID(), err)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// return nil
|
|
||||||
// }
|
|
||||||
|
|
||||||
func (t *timeline) indexBehind(ctx context.Context, itemID string, amount int) error {
|
func (t *timeline) indexBehind(ctx context.Context, itemID string, amount int) error {
|
||||||
l := log.WithFields(kv.Fields{{"amount", amount}}...)
|
l := log.WithContext(ctx).
|
||||||
|
WithFields(kv.Fields{{"amount", amount}}...)
|
||||||
|
|
||||||
// lazily initialize index if it hasn't been done already
|
// lazily initialize index if it hasn't been done already
|
||||||
if t.indexedItems.data == nil {
|
if t.indexedItems.data == nil {
|
||||||
|
|
|
@ -134,10 +134,11 @@ func (m *manager) Stop() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *manager) Ingest(ctx context.Context, item Timelineable, timelineAccountID string) (bool, error) {
|
func (m *manager) Ingest(ctx context.Context, item Timelineable, timelineAccountID string) (bool, error) {
|
||||||
l := log.WithFields(kv.Fields{
|
l := log.WithContext(ctx).
|
||||||
{"timelineAccountID", timelineAccountID},
|
WithFields(kv.Fields{
|
||||||
{"itemID", item.GetID()},
|
{"timelineAccountID", timelineAccountID},
|
||||||
}...)
|
{"itemID", item.GetID()},
|
||||||
|
}...)
|
||||||
|
|
||||||
t, err := m.getOrCreateTimeline(ctx, timelineAccountID)
|
t, err := m.getOrCreateTimeline(ctx, timelineAccountID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -149,10 +150,11 @@ func (m *manager) Ingest(ctx context.Context, item Timelineable, timelineAccount
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *manager) IngestAndPrepare(ctx context.Context, item Timelineable, timelineAccountID string) (bool, error) {
|
func (m *manager) IngestAndPrepare(ctx context.Context, item Timelineable, timelineAccountID string) (bool, error) {
|
||||||
l := log.WithFields(kv.Fields{
|
l := log.WithContext(ctx).
|
||||||
{"timelineAccountID", timelineAccountID},
|
WithFields(kv.Fields{
|
||||||
{"itemID", item.GetID()},
|
{"timelineAccountID", timelineAccountID},
|
||||||
}...)
|
{"itemID", item.GetID()},
|
||||||
|
}...)
|
||||||
|
|
||||||
t, err := m.getOrCreateTimeline(ctx, timelineAccountID)
|
t, err := m.getOrCreateTimeline(ctx, timelineAccountID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -164,10 +166,11 @@ func (m *manager) IngestAndPrepare(ctx context.Context, item Timelineable, timel
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *manager) Remove(ctx context.Context, timelineAccountID string, itemID string) (int, error) {
|
func (m *manager) Remove(ctx context.Context, timelineAccountID string, itemID string) (int, error) {
|
||||||
l := log.WithFields(kv.Fields{
|
l := log.WithContext(ctx).
|
||||||
{"timelineAccountID", timelineAccountID},
|
WithFields(kv.Fields{
|
||||||
{"itemID", itemID},
|
{"timelineAccountID", timelineAccountID},
|
||||||
}...)
|
{"itemID", itemID},
|
||||||
|
}...)
|
||||||
|
|
||||||
t, err := m.getOrCreateTimeline(ctx, timelineAccountID)
|
t, err := m.getOrCreateTimeline(ctx, timelineAccountID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -179,7 +182,8 @@ func (m *manager) Remove(ctx context.Context, timelineAccountID string, itemID s
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *manager) GetTimeline(ctx context.Context, timelineAccountID string, maxID string, sinceID string, minID string, limit int, local bool) ([]Preparable, error) {
|
func (m *manager) GetTimeline(ctx context.Context, timelineAccountID string, maxID string, sinceID string, minID string, limit int, local bool) ([]Preparable, error) {
|
||||||
l := log.WithFields(kv.Fields{{"timelineAccountID", timelineAccountID}}...)
|
l := log.WithContext(ctx).
|
||||||
|
WithFields(kv.Fields{{"timelineAccountID", timelineAccountID}}...)
|
||||||
|
|
||||||
t, err := m.getOrCreateTimeline(ctx, timelineAccountID)
|
t, err := m.getOrCreateTimeline(ctx, timelineAccountID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -31,7 +31,8 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func (t *timeline) PrepareFromTop(ctx context.Context, amount int) error {
|
func (t *timeline) PrepareFromTop(ctx context.Context, amount int) error {
|
||||||
l := log.WithFields(kv.Fields{{"amount", amount}}...)
|
l := log.WithContext(ctx).
|
||||||
|
WithFields(kv.Fields{{"amount", amount}}...)
|
||||||
|
|
||||||
// lazily initialize prepared posts if it hasn't been done already
|
// lazily initialize prepared posts if it hasn't been done already
|
||||||
if t.preparedItems.data == nil {
|
if t.preparedItems.data == nil {
|
||||||
|
@ -85,12 +86,13 @@ prepareloop:
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *timeline) prepareNextQuery(ctx context.Context, amount int, maxID string, sinceID string, minID string) error {
|
func (t *timeline) prepareNextQuery(ctx context.Context, amount int, maxID string, sinceID string, minID string) error {
|
||||||
l := log.WithFields(kv.Fields{
|
l := log.WithContext(ctx).
|
||||||
{"amount", amount},
|
WithFields(kv.Fields{
|
||||||
{"maxID", maxID},
|
{"amount", amount},
|
||||||
{"sinceID", sinceID},
|
{"maxID", maxID},
|
||||||
{"minID", minID},
|
{"sinceID", sinceID},
|
||||||
}...)
|
{"minID", minID},
|
||||||
|
}...)
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
switch {
|
switch {
|
||||||
|
|
|
@ -28,10 +28,11 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func (t *timeline) Remove(ctx context.Context, statusID string) (int, error) {
|
func (t *timeline) Remove(ctx context.Context, statusID string) (int, error) {
|
||||||
l := log.WithFields(kv.Fields{
|
l := log.WithContext(ctx).
|
||||||
{"accountTimeline", t.accountID},
|
WithFields(kv.Fields{
|
||||||
{"statusID", statusID},
|
{"accountTimeline", t.accountID},
|
||||||
}...)
|
{"statusID", statusID},
|
||||||
|
}...)
|
||||||
|
|
||||||
t.Lock()
|
t.Lock()
|
||||||
defer t.Unlock()
|
defer t.Unlock()
|
||||||
|
@ -80,10 +81,11 @@ func (t *timeline) Remove(ctx context.Context, statusID string) (int, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *timeline) RemoveAllBy(ctx context.Context, accountID string) (int, error) {
|
func (t *timeline) RemoveAllBy(ctx context.Context, accountID string) (int, error) {
|
||||||
l := log.WithFields(kv.Fields{
|
l := log.WithContext(ctx).
|
||||||
{"accountTimeline", t.accountID},
|
WithFields(kv.Fields{
|
||||||
{"accountID", accountID},
|
{"accountTimeline", t.accountID},
|
||||||
}...)
|
{"accountID", accountID},
|
||||||
|
}...)
|
||||||
|
|
||||||
t.Lock()
|
t.Lock()
|
||||||
defer t.Unlock()
|
defer t.Unlock()
|
||||||
|
|
|
@ -48,7 +48,7 @@ func (i *importer) Import(ctx context.Context, path string) error {
|
||||||
err := decoder.Decode(&entry)
|
err := decoder.Decode(&entry)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == io.EOF {
|
if err == io.EOF {
|
||||||
log.Infof("Import: reached end of file")
|
log.Infof(ctx, "reached end of file")
|
||||||
return neatClose(file)
|
return neatClose(file)
|
||||||
}
|
}
|
||||||
return fmt.Errorf("Import: error decoding in readLoop: %s", err)
|
return fmt.Errorf("Import: error decoding in readLoop: %s", err)
|
||||||
|
@ -74,7 +74,7 @@ func (i *importer) inputEntry(ctx context.Context, entry transmodel.Entry) error
|
||||||
if err := i.putInDB(ctx, account); err != nil {
|
if err := i.putInDB(ctx, account); err != nil {
|
||||||
return fmt.Errorf("inputEntry: error adding account to database: %s", err)
|
return fmt.Errorf("inputEntry: error adding account to database: %s", err)
|
||||||
}
|
}
|
||||||
log.Infof("inputEntry: added account with id %s", account.ID)
|
log.Infof(ctx, "added account with id %s", account.ID)
|
||||||
return nil
|
return nil
|
||||||
case transmodel.TransBlock:
|
case transmodel.TransBlock:
|
||||||
block, err := i.blockDecode(entry)
|
block, err := i.blockDecode(entry)
|
||||||
|
@ -84,7 +84,7 @@ func (i *importer) inputEntry(ctx context.Context, entry transmodel.Entry) error
|
||||||
if err := i.putInDB(ctx, block); err != nil {
|
if err := i.putInDB(ctx, block); err != nil {
|
||||||
return fmt.Errorf("inputEntry: error adding block to database: %s", err)
|
return fmt.Errorf("inputEntry: error adding block to database: %s", err)
|
||||||
}
|
}
|
||||||
log.Infof("inputEntry: added block with id %s", block.ID)
|
log.Infof(ctx, "added block with id %s", block.ID)
|
||||||
return nil
|
return nil
|
||||||
case transmodel.TransDomainBlock:
|
case transmodel.TransDomainBlock:
|
||||||
block, err := i.domainBlockDecode(entry)
|
block, err := i.domainBlockDecode(entry)
|
||||||
|
@ -94,7 +94,7 @@ func (i *importer) inputEntry(ctx context.Context, entry transmodel.Entry) error
|
||||||
if err := i.putInDB(ctx, block); err != nil {
|
if err := i.putInDB(ctx, block); err != nil {
|
||||||
return fmt.Errorf("inputEntry: error adding domain block to database: %s", err)
|
return fmt.Errorf("inputEntry: error adding domain block to database: %s", err)
|
||||||
}
|
}
|
||||||
log.Infof("inputEntry: added domain block with id %s", block.ID)
|
log.Infof(ctx, "added domain block with id %s", block.ID)
|
||||||
return nil
|
return nil
|
||||||
case transmodel.TransFollow:
|
case transmodel.TransFollow:
|
||||||
follow, err := i.followDecode(entry)
|
follow, err := i.followDecode(entry)
|
||||||
|
@ -104,7 +104,7 @@ func (i *importer) inputEntry(ctx context.Context, entry transmodel.Entry) error
|
||||||
if err := i.putInDB(ctx, follow); err != nil {
|
if err := i.putInDB(ctx, follow); err != nil {
|
||||||
return fmt.Errorf("inputEntry: error adding follow to database: %s", err)
|
return fmt.Errorf("inputEntry: error adding follow to database: %s", err)
|
||||||
}
|
}
|
||||||
log.Infof("inputEntry: added follow with id %s", follow.ID)
|
log.Infof(ctx, "added follow with id %s", follow.ID)
|
||||||
return nil
|
return nil
|
||||||
case transmodel.TransFollowRequest:
|
case transmodel.TransFollowRequest:
|
||||||
fr, err := i.followRequestDecode(entry)
|
fr, err := i.followRequestDecode(entry)
|
||||||
|
@ -114,7 +114,7 @@ func (i *importer) inputEntry(ctx context.Context, entry transmodel.Entry) error
|
||||||
if err := i.putInDB(ctx, fr); err != nil {
|
if err := i.putInDB(ctx, fr); err != nil {
|
||||||
return fmt.Errorf("inputEntry: error adding follow request to database: %s", err)
|
return fmt.Errorf("inputEntry: error adding follow request to database: %s", err)
|
||||||
}
|
}
|
||||||
log.Infof("inputEntry: added follow request with id %s", fr.ID)
|
log.Infof(ctx, "added follow request with id %s", fr.ID)
|
||||||
return nil
|
return nil
|
||||||
case transmodel.TransInstance:
|
case transmodel.TransInstance:
|
||||||
inst, err := i.instanceDecode(entry)
|
inst, err := i.instanceDecode(entry)
|
||||||
|
@ -124,7 +124,7 @@ func (i *importer) inputEntry(ctx context.Context, entry transmodel.Entry) error
|
||||||
if err := i.putInDB(ctx, inst); err != nil {
|
if err := i.putInDB(ctx, inst); err != nil {
|
||||||
return fmt.Errorf("inputEntry: error adding instance to database: %s", err)
|
return fmt.Errorf("inputEntry: error adding instance to database: %s", err)
|
||||||
}
|
}
|
||||||
log.Infof("inputEntry: added instance with id %s", inst.ID)
|
log.Infof(ctx, "added instance with id %s", inst.ID)
|
||||||
return nil
|
return nil
|
||||||
case transmodel.TransUser:
|
case transmodel.TransUser:
|
||||||
user, err := i.userDecode(entry)
|
user, err := i.userDecode(entry)
|
||||||
|
@ -134,11 +134,11 @@ func (i *importer) inputEntry(ctx context.Context, entry transmodel.Entry) error
|
||||||
if err := i.putInDB(ctx, user); err != nil {
|
if err := i.putInDB(ctx, user); err != nil {
|
||||||
return fmt.Errorf("inputEntry: error adding user to database: %s", err)
|
return fmt.Errorf("inputEntry: error adding user to database: %s", err)
|
||||||
}
|
}
|
||||||
log.Infof("inputEntry: added user with id %s", user.ID)
|
log.Infof(ctx, "added user with id %s", user.ID)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Errorf("inputEntry: didn't recognize transtype '%s', skipping it", t)
|
log.Errorf(ctx, "didn't recognize transtype '%s', skipping it", t)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -76,13 +76,13 @@ func NewController(db db.DB, federatingDB federatingdb.DB, clock pub.Clock, clie
|
||||||
// Transport cache has TTL=1hr freq=1min
|
// Transport cache has TTL=1hr freq=1min
|
||||||
c.trspCache.SetTTL(time.Hour, false)
|
c.trspCache.SetTTL(time.Hour, false)
|
||||||
if !c.trspCache.Start(time.Minute) {
|
if !c.trspCache.Start(time.Minute) {
|
||||||
log.Panic("failed to start transport controller cache")
|
log.Panic(nil, "failed to start transport controller cache")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bad hosts cache has TTL=15min freq=1min
|
// Bad hosts cache has TTL=15min freq=1min
|
||||||
c.badHosts.SetTTL(15*time.Minute, false)
|
c.badHosts.SetTTL(15*time.Minute, false)
|
||||||
if !c.badHosts.Start(time.Minute) {
|
if !c.badHosts.Start(time.Minute) {
|
||||||
log.Panic("failed to start transport controller cache")
|
log.Panic(nil, "failed to start transport controller cache")
|
||||||
}
|
}
|
||||||
|
|
||||||
return c
|
return c
|
||||||
|
|
|
@ -45,26 +45,26 @@ func (t *transport) DereferenceInstance(ctx context.Context, iri *url.URL) (*gts
|
||||||
// This will provide the most complete picture of an instance, and avoid unnecessary api calls.
|
// This will provide the most complete picture of an instance, and avoid unnecessary api calls.
|
||||||
//
|
//
|
||||||
// This will only work with Mastodon-api compatible instances: Mastodon, some Pleroma instances, GoToSocial.
|
// This will only work with Mastodon-api compatible instances: Mastodon, some Pleroma instances, GoToSocial.
|
||||||
log.Debugf("trying to dereference instance %s by /api/v1/instance", iri.Host)
|
log.Debugf(ctx, "trying to dereference instance %s by /api/v1/instance", iri.Host)
|
||||||
i, err = dereferenceByAPIV1Instance(ctx, t, iri)
|
i, err = dereferenceByAPIV1Instance(ctx, t, iri)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
log.Debugf("successfully dereferenced instance using /api/v1/instance")
|
log.Debugf(ctx, "successfully dereferenced instance using /api/v1/instance")
|
||||||
return i, nil
|
return i, nil
|
||||||
}
|
}
|
||||||
log.Debugf("couldn't dereference instance using /api/v1/instance: %s", err)
|
log.Debugf(ctx, "couldn't dereference instance using /api/v1/instance: %s", err)
|
||||||
|
|
||||||
// If that doesn't work, try to dereference using /.well-known/nodeinfo.
|
// If that doesn't work, try to dereference using /.well-known/nodeinfo.
|
||||||
// This will involve two API calls and return less info overall, but should be more widely compatible.
|
// This will involve two API calls and return less info overall, but should be more widely compatible.
|
||||||
log.Debugf("trying to dereference instance %s by /.well-known/nodeinfo", iri.Host)
|
log.Debugf(ctx, "trying to dereference instance %s by /.well-known/nodeinfo", iri.Host)
|
||||||
i, err = dereferenceByNodeInfo(ctx, t, iri)
|
i, err = dereferenceByNodeInfo(ctx, t, iri)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
log.Debugf("successfully dereferenced instance using /.well-known/nodeinfo")
|
log.Debugf(ctx, "successfully dereferenced instance using /.well-known/nodeinfo")
|
||||||
return i, nil
|
return i, nil
|
||||||
}
|
}
|
||||||
log.Debugf("couldn't dereference instance using /.well-known/nodeinfo: %s", err)
|
log.Debugf(ctx, "couldn't dereference instance using /.well-known/nodeinfo: %s", err)
|
||||||
|
|
||||||
// we couldn't dereference the instance using any of the known methods, so just return a minimal representation
|
// we couldn't dereference the instance using any of the known methods, so just return a minimal representation
|
||||||
log.Debugf("returning minimal representation of instance %s", iri.Host)
|
log.Debugf(ctx, "returning minimal representation of instance %s", iri.Host)
|
||||||
id, err := id.NewRandomULID()
|
id, err := id.NewRandomULID()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("error creating new id for instance %s: %s", iri.Host, err)
|
return nil, fmt.Errorf("error creating new id for instance %s: %s", iri.Host, err)
|
||||||
|
|
|
@ -130,11 +130,12 @@ func (t *transport) do(r *http.Request, signer func(*http.Request) error) (*http
|
||||||
fastFail := IsFastfail(r.Context())
|
fastFail := IsFastfail(r.Context())
|
||||||
|
|
||||||
// Start a log entry for this request
|
// Start a log entry for this request
|
||||||
l := log.WithFields(kv.Fields{
|
l := log.WithContext(r.Context()).
|
||||||
{"pubKeyID", t.pubKeyID},
|
WithFields(kv.Fields{
|
||||||
{"method", r.Method},
|
{"pubKeyID", t.pubKeyID},
|
||||||
{"url", r.URL.String()},
|
{"method", r.Method},
|
||||||
}...)
|
{"url", r.URL.String()},
|
||||||
|
}...)
|
||||||
|
|
||||||
r.Header.Set("User-Agent", t.controller.userAgent)
|
r.Header.Set("User-Agent", t.controller.userAgent)
|
||||||
|
|
||||||
|
|
|
@ -82,7 +82,7 @@ func (c *converter) ASRepresentationToAccount(ctx context.Context, accountable a
|
||||||
|
|
||||||
// account emojis (used in bio, display name, fields)
|
// account emojis (used in bio, display name, fields)
|
||||||
if emojis, err := ap.ExtractEmojis(accountable); err != nil {
|
if emojis, err := ap.ExtractEmojis(accountable); err != nil {
|
||||||
log.Infof("ASRepresentationToAccount: error extracting account emojis: %s", err)
|
log.Infof(nil, "error extracting account emojis: %s", err)
|
||||||
} else {
|
} else {
|
||||||
acct.Emojis = emojis
|
acct.Emojis = emojis
|
||||||
}
|
}
|
||||||
|
@ -217,13 +217,13 @@ func (c *converter) extractAttachments(i ap.WithAttachment) []*gtsmodel.MediaAtt
|
||||||
|
|
||||||
attachmentable, ok := t.(ap.Attachmentable)
|
attachmentable, ok := t.(ap.Attachmentable)
|
||||||
if !ok {
|
if !ok {
|
||||||
log.Error("ap attachment was not attachmentable")
|
log.Error(nil, "ap attachment was not attachmentable")
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
attachment, err := ap.ExtractAttachment(attachmentable)
|
attachment, err := ap.ExtractAttachment(attachmentable)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("error extracting attachment: %s", err)
|
log.Errorf(nil, "error extracting attachment: %s", err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -684,7 +684,7 @@ func (c *converter) ASFlagToReport(ctx context.Context, flaggable ap.Flaggable)
|
||||||
return nil, fmt.Errorf("ASFlagToReport: db error getting status with url %s: %w", statusURIString, err)
|
return nil, fmt.Errorf("ASFlagToReport: db error getting status with url %s: %w", statusURIString, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Warnf("ASFlagToReport: reported status %s could not be found in the db, skipping it", statusURIString)
|
log.Warnf(nil, "reported status %s could not be found in the db, skipping it", statusURIString)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,13 +41,13 @@ const defaultHeaderPath = "/assets/default_header.png"
|
||||||
func populateDefaultAvatars() (defaultAvatars []string) {
|
func populateDefaultAvatars() (defaultAvatars []string) {
|
||||||
webAssetsAbsFilePath, err := filepath.Abs(config.GetWebAssetBaseDir())
|
webAssetsAbsFilePath, err := filepath.Abs(config.GetWebAssetBaseDir())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Panicf("populateDefaultAvatars: error getting abs path for web assets: %s", err)
|
log.Panicf(nil, "error getting abs path for web assets: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
defaultAvatarsAbsFilePath := filepath.Join(webAssetsAbsFilePath, "default_avatars")
|
defaultAvatarsAbsFilePath := filepath.Join(webAssetsAbsFilePath, "default_avatars")
|
||||||
defaultAvatarFiles, err := os.ReadDir(defaultAvatarsAbsFilePath)
|
defaultAvatarFiles, err := os.ReadDir(defaultAvatarsAbsFilePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warnf("populateDefaultAvatars: error reading default avatars at %s: %s", defaultAvatarsAbsFilePath, err)
|
log.Warnf(nil, "error reading default avatars at %s: %s", defaultAvatarsAbsFilePath, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue