package firebase import ( "context" fb "firebase.google.com/go/v4" "firebase.google.com/go/v4/auth" "code.nochebuena.dev/go/health" "code.nochebuena.dev/go/launcher" "code.nochebuena.dev/go/logz" "code.nochebuena.dev/go/xerrors" ) // Provider is the minimal interface for consumers that only need the firebase App. type Provider interface { App() *fb.App } // Component adds lifecycle management and health check to Provider. type Component interface { launcher.Component health.Checkable Provider } // Config holds Firebase configuration. type Config struct { // ProjectID is the Google Cloud Project ID. ProjectID string `env:"FIREBASE_PROJECT_ID,required"` } type firebaseComponent struct { cfg Config logger logz.Logger app *fb.App authClient *auth.Client } // New returns a firebase Component. Call lc.Append(fb) to manage its lifecycle. func New(logger logz.Logger, cfg Config) Component { return &firebaseComponent{cfg: cfg, logger: logger} } func (f *firebaseComponent) OnInit() error { if f.cfg.ProjectID == "" { return xerrors.New(xerrors.ErrInvalidInput, "firebase: ProjectID is required") } f.logger.Info("firebase: initializing app", "project_id", f.cfg.ProjectID) app, err := fb.NewApp(context.Background(), &fb.Config{ ProjectID: f.cfg.ProjectID, }) if err != nil { f.logger.Error("firebase: failed to create app", err) return xerrors.Wrap(xerrors.ErrInternal, "firebase: create app", err) } f.app = app authClient, err := app.Auth(context.Background()) if err != nil { return xerrors.Wrap(xerrors.ErrInternal, "firebase: get auth client", err) } f.authClient = authClient return nil } func (f *firebaseComponent) OnStart() error { f.logger.Info("firebase: app ready") return nil } func (f *firebaseComponent) OnStop() error { f.logger.Info("firebase: shutting down") return nil } func (f *firebaseComponent) App() *fb.App { return f.app } func (f *firebaseComponent) HealthCheck(ctx context.Context) error { if f.authClient == nil { return xerrors.New(xerrors.ErrInternal, "firebase: app not initialized") } _, err := f.authClient.GetUser(ctx, "health-probe-non-existent") if err != nil { if auth.IsUserNotFound(err) { return nil // expected: probe of non-existent UID succeeded } return err } return nil } func (f *firebaseComponent) Name() string { return "firebase" } func (f *firebaseComponent) Priority() health.Level { return health.LevelCritical }