diff options
Diffstat (limited to 'cmd/gotosocial/action/server/server.go')
-rw-r--r-- | cmd/gotosocial/action/server/server.go | 225 |
1 files changed, 225 insertions, 0 deletions
diff --git a/cmd/gotosocial/action/server/server.go b/cmd/gotosocial/action/server/server.go new file mode 100644 index 000000000..57384ac6f --- /dev/null +++ b/cmd/gotosocial/action/server/server.go @@ -0,0 +1,225 @@ +/* + 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 <http://www.gnu.org/licenses/>. +*/ + +package server + +import ( + "context" + "fmt" + "net/http" + "os" + "os/signal" + "syscall" + + "codeberg.org/gruf/go-store/kv" + "github.com/sirupsen/logrus" + "github.com/spf13/viper" + "github.com/superseriousbusiness/gotosocial/cmd/gotosocial/action" + "github.com/superseriousbusiness/gotosocial/internal/api" + "github.com/superseriousbusiness/gotosocial/internal/api/client/account" + "github.com/superseriousbusiness/gotosocial/internal/api/client/admin" + "github.com/superseriousbusiness/gotosocial/internal/api/client/app" + "github.com/superseriousbusiness/gotosocial/internal/api/client/auth" + "github.com/superseriousbusiness/gotosocial/internal/api/client/blocks" + "github.com/superseriousbusiness/gotosocial/internal/api/client/emoji" + "github.com/superseriousbusiness/gotosocial/internal/api/client/favourites" + "github.com/superseriousbusiness/gotosocial/internal/api/client/fileserver" + "github.com/superseriousbusiness/gotosocial/internal/api/client/filter" + "github.com/superseriousbusiness/gotosocial/internal/api/client/followrequest" + "github.com/superseriousbusiness/gotosocial/internal/api/client/instance" + "github.com/superseriousbusiness/gotosocial/internal/api/client/list" + mediaModule "github.com/superseriousbusiness/gotosocial/internal/api/client/media" + "github.com/superseriousbusiness/gotosocial/internal/api/client/notification" + "github.com/superseriousbusiness/gotosocial/internal/api/client/search" + "github.com/superseriousbusiness/gotosocial/internal/api/client/status" + "github.com/superseriousbusiness/gotosocial/internal/api/client/streaming" + "github.com/superseriousbusiness/gotosocial/internal/api/client/timeline" + userClient "github.com/superseriousbusiness/gotosocial/internal/api/client/user" + "github.com/superseriousbusiness/gotosocial/internal/api/s2s/nodeinfo" + "github.com/superseriousbusiness/gotosocial/internal/api/s2s/user" + "github.com/superseriousbusiness/gotosocial/internal/api/s2s/webfinger" + "github.com/superseriousbusiness/gotosocial/internal/api/security" + "github.com/superseriousbusiness/gotosocial/internal/config" + "github.com/superseriousbusiness/gotosocial/internal/db/bundb" + "github.com/superseriousbusiness/gotosocial/internal/email" + "github.com/superseriousbusiness/gotosocial/internal/federation" + "github.com/superseriousbusiness/gotosocial/internal/federation/federatingdb" + "github.com/superseriousbusiness/gotosocial/internal/gotosocial" + "github.com/superseriousbusiness/gotosocial/internal/media" + "github.com/superseriousbusiness/gotosocial/internal/oauth" + "github.com/superseriousbusiness/gotosocial/internal/oidc" + "github.com/superseriousbusiness/gotosocial/internal/processing" + "github.com/superseriousbusiness/gotosocial/internal/router" + timelineprocessing "github.com/superseriousbusiness/gotosocial/internal/timeline" + "github.com/superseriousbusiness/gotosocial/internal/transport" + "github.com/superseriousbusiness/gotosocial/internal/typeutils" + "github.com/superseriousbusiness/gotosocial/internal/web" +) + +// Start creates and starts a gotosocial server +var Start action.GTSAction = func(ctx context.Context) error { + dbService, err := bundb.NewBunDBService(ctx) + if err != nil { + return fmt.Errorf("error creating dbservice: %s", err) + } + + if err := dbService.CreateInstanceAccount(ctx); err != nil { + return fmt.Errorf("error creating instance account: %s", err) + } + + if err := dbService.CreateInstanceInstance(ctx); err != nil { + return fmt.Errorf("error creating instance instance: %s", err) + } + + federatingDB := federatingdb.New(dbService) + + router, err := router.New(ctx, dbService) + if err != nil { + return fmt.Errorf("error creating router: %s", err) + } + + // build converters and util + typeConverter := typeutils.NewConverter(dbService) + timelineManager := timelineprocessing.NewManager(dbService, typeConverter) + + // Open the storage backend + storageBasePath := viper.GetString(config.Keys.StorageBasePath) + storage, err := kv.OpenFile(storageBasePath, nil) + if err != nil { + return fmt.Errorf("error creating storage backend: %s", err) + } + + // build backend handlers + mediaHandler := media.New(dbService, storage) + oauthServer := oauth.New(ctx, dbService) + transportController := transport.NewController(dbService, &federation.Clock{}, http.DefaultClient) + federator := federation.NewFederator(dbService, federatingDB, transportController, typeConverter, mediaHandler) + + // decide whether to create a noop email sender (won't send emails) or a real one + var emailSender email.Sender + smtpHost := viper.GetString(config.Keys.SMTPHost) + if smtpHost != "" { + // host is defined so create a proper sender + emailSender, err = email.NewSender() + if err != nil { + return fmt.Errorf("error creating email sender: %s", err) + } + } else { + // no host is defined so create a noop sender + emailSender, err = email.NewNoopSender(nil) + if err != nil { + return fmt.Errorf("error creating noop email sender: %s", err) + } + } + + // create and start the message processor using the other services we've created so far + processor := processing.NewProcessor(typeConverter, federator, oauthServer, mediaHandler, storage, timelineManager, dbService, emailSender) + if err := processor.Start(ctx); err != nil { + return fmt.Errorf("error starting processor: %s", err) + } + + idp, err := oidc.NewIDP(ctx) + if err != nil { + return fmt.Errorf("error creating oidc idp: %s", err) + } + + // build client api modules + authModule := auth.New(dbService, oauthServer, idp) + accountModule := account.New(processor) + instanceModule := instance.New(processor) + appsModule := app.New(processor) + followRequestsModule := followrequest.New(processor) + webfingerModule := webfinger.New(processor) + nodeInfoModule := nodeinfo.New(processor) + webBaseModule := web.New(processor) + usersModule := user.New(processor) + timelineModule := timeline.New(processor) + notificationModule := notification.New(processor) + searchModule := search.New(processor) + filtersModule := filter.New(processor) + emojiModule := emoji.New(processor) + listsModule := list.New(processor) + mm := mediaModule.New(processor) + fileServerModule := fileserver.New(processor) + adminModule := admin.New(processor) + statusModule := status.New(processor) + securityModule := security.New(dbService, oauthServer) + streamingModule := streaming.New(processor) + favouritesModule := favourites.New(processor) + blocksModule := blocks.New(processor) + userClientModule := userClient.New(processor) + + apis := []api.ClientModule{ + // modules with middleware go first + securityModule, + authModule, + + // now everything else + webBaseModule, + accountModule, + instanceModule, + appsModule, + followRequestsModule, + mm, + fileServerModule, + adminModule, + statusModule, + webfingerModule, + nodeInfoModule, + usersModule, + timelineModule, + notificationModule, + searchModule, + filtersModule, + emojiModule, + listsModule, + streamingModule, + favouritesModule, + blocksModule, + userClientModule, + } + + for _, m := range apis { + if err := m.Route(router); err != nil { + return fmt.Errorf("routing error: %s", err) + } + } + + gts, err := gotosocial.NewServer(dbService, router, federator) + if err != nil { + return fmt.Errorf("error creating gotosocial service: %s", err) + } + + if err := gts.Start(ctx); err != nil { + return fmt.Errorf("error starting gotosocial service: %s", err) + } + + // catch shutdown signals from the operating system + sigs := make(chan os.Signal, 1) + signal.Notify(sigs, os.Interrupt, syscall.SIGTERM) + sig := <-sigs + logrus.Infof("received signal %s, shutting down", sig) + + // close down all running services in order + if err := gts.Stop(ctx); err != nil { + return fmt.Errorf("error closing gotosocial service: %s", err) + } + + logrus.Info("done! exiting...") + return nil +} |