forked from Silverfish/proton-bridge
GODT-1837: Fix restart.
GOTD-1837: added wait flag. GODT-1837: strip --wait flag from launcher command-line. GODT-1837: hide main window before restart.
This commit is contained in:
@ -31,8 +31,8 @@ using namespace bridgepp;
|
||||
EventStreamReader::EventStreamReader(QObject *parent)
|
||||
: Worker(parent)
|
||||
{
|
||||
connect(this, &EventStreamReader::started, [&]() { app().log().debug("EventStreamReader started"); });
|
||||
connect(this, &EventStreamReader::finished, [&]() { app().log().debug("EventStreamReader finished"); });
|
||||
connect(this, &EventStreamReader::started, this, &EventStreamReader::onStarted);
|
||||
connect(this, &EventStreamReader::finished, this, &EventStreamReader::onFinished);
|
||||
connect(this, &EventStreamReader::error, &app().log(), &Log::error);
|
||||
}
|
||||
|
||||
@ -57,3 +57,27 @@ void EventStreamReader::run()
|
||||
emit error(e.qwhat());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//****************************************************************************************************************************************************
|
||||
//
|
||||
//****************************************************************************************************************************************************
|
||||
void EventStreamReader::onStarted() const
|
||||
{
|
||||
app().log().debug("EventStreamReader started");
|
||||
}
|
||||
|
||||
|
||||
//****************************************************************************************************************************************************
|
||||
//
|
||||
//****************************************************************************************************************************************************
|
||||
void EventStreamReader::onFinished() const
|
||||
{
|
||||
app().log().debug("EventStreamReader finished");
|
||||
if (!app().bridgeMonitor())
|
||||
{
|
||||
// no bridge monitor means we are in a debug environment, running in attached mode. Event stream has terminated, so bridge is shutting
|
||||
// down. Because we're in attached mode, bridge-gui will not get notified that bridge is going down, so we shutdown manually here.
|
||||
qApp->exit(EXIT_SUCCESS);
|
||||
}
|
||||
}
|
||||
|
||||
@ -39,6 +39,8 @@ public: // member functions
|
||||
|
||||
public slots:
|
||||
void run() override; ///< Run the reader.
|
||||
void onStarted() const; ///< Slot for the 'started' signal.
|
||||
void onFinished() const; ///< Slot for the 'finished' signal.
|
||||
|
||||
signals:
|
||||
void eventReceived(QString eventString); ///< signal for events.
|
||||
|
||||
@ -229,6 +229,10 @@ void QMLBackend::restart()
|
||||
app().grpc().quit();
|
||||
}
|
||||
|
||||
|
||||
//****************************************************************************************************************************************************
|
||||
/// \param[in] launcher The path to the launcher.
|
||||
//****************************************************************************************************************************************************
|
||||
void QMLBackend::forceLauncher(QString launcher)
|
||||
{
|
||||
app().grpc().forceLauncher(launcher);
|
||||
@ -270,8 +274,9 @@ void QMLBackend::changeColorScheme(QString const &scheme)
|
||||
//****************************************************************************************************************************************************
|
||||
void QMLBackend::toggleUseSSLforSMTP(bool makeItActive)
|
||||
{
|
||||
if (app().grpc().setUseSSLForSMTP(makeItActive).ok())
|
||||
emit useSSLforSMTPChanged(makeItActive);
|
||||
// if call succeed, app will restart. No need to emit a value change signal, because it will trigger a read-back via gRPC that will fail.
|
||||
emit hideMainWindow();
|
||||
app().grpc().setUseSSLForSMTP(makeItActive);
|
||||
}
|
||||
|
||||
|
||||
@ -281,11 +286,21 @@ void QMLBackend::toggleUseSSLforSMTP(bool makeItActive)
|
||||
//****************************************************************************************************************************************************
|
||||
void QMLBackend::changePorts(int imapPort, int smtpPort)
|
||||
{
|
||||
if (app().grpc().changePorts(imapPort, smtpPort).ok())
|
||||
{
|
||||
emit portIMAPChanged(imapPort);
|
||||
emit portSMTPChanged(smtpPort);
|
||||
}
|
||||
// if call succeed, app will restart. No need to emit a value change signal, because it will trigger a read-back via gRPC that will fail.
|
||||
emit hideMainWindow();
|
||||
app().grpc().changePorts(imapPort, smtpPort);
|
||||
}
|
||||
|
||||
|
||||
//****************************************************************************************************************************************************
|
||||
/// \param[in] enable Is cache enabled?
|
||||
/// \param[in] path The path of the cache.
|
||||
//****************************************************************************************************************************************************
|
||||
void QMLBackend::changeLocalCache(bool enable, QUrl const &path)
|
||||
{
|
||||
// if call succeed, app will restart. No need to emit a value change signal, because it will trigger a read-back via gRPC that will fail.
|
||||
emit hideMainWindow();
|
||||
app().grpc().changeLocalCache(enable, path);
|
||||
}
|
||||
|
||||
|
||||
@ -353,3 +368,5 @@ void QMLBackend::onResetFinished()
|
||||
emit resetFinished();
|
||||
this->restart();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -143,7 +143,7 @@ public slots: // slot for signals received from QML -> To be forwarded to Bridge
|
||||
void toggleAutostart(bool active); // _ func(makeItActive bool) `slot:"toggleAutostart"`
|
||||
void toggleBeta(bool active); // _ func(makeItActive bool) `slot:"toggleBeta"`
|
||||
void changeColorScheme(QString const &scheme); // _ func(string) `slot:"changeColorScheme"`
|
||||
void changeLocalCache(bool enable, QUrl const& path) { app().grpc().changeLocalCache(enable, path); } // _ func(enableDiskCache bool, diskCachePath core.QUrl) `slot:"changeLocalCache"`
|
||||
void changeLocalCache(bool enable, QUrl const& path); // _ func(enableDiskCache bool, diskCachePath core.QUrl) `slot:"changeLocalCache"`
|
||||
void login(QString const& username, QString const& password) { app().grpc().login(username, password);} // _ func(username, password string) `slot:"login"`
|
||||
void login2FA(QString const& username, QString const& code) { app().grpc().login2FA(username, code);} // _ func(username, code string) `slot:"login2FA"`
|
||||
void login2Password(QString const& username, QString const& password) { app().grpc().login2Passwords(username, password);} // _ func(username, password string) `slot:"login2Password"`
|
||||
@ -211,6 +211,7 @@ signals: // Signals received from the Go backend, to be forwarded to QML
|
||||
void bugReportSendSuccess(); // _ func() `signal:"bugReportSendSuccess"`
|
||||
void bugReportSendError(); // _ func() `signal:"bugReportSendError"`
|
||||
void showMainWindow(); // _ func() `signal:showMainWindow`
|
||||
void hideMainWindow();
|
||||
|
||||
private: // member functions
|
||||
void retrieveUserList(); ///< Retrieve the list of users via gRPC.
|
||||
|
||||
@ -224,12 +224,14 @@ void closeBridgeApp()
|
||||
//****************************************************************************************************************************************************
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
// The application instance is needed to display system message boxes. As we may have to do it in the exception handler,
|
||||
// application instance is create outside the try/catch clause.
|
||||
if (QSysInfo::productType() != "windows")
|
||||
QCoreApplication::setAttribute(Qt::AA_UseSoftwareOpenGL);
|
||||
QApplication guiApp(argc, argv);
|
||||
|
||||
try
|
||||
{
|
||||
if (QSysInfo::productType() != "windows")
|
||||
QCoreApplication::setAttribute(Qt::AA_UseSoftwareOpenGL);
|
||||
|
||||
QApplication guiApp(argc, argv);
|
||||
initQtApplication();
|
||||
|
||||
Log &log = initLog();
|
||||
@ -302,6 +304,7 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
catch (Exception const &e)
|
||||
{
|
||||
QMessageBox::critical(nullptr, "Error", e.qwhat());
|
||||
QTextStream(stderr) << e.qwhat() << "\n";
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
@ -59,6 +59,10 @@ QtObject {
|
||||
mainWindow.showAndRise()
|
||||
}
|
||||
function onColorSchemeNameChanged(scheme) { root.setColorScheme() }
|
||||
|
||||
function onHideMainWindow() {
|
||||
mainWindow.hide();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -288,7 +288,9 @@ grpc::Status GRPCClient::reportBug(QString const &description, QString const &ad
|
||||
//****************************************************************************************************************************************************
|
||||
grpc::Status GRPCClient::useSSLForSMTP(bool &outUseSSL)
|
||||
{
|
||||
return this->logGRPCCallStatus(this->getBool(&Bridge::Stub::UseSslForSmtp, outUseSSL), __FUNCTION__);
|
||||
Status status = this->getBool(&Bridge::Stub::UseSslForSmtp, outUseSSL);
|
||||
return this->logGRPCCallStatus(status, __FUNCTION__);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -363,7 +365,8 @@ grpc::Status GRPCClient::setIsDoHEnabled(bool enabled)
|
||||
grpc::Status GRPCClient::quit()
|
||||
{
|
||||
grpc::ClientContext ctx;
|
||||
return this->logGRPCCallStatus(stub_->Quit(&ctx, empty, &empty), __FUNCTION__);
|
||||
// quitting will shut down the gRPC service, to we may get an 'Unavailable' response for the call
|
||||
return this->logGRPCCallStatus(stub_->Quit(&ctx, empty, &empty), __FUNCTION__, { StatusCode::UNAVAILABLE });
|
||||
}
|
||||
|
||||
|
||||
@ -373,7 +376,8 @@ grpc::Status GRPCClient::quit()
|
||||
grpc::Status GRPCClient::restart()
|
||||
{
|
||||
grpc::ClientContext ctx;
|
||||
return this->logGRPCCallStatus(stub_->Restart(&ctx, empty, &empty), __FUNCTION__);
|
||||
// restarting will shut down the gRPC service, to we may get an 'Unavailable' response for the call
|
||||
return this->logGRPCCallStatus(stub_->Restart(&ctx, empty, &empty), __FUNCTION__, { StatusCode::UNAVAILABLE });
|
||||
}
|
||||
|
||||
|
||||
@ -882,11 +886,11 @@ void GRPCClient::logError(QString const &message)
|
||||
/// \param[in] status The status
|
||||
/// \param[in] callName The call name.
|
||||
//****************************************************************************************************************************************************
|
||||
grpc::Status GRPCClient::logGRPCCallStatus(Status const &status, QString const &callName)
|
||||
grpc::Status GRPCClient::logGRPCCallStatus(Status const &status, QString const &callName, QList<grpc::StatusCode> allowedErrors)
|
||||
{
|
||||
if (log_)
|
||||
{
|
||||
if (status.ok())
|
||||
if (status.ok() || allowedErrors.contains(status.error_code()))
|
||||
log_->debug(QString("%1()").arg(callName));
|
||||
else
|
||||
log_->error(QString("%1() FAILED").arg(callName));
|
||||
|
||||
@ -201,7 +201,7 @@ private slots:
|
||||
private:
|
||||
void logDebug(QString const &message); ///< Log an event.
|
||||
void logError(QString const &message); ///< Log an event.
|
||||
grpc::Status logGRPCCallStatus(grpc::Status const &status, QString const &callName); ///< Log the status of a gRPC code.
|
||||
grpc::Status logGRPCCallStatus(grpc::Status const &status, QString const &callName, QList<grpc::StatusCode> allowedErrors = {}); ///< Log the status of a gRPC code.
|
||||
grpc::Status simpleMethod(SimpleMethod method); ///< perform a gRPC call to a bool setter.
|
||||
grpc::Status setBool(BoolSetter setter, bool value); ///< perform a gRPC call to a bool setter.
|
||||
grpc::Status getBool(BoolGetter getter, bool &outValue); ///< perform a gRPC call to a bool getter.
|
||||
|
||||
@ -20,6 +20,7 @@ package grpc
|
||||
//go:generate protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative bridge.proto
|
||||
|
||||
import (
|
||||
"context"
|
||||
cryptotls "crypto/tls"
|
||||
"net"
|
||||
"strings"
|
||||
@ -39,6 +40,7 @@ import (
|
||||
"github.com/sirupsen/logrus"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/credentials"
|
||||
"google.golang.org/protobuf/types/known/emptypb"
|
||||
)
|
||||
|
||||
// Service is the RPC service struct.
|
||||
@ -223,7 +225,7 @@ func (s *Service) watchEvents() { // nolint:funlen
|
||||
case <-secondInstanceCh:
|
||||
_ = s.SendEvent(NewShowMainWindowEvent())
|
||||
case <-restartBridgeCh:
|
||||
s.restart()
|
||||
_, _ = s.Restart(context.Background(), &emptypb.Empty{})
|
||||
case address := <-addressChangedCh:
|
||||
_ = s.SendEvent(NewMailAddressChangeEvent(address))
|
||||
case address := <-addressChangedLogoutCh:
|
||||
@ -311,10 +313,6 @@ func (s *Service) waitForUserChangeDone(done <-chan string, userID string) {
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Service) restart() {
|
||||
s.restarter.SetToRestart()
|
||||
}
|
||||
|
||||
func (s *Service) triggerReset() {
|
||||
defer func() {
|
||||
_ = s.SendEvent(NewResetFinishedEvent())
|
||||
|
||||
@ -38,8 +38,6 @@ import (
|
||||
"google.golang.org/protobuf/types/known/wrapperspb"
|
||||
)
|
||||
|
||||
var ErrNotImplemented = status.Errorf(codes.Unimplemented, "Not implemented")
|
||||
|
||||
func (s *Service) AddLogEntry(_ context.Context, request *AddLogEntryRequest) (*emptypb.Empty, error) {
|
||||
entry := s.log
|
||||
if len(request.Package) > 0 {
|
||||
@ -77,31 +75,30 @@ func (s *Service) GuiReady(context.Context, *emptypb.Empty) (*emptypb.Empty, err
|
||||
// Quit implement the Quit gRPC service call.
|
||||
func (s *Service) Quit(ctx context.Context, empty *emptypb.Empty) (*emptypb.Empty, error) {
|
||||
s.log.Info("Quit")
|
||||
var err error
|
||||
if s.eventStreamCh != nil {
|
||||
if _, err = s.StopEventStream(ctx, empty); err != nil {
|
||||
s.log.WithError(err).Error("Quit failed.")
|
||||
}
|
||||
}
|
||||
|
||||
// The following call is launched as a goroutine, as it will wait for current calls to end, including this one.
|
||||
go func() { s.grpcServer.GracefulStop() }()
|
||||
|
||||
return &emptypb.Empty{}, err
|
||||
}
|
||||
|
||||
// Restart implement the Restart gRPC service call.
|
||||
func (s *Service) Restart(context.Context, *emptypb.Empty) (*emptypb.Empty, error) {
|
||||
s.log.Info("Restart")
|
||||
// Windows is notably slow at Quitting. We do it in a goroutine to speed things up a bit.
|
||||
go func() {
|
||||
defer s.panicHandler.HandlePanic()
|
||||
var err error
|
||||
if s.eventStreamCh != nil {
|
||||
if _, err = s.StopEventStream(ctx, empty); err != nil {
|
||||
s.log.WithError(err).Error("Quit failed.")
|
||||
}
|
||||
}
|
||||
|
||||
s.restart()
|
||||
// The following call is launched as a goroutine, as it will wait for current calls to end, including this one.
|
||||
s.grpcServer.GracefulStop()
|
||||
}()
|
||||
|
||||
return &emptypb.Empty{}, nil
|
||||
}
|
||||
|
||||
// Restart implement the Restart gRPC service call.
|
||||
func (s *Service) Restart(ctx context.Context, empty *emptypb.Empty) (*emptypb.Empty, error) {
|
||||
s.log.Info("Restart")
|
||||
s.restarter.SetToRestart()
|
||||
return s.Quit(ctx, empty)
|
||||
}
|
||||
|
||||
func (s *Service) ShowOnStartup(context.Context, *emptypb.Empty) (*wrapperspb.BoolValue, error) {
|
||||
s.log.Info("ShowOnStartup")
|
||||
|
||||
@ -486,11 +483,12 @@ func (s *Service) DiskCachePath(context.Context, *emptypb.Empty) (*wrapperspb.St
|
||||
return wrapperspb.String(s.bridge.Get(settings.CacheLocationKey)), nil
|
||||
}
|
||||
|
||||
func (s *Service) ChangeLocalCache(_ context.Context, change *ChangeLocalCacheRequest) (*emptypb.Empty, error) {
|
||||
func (s *Service) ChangeLocalCache(ctx context.Context, change *ChangeLocalCacheRequest) (*emptypb.Empty, error) {
|
||||
s.log.WithField("enableDiskCache", change.EnableDiskCache).
|
||||
WithField("diskCachePath", change.DiskCachePath).
|
||||
Info("DiskCachePath")
|
||||
|
||||
defer func() { _, _ = s.Restart(ctx, &emptypb.Empty{}) }()
|
||||
defer func() { _ = s.SendEvent(NewCacheChangeLocalCacheFinishedEvent()) }()
|
||||
defer func() { _ = s.SendEvent(NewIsCacheOnDiskEnabledChanged(s.bridge.GetBool(settings.CacheEnabledKey))) }()
|
||||
defer func() { _ = s.SendEvent(NewDiskCachePathChanged(s.bridge.Get(settings.CacheCompressionKey))) }()
|
||||
@ -523,7 +521,6 @@ func (s *Service) ChangeLocalCache(_ context.Context, change *ChangeLocalCacheRe
|
||||
}
|
||||
|
||||
_ = s.SendEvent(NewCacheLocationChangeSuccessEvent())
|
||||
s.restart()
|
||||
|
||||
return &emptypb.Empty{}, nil
|
||||
}
|
||||
@ -542,19 +539,18 @@ func (s *Service) IsDoHEnabled(context.Context, *emptypb.Empty) (*wrapperspb.Boo
|
||||
return wrapperspb.Bool(s.bridge.GetProxyAllowed()), nil
|
||||
}
|
||||
|
||||
func (s *Service) SetUseSslForSmtp(_ context.Context, useSsl *wrapperspb.BoolValue) (*emptypb.Empty, error) { //nolint:revive,stylecheck
|
||||
func (s *Service) SetUseSslForSmtp(ctx context.Context, useSsl *wrapperspb.BoolValue) (*emptypb.Empty, error) { //nolint:revive,stylecheck
|
||||
s.log.WithField("useSsl", useSsl.Value).Info("SetUseSslForSmtp")
|
||||
|
||||
if s.bridge.GetBool(settings.SMTPSSLKey) == useSsl.Value {
|
||||
return &emptypb.Empty{}, nil
|
||||
}
|
||||
|
||||
defer func() { _ = s.SendEvent(NewMailSettingsUseSslForSmtpFinishedEvent()) }()
|
||||
|
||||
s.bridge.SetBool(settings.SMTPSSLKey, useSsl.Value)
|
||||
s.restart()
|
||||
|
||||
return &emptypb.Empty{}, nil
|
||||
defer func() { _, _ = s.Restart(ctx, &emptypb.Empty{}) }()
|
||||
|
||||
return &emptypb.Empty{}, s.SendEvent(NewMailSettingsUseSslForSmtpFinishedEvent())
|
||||
}
|
||||
|
||||
func (s *Service) UseSslForSmtp(context.Context, *emptypb.Empty) (*wrapperspb.BoolValue, error) { //nolint:revive,stylecheck
|
||||
@ -581,16 +577,15 @@ func (s *Service) SmtpPort(context.Context, *emptypb.Empty) (*wrapperspb.Int32Va
|
||||
return wrapperspb.Int32(int32(s.bridge.GetInt(settings.SMTPPortKey))), nil
|
||||
}
|
||||
|
||||
func (s *Service) ChangePorts(_ context.Context, ports *ChangePortsRequest) (*emptypb.Empty, error) {
|
||||
func (s *Service) ChangePorts(ctx context.Context, ports *ChangePortsRequest) (*emptypb.Empty, error) {
|
||||
s.log.WithField("imapPort", ports.ImapPort).WithField("smtpPort", ports.SmtpPort).Info("ChangePorts")
|
||||
|
||||
defer func() { _ = s.SendEvent(NewMailSettingsChangePortFinishedEvent()) }()
|
||||
|
||||
s.bridge.SetInt(settings.IMAPPortKey, int(ports.ImapPort))
|
||||
s.bridge.SetInt(settings.SMTPPortKey, int(ports.SmtpPort))
|
||||
|
||||
s.restart()
|
||||
return &emptypb.Empty{}, nil
|
||||
defer func() { _, _ = s.Restart(ctx, &emptypb.Empty{}) }()
|
||||
|
||||
return &emptypb.Empty{}, s.SendEvent(NewMailSettingsChangePortFinishedEvent())
|
||||
}
|
||||
|
||||
func (s *Service) IsPortFree(_ context.Context, port *wrapperspb.Int32Value) (*wrapperspb.BoolValue, error) {
|
||||
|
||||
@ -124,7 +124,7 @@ func (s *Service) RemoveUser(_ context.Context, userID *wrapperspb.StringValue)
|
||||
return &emptypb.Empty{}, nil
|
||||
}
|
||||
|
||||
func (s *Service) ConfigureUserAppleMail(_ context.Context, request *ConfigureAppleMailRequest) (*emptypb.Empty, error) {
|
||||
func (s *Service) ConfigureUserAppleMail(ctx context.Context, request *ConfigureAppleMailRequest) (*emptypb.Empty, error) {
|
||||
s.log.WithField("UserID", request.UserID).WithField("Address", request.Address).Info("ConfigureUserAppleMail")
|
||||
|
||||
restart, err := s.bridge.ConfigureAppleMail(request.UserID, request.Address)
|
||||
@ -137,7 +137,7 @@ func (s *Service) ConfigureUserAppleMail(_ context.Context, request *ConfigureAp
|
||||
if restart {
|
||||
s.log.Warn("Detected Catalina or newer with bad SMTP SSL settings, now using SSL, bridge needs to restart")
|
||||
time.Sleep(2 * time.Second)
|
||||
s.restart()
|
||||
return s.Restart(ctx, &emptypb.Empty{})
|
||||
}
|
||||
|
||||
return &emptypb.Empty{}, nil
|
||||
|
||||
Reference in New Issue
Block a user