mirror of
https://github.com/getAlby/hub.git
synced 2026-08-13 12:33:39 +02:00
fix: replace fatal logs with proper error handling (#707)
* fix: replace fatal logs with proper error handling - fires nwc shutdown event synchronously - requires at least one minute leeway for access token expiry * chore: rename error * fix: do not mask original reason for error * fix: config error handling and error messages * chore: rename
This commit is contained in:
parent
ff417c4f1e
commit
8ebb4ad716
14 changed files with 264 additions and 94 deletions
|
|
@ -97,7 +97,10 @@ func (svc *albyOAuthService) CallbackHandler(ctx context.Context, code string, l
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Logger.WithError(err).Error("Failed to fetch user me")
|
logger.Logger.WithError(err).Error("Failed to fetch user me")
|
||||||
// remove token so user can retry
|
// remove token so user can retry
|
||||||
svc.cfg.SetUpdate(accessTokenKey, "", "")
|
cfgErr := svc.cfg.SetUpdate(accessTokenKey, "", "")
|
||||||
|
if cfgErr != nil {
|
||||||
|
logger.Logger.WithError(cfgErr).Error("failed to remove existing access token")
|
||||||
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -109,7 +112,11 @@ func (svc *albyOAuthService) CallbackHandler(ctx context.Context, code string, l
|
||||||
|
|
||||||
// save the user's alby account ID on first time login
|
// save the user's alby account ID on first time login
|
||||||
if existingUserIdentifier == "" {
|
if existingUserIdentifier == "" {
|
||||||
svc.cfg.SetUpdate(userIdentifierKey, me.Identifier, "")
|
err := svc.cfg.SetUpdate(userIdentifierKey, me.Identifier, "")
|
||||||
|
if err != nil {
|
||||||
|
logger.Logger.WithError(err).Error("Failed to set user identifier")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
if svc.cfg.GetEnv().AutoLinkAlbyAccount {
|
if svc.cfg.GetEnv().AutoLinkAlbyAccount {
|
||||||
// link account on first login
|
// link account on first login
|
||||||
|
|
@ -121,7 +128,10 @@ func (svc *albyOAuthService) CallbackHandler(ctx context.Context, code string, l
|
||||||
|
|
||||||
} else if me.Identifier != existingUserIdentifier {
|
} else if me.Identifier != existingUserIdentifier {
|
||||||
// remove token so user can retry with correct account
|
// remove token so user can retry with correct account
|
||||||
svc.cfg.SetUpdate(accessTokenKey, "", "")
|
err := svc.cfg.SetUpdate(accessTokenKey, "", "")
|
||||||
|
if err != nil {
|
||||||
|
logger.Logger.WithError(err).Error("Failed to set user access token")
|
||||||
|
}
|
||||||
return errors.New("Alby Hub is connected to a different alby account. Please log out of your Alby Account at getalby.com and try again.")
|
return errors.New("Alby Hub is connected to a different alby account. Please log out of your Alby Account at getalby.com and try again.")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -155,9 +165,18 @@ func (svc *albyOAuthService) IsConnected(ctx context.Context) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (svc *albyOAuthService) saveToken(token *oauth2.Token) {
|
func (svc *albyOAuthService) saveToken(token *oauth2.Token) {
|
||||||
svc.cfg.SetUpdate(accessTokenExpiryKey, strconv.FormatInt(token.Expiry.Unix(), 10), "")
|
err := svc.cfg.SetUpdate(accessTokenExpiryKey, strconv.FormatInt(token.Expiry.Unix(), 10), "")
|
||||||
svc.cfg.SetUpdate(accessTokenKey, token.AccessToken, "")
|
if err != nil {
|
||||||
svc.cfg.SetUpdate(refreshTokenKey, token.RefreshToken, "")
|
logger.Logger.WithError(err).Error("Failed to save access token expiry")
|
||||||
|
}
|
||||||
|
err = svc.cfg.SetUpdate(accessTokenKey, token.AccessToken, "")
|
||||||
|
if err != nil {
|
||||||
|
logger.Logger.WithError(err).Error("Failed to save access token")
|
||||||
|
}
|
||||||
|
err = svc.cfg.SetUpdate(refreshTokenKey, token.RefreshToken, "")
|
||||||
|
if err != nil {
|
||||||
|
logger.Logger.WithError(err).Error("Failed to save refresh token")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var tokenMutex sync.Mutex
|
var tokenMutex sync.Mutex
|
||||||
|
|
@ -202,8 +221,8 @@ func (svc *albyOAuthService) fetchUserToken(ctx context.Context) (*oauth2.Token,
|
||||||
RefreshToken: refreshToken,
|
RefreshToken: refreshToken,
|
||||||
}
|
}
|
||||||
|
|
||||||
// only use the current token if it has at least 20 seconds before expiry
|
// only use the current token if it has at least 60 seconds before expiry
|
||||||
if currentToken.Expiry.After(time.Now().Add(time.Duration(20) * time.Second)) {
|
if currentToken.Expiry.After(time.Now().Add(time.Duration(60) * time.Second)) {
|
||||||
logger.Logger.Debug("Using existing Alby OAuth token")
|
logger.Logger.Debug("Using existing Alby OAuth token")
|
||||||
return currentToken, nil
|
return currentToken, nil
|
||||||
}
|
}
|
||||||
|
|
@ -290,7 +309,10 @@ func (svc *albyOAuthService) GetMe(ctx context.Context) (*AlbyMe, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
svc.cfg.SetUpdate(lightningAddressKey, me.LightningAddress, "")
|
err = svc.cfg.SetUpdate(lightningAddressKey, me.LightningAddress, "")
|
||||||
|
if err != nil {
|
||||||
|
logger.Logger.WithError(err).Error("Failed to save lightning address")
|
||||||
|
}
|
||||||
|
|
||||||
logger.Logger.WithFields(logrus.Fields{"me": me}).Info("Alby me response")
|
logger.Logger.WithFields(logrus.Fields{"me": me}).Info("Alby me response")
|
||||||
return me, nil
|
return me, nil
|
||||||
|
|
@ -451,9 +473,6 @@ func (svc *albyOAuthService) SendPayment(ctx context.Context, invoice string) er
|
||||||
}
|
}
|
||||||
|
|
||||||
func (svc *albyOAuthService) GetAuthUrl() string {
|
func (svc *albyOAuthService) GetAuthUrl() string {
|
||||||
if svc.cfg.GetEnv().AlbyClientId == "" || svc.cfg.GetEnv().AlbyClientSecret == "" {
|
|
||||||
logger.Logger.Fatalf("No ALBY_OAUTH_CLIENT_ID or ALBY_OAUTH_CLIENT_SECRET set")
|
|
||||||
}
|
|
||||||
return svc.oauthConf.AuthCodeURL("unused")
|
return svc.oauthConf.AuthCodeURL("unused")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -464,11 +483,26 @@ func (svc *albyOAuthService) UnlinkAccount(ctx context.Context) error {
|
||||||
}
|
}
|
||||||
svc.deleteAlbyAccountApps()
|
svc.deleteAlbyAccountApps()
|
||||||
|
|
||||||
svc.cfg.SetUpdate(userIdentifierKey, "", "")
|
err = svc.cfg.SetUpdate(userIdentifierKey, "", "")
|
||||||
svc.cfg.SetUpdate(accessTokenKey, "", "")
|
if err != nil {
|
||||||
svc.cfg.SetUpdate(accessTokenExpiryKey, "", "")
|
logger.Logger.WithError(err).Error("Failed to remove user identifier from config")
|
||||||
svc.cfg.SetUpdate(refreshTokenKey, "", "")
|
}
|
||||||
svc.cfg.SetUpdate(lightningAddressKey, "", "")
|
err = svc.cfg.SetUpdate(accessTokenKey, "", "")
|
||||||
|
if err != nil {
|
||||||
|
logger.Logger.WithError(err).Error("Failed to remove access token from config")
|
||||||
|
}
|
||||||
|
err = svc.cfg.SetUpdate(accessTokenExpiryKey, "", "")
|
||||||
|
if err != nil {
|
||||||
|
logger.Logger.WithError(err).Error("Failed to remove access token expiry from config")
|
||||||
|
}
|
||||||
|
err = svc.cfg.SetUpdate(refreshTokenKey, "", "")
|
||||||
|
if err != nil {
|
||||||
|
logger.Logger.WithError(err).Error("Failed to remove refresh token from config")
|
||||||
|
}
|
||||||
|
err = svc.cfg.SetUpdate(lightningAddressKey, "", "")
|
||||||
|
if err != nil {
|
||||||
|
logger.Logger.WithError(err).Error("Failed to remove lightning address from config")
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
83
api/api.go
83
api/api.go
|
|
@ -525,7 +525,10 @@ func (api *api) GetNewOnchainAddress(ctx context.Context) (string, error) {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
api.cfg.SetUpdate(config.OnchainAddressKey, address, "")
|
err = api.cfg.SetUpdate(config.OnchainAddressKey, address, "")
|
||||||
|
if err != nil {
|
||||||
|
logger.Logger.WithError(err).Error("Failed to save new onchain address to config")
|
||||||
|
}
|
||||||
|
|
||||||
return address, nil
|
return address, nil
|
||||||
}
|
}
|
||||||
|
|
@ -706,7 +709,10 @@ func (api *api) GetMnemonic(unlockPassword string) (*MnemonicResponse, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (api *api) SetNextBackupReminder(backupReminderRequest *BackupReminderRequest) error {
|
func (api *api) SetNextBackupReminder(backupReminderRequest *BackupReminderRequest) error {
|
||||||
api.cfg.SetUpdate("NextBackupReminder", backupReminderRequest.NextBackupReminder, "")
|
err := api.cfg.SetUpdate("NextBackupReminder", backupReminderRequest.NextBackupReminder, "")
|
||||||
|
if err != nil {
|
||||||
|
logger.Logger.WithError(err).Error("Failed to save next backup reminder to config")
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -751,44 +757,89 @@ func (api *api) Setup(ctx context.Context, setupRequest *SetupRequest) error {
|
||||||
return errors.New("no unlock password provided")
|
return errors.New("no unlock password provided")
|
||||||
}
|
}
|
||||||
|
|
||||||
api.cfg.Setup(setupRequest.UnlockPassword)
|
err = api.cfg.SaveUnlockPasswordCheck(setupRequest.UnlockPassword)
|
||||||
|
if err != nil {
|
||||||
// TODO: move all below code to cfg.Setup()
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
// update next backup reminder
|
// update next backup reminder
|
||||||
api.cfg.SetUpdate("NextBackupReminder", setupRequest.NextBackupReminder, "")
|
err = api.cfg.SetUpdate("NextBackupReminder", setupRequest.NextBackupReminder, "")
|
||||||
|
if err != nil {
|
||||||
|
logger.Logger.WithError(err).Error("Failed to save next backup reminder")
|
||||||
|
}
|
||||||
|
|
||||||
// only update non-empty values
|
// only update non-empty values
|
||||||
if setupRequest.LNBackendType != "" {
|
if setupRequest.LNBackendType != "" {
|
||||||
api.cfg.SetUpdate("LNBackendType", setupRequest.LNBackendType, "")
|
err = api.cfg.SetUpdate("LNBackendType", setupRequest.LNBackendType, "")
|
||||||
|
if err != nil {
|
||||||
|
logger.Logger.WithError(err).Error("Failed to save backend type")
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if setupRequest.BreezAPIKey != "" {
|
if setupRequest.BreezAPIKey != "" {
|
||||||
api.cfg.SetUpdate("BreezAPIKey", setupRequest.BreezAPIKey, setupRequest.UnlockPassword)
|
err = api.cfg.SetUpdate("BreezAPIKey", setupRequest.BreezAPIKey, setupRequest.UnlockPassword)
|
||||||
|
if err != nil {
|
||||||
|
logger.Logger.WithError(err).Error("Failed to save breez api key")
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if setupRequest.Mnemonic != "" {
|
if setupRequest.Mnemonic != "" {
|
||||||
api.cfg.SetUpdate("Mnemonic", setupRequest.Mnemonic, setupRequest.UnlockPassword)
|
err = api.cfg.SetUpdate("Mnemonic", setupRequest.Mnemonic, setupRequest.UnlockPassword)
|
||||||
|
if err != nil {
|
||||||
|
logger.Logger.WithError(err).Error("Failed to save encrypted mnemonic")
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if setupRequest.GreenlightInviteCode != "" {
|
if setupRequest.GreenlightInviteCode != "" {
|
||||||
api.cfg.SetUpdate("GreenlightInviteCode", setupRequest.GreenlightInviteCode, setupRequest.UnlockPassword)
|
err = api.cfg.SetUpdate("GreenlightInviteCode", setupRequest.GreenlightInviteCode, setupRequest.UnlockPassword)
|
||||||
|
if err != nil {
|
||||||
|
logger.Logger.WithError(err).Error("Failed to save greenlight invite code")
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if setupRequest.LNDAddress != "" {
|
if setupRequest.LNDAddress != "" {
|
||||||
api.cfg.SetUpdate("LNDAddress", setupRequest.LNDAddress, setupRequest.UnlockPassword)
|
err = api.cfg.SetUpdate("LNDAddress", setupRequest.LNDAddress, setupRequest.UnlockPassword)
|
||||||
|
if err != nil {
|
||||||
|
logger.Logger.WithError(err).Error("Failed to save lnd address")
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if setupRequest.LNDCertHex != "" {
|
if setupRequest.LNDCertHex != "" {
|
||||||
api.cfg.SetUpdate("LNDCertHex", setupRequest.LNDCertHex, setupRequest.UnlockPassword)
|
err = api.cfg.SetUpdate("LNDCertHex", setupRequest.LNDCertHex, setupRequest.UnlockPassword)
|
||||||
|
if err != nil {
|
||||||
|
logger.Logger.WithError(err).Error("Failed to save lnd cert hex")
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if setupRequest.LNDMacaroonHex != "" {
|
if setupRequest.LNDMacaroonHex != "" {
|
||||||
api.cfg.SetUpdate("LNDMacaroonHex", setupRequest.LNDMacaroonHex, setupRequest.UnlockPassword)
|
err = api.cfg.SetUpdate("LNDMacaroonHex", setupRequest.LNDMacaroonHex, setupRequest.UnlockPassword)
|
||||||
|
if err != nil {
|
||||||
|
logger.Logger.WithError(err).Error("Failed to save lnd macaroon hex")
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if setupRequest.PhoenixdAddress != "" {
|
if setupRequest.PhoenixdAddress != "" {
|
||||||
api.cfg.SetUpdate("PhoenixdAddress", setupRequest.PhoenixdAddress, setupRequest.UnlockPassword)
|
err = api.cfg.SetUpdate("PhoenixdAddress", setupRequest.PhoenixdAddress, setupRequest.UnlockPassword)
|
||||||
|
if err != nil {
|
||||||
|
logger.Logger.WithError(err).Error("Failed to save phoenix address")
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if setupRequest.PhoenixdAuthorization != "" {
|
if setupRequest.PhoenixdAuthorization != "" {
|
||||||
api.cfg.SetUpdate("PhoenixdAuthorization", setupRequest.PhoenixdAuthorization, setupRequest.UnlockPassword)
|
err = api.cfg.SetUpdate("PhoenixdAuthorization", setupRequest.PhoenixdAuthorization, setupRequest.UnlockPassword)
|
||||||
|
if err != nil {
|
||||||
|
logger.Logger.WithError(err).Error("Failed to save phoenix auth")
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if setupRequest.CashuMintUrl != "" {
|
if setupRequest.CashuMintUrl != "" {
|
||||||
api.cfg.SetUpdate("CashuMintUrl", setupRequest.CashuMintUrl, setupRequest.UnlockPassword)
|
err = api.cfg.SetUpdate("CashuMintUrl", setupRequest.CashuMintUrl, setupRequest.UnlockPassword)
|
||||||
|
if err != nil {
|
||||||
|
logger.Logger.WithError(err).Error("Failed to save cashu mint url")
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
|
||||||
|
|
@ -21,8 +21,8 @@ func main() {
|
||||||
|
|
||||||
// Create a channel to receive OS signals.
|
// Create a channel to receive OS signals.
|
||||||
osSignalChannel := make(chan os.Signal, 1)
|
osSignalChannel := make(chan os.Signal, 1)
|
||||||
// Notify the channel on os.Interrupt, syscall.SIGTERM, and os.Kill.
|
// Notify the channel on os.Interrupt, syscall.SIGTERM. os.Kill cannot be caught.
|
||||||
signal.Notify(osSignalChannel, os.Interrupt, syscall.SIGTERM, os.Kill)
|
signal.Notify(osSignalChannel, os.Interrupt, syscall.SIGTERM)
|
||||||
|
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
svc, _ := service.NewService(ctx)
|
svc, _ := service.NewService(ctx)
|
||||||
|
|
@ -35,7 +35,8 @@ func main() {
|
||||||
//start Echo server
|
//start Echo server
|
||||||
go func() {
|
go func() {
|
||||||
if err := e.Start(fmt.Sprintf(":%v", svc.GetConfig().GetEnv().Port)); err != nil && err != nethttp.ErrServerClosed {
|
if err := e.Start(fmt.Sprintf(":%v", svc.GetConfig().GetEnv().Port)); err != nil && err != nethttp.ErrServerClosed {
|
||||||
logger.Logger.Fatalf("shutting down the server: %v", err)
|
logger.Logger.WithError(err).Error("echo server failed to start")
|
||||||
|
ctx.Done()
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -25,50 +25,77 @@ const (
|
||||||
unlockPasswordCheck = "THIS STRING SHOULD MATCH IF PASSWORD IS CORRECT"
|
unlockPasswordCheck = "THIS STRING SHOULD MATCH IF PASSWORD IS CORRECT"
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewConfig(env *AppConfig, db *gorm.DB) *config {
|
func NewConfig(env *AppConfig, db *gorm.DB) (*config, error) {
|
||||||
cfg := &config{
|
cfg := &config{
|
||||||
db: db,
|
db: db,
|
||||||
}
|
}
|
||||||
cfg.init(env)
|
err := cfg.init(env)
|
||||||
return cfg
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return cfg, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cfg *config) init(env *AppConfig) {
|
func (cfg *config) init(env *AppConfig) error {
|
||||||
cfg.Env = env
|
cfg.Env = env
|
||||||
|
|
||||||
if cfg.Env.Relay != "" {
|
if cfg.Env.Relay != "" {
|
||||||
cfg.SetIgnore("Relay", cfg.Env.Relay, "")
|
err := cfg.SetIgnore("Relay", cfg.Env.Relay, "")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if cfg.Env.LNBackendType != "" {
|
if cfg.Env.LNBackendType != "" {
|
||||||
cfg.SetIgnore("LNBackendType", cfg.Env.LNBackendType, "")
|
err := cfg.SetIgnore("LNBackendType", cfg.Env.LNBackendType, "")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// LND specific to support env variables
|
// LND specific to support env variables
|
||||||
if cfg.Env.LNDAddress != "" {
|
if cfg.Env.LNDAddress != "" {
|
||||||
cfg.SetIgnore("LNDAddress", cfg.Env.LNDAddress, "")
|
err := cfg.SetIgnore("LNDAddress", cfg.Env.LNDAddress, "")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if cfg.Env.LNDCertFile != "" {
|
if cfg.Env.LNDCertFile != "" {
|
||||||
certBytes, err := os.ReadFile(cfg.Env.LNDCertFile)
|
certBytes, err := os.ReadFile(cfg.Env.LNDCertFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Logger.Fatalf("Failed to read LND cert file: %v", err)
|
logger.Logger.WithError(err).Error("Failed to read LND cert file")
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
certHex := hex.EncodeToString(certBytes)
|
certHex := hex.EncodeToString(certBytes)
|
||||||
cfg.SetIgnore("LNDCertHex", certHex, "")
|
err = cfg.SetIgnore("LNDCertHex", certHex, "")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if cfg.Env.LNDMacaroonFile != "" {
|
if cfg.Env.LNDMacaroonFile != "" {
|
||||||
macBytes, err := os.ReadFile(cfg.Env.LNDMacaroonFile)
|
macBytes, err := os.ReadFile(cfg.Env.LNDMacaroonFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Logger.Fatalf("Failed to read LND macaroon file: %v", err)
|
logger.Logger.WithError(err).Error("Failed to read LND macaroon file")
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
macHex := hex.EncodeToString(macBytes)
|
macHex := hex.EncodeToString(macBytes)
|
||||||
cfg.SetIgnore("LNDMacaroonHex", macHex, "")
|
err = cfg.SetIgnore("LNDMacaroonHex", macHex, "")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Phoenix specific to support env variables
|
// Phoenix specific to support env variables
|
||||||
if cfg.Env.PhoenixdAddress != "" {
|
if cfg.Env.PhoenixdAddress != "" {
|
||||||
cfg.SetIgnore("PhoenixdAddress", cfg.Env.PhoenixdAddress, "")
|
err := cfg.SetIgnore("PhoenixdAddress", cfg.Env.PhoenixdAddress, "")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if cfg.Env.PhoenixdAuthorization != "" {
|
if cfg.Env.PhoenixdAuthorization != "" {
|
||||||
cfg.SetIgnore("PhoenixdAuthorization", cfg.Env.PhoenixdAuthorization, "")
|
err := cfg.SetIgnore("PhoenixdAuthorization", cfg.Env.PhoenixdAuthorization, "")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// set the JWT secret to the one from the env
|
// set the JWT secret to the one from the env
|
||||||
|
|
@ -76,11 +103,17 @@ func (cfg *config) init(env *AppConfig) {
|
||||||
cfg.JWTSecret = cfg.Env.JWTSecret
|
cfg.JWTSecret = cfg.Env.JWTSecret
|
||||||
if cfg.JWTSecret == "" {
|
if cfg.JWTSecret == "" {
|
||||||
hex, err := randomHex(32)
|
hex, err := randomHex(32)
|
||||||
if err == nil {
|
if err != nil {
|
||||||
cfg.SetIgnore("JWTSecret", hex, "")
|
logger.Logger.WithError(err).Error("failed to generate JWT secret")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = cfg.SetIgnore("JWTSecret", hex, "")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
cfg.JWTSecret, _ = cfg.Get("JWTSecret", "")
|
cfg.JWTSecret, _ = cfg.Get("JWTSecret", "")
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cfg *config) SetupCompleted() bool {
|
func (cfg *config) SetupCompleted() bool {
|
||||||
|
|
@ -147,26 +180,30 @@ func (cfg *config) set(key string, value string, clauses clause.OnConflict, encr
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cfg *config) SetIgnore(key string, value string, encryptionKey string) {
|
func (cfg *config) SetIgnore(key string, value string, encryptionKey string) error {
|
||||||
clauses := clause.OnConflict{
|
clauses := clause.OnConflict{
|
||||||
Columns: []clause.Column{{Name: "key"}},
|
Columns: []clause.Column{{Name: "key"}},
|
||||||
DoNothing: true,
|
DoNothing: true,
|
||||||
}
|
}
|
||||||
err := cfg.set(key, value, clauses, encryptionKey, cfg.db)
|
err := cfg.set(key, value, clauses, encryptionKey, cfg.db)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Logger.Fatalf("Failed to save config: %v", err)
|
logger.Logger.WithField("key", key).WithError(err).Error("Failed to set config key with ignore", err)
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cfg *config) SetUpdate(key string, value string, encryptionKey string) {
|
func (cfg *config) SetUpdate(key string, value string, encryptionKey string) error {
|
||||||
clauses := clause.OnConflict{
|
clauses := clause.OnConflict{
|
||||||
Columns: []clause.Column{{Name: "key"}},
|
Columns: []clause.Column{{Name: "key"}},
|
||||||
DoUpdates: clause.AssignmentColumns([]string{"value"}),
|
DoUpdates: clause.AssignmentColumns([]string{"value"}),
|
||||||
}
|
}
|
||||||
err := cfg.set(key, value, clauses, encryptionKey, cfg.db)
|
err := cfg.set(key, value, clauses, encryptionKey, cfg.db)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Logger.Fatalf("Failed to save config: %v", err)
|
logger.Logger.WithField("key", key).WithError(err).Error("Failed to set config key with update", err)
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cfg *config) ChangeUnlockPassword(currentUnlockPassword string, newUnlockPassword string) error {
|
func (cfg *config) ChangeUnlockPassword(currentUnlockPassword string, newUnlockPassword string) error {
|
||||||
|
|
@ -219,9 +256,13 @@ func (cfg *config) CheckUnlockPassword(encryptionKey string) bool {
|
||||||
return err == nil && (decryptedValue == "" || decryptedValue == unlockPasswordCheck)
|
return err == nil && (decryptedValue == "" || decryptedValue == unlockPasswordCheck)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: rename
|
func (cfg *config) SaveUnlockPasswordCheck(encryptionKey string) error {
|
||||||
func (cfg *config) Setup(encryptionKey string) {
|
err := cfg.SetUpdate("UnlockPasswordCheck", unlockPasswordCheck, encryptionKey)
|
||||||
cfg.SetUpdate("UnlockPasswordCheck", unlockPasswordCheck, encryptionKey)
|
if err != nil {
|
||||||
|
logger.Logger.WithError(err).Error("Failed to save unlock password check to config")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cfg *config) GetEnv() *AppConfig {
|
func (cfg *config) GetEnv() *AppConfig {
|
||||||
|
|
|
||||||
|
|
@ -50,13 +50,13 @@ func (c *AppConfig) IsDefaultClientId() bool {
|
||||||
|
|
||||||
type Config interface {
|
type Config interface {
|
||||||
Get(key string, encryptionKey string) (string, error)
|
Get(key string, encryptionKey string) (string, error)
|
||||||
SetIgnore(key string, value string, encryptionKey string)
|
SetIgnore(key string, value string, encryptionKey string) error
|
||||||
SetUpdate(key string, value string, encryptionKey string)
|
SetUpdate(key string, value string, encryptionKey string) error
|
||||||
GetJWTSecret() string
|
GetJWTSecret() string
|
||||||
GetRelayUrl() string
|
GetRelayUrl() string
|
||||||
GetEnv() *AppConfig
|
GetEnv() *AppConfig
|
||||||
CheckUnlockPassword(password string) bool
|
CheckUnlockPassword(password string) bool
|
||||||
ChangeUnlockPassword(currentUnlockPassword string, newUnlockPassword string) error
|
ChangeUnlockPassword(currentUnlockPassword string, newUnlockPassword string) error
|
||||||
Setup(encryptionKey string)
|
SaveUnlockPasswordCheck(encryptionKey string) error
|
||||||
SetupCompleted() bool
|
SetupCompleted() bool
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -46,12 +46,23 @@ func (ep *eventPublisher) RemoveSubscriber(listenerToRemove EventSubscriber) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ep *eventPublisher) Publish(event *Event) {
|
func (ep *eventPublisher) Publish(event *Event) {
|
||||||
|
ep.publish(event, false)
|
||||||
|
}
|
||||||
|
func (ep *eventPublisher) PublishSync(event *Event) {
|
||||||
|
ep.publish(event, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ep *eventPublisher) publish(event *Event, sync bool) {
|
||||||
ep.subscriberMtx.Lock()
|
ep.subscriberMtx.Lock()
|
||||||
defer ep.subscriberMtx.Unlock()
|
defer ep.subscriberMtx.Unlock()
|
||||||
logger.Logger.WithFields(logrus.Fields{"event": event, "global": ep.globalProperties}).Debug("Publishing event")
|
logger.Logger.WithFields(logrus.Fields{"event": event, "global": ep.globalProperties}).Debug("Publishing event")
|
||||||
for _, listener := range ep.listeners {
|
for _, listener := range ep.listeners {
|
||||||
// consume event without blocking thread
|
if sync {
|
||||||
go listener.ConsumeEvent(context.Background(), event, ep.globalProperties)
|
listener.ConsumeEvent(context.Background(), event, ep.globalProperties)
|
||||||
|
} else {
|
||||||
|
// consume event without blocking thread
|
||||||
|
go listener.ConsumeEvent(context.Background(), event, ep.globalProperties)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ type EventPublisher interface {
|
||||||
RegisterSubscriber(eventListener EventSubscriber)
|
RegisterSubscriber(eventListener EventSubscriber)
|
||||||
RemoveSubscriber(eventListener EventSubscriber)
|
RemoveSubscriber(eventListener EventSubscriber)
|
||||||
Publish(event *Event)
|
Publish(event *Event)
|
||||||
|
PublishSync(event *Event)
|
||||||
SetGlobalProperty(key string, value interface{})
|
SetGlobalProperty(key string, value interface{})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -66,14 +66,19 @@ func NewGreenlightService(cfg config.Config, mnemonic, inviteCode, workDir, encr
|
||||||
credentials = &recoveredCredentials
|
credentials = &recoveredCredentials
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Logger.Fatalf("Failed to register new node")
|
logger.Logger.WithError(err).Error("Failed to register new node")
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if credentials == nil || credentials.GlCreds == "" {
|
if credentials == nil || credentials.GlCreds == "" {
|
||||||
return nil, errors.New("unexpected response from Recover")
|
return nil, errors.New("unexpected response from Recover")
|
||||||
}
|
}
|
||||||
cfg.SetUpdate(DEVICE_CREDENTIALS_KEY, credentials.GlCreds, encryptionKey)
|
err = cfg.SetUpdate(DEVICE_CREDENTIALS_KEY, credentials.GlCreds, encryptionKey)
|
||||||
|
if err != nil {
|
||||||
|
logger.Logger.WithError(err).Error("Failed to save greenlight credentials")
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
client, err := glalby.NewBlockingGreenlightAlbyClient(mnemonic, *credentials)
|
client, err := glalby.NewBlockingGreenlightAlbyClient(mnemonic, *credentials)
|
||||||
|
|
@ -83,7 +88,7 @@ func NewGreenlightService(cfg config.Config, mnemonic, inviteCode, workDir, encr
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if client == nil {
|
if client == nil {
|
||||||
log.Fatalf("unexpected response from NewBlockingGreenlightAlbyClient")
|
logger.Logger.Error("unexpected response from NewBlockingGreenlightAlbyClient")
|
||||||
}
|
}
|
||||||
|
|
||||||
nodeInfo, err := client.GetInfo()
|
nodeInfo, err := client.GetInfo()
|
||||||
|
|
|
||||||
|
|
@ -415,10 +415,15 @@ func (ls *LDKService) resetRouterInternal() {
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Logger.Error("Failed to retrieve ResetRouter key")
|
logger.Logger.Error("Failed to retrieve ResetRouter key")
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if key != "" {
|
if key != "" {
|
||||||
ls.cfg.SetUpdate(resetRouterKey, "", "")
|
err = ls.cfg.SetUpdate(resetRouterKey, "", "")
|
||||||
|
if err != nil {
|
||||||
|
logger.Logger.WithError(err).Error("Failed to remove reset router key")
|
||||||
|
return
|
||||||
|
}
|
||||||
logger.Logger.WithField("key", key).Info("Resetting router")
|
logger.Logger.WithField("key", key).Info("Resetting router")
|
||||||
|
|
||||||
ldkDbPath := filepath.Join(ls.workdir, "storage", "ldk_node_data.sqlite")
|
ldkDbPath := filepath.Join(ls.workdir, "storage", "ldk_node_data.sqlite")
|
||||||
|
|
@ -1086,7 +1091,11 @@ func (ls *LDKService) RedeemOnchainFunds(ctx context.Context, toAddress string,
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ls *LDKService) ResetRouter(key string) error {
|
func (ls *LDKService) ResetRouter(key string) error {
|
||||||
ls.cfg.SetUpdate(resetRouterKey, key, "")
|
err := ls.cfg.SetUpdate(resetRouterKey, key, "")
|
||||||
|
if err != nil {
|
||||||
|
logger.Logger.WithError(err).Error("Failed to set reset router key")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,11 @@ func (keys *keys) Init(cfg config.Config, encryptionKey string) error {
|
||||||
|
|
||||||
if nostrSecretKey == "" {
|
if nostrSecretKey == "" {
|
||||||
nostrSecretKey = nostr.GeneratePrivateKey()
|
nostrSecretKey = nostr.GeneratePrivateKey()
|
||||||
cfg.SetUpdate("NostrSecretKey", nostrSecretKey, encryptionKey)
|
err := cfg.SetUpdate("NostrSecretKey", nostrSecretKey, encryptionKey)
|
||||||
|
if err != nil {
|
||||||
|
logger.Logger.WithError(err).Error("Failed to save generated nostr secret key")
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
nostrPublicKey, err := nostr.GetPublicKey(nostrSecretKey)
|
nostrPublicKey, err := nostr.GetPublicKey(nostrSecretKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -41,15 +45,9 @@ func (keys *keys) Init(cfg config.Config, encryptionKey string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (keys *keys) GetNostrPublicKey() string {
|
func (keys *keys) GetNostrPublicKey() string {
|
||||||
if keys.nostrPublicKey == "" {
|
|
||||||
logger.Logger.Fatal("keys not initialized")
|
|
||||||
}
|
|
||||||
return keys.nostrPublicKey
|
return keys.nostrPublicKey
|
||||||
}
|
}
|
||||||
|
|
||||||
func (keys *keys) GetNostrSecretKey() string {
|
func (keys *keys) GetNostrSecretKey() string {
|
||||||
if keys.nostrSecretKey == "" {
|
|
||||||
logger.Logger.Fatal("keys not initialized")
|
|
||||||
}
|
|
||||||
return keys.nostrSecretKey
|
return keys.nostrSecretKey
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@ package service
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"time"
|
|
||||||
|
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
@ -69,7 +68,11 @@ func NewService(ctx context.Context) (*service, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
finishRestoreNode(appConfig.Workdir)
|
err = finishRestoreNode(appConfig.Workdir)
|
||||||
|
if err != nil {
|
||||||
|
logger.Logger.WithError(err).Error("failed to restore backup")
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
// If DATABASE_URI is a URI or a path, leave it unchanged.
|
// If DATABASE_URI is a URI or a path, leave it unchanged.
|
||||||
// If it only contains a filename, prepend the workdir.
|
// If it only contains a filename, prepend the workdir.
|
||||||
|
|
@ -85,7 +88,10 @@ func NewService(ctx context.Context) (*service, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg := config.NewConfig(appConfig, gormDB)
|
cfg, err := config.NewConfig(appConfig, gormDB)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
eventPublisher := events.NewEventPublisher()
|
eventPublisher := events.NewEventPublisher()
|
||||||
|
|
||||||
|
|
@ -167,21 +173,23 @@ func (svc *service) StartSubscription(ctx context.Context, sub *nostr.Subscripti
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func finishRestoreNode(workDir string) {
|
func finishRestoreNode(workDir string) error {
|
||||||
restoreDir := filepath.Join(workDir, "restore")
|
restoreDir := filepath.Join(workDir, "restore")
|
||||||
if restoreDirStat, err := os.Stat(restoreDir); err == nil && restoreDirStat.IsDir() {
|
if restoreDirStat, err := os.Stat(restoreDir); err == nil && restoreDirStat.IsDir() {
|
||||||
logger.Logger.WithField("restoreDir", restoreDir).Infof("Restore directory found. Finishing Node restore")
|
logger.Logger.WithField("restoreDir", restoreDir).Infof("Restore directory found. Finishing Node restore")
|
||||||
|
|
||||||
existingFiles, err := os.ReadDir(restoreDir)
|
existingFiles, err := os.ReadDir(restoreDir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Logger.WithError(err).Fatal("Failed to read WORK_DIR")
|
logger.Logger.WithError(err).Error("Failed to read WORK_DIR")
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, file := range existingFiles {
|
for _, file := range existingFiles {
|
||||||
if file.Name() != "restore" {
|
if file.Name() != "restore" {
|
||||||
err = os.RemoveAll(filepath.Join(workDir, file.Name()))
|
err = os.RemoveAll(filepath.Join(workDir, file.Name()))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Logger.WithField("filename", file.Name()).WithError(err).Fatal("Failed to remove file")
|
logger.Logger.WithField("filename", file.Name()).WithError(err).Error("Failed to remove file")
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
logger.Logger.WithField("filename", file.Name()).Info("removed file")
|
logger.Logger.WithField("filename", file.Name()).Info("removed file")
|
||||||
}
|
}
|
||||||
|
|
@ -189,31 +197,33 @@ func finishRestoreNode(workDir string) {
|
||||||
|
|
||||||
files, err := os.ReadDir(restoreDir)
|
files, err := os.ReadDir(restoreDir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Logger.WithError(err).Fatal("Failed to read restore directory")
|
logger.Logger.WithError(err).Error("Failed to read restore directory")
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
for _, file := range files {
|
for _, file := range files {
|
||||||
err = os.Rename(filepath.Join(restoreDir, file.Name()), filepath.Join(workDir, file.Name()))
|
err = os.Rename(filepath.Join(restoreDir, file.Name()), filepath.Join(workDir, file.Name()))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Logger.WithField("filename", file.Name()).WithError(err).Fatal("Failed to move file")
|
logger.Logger.WithField("filename", file.Name()).WithError(err).Error("Failed to move file")
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
logger.Logger.WithField("filename", file.Name()).Info("copied file from restore directory")
|
logger.Logger.WithField("filename", file.Name()).Info("copied file from restore directory")
|
||||||
}
|
}
|
||||||
err = os.RemoveAll(restoreDir)
|
err = os.RemoveAll(restoreDir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Logger.WithError(err).Fatal("Failed to remove restore directory")
|
logger.Logger.WithError(err).Error("Failed to remove restore directory")
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
logger.Logger.WithField("restoreDir", restoreDir).Info("removed restore directory")
|
logger.Logger.WithField("restoreDir", restoreDir).Info("removed restore directory")
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (svc *service) Shutdown() {
|
func (svc *service) Shutdown() {
|
||||||
svc.StopApp()
|
svc.StopApp()
|
||||||
svc.eventPublisher.Publish(&events.Event{
|
svc.eventPublisher.PublishSync(&events.Event{
|
||||||
Event: "nwc_stopped",
|
Event: "nwc_stopped",
|
||||||
})
|
})
|
||||||
db.Stop(svc.db)
|
db.Stop(svc.db)
|
||||||
// wait for any remaining events
|
|
||||||
time.Sleep(1 * time.Second)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (svc *service) GetDB() *gorm.DB {
|
func (svc *service) GetDB() *gorm.DB {
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ package service
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"path"
|
"path"
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
@ -29,12 +30,14 @@ func (svc *service) startNostr(ctx context.Context, encryptionKey string) error
|
||||||
|
|
||||||
err := svc.keys.Init(svc.cfg, encryptionKey)
|
err := svc.keys.Init(svc.cfg, encryptionKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Logger.WithError(err).Fatal("Failed to init nostr keys")
|
logger.Logger.WithError(err).Error("Failed to init nostr keys")
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
npub, err := nip19.EncodePublicKey(svc.keys.GetNostrPublicKey())
|
npub, err := nip19.EncodePublicKey(svc.keys.GetNostrPublicKey())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Logger.WithError(err).Fatal("Error converting nostr privkey to pubkey")
|
logger.Logger.WithError(err).Error("Error converting nostr privkey to pubkey")
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.Logger.WithFields(logrus.Fields{
|
logger.Logger.WithFields(logrus.Fields{
|
||||||
|
|
@ -204,7 +207,8 @@ func (svc *service) launchLNBackend(ctx context.Context, encryptionKey string) e
|
||||||
|
|
||||||
lnClient, err = cashu.NewCashuService(cashuWorkdir, cashuMintUrl)
|
lnClient, err = cashu.NewCashuService(cashuWorkdir, cashuMintUrl)
|
||||||
default:
|
default:
|
||||||
logger.Logger.Fatalf("Unsupported LNBackendType: %v", lnBackend)
|
logger.Logger.WithField("backend_type", lnBackend).Error("Unsupported LNBackendType")
|
||||||
|
return fmt.Errorf("unsupported backend type: %s", lnBackend)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Logger.WithError(err).Error("Failed to launch LN backend")
|
logger.Logger.WithError(err).Error("Failed to launch LN backend")
|
||||||
|
|
@ -227,7 +231,10 @@ func (svc *service) launchLNBackend(ctx context.Context, encryptionKey string) e
|
||||||
|
|
||||||
// Mark that the node has successfully started
|
// Mark that the node has successfully started
|
||||||
// This will ensure the user cannot go through the setup again
|
// This will ensure the user cannot go through the setup again
|
||||||
svc.cfg.SetUpdate("NodeLastStartTime", strconv.FormatInt(time.Now().Unix(), 10), "")
|
err = svc.cfg.SetUpdate("NodeLastStartTime", strconv.FormatInt(time.Now().Unix(), 10), "")
|
||||||
|
if err != nil {
|
||||||
|
logger.Logger.WithError(err).Error("Failed to set last node start time")
|
||||||
|
}
|
||||||
|
|
||||||
svc.eventPublisher.Publish(&events.Event{
|
svc.eventPublisher.Publish(&events.Event{
|
||||||
Event: "nwc_node_started",
|
Event: "nwc_node_started",
|
||||||
|
|
|
||||||
|
|
@ -33,10 +33,13 @@ func CreateTestService() (svc *TestService, err error) {
|
||||||
Workdir: ".test",
|
Workdir: ".test",
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg := config.NewConfig(
|
cfg, err := config.NewConfig(
|
||||||
appConfig,
|
appConfig,
|
||||||
gormDb,
|
gormDb,
|
||||||
)
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
keys := keys.NewKeys()
|
keys := keys.NewKeys()
|
||||||
keys.Init(cfg, "")
|
keys.Init(cfg, "")
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@ package wails
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"embed"
|
"embed"
|
||||||
"log"
|
|
||||||
|
|
||||||
"github.com/getAlby/hub/api"
|
"github.com/getAlby/hub/api"
|
||||||
"github.com/getAlby/hub/logger"
|
"github.com/getAlby/hub/logger"
|
||||||
|
|
@ -65,7 +64,7 @@ func LaunchWailsApp(app *WailsApp, assets embed.FS, appIcon []byte) {
|
||||||
})
|
})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("Error %v", err)
|
logger.Logger.WithError(err).Error("failed to run Wails app")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue