mirror of
https://github.com/ProtonMail/proton-bridge.git
synced 2025-12-10 04:36:43 +00:00
150 lines
3.9 KiB
Go
150 lines
3.9 KiB
Go
package app
|
|
|
|
import (
|
|
"fmt"
|
|
"path/filepath"
|
|
|
|
"github.com/ProtonMail/proton-bridge/v2/internal/constants"
|
|
"github.com/ProtonMail/proton-bridge/v2/internal/crash"
|
|
"github.com/ProtonMail/proton-bridge/v2/internal/focus"
|
|
bridgeCLI "github.com/ProtonMail/proton-bridge/v2/internal/frontend/cli"
|
|
"github.com/ProtonMail/proton-bridge/v2/internal/frontend/grpc"
|
|
"github.com/ProtonMail/proton-bridge/v2/internal/locations"
|
|
"github.com/ProtonMail/proton-bridge/v2/internal/sentry"
|
|
"github.com/ProtonMail/proton-bridge/v2/internal/useragent"
|
|
"github.com/ProtonMail/proton-bridge/v2/pkg/restarter"
|
|
"github.com/pkg/profile"
|
|
"github.com/urfave/cli/v2"
|
|
)
|
|
|
|
const (
|
|
flagCPUProfile = "cpu-prof"
|
|
flagCPUProfileShort = "p"
|
|
|
|
flagMemProfile = "mem-prof"
|
|
flagMemProfileShort = "m"
|
|
|
|
flagLogLevel = "log-level"
|
|
flagLogLevelShort = "l"
|
|
|
|
flagCLI = "cli"
|
|
flagCLIShort = "c"
|
|
|
|
flagNoWindow = "no-window"
|
|
flagNonInteractive = "non-interactive"
|
|
)
|
|
|
|
const (
|
|
appUsage = "Proton Mail IMAP and SMTP Bridge"
|
|
)
|
|
|
|
func New() *cli.App {
|
|
app := cli.NewApp()
|
|
|
|
app.Name = constants.FullAppName
|
|
app.Usage = appUsage
|
|
app.Flags = []cli.Flag{
|
|
&cli.BoolFlag{
|
|
Name: flagCPUProfile,
|
|
Aliases: []string{flagCPUProfileShort},
|
|
Usage: "Generate CPU profile",
|
|
},
|
|
&cli.BoolFlag{
|
|
Name: flagMemProfile,
|
|
Aliases: []string{flagMemProfileShort},
|
|
Usage: "Generate memory profile",
|
|
},
|
|
&cli.StringFlag{
|
|
Name: flagLogLevel,
|
|
Aliases: []string{flagLogLevelShort},
|
|
Usage: "Set the log level (one of panic, fatal, error, warn, info, debug)",
|
|
},
|
|
&cli.BoolFlag{
|
|
Name: flagCLI,
|
|
Aliases: []string{flagCLIShort},
|
|
Usage: "Use command line interface",
|
|
},
|
|
&cli.BoolFlag{
|
|
Name: flagNoWindow,
|
|
Usage: "Don't show window after start",
|
|
Hidden: true,
|
|
},
|
|
}
|
|
|
|
app.Action = run
|
|
|
|
return app
|
|
}
|
|
|
|
func run(c *cli.Context) error {
|
|
// If there's another instance already running, try to raise it and exit.
|
|
if raised := focus.TryRaise(); raised {
|
|
return nil
|
|
}
|
|
|
|
// Start CPU profile if requested.
|
|
if c.Bool(flagCPUProfile) {
|
|
p := profile.Start(profile.CPUProfile, profile.ProfilePath("."))
|
|
defer p.Stop()
|
|
}
|
|
|
|
// Start memory profile if requested.
|
|
if c.Bool(flagMemProfile) {
|
|
p := profile.Start(profile.MemProfile, profile.MemProfileAllocs, profile.ProfilePath("."))
|
|
defer p.Stop()
|
|
}
|
|
|
|
// Create the restarter.
|
|
restarter := restarter.New()
|
|
defer restarter.Restart()
|
|
|
|
// Create a user agent that will be used for all requests.
|
|
identifier := useragent.New()
|
|
|
|
// Create a crash handler that will send crash reports to sentry.
|
|
crashHandler := crash.NewHandler(
|
|
sentry.NewReporter(constants.FullAppName, constants.Version, identifier).ReportException,
|
|
crash.ShowErrorNotification(constants.FullAppName),
|
|
func(r interface{}) error { restarter.Set(true, true); return nil },
|
|
)
|
|
defer crashHandler.HandlePanic()
|
|
|
|
// Create a locations provider to determine where to store our files.
|
|
provider, err := locations.NewDefaultProvider(filepath.Join(constants.VendorName, constants.ConfigName))
|
|
if err != nil {
|
|
return fmt.Errorf("could not create locations provider: %w", err)
|
|
}
|
|
|
|
// Create a new locations object that will be used to provide paths to store files.
|
|
locations := locations.New(provider, constants.ConfigName)
|
|
|
|
// Initialize the logging.
|
|
if err := initLogging(c, locations, crashHandler); err != nil {
|
|
return fmt.Errorf("could not initialize logging: %w", err)
|
|
}
|
|
|
|
// Create the bridge.
|
|
bridge, err := newBridge(locations, identifier)
|
|
if err != nil {
|
|
return fmt.Errorf("could not create bridge: %w", err)
|
|
}
|
|
defer bridge.Close(c.Context)
|
|
|
|
// Start the frontend.
|
|
switch {
|
|
case c.Bool(flagCLI):
|
|
return bridgeCLI.New(bridge).Loop()
|
|
|
|
case c.Bool(flagNonInteractive):
|
|
select {}
|
|
|
|
default:
|
|
service, err := grpc.NewService(crashHandler, restarter, locations, bridge, !c.Bool(flagNoWindow))
|
|
if err != nil {
|
|
return fmt.Errorf("could not create service: %w", err)
|
|
}
|
|
|
|
return service.Loop()
|
|
}
|
|
}
|