From aa9ce272dcfa1380b2f05bc3a90ef8ca1b0a7f62 Mon Sep 17 00:00:00 2001 From: Tobi Smethurst <31960611+tsmethurst@users.noreply.github.com> Date: Mon, 22 Mar 2021 22:26:54 +0100 Subject: Oauth/token (#7) * add host and protocol options * some fiddling * tidying up and comments * tick off /oauth/token * tidying a bit * tidying * go mod tidy * allow attaching middleware to server * add middleware * more user friendly * add comments * comments * store account + app * tidying * lots of restructuring * lint + tidy --- internal/db/actions.go | 11 +- internal/db/db.go | 47 ++++--- internal/db/pg-fed.go | 137 +++++++++++++++++++ internal/db/pg.go | 251 +++++++++++++++++++++++++++++++++++ internal/db/postgres.go | 343 ------------------------------------------------ 5 files changed, 426 insertions(+), 363 deletions(-) create mode 100644 internal/db/pg-fed.go create mode 100644 internal/db/pg.go delete mode 100644 internal/db/postgres.go (limited to 'internal/db') diff --git a/internal/db/actions.go b/internal/db/actions.go index 6fa7d23ae..01fb44b5d 100644 --- a/internal/db/actions.go +++ b/internal/db/actions.go @@ -28,9 +28,10 @@ import ( // Initialize will initialize the database given in the config for use with GoToSocial var Initialize action.GTSAction = func(ctx context.Context, c *config.Config, log *logrus.Logger) error { - db, err := New(ctx, c, log) - if err != nil { - return err - } - return db.CreateSchema(ctx) + // db, err := New(ctx, c, log) + // if err != nil { + // return err + // } + return nil + // return db.CreateSchema(ctx) } diff --git a/internal/db/db.go b/internal/db/db.go index 4ea4e1af6..9952e5e97 100644 --- a/internal/db/db.go +++ b/internal/db/db.go @@ -30,30 +30,47 @@ import ( const dbTypePostgres string = "POSTGRES" -// DB provides methods for interacting with an underlying database (for now, just postgres). -// The function mapping lines up with the DB interface described in go-fed. -// See here: https://github.com/go-fed/activity/blob/master/pub/database.go +// DB provides methods for interacting with an underlying database or other storage mechanism (for now, just postgres). type DB interface { - /* - GO-FED DATABASE FUNCTIONS - */ - pub.Database + // Federation returns an interface that's compatible with go-fed, for performing federation storage/retrieval functions. + // See: https://pkg.go.dev/github.com/go-fed/activity@v1.0.0/pub?utm_source=gopls#Database + Federation() pub.Database - /* - ANY ADDITIONAL DESIRED FUNCTIONS - */ + // CreateTable creates a table for the given interface + CreateTable(i interface{}) error - // CreateSchema should populate the database with the required tables - CreateSchema(context.Context) error + // DropTable drops the table for the given interface + DropTable(i interface{}) error // Stop should stop and close the database connection cleanly, returning an error if this is not possible - Stop(context.Context) error + Stop(ctx context.Context) error // IsHealthy should return nil if the database connection is healthy, or an error if not - IsHealthy(context.Context) error + IsHealthy(ctx context.Context) error + + // GetByID gets one entry by its id. + GetByID(id string, i interface{}) error + + // GetWhere gets one entry where key = value + GetWhere(key string, value interface{}, i interface{}) error + + // GetAll gets all entries of interface type i + GetAll(i interface{}) error + + // Put stores i + Put(i interface{}) error + + // Update by id updates i with id id + UpdateByID(id string, i interface{}) error + + // Delete by id removes i with id id + DeleteByID(id string, i interface{}) error + + // Delete where deletes i where key = value + DeleteWhere(key string, value interface{}, i interface{}) error } -// New returns a new database service that satisfies the Service interface and, by extension, +// New returns a new database service that satisfies the DB interface and, by extension, // the go-fed database interface described here: https://github.com/go-fed/activity/blob/master/pub/database.go func New(ctx context.Context, c *config.Config, log *logrus.Logger) (DB, error) { switch strings.ToUpper(c.DBConfig.Type) { diff --git a/internal/db/pg-fed.go b/internal/db/pg-fed.go new file mode 100644 index 000000000..ec1957abc --- /dev/null +++ b/internal/db/pg-fed.go @@ -0,0 +1,137 @@ +package db + +import ( + "context" + "errors" + "net/url" + "sync" + + "github.com/go-fed/activity/pub" + "github.com/go-fed/activity/streams" + "github.com/go-fed/activity/streams/vocab" + "github.com/go-pg/pg/v10" +) + +type postgresFederation struct { + locks *sync.Map + conn *pg.DB +} + +func newPostgresFederation(conn *pg.DB) pub.Database { + return &postgresFederation{ + locks: new(sync.Map), + conn: conn, + } +} + +/* + GO-FED DB INTERFACE-IMPLEMENTING FUNCTIONS +*/ +func (pf *postgresFederation) Lock(ctx context.Context, id *url.URL) error { + // Before any other Database methods are called, the relevant `id` + // entries are locked to allow for fine-grained concurrency. + + // Strategy: create a new lock, if stored, continue. Otherwise, lock the + // existing mutex. + mu := &sync.Mutex{} + mu.Lock() // Optimistically lock if we do store it. + i, loaded := pf.locks.LoadOrStore(id.String(), mu) + if loaded { + mu = i.(*sync.Mutex) + mu.Lock() + } + return nil +} + +func (pf *postgresFederation) Unlock(ctx context.Context, id *url.URL) error { + // Once Go-Fed is done calling Database methods, the relevant `id` + // entries are unlocked. + + i, ok := pf.locks.Load(id.String()) + if !ok { + return errors.New("missing an id in unlock") + } + mu := i.(*sync.Mutex) + mu.Unlock() + return nil +} + +func (pf *postgresFederation) InboxContains(ctx context.Context, inbox *url.URL, id *url.URL) (bool, error) { + return false, nil +} + +func (pf *postgresFederation) GetInbox(ctx context.Context, inboxIRI *url.URL) (inbox vocab.ActivityStreamsOrderedCollectionPage, err error) { + return nil, nil +} + +func (pf *postgresFederation) SetInbox(ctx context.Context, inbox vocab.ActivityStreamsOrderedCollectionPage) error { + return nil +} + +func (pf *postgresFederation) Owns(ctx context.Context, id *url.URL) (owns bool, err error) { + return false, nil +} + +func (pf *postgresFederation) ActorForOutbox(ctx context.Context, outboxIRI *url.URL) (actorIRI *url.URL, err error) { + return nil, nil +} + +func (pf *postgresFederation) ActorForInbox(ctx context.Context, inboxIRI *url.URL) (actorIRI *url.URL, err error) { + return nil, nil +} + +func (pf *postgresFederation) OutboxForInbox(ctx context.Context, inboxIRI *url.URL) (outboxIRI *url.URL, err error) { + return nil, nil +} + +func (pf *postgresFederation) Exists(ctx context.Context, id *url.URL) (exists bool, err error) { + return false, nil +} + +func (pf *postgresFederation) Get(ctx context.Context, id *url.URL) (value vocab.Type, err error) { + return nil, nil +} + +func (pf *postgresFederation) Create(ctx context.Context, asType vocab.Type) error { + t, err := streams.NewTypeResolver() + if err != nil { + return err + } + if err := t.Resolve(ctx, asType); err != nil { + return err + } + asType.GetTypeName() + return nil +} + +func (pf *postgresFederation) Update(ctx context.Context, asType vocab.Type) error { + return nil +} + +func (pf *postgresFederation) Delete(ctx context.Context, id *url.URL) error { + return nil +} + +func (pf *postgresFederation) GetOutbox(ctx context.Context, outboxIRI *url.URL) (inbox vocab.ActivityStreamsOrderedCollectionPage, err error) { + return nil, nil +} + +func (pf *postgresFederation) SetOutbox(ctx context.Context, outbox vocab.ActivityStreamsOrderedCollectionPage) error { + return nil +} + +func (pf *postgresFederation) NewID(ctx context.Context, t vocab.Type) (id *url.URL, err error) { + return nil, nil +} + +func (pf *postgresFederation) Followers(ctx context.Context, actorIRI *url.URL) (followers vocab.ActivityStreamsCollection, err error) { + return nil, nil +} + +func (pf *postgresFederation) Following(ctx context.Context, actorIRI *url.URL) (followers vocab.ActivityStreamsCollection, err error) { + return nil, nil +} + +func (pf *postgresFederation) Liked(ctx context.Context, actorIRI *url.URL) (followers vocab.ActivityStreamsCollection, err error) { + return nil, nil +} diff --git a/internal/db/pg.go b/internal/db/pg.go new file mode 100644 index 000000000..487af184f --- /dev/null +++ b/internal/db/pg.go @@ -0,0 +1,251 @@ +/* + GoToSocial + Copyright (C) 2021 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 . +*/ + +package db + +import ( + "context" + "errors" + "fmt" + "regexp" + "strings" + "time" + + "github.com/go-fed/activity/pub" + "github.com/go-pg/pg/extra/pgdebug" + "github.com/go-pg/pg/v10" + "github.com/go-pg/pg/v10/orm" + "github.com/gotosocial/gotosocial/internal/config" + "github.com/gotosocial/gotosocial/internal/gtsmodel" + "github.com/sirupsen/logrus" +) + +// postgresService satisfies the DB interface +type postgresService struct { + config *config.DBConfig + conn *pg.DB + log *logrus.Entry + cancel context.CancelFunc + federationDB pub.Database +} + +// newPostgresService returns a postgresService derived from the provided config, which implements the go-fed DB interface. +// Under the hood, it uses https://github.com/go-pg/pg to create and maintain a database connection. +func newPostgresService(ctx context.Context, c *config.Config, log *logrus.Entry) (*postgresService, error) { + opts, err := derivePGOptions(c) + if err != nil { + return nil, fmt.Errorf("could not create postgres service: %s", err) + } + log.Debugf("using pg options: %+v", opts) + + readyChan := make(chan interface{}) + opts.OnConnect = func(ctx context.Context, c *pg.Conn) error { + close(readyChan) + return nil + } + + // create a connection + pgCtx, cancel := context.WithCancel(ctx) + conn := pg.Connect(opts).WithContext(pgCtx) + + // this will break the logfmt format we normally log in, + // since we can't choose where pg outputs to and it defaults to + // stdout. So use this option with care! + if log.Logger.GetLevel() >= logrus.TraceLevel { + conn.AddQueryHook(pgdebug.DebugHook{ + // Print all queries. + Verbose: true, + }) + } + + // actually *begin* the connection so that we can tell if the db is there + // and listening, and also trigger the opts.OnConnect function passed in above + if err := conn.Ping(ctx); err != nil { + cancel() + return nil, fmt.Errorf("db connection error: %s", err) + } + + // print out discovered postgres version + var version string + if _, err = conn.QueryOneContext(ctx, pg.Scan(&version), "SELECT version()"); err != nil { + cancel() + return nil, fmt.Errorf("db connection error: %s", err) + } + log.Infof("connected to postgres version: %s", version) + + // make sure the opts.OnConnect function has been triggered + // and closed the ready channel + select { + case <-readyChan: + log.Infof("postgres connection ready") + case <-time.After(5 * time.Second): + cancel() + return nil, errors.New("db connection timeout") + } + + // we can confidently return this useable postgres service now + return &postgresService{ + config: c.DBConfig, + conn: conn, + log: log, + cancel: cancel, + federationDB: newPostgresFederation(conn), + }, nil +} + +func (ps *postgresService) Federation() pub.Database { + return ps.federationDB +} + +/* + HANDY STUFF +*/ + +// derivePGOptions takes an application config and returns either a ready-to-use *pg.Options +// with sensible defaults, or an error if it's not satisfied by the provided config. +func derivePGOptions(c *config.Config) (*pg.Options, error) { + if strings.ToUpper(c.DBConfig.Type) != dbTypePostgres { + return nil, fmt.Errorf("expected db type of %s but got %s", dbTypePostgres, c.DBConfig.Type) + } + + // validate port + if c.DBConfig.Port == 0 { + return nil, errors.New("no port set") + } + + // validate address + if c.DBConfig.Address == "" { + return nil, errors.New("no address set") + } + + ipv4Regex := regexp.MustCompile(`^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$`) + hostnameRegex := regexp.MustCompile(`^(?:[a-z0-9]+(?:-[a-z0-9]+)*\.)+[a-z]{2,}$`) + if !hostnameRegex.MatchString(c.DBConfig.Address) && !ipv4Regex.MatchString(c.DBConfig.Address) && c.DBConfig.Address != "localhost" { + return nil, fmt.Errorf("address %s was neither an ipv4 address nor a valid hostname", c.DBConfig.Address) + } + + // validate username + if c.DBConfig.User == "" { + return nil, errors.New("no user set") + } + + // validate that there's a password + if c.DBConfig.Password == "" { + return nil, errors.New("no password set") + } + + // validate database + if c.DBConfig.Database == "" { + return nil, errors.New("no database set") + } + + // We can rely on the pg library we're using to set + // sensible defaults for everything we don't set here. + options := &pg.Options{ + Addr: fmt.Sprintf("%s:%d", c.DBConfig.Address, c.DBConfig.Port), + User: c.DBConfig.User, + Password: c.DBConfig.Password, + Database: c.DBConfig.Database, + ApplicationName: c.ApplicationName, + } + + return options, nil +} + +/* + EXTRA FUNCTIONS +*/ + +func (ps *postgresService) Stop(ctx context.Context) error { + ps.log.Info("closing db connection") + if err := ps.conn.Close(); err != nil { + // only cancel if there's a problem closing the db + ps.cancel() + return err + } + return nil +} + +func (ps *postgresService) CreateSchema(ctx context.Context) error { + models := []interface{}{ + (*gtsmodel.Account)(nil), + (*gtsmodel.Status)(nil), + (*gtsmodel.User)(nil), + } + ps.log.Info("creating db schema") + + for _, model := range models { + err := ps.conn.Model(model).CreateTable(&orm.CreateTableOptions{ + IfNotExists: true, + }) + if err != nil { + return err + } + } + + ps.log.Info("db schema created") + return nil +} + +func (ps *postgresService) IsHealthy(ctx context.Context) error { + return ps.conn.Ping(ctx) +} + +func (ps *postgresService) CreateTable(i interface{}) error { + return ps.conn.Model(i).CreateTable(&orm.CreateTableOptions{ + IfNotExists: true, + }) +} + +func (ps *postgresService) DropTable(i interface{}) error { + return ps.conn.Model(i).DropTable(&orm.DropTableOptions{ + IfExists: true, + }) +} + +func (ps *postgresService) GetByID(id string, i interface{}) error { + return ps.conn.Model(i).Where("id = ?", id).Select() +} + +func (ps *postgresService) GetWhere(key string, value interface{}, i interface{}) error { + return ps.conn.Model(i).Where(fmt.Sprintf("%s = ?", key), value).Select() +} + +func (ps *postgresService) GetAll(i interface{}) error { + return ps.conn.Model(i).Select() +} + +func (ps *postgresService) Put(i interface{}) error { + _, err := ps.conn.Model(i).Insert(i) + return err +} + +func (ps *postgresService) UpdateByID(id string, i interface{}) error { + _, err := ps.conn.Model(i).OnConflict("(id) DO UPDATE").Insert() + return err +} + +func (ps *postgresService) DeleteByID(id string, i interface{}) error { + _, err := ps.conn.Model(i).Where("id = ?", id).Delete() + return err +} + +func (ps *postgresService) DeleteWhere(key string, value interface{}, i interface{}) error { + _, err := ps.conn.Model(i).Where(fmt.Sprintf("%s = ?", key), value).Delete() + return err +} diff --git a/internal/db/postgres.go b/internal/db/postgres.go deleted file mode 100644 index dae6b11e2..000000000 --- a/internal/db/postgres.go +++ /dev/null @@ -1,343 +0,0 @@ -/* - GoToSocial - Copyright (C) 2021 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 . -*/ - -package db - -import ( - "context" - "errors" - "fmt" - "net/url" - "regexp" - "strings" - "sync" - "time" - - "github.com/go-fed/activity/streams" - "github.com/go-fed/activity/streams/vocab" - "github.com/go-pg/pg/extra/pgdebug" - "github.com/go-pg/pg/v10" - "github.com/go-pg/pg/v10/orm" - "github.com/gotosocial/gotosocial/internal/config" - "github.com/gotosocial/gotosocial/internal/gtsmodel" - "github.com/gotosocial/oauth2/v4" - "github.com/sirupsen/logrus" -) - -type postgresService struct { - config *config.DBConfig - conn *pg.DB - log *logrus.Entry - cancel context.CancelFunc - locks *sync.Map - tokenStore oauth2.TokenStore -} - -// newPostgresService returns a postgresService derived from the provided config, which implements the go-fed DB interface. -// Under the hood, it uses https://github.com/go-pg/pg to create and maintain a database connection. -func newPostgresService(ctx context.Context, c *config.Config, log *logrus.Entry) (*postgresService, error) { - opts, err := derivePGOptions(c) - if err != nil { - return nil, fmt.Errorf("could not create postgres service: %s", err) - } - log.Debugf("using pg options: %+v", opts) - - readyChan := make(chan interface{}) - opts.OnConnect = func(ctx context.Context, c *pg.Conn) error { - close(readyChan) - return nil - } - - // create a connection - pgCtx, cancel := context.WithCancel(ctx) - conn := pg.Connect(opts).WithContext(pgCtx) - - // this will break the logfmt format we normally log in, - // since we can't choose where pg outputs to and it defaults to - // stdout. So use this option with care! - if log.Logger.GetLevel() >= logrus.TraceLevel { - conn.AddQueryHook(pgdebug.DebugHook{ - // Print all queries. - Verbose: true, - }) - } - - // actually *begin* the connection so that we can tell if the db is there - // and listening, and also trigger the opts.OnConnect function passed in above - if err := conn.Ping(ctx); err != nil { - cancel() - return nil, fmt.Errorf("db connection error: %s", err) - } - - // print out discovered postgres version - var version string - if _, err = conn.QueryOneContext(ctx, pg.Scan(&version), "SELECT version()"); err != nil { - cancel() - return nil, fmt.Errorf("db connection error: %s", err) - } - log.Infof("connected to postgres version: %s", version) - - // make sure the opts.OnConnect function has been triggered - // and closed the ready channel - select { - case <-readyChan: - log.Infof("postgres connection ready") - case <-time.After(5 * time.Second): - cancel() - return nil, errors.New("db connection timeout") - } - - // acc := model.StubAccount() - // if _, err := conn.Model(acc).Returning("id").Insert(); err != nil { - // cancel() - // return nil, fmt.Errorf("db insert error: %s", err) - // } - // log.Infof("created account with id %s", acc.ID) - - // note := &model.Note{ - // Visibility: &model.Visibility{ - // Local: true, - // }, - // CreatedAt: time.Now(), - // UpdatedAt: time.Now(), - // } - // if _, err := conn.WithContext(ctx).Model(note).Returning("id").Insert(); err != nil { - // cancel() - // return nil, fmt.Errorf("db insert error: %s", err) - // } - // log.Infof("created note with id %s", note.ID) - - // we can confidently return this useable postgres service now - return &postgresService{ - config: c.DBConfig, - conn: conn, - log: log, - cancel: cancel, - locks: &sync.Map{}, - }, nil -} - -/* - HANDY STUFF -*/ - -// derivePGOptions takes an application config and returns either a ready-to-use *pg.Options -// with sensible defaults, or an error if it's not satisfied by the provided config. -func derivePGOptions(c *config.Config) (*pg.Options, error) { - if strings.ToUpper(c.DBConfig.Type) != dbTypePostgres { - return nil, fmt.Errorf("expected db type of %s but got %s", dbTypePostgres, c.DBConfig.Type) - } - - // validate port - if c.DBConfig.Port == 0 { - return nil, errors.New("no port set") - } - - // validate address - if c.DBConfig.Address == "" { - return nil, errors.New("no address set") - } - - ipv4Regex := regexp.MustCompile(`^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$`) - hostnameRegex := regexp.MustCompile(`^(?:[a-z0-9]+(?:-[a-z0-9]+)*\.)+[a-z]{2,}$`) - if !hostnameRegex.MatchString(c.DBConfig.Address) && !ipv4Regex.MatchString(c.DBConfig.Address) && c.DBConfig.Address != "localhost" { - return nil, fmt.Errorf("address %s was neither an ipv4 address nor a valid hostname", c.DBConfig.Address) - } - - // validate username - if c.DBConfig.User == "" { - return nil, errors.New("no user set") - } - - // validate that there's a password - if c.DBConfig.Password == "" { - return nil, errors.New("no password set") - } - - // validate database - if c.DBConfig.Database == "" { - return nil, errors.New("no database set") - } - - // We can rely on the pg library we're using to set - // sensible defaults for everything we don't set here. - options := &pg.Options{ - Addr: fmt.Sprintf("%s:%d", c.DBConfig.Address, c.DBConfig.Port), - User: c.DBConfig.User, - Password: c.DBConfig.Password, - Database: c.DBConfig.Database, - ApplicationName: c.ApplicationName, - } - - return options, nil -} - -/* - GO-FED DB INTERFACE-IMPLEMENTING FUNCTIONS -*/ -func (ps *postgresService) Lock(ctx context.Context, id *url.URL) error { - // Before any other Database methods are called, the relevant `id` - // entries are locked to allow for fine-grained concurrency. - - // Strategy: create a new lock, if stored, continue. Otherwise, lock the - // existing mutex. - mu := &sync.Mutex{} - mu.Lock() // Optimistically lock if we do store it. - i, loaded := ps.locks.LoadOrStore(id.String(), mu) - if loaded { - mu = i.(*sync.Mutex) - mu.Lock() - } - return nil -} - -func (ps *postgresService) Unlock(ctx context.Context, id *url.URL) error { - // Once Go-Fed is done calling Database methods, the relevant `id` - // entries are unlocked. - - i, ok := ps.locks.Load(id.String()) - if !ok { - return errors.New("missing an id in unlock") - } - mu := i.(*sync.Mutex) - mu.Unlock() - return nil -} - -func (ps *postgresService) InboxContains(ctx context.Context, inbox *url.URL, id *url.URL) (bool, error) { - return false, nil -} - -func (ps *postgresService) GetInbox(ctx context.Context, inboxIRI *url.URL) (inbox vocab.ActivityStreamsOrderedCollectionPage, err error) { - return nil, nil -} - -func (ps *postgresService) SetInbox(ctx context.Context, inbox vocab.ActivityStreamsOrderedCollectionPage) error { - return nil -} - -func (ps *postgresService) Owns(ctx context.Context, id *url.URL) (owns bool, err error) { - return false, nil -} - -func (ps *postgresService) ActorForOutbox(ctx context.Context, outboxIRI *url.URL) (actorIRI *url.URL, err error) { - return nil, nil -} - -func (ps *postgresService) ActorForInbox(ctx context.Context, inboxIRI *url.URL) (actorIRI *url.URL, err error) { - return nil, nil -} - -func (ps *postgresService) OutboxForInbox(ctx context.Context, inboxIRI *url.URL) (outboxIRI *url.URL, err error) { - return nil, nil -} - -func (ps *postgresService) Exists(ctx context.Context, id *url.URL) (exists bool, err error) { - return false, nil -} - -func (ps *postgresService) Get(ctx context.Context, id *url.URL) (value vocab.Type, err error) { - return nil, nil -} - -func (ps *postgresService) Create(ctx context.Context, asType vocab.Type) error { - t, err := streams.NewTypeResolver() - if err != nil { - return err - } - if err := t.Resolve(ctx, asType); err != nil { - return err - } - asType.GetTypeName() - return nil -} - -func (ps *postgresService) Update(ctx context.Context, asType vocab.Type) error { - return nil -} - -func (ps *postgresService) Delete(ctx context.Context, id *url.URL) error { - return nil -} - -func (ps *postgresService) GetOutbox(ctx context.Context, outboxIRI *url.URL) (inbox vocab.ActivityStreamsOrderedCollectionPage, err error) { - return nil, nil -} - -func (ps *postgresService) SetOutbox(ctx context.Context, outbox vocab.ActivityStreamsOrderedCollectionPage) error { - return nil -} - -func (ps *postgresService) NewID(ctx context.Context, t vocab.Type) (id *url.URL, err error) { - return nil, nil -} - -func (ps *postgresService) Followers(ctx context.Context, actorIRI *url.URL) (followers vocab.ActivityStreamsCollection, err error) { - return nil, nil -} - -func (ps *postgresService) Following(ctx context.Context, actorIRI *url.URL) (followers vocab.ActivityStreamsCollection, err error) { - return nil, nil -} - -func (ps *postgresService) Liked(ctx context.Context, actorIRI *url.URL) (followers vocab.ActivityStreamsCollection, err error) { - return nil, nil -} - -/* - EXTRA FUNCTIONS -*/ - -func (ps *postgresService) Stop(ctx context.Context) error { - ps.log.Info("closing db connection") - if err := ps.conn.Close(); err != nil { - // only cancel if there's a problem closing the db - ps.cancel() - return err - } - return nil -} - -func (ps *postgresService) CreateSchema(ctx context.Context) error { - models := []interface{}{ - (*gtsmodel.Account)(nil), - (*gtsmodel.Status)(nil), - (*gtsmodel.User)(nil), - } - ps.log.Info("creating db schema") - - for _, model := range models { - err := ps.conn.Model(model).CreateTable(&orm.CreateTableOptions{ - IfNotExists: true, - }) - if err != nil { - return err - } - } - - ps.log.Info("db schema created") - return nil -} - -func (ps *postgresService) IsHealthy(ctx context.Context) error { - return ps.conn.Ping(ctx) -} - -func (ps *postgresService) TokenStore() oauth2.TokenStore { - return ps.tokenStore -} -- cgit v1.2.3