synapsecns/sanguine

View on GitHub
contrib/opbot/signoz/example/main.go

Summary

Maintainability
A
2 hrs
Test Coverage
package main

import (
    "context"
    "errors"
    "fmt"
    "github.com/badoux/checkmail"
    "github.com/charmbracelet/huh"
    "github.com/charmbracelet/huh/spinner"
    "github.com/davidmytton/url-verifier"
    "github.com/synapsecns/sanguine/contrib/opbot/signoz"
    "github.com/synapsecns/sanguine/contrib/opbot/signoz/example/keychain"
    "github.com/synapsecns/sanguine/core"
    "github.com/synapsecns/sanguine/core/metrics"
    "os"
)

func main() {
    client := loadConfig()

    resp, err := client.SearchTraces(context.Background(), signoz.Last1Hr, map[string]string{})
    if err != nil {
        panic(err)
    }

    _ = resp
}

const (
    // ConfigPath for plaintext config files.
    ConfigPath = "~/.signoz/"
    // EmailPath path to email file.
    EmailPath = ConfigPath + "email"
    // URLPath path to url file.
    URLPath = ConfigPath + "url"
    // KeychainServiceName (service name for key chain: ios only).
    KeychainServiceName = "signoz-example"
)

type config struct {
    email    string
    url      string
    password string
}

func loadConfig() *signoz.Client {
    cfg := config{}

    var configFormFields []huh.Field

    if cfg.url = readPath(URLPath); cfg.url == "" {
        configFormFields = append(configFormFields, huh.NewInput().
            Value(&cfg.url).
            Title("URL").
            Validate(func(s string) error {
                verifier := urlverifier.NewVerifier()
                if _, err := verifier.Verify(s); err != nil {
                    return fmt.Errorf("invalid URL: %w", err)
                }
                return nil
            }).
            Placeholder("URL Path"))
    }

    if cfg.email = readPath(EmailPath); cfg.email == "" {
        configFormFields = append(configFormFields, huh.NewInput().
            Value(&cfg.email).
            Title("Email").
            Validate(func(s string) error {
                err := checkmail.ValidateFormat(s)
                if err != nil {
                    return fmt.Errorf("invalid email address: %w", err)
                }
                return nil
            }).
            Placeholder("Email Address"))
    }

    var err error
    cfg.password, err = getPassword()
    if err != nil {
        panic(err)
    }

    if cfg.password == "" {
        configFormFields = append(configFormFields, huh.NewInput().
            Value(&cfg.password).
            EchoMode(huh.EchoModePassword).
            Title("Password").
            Placeholder("Password"))
    }

    // if either key is not set, prepend the note to the form
    if len(configFormFields) > 0 {
        configFormFields = append([]huh.Field{
            huh.NewNote().
                Title("Setup Signoz Configuration").
                Next(true).
                Description("Signoz requires an API key to authenticate with the server. You can find your API key in the Signoz dashboard.")}, configFormFields...)

        group := huh.NewGroup(configFormFields...)
        err = huh.NewForm(group).Run()
        if err != nil {
            panic(err)
        }
    }

    // try to login, if it works, save creds otherwise panic!
    var clientErr error
    var client *signoz.Client

    err = spinner.New().
        Title("Logging in...").
        Action(func() {
            client = signoz.NewClientFromUser(metrics.NewNullHandler(), cfg.url, cfg.email, cfg.password)

            _, err := client.Services(context.Background(), signoz.Last1Hr)
            if err != nil {
                clientErr = fmt.Errorf("could not login: %w", err)
            }
        }).Run()
    if err != nil {
        panic(err)
    }

    if clientErr != nil {
        panic(clientErr)
    }

    storeConfig(cfg)

    return client
}

func storeConfig(cfg config) {
    _ = os.MkdirAll(core.ExpandOrReturnPath(ConfigPath), 0700)
    err := os.WriteFile(core.ExpandOrReturnPath(EmailPath), []byte(cfg.email), 0600)
    if err != nil {
        panic(err)
    }

    err = os.WriteFile(core.ExpandOrReturnPath(URLPath), []byte(cfg.url), 0600)
    if err != nil {
        panic(err)
    }

    _, err = getPassword()
    if err != nil {
        item := keychain.NewGenericPassword(KeychainServiceName, KeychainServiceName, "signoz password", []byte(cfg.password), KeychainServiceName)
        err := keychain.AddItem(item)
        if err != nil {
            panic(err)
        }
    }
}

// readPath reads a path.
func readPath(path string) string {
    fileBytes, err := os.ReadFile(core.ExpandOrReturnPath(path))
    if err != nil && !errors.Is(err, os.ErrNotExist) {
        panic(err)
    }

    return string(fileBytes)
}

func getPassword() (string, error) {
    res, err := keychain.GetGenericPassword(KeychainServiceName, KeychainServiceName, "signoz password", KeychainServiceName)
    return string(res), err
}